From 30175c97ace6c675cdb4d2c505fde1b5df07d477 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 27 Jan 2023 22:01:59 +0000 Subject: [PATCH] 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 --- .../class-wp-rest-autosaves-controller.php | 39 +++++++++---------- .../rest-api/rest-autosaves-controller.php | 34 ++++++++++++++++ 2 files changed, 53 insertions(+), 20 deletions(-) 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 f99a201974..e5409e7329 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 @@ -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 ); diff --git a/tests/phpunit/tests/rest-api/rest-autosaves-controller.php b/tests/phpunit/tests/rest-api/rest-autosaves-controller.php index 088f02b67d..32ba9768e7 100644 --- a/tests/phpunit/tests/rest-api/rest-autosaves-controller.php +++ b/tests/phpunit/tests/rest-api/rest-autosaves-controller.php @@ -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"' ); + } }