Revisions: only create autosave when content changed.

In the autosave REST API endpoint, avoid excessive database writes when an autosave is sent with content that is unchanged from the saved post. 

Before this fix, clicking "preview" in the editor (which uses the autosave feature) multiple times would cause an identical autosave entry to be deleted and re-created repeatedly.

Props inwerpsel, aduth, mukesh27, ironprogrammer.
Fixes #49532.



git-svn-id: https://develop.svn.wordpress.org/trunk@55154 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Adam Silverstein 2023-01-27 22:01:59 +00:00
parent ece2e850ca
commit 30175c97ac
2 changed files with 53 additions and 20 deletions

View File

@ -360,35 +360,34 @@ class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller {
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;
}
}
if ( ! $autosave_is_different ) {
return new WP_Error(
'rest_autosave_no_changes',
__( 'There is nothing to save. The autosave and the post content are the same.' ),
array( 'status' => 400 )
);
}
$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 ) {
$new_autosave = _wp_post_revision_data( $post_data, true );
$new_autosave['ID'] = $old_autosave->ID;
$new_autosave['post_author'] = $user_id;
// If the new autosave has the same content as the post, delete the autosave.
$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( $post->$field ) ) {
$autosave_is_different = true;
break;
}
}
if ( ! $autosave_is_different ) {
wp_delete_post_revision( $old_autosave->ID );
return new WP_Error(
'rest_autosave_no_changes',
__( 'There is nothing to save. The autosave and the post content are the same.' ),
array( 'status' => 400 )
);
}
/** This filter is documented in wp-admin/post.php */
do_action( 'wp_creating_autosave', $new_autosave );

View File

@ -674,4 +674,38 @@ class WP_Test_REST_Autosaves_Controller extends WP_Test_REST_Post_Type_Controlle
wp_delete_post( $post_id );
}
/**
* @ticket 49532
*
* @covers WP_REST_Autosaves_Controller::create_post_autosave
*/
public function test_rest_autosave_do_not_create_autosave_when_post_is_unchanged() {
// Create a post by the editor.
$post_data = array(
'post_content' => 'Test post content',
'post_title' => 'Test post title',
'post_excerpt' => 'Test post excerpt',
'post_author' => self::$editor_id,
'post_status' => 'publish',
);
$post_id = wp_insert_post( $post_data );
wp_set_current_user( self::$editor_id );
$autosave_data = array(
'post_content' => $post_data['post_content'],
);
// Create autosaves response.
$request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . $post_id . '/autosaves' );
$request->add_header( 'content-type', 'application/json' );
$request->set_body( wp_json_encode( $autosave_data ) );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertSame( 400, $response->get_status(), 'Response status is not 400.' );
$this->assertSame( 'rest_autosave_no_changes', $data['code'], 'Response "code" is not "rest_autosave_no_changes"' );
}
}