Commit df893e5505 for wordpress.org

commit df893e5505810bf0eea50b1434fff1c792e8b66e
Author: adamsilverstein <adamsilverstein@git.wordpress.org>
Date:   Mon Oct 26 17:34:53 2026 +0000

    REST API: only include revisioned meta in revision responses.

    Fix an issue where restoring a revision in the editor overwrote meta values that weren't associated with the revision.

    Visual Revisions in the block editor, introduced in 7.0, restores a revision by saving the `meta` returned from the revisions endpoint onto the post. That endpoint returned every `show_in_rest` meta key for the parent post type, but only revisioned keys are stored on a revision, so the rest came back as their default (or `null`) and the restore overwrote the post's real values. Unsynced patterns silently became synced, synced patterns failed to restore with a `rest_invalid_stored_value` error, and any other non-revisioned `show_in_rest` key was reset.

    Introduce `WP_REST_Revision_Meta_Fields`, used by `WP_REST_Revisions_Controller`, which limits a revision's `meta` and its schema to the keys from `wp_post_revision_meta_keys()`. This matches what `wp_restore_post_revision()` restores from the classic revisions screen, and requires no editor change. Autosave responses follow the same rules, since they are prepared by the revisions controller; autosave requests still accept all of the parent post type's meta. Plugins that write meta onto revisions directly should add those keys with the `wp_post_revision_meta_keys` filter to keep them in responses.

    Also fixes https://github.com/WordPress/gutenberg/issues/84809.

    Props dlocc, davidsword, talldanwp, rachelbaker, prasadkarmalkar, umeshnevase.
    Fixes #66329.


    Built from https://develop.svn.wordpress.org/trunk@64731


    git-svn-id: http://core.svn.wordpress.org/trunk@63881 1a063a9b-81f0-0310-95a4-ce76da25c4cd

diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php
index 2dbba2b6d5..9abced65e6 100644
--- a/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php
+++ b/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php
@@ -28,6 +28,7 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
 	 * Instance of a revision meta fields object.
 	 *
 	 * @since 6.4.0
+	 * @since 7.2.0 Now a WP_REST_Revision_Meta_Fields instance, which only exposes revisioned meta keys.
 	 * @var WP_REST_Post_Meta_Fields
 	 */
 	protected $meta;
@@ -68,7 +69,7 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
 		$this->rest_base         = 'revisions';
 		$this->parent_base       = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
 		$this->namespace         = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2';
-		$this->meta              = new WP_REST_Post_Meta_Fields( $parent_post_type );
+		$this->meta              = new WP_REST_Revision_Meta_Fields( $parent_post_type );
 	}

 	/**
@@ -596,6 +597,7 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
 	 * @since 4.7.0
 	 * @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support.
 	 * @since 7.1.0 The global post is now restored to its previous value before returning.
+	 * @since 7.2.0 The `meta` field only includes the meta keys that are revisioned for the parent post type.
 	 *
 	 * @global WP_Post|null $post Global post object.
 	 *
@@ -813,6 +815,7 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
 	 * Retrieves the revision's schema, conforming to JSON Schema.
 	 *
 	 * @since 4.7.0
+	 * @since 7.2.0 The `meta` property only describes the meta keys that are revisioned for the parent post type.
 	 *
 	 * @return array Item schema data.
 	 */
diff --git a/wp-includes/rest-api/fields/class-wp-rest-revision-meta-fields.php b/wp-includes/rest-api/fields/class-wp-rest-revision-meta-fields.php
new file mode 100644
index 0000000000..3db7c0a6dc
--- /dev/null
+++ b/wp-includes/rest-api/fields/class-wp-rest-revision-meta-fields.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * REST API: WP_REST_Revision_Meta_Fields class
+ *
+ * @package WordPress
+ * @subpackage REST_API
+ * @since 7.2.0
+ */
+
+/**
+ * Core class used to read the meta values of post revisions via the REST API.
+ *
+ * Only the meta keys that are revisioned for the parent post type are exposed,
+ * because those are the only values that are stored on a revision. Any other
+ * meta key registered for the post type would be read from the revision ID,
+ * find nothing, and be reported with its default value instead.
+ *
+ * @since 7.2.0
+ *
+ * @see WP_REST_Post_Meta_Fields
+ * @see wp_post_revision_meta_keys()
+ */
+class WP_REST_Revision_Meta_Fields extends WP_REST_Post_Meta_Fields {
+
+	/**
+	 * Retrieves the meta field values for a revision.
+	 *
+	 * When an author autosaves their own draft, the autosaves controller updates
+	 * the post itself and returns it instead of an autosave. That post stores all
+	 * of its meta, so its values are read as regular post meta.
+	 *
+	 * @since 7.2.0
+	 *
+	 * @param int             $object_id Object ID to fetch meta for.
+	 * @param WP_REST_Request $request   Full details about the request.
+	 * @return array Array containing the meta values keyed by name.
+	 */
+	public function get_value( $object_id, $request ) {
+		if ( 'revision' !== get_post_type( $object_id ) ) {
+			$post_meta = new WP_REST_Post_Meta_Fields( $this->post_type );
+			return $post_meta->get_value( $object_id, $request );
+		}
+
+		return parent::get_value( $object_id, $request );
+	}
+
+	/**
+	 * Retrieves the registered meta fields that are revisioned for the parent post type.
+	 *
+	 * @since 7.2.0
+	 *
+	 * @return array Registered fields, limited to the revisioned meta keys.
+	 */
+	protected function get_registered_fields() {
+		// The keys are filterable, so ignore anything that isn't a meta key.
+		$revisioned_keys = array_filter( (array) wp_post_revision_meta_keys( $this->post_type ), 'is_string' );
+
+		return array_intersect_key(
+			parent::get_registered_fields(),
+			array_flip( $revisioned_keys )
+		);
+	}
+}
diff --git a/wp-includes/version.php b/wp-includes/version.php
index bd743353b4..76c3b10660 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '7.2-beta1-64730';
+$wp_version = '7.2-beta1-64731';

 /**
  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
diff --git a/wp-settings.php b/wp-settings.php
index cf8fb4d090..92f9456aa0 100644
--- a/wp-settings.php
+++ b/wp-settings.php
@@ -398,6 +398,7 @@ require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-abilities-v1-run-co
 require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php';
 require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-comment-meta-fields.php';
 require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php';
+require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-revision-meta-fields.php';
 require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-term-meta-fields.php';
 require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-user-meta-fields.php';
 require ABSPATH . WPINC . '/rest-api/search/class-wp-rest-search-handler.php';