Skip to content

Visual Revisions fail to restore meta controlled by Classic Meta Boxes #78130

Description

@karthikeya-io

Description

  1. Restoring a revision via the Visual Revisions screen does not successfully restore meta values that are controlled by a Classic Meta Box. However, meta controlled by a Gutenberg block/sidebar restores correctly. In the classic revisions screen, both restore properly.
  2. In the Visual Revisions sidebar, long meta keys overlap visually with the diff text values , making it unreadable.

#74742 (comment)

Step-by-step reproduction instructions

  1. Register one classic meta box and one Gutenberg sidebar meta field, ensuring both support revisions.
  2. Create a new post.
  3. Enter a value into the "Classic Meta Field" (meta box).
  4. Enter a value into the "Gutenberg Meta Field" (sidebar panel).
  5. Publish or save the post.
  6. Modify both values and update the post to generate a revision.
  7. Open the Visual Revisions screen.
  8. Observe the UI: Look at the "Meta" section in the right sidebar and notice that the long meta keys overlap with the value text.
  9. Click Restore to revert to the previous revision.
  10. Observe the result: The Gutenberg Meta Field will have successfully restored to its previous value, but the Classic Meta Field will remain at the newer value.
Code I used to register the meta:

<?php
/**
 * Plugin Name: MyGuten Separate Meta Test
 * Description: Classic meta box + Gutenberg sidebar meta field, both REST and revision enabled.
 * Version: 1.0.0
 */

if (!defined('ABSPATH')) {
    exit;
}

const MYGUTEN_CLASSIC_META_KEY = 'myguten_classic_meta_field';
const MYGUTEN_GUTENBERG_META_KEY = 'myguten_gutenberg_meta_field';

/**
 * Register meta fields.
 */
add_action('init', function() {
    $common_args = [
        'type'              => 'string',
        'single'            => true,
        'show_in_rest'      => true,
        'revisions_enabled' => true,
        'sanitize_callback' => 'sanitize_text_field',
        'auth_callback'     => function () {
            return current_user_can('edit_posts');
        },
    ];

    register_post_meta('post', MYGUTEN_CLASSIC_META_KEY, $common_args);
    register_post_meta('post', MYGUTEN_GUTENBERG_META_KEY, $common_args);
});

/**
 * Show meta fields in revisions
 */
add_filter( '_wp_post_revision_fields', function( $fields ) {
    $fields[ MYGUTEN_CLASSIC_META_KEY ] = 'Classic Meta Field';
    $fields[ MYGUTEN_GUTENBERG_META_KEY ] = 'Gutenberg Meta Field';
    return $fields;
} );

/**
 * Enqueue Block Editor Assets
 */
add_action('enqueue_block_editor_assets', function() {
    $script_path = plugin_dir_path(__FILE__) . 'sidebar.js';
    wp_enqueue_script(
        'myguten-meta-sidebar',
        plugin_dir_url(__FILE__) . 'sidebar.js',
        ['wp-plugins', 'wp-edit-post', 'wp-element', 'wp-components', 'wp-data', 'wp-core-data'],
        file_exists($script_path) ? filemtime($script_path) : '1.0.0',
        true
    );
});

/**
 * Classic Meta Box Setup
 */
add_action('add_meta_boxes', function() {
    add_meta_box(
        'myguten_classic_meta_box',
        'Classic Meta Field',
        'myguten_render_classic_meta_box',
        'post',
        'side'
    );
});

function myguten_render_classic_meta_box($post) {
    $value = get_post_meta($post->ID, MYGUTEN_CLASSIC_META_KEY, true);
    wp_nonce_field('myguten_save_classic_meta', 'myguten_nonce');
    
    printf(
        '<input type="text" name="%1$s" value="%2$s" style="width:100%%;" />',
        esc_attr(MYGUTEN_CLASSIC_META_KEY),
        esc_attr($value)
    );
}

/**
 * Save Classic Meta
 */
