diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php index 65ca4e0018cb6..00924b79a15e0 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php @@ -370,13 +370,14 @@ public function get_item_schema() { * * @since 5.0.0 * @since 6.4.0 The `$meta` parameter was added. + * @since 7.1.0 Compares incoming data against the existing autosave instead + * of the published post. * * @param array $post_data Associative array containing the post data. * @param array $meta Associative array containing the post meta data. * @return mixed The autosave revision ID or WP_Error. */ public function create_post_autosave( $post_data, array $meta = array() ) { - $post_id = (int) $post_data['ID']; $post = get_post( $post_id ); @@ -384,43 +385,54 @@ public function create_post_autosave( $post_data, array $meta = array() ) { return $post; } - // Only create an autosave when it is different from the saved post. - $autosave_is_different = false; - $new_autosave = _wp_post_revision_data( $post_data, true ); - - foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $post ) ) ) as $field ) { - if ( normalize_whitespace( $new_autosave[ $field ] ) !== normalize_whitespace( $post->$field ) ) { - $autosave_is_different = true; - break; - } - } + $new_autosave = _wp_post_revision_data( $post_data, true ); - // Check if meta values have changed. if ( ! empty( $meta ) ) { $revisioned_meta_keys = wp_post_revision_meta_keys( $post->post_type ); - foreach ( $revisioned_meta_keys as $meta_key ) { - // get_metadata_raw is used to avoid retrieving the default value. - $old_meta = get_metadata_raw( 'post', $post_id, $meta_key, true ); - $new_meta = $meta[ $meta_key ] ?? ''; + } - if ( $new_meta !== $old_meta ) { + $user_id = get_current_user_id(); + + // Store one autosave per author. If there is already an autosave, overwrite it. + $old_autosave = wp_get_post_autosave( $post_id, $user_id ); + + if ( $old_autosave ) { + /* + * When an autosave revision already exists, compare the incoming data + * against its current field values rather than the published post. A field + * reverted to the published value - such as a title edit that was undone - + * must still overwrite any stale value in the existing autosave, otherwise + * consumers like Preview will display incorrect content indefinitely. + */ + $autosave_is_different = false; + foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $post ) ) ) as $field ) { + if ( normalize_whitespace( $new_autosave[ $field ] ) !== normalize_whitespace( $old_autosave->$field ) ) { $autosave_is_different = true; break; } } - } - $user_id = get_current_user_id(); + if ( ! $autosave_is_different && ! empty( $meta ) ) { + foreach ( $revisioned_meta_keys as $meta_key ) { + if ( ! array_key_exists( $meta_key, $meta ) ) { + continue; + } - // Store one autosave per author. If there is already an autosave, overwrite it. - $old_autosave = wp_get_post_autosave( $post_id, $user_id ); + $old_meta_value = get_metadata_raw( 'post', $old_autosave->ID, $meta_key, true ); + $new_meta_value = $meta[ $meta_key ]; - if ( ! $autosave_is_different && $old_autosave ) { - // Nothing to save, return the existing autosave. - return $old_autosave->ID; - } + if ( $new_meta_value !== $old_meta_value ) { + $autosave_is_different = true; + break; + } + } + } + + if ( ! $autosave_is_different ) { + // Nothing to save, return the existing autosave. + return $old_autosave->ID; + } - if ( $old_autosave ) { $new_autosave['ID'] = $old_autosave->ID; $new_autosave['post_author'] = $user_id; diff --git a/tests/phpunit/tests/rest-api/rest-autosaves-controller.php b/tests/phpunit/tests/rest-api/rest-autosaves-controller.php index 7815f8ced23c9..7b43f6354faf9 100644 --- a/tests/phpunit/tests/rest-api/rest-autosaves-controller.php +++ b/tests/phpunit/tests/rest-api/rest-autosaves-controller.php @@ -920,4 +920,38 @@ public static function data_head_request_with_specified_fields_returns_success_r 'get_items request' => array( '/wp/v2/posts/%d' ), ); } + + /** + * @ticket 65694 + */ + public function test_create_post_autosave_updates_stale_field_on_revert() { + wp_set_current_user( self::$editor_id ); + + $post_id = $this->factory->post->create( + array( + 'post_title' => 'Original Title', + 'post_status' => 'publish', + 'post_author' => self::$editor_id, + ) + ); + + $controller = new WP_REST_Autosaves_Controller( 'post' ); + + $controller->create_post_autosave( + array( + 'ID' => $post_id, + 'post_title' => 'Original Title !!', + ) + ); + + $controller->create_post_autosave( + array( + 'ID' => $post_id, + 'post_title' => 'Original Title', + ) + ); + + $autosave = wp_get_post_autosave( $post_id, self::$editor_id ); + $this->assertSame( 'Original Title', $autosave->post_title ); + } }