add_action('save_post_post', function($post_id) {
    if (!isset($_POST['myguten_nonce']) || !wp_verify_nonce($_POST['myguten_nonce'], 'myguten_save_classic_meta')) {
        return;
    }

    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    if (!current_user_can('edit_post', $post_id)) return;

    if (isset($_POST['myguten_classic_meta_field'])) {
        update_post_meta($post_id, MYGUTEN_CLASSIC_META_KEY, sanitize_text_field(wp_unslash($_POST['myguten_classic_meta_field'])));
    }
});
( function ( wp ) {
    const { registerPlugin } = wp.plugins;
    const { PluginDocumentSettingPanel } = wp.editPost;
    const { TextControl } = wp.components;
    const { useSelect, useDispatch } = wp.data; // Added useDispatch for more control if needed
    const { useEntityProp } = wp.coreData;
    const { createElement: el } = wp.element;
    const { __ } = wp.i18n; // For translations

    const META_KEY = 'myguten_gutenberg_meta_field';

    function MyGutenMetaPanel() {
        const postType = useSelect( ( select ) => {
            return select( 'core/editor' ).getCurrentPostType();
        }, [] );

        if ( ! [ 'post' ].includes( postType ) ) {
            return null;
        }

        const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );

        const value = meta?.[ META_KEY ] || '';

        const updateValue = ( newValue ) => {
            setMeta( {
                ...meta,
                [ META_KEY ]: newValue,
            } );
        };

        return el(
            PluginDocumentSettingPanel,
            {
                name: 'myguten-meta-sidebar-panel',
                title: __( 'Meta block Field', 'my-text-domain' ),
                className: 'myguten-meta-sidebar-panel',
            },
            el( TextControl, {
                label: __( 'Gutenberg Meta Field', 'my-text-domain' ),
                value: value,
                onChange: updateValue,
                help: __( 'This field saves to separate Gutenberg post meta.', 'my-text-domain' ),
            } )
        );
    }

    registerPlugin( 'myguten-meta-sidebar', {
        render: MyGutenMetaPanel,
        // Optional: icon: 'admin-settings',
    } );
} )( window.wp );

Screenshots, screen recording, code snippet

Classic Revisions Visual Revisions
classic-revisions.mp4
visual-revision.mp4

Environment info

No response

Please confirm that you have searched existing issues in the repo.

  • Yes

Please confirm that you have tested with all plugins deactivated except Gutenberg.

  • Yes

Please confirm which theme type you used for testing.

  • Block
  • Classic
  • Hybrid (e.g. classic with theme.json)
  • Not sure

Activity

  1. t-hamano commented on May 11, 2026

    @t-hamano
    Contributor

    Thanks for the report.

    Restoring a revision via the Visual Revisions screen does not successfully restore meta values that are controlled by a Classic Meta Box. However, meta controlled by a Gutenberg block/sidebar restores correctly. In the classic revisions screen, both restore properly.

    We may need to disable the visual revision diff if the metabox is enabled. cc @ellatrix

    In the Visual Revisions sidebar, long meta keys overlap visually with the diff text values , making it unreadable.

    I believe this is an issue that can be fixed separately from the metabox.

  2. Mustafabharmal commented on May 11, 2026

    @Mustafabharmal
    Contributor

    I'm working on a fix for this. The root cause for the meta restoration bug is that after restoreRevision calls savePost(), the editor.savePost hook fires requestMetaBoxUpdates() which resubmits the classic meta box form fields with their current (unreverted) DOM values, overwriting the meta values just restored via the REST API. The fix is to pass an isRevisionsRestore flag to savePost() so the hook skips the meta box resubmission. The label overlap issue will be fixed with word-break: break-word on the panel row label.

  3. moved this from 📥 Todo to 📋 Iteration/Tracking Issues in WordPress 7.0 Editor Taskson May 11, 2026
  4. moved this from 📋 Iteration/Tracking Issues to 📥 Todo in WordPress 7.0 Editor Taskson May 11, 2026
  5. ellatrix commented on May 12, 2026

    @ellatrix
    Member

    I think we should probably disable if there's classic meta boxes, but it's kind of a pity. I'd love to hear more opinions, but disabling seems like the safer thing to do at this stage.

  6. t-hamano commented on May 13, 2026

    @t-hamano
    Contributor

    @Mustafabharmal, can you split #78156 into two PRs? Splitting into two PRs is easier to review and make decisions on than addressing two bugs in one PR. The two bugs are completely different in nature.

  7. moved this from 📥 Todo to 📋 Iteration/Tracking Issues in WordPress 7.0 Editor Taskson May 13, 2026
  8. ellatrix commented on May 13, 2026

    @ellatrix
    Member

    Also made a PR in #78249.

    Alternatively we have to restore on the server and reload the editor.

  9. moved this from 📋 Iteration/Tracking Issues to ✅ Done in WordPress 7.0 Editor Taskson May 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

[Feature] HistoryHistory, undo, redo, revisions, autosave.[Status] In ProgressTracking issues with work in progress[Type] BugAn existing feature does not function as intended

Type

No type

Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions