Make WordPress Core

Changeset 55154


Ignore:
Timestamp:
01/27/2023 10:01:59 PM (16 months ago)
Author:
adamsilverstein
Message:

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.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php

    r54130 r55154  
    361361        }
    362362
     363        // Only create an autosave when it is different from the saved post.
     364        $autosave_is_different = false;
     365        $new_autosave          = _wp_post_revision_data( $post_data, true );
     366
     367        foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $post ) ) ) as $field ) {
     368            if ( normalize_whitespace( $new_autosave[ $field ] ) !== normalize_whitespace( $post->$field ) ) {
     369                $autosave_is_different = true;
     370                break;
     371            }
     372        }
     373
     374        if ( ! $autosave_is_different ) {
     375            return new WP_Error(
     376                'rest_autosave_no_changes',
     377                __( 'There is nothing to save. The autosave and the post content are the same.' ),
     378                array( 'status' => 400 )
     379            );
     380        }
     381
    363382        $user_id = get_current_user_id();
    364383
     
    367386
    368387        if ( $old_autosave ) {
    369             $new_autosave                = _wp_post_revision_data( $post_data, true );
    370388            $new_autosave['ID']          = $old_autosave->ID;
    371389            $new_autosave['post_author'] = $user_id;
    372 
    373             // If the new autosave has the same content as the post, delete the autosave.
    374             $autosave_is_different = false;
    375 
    376             foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $post ) ) ) as $field ) {
    377                 if ( normalize_whitespace( $new_autosave[ $field ] ) !== normalize_whitespace( $post->$field ) ) {
    378                     $autosave_is_different = true;
    379                     break;
    380                 }
    381             }
    382 
    383             if ( ! $autosave_is_different ) {
    384                 wp_delete_post_revision( $old_autosave->ID );
    385                 return new WP_Error(
    386                     'rest_autosave_no_changes',
    387                     __( 'There is nothing to save. The autosave and the post content are the same.' ),
    388                     array( 'status' => 400 )
    389                 );
    390             }
    391390
    392391            /** This filter is documented in wp-admin/post.php */
  • trunk/tests/phpunit/tests/rest-api/rest-autosaves-controller.php

    r55104 r55154  
    675675        wp_delete_post( $post_id );
    676676    }
     677
     678    /**
     679     * @ticket 49532
     680     *
     681     * @covers WP_REST_Autosaves_Controller::create_post_autosave
     682     */
     683    public function test_rest_autosave_do_not_create_autosave_when_post_is_unchanged() {
     684        // Create a post by the editor.
     685        $post_data = array(
     686            'post_content' => 'Test post content',
     687            'post_title'   => 'Test post title',
     688            'post_excerpt' => 'Test post excerpt',
     689            'post_author'  => self::$editor_id,
     690            'post_status'  => 'publish',
     691        );
     692        $post_id   = wp_insert_post( $post_data );
     693
     694        wp_set_current_user( self::$editor_id );
     695
     696        $autosave_data = array(
     697            'post_content' => $post_data['post_content'],
     698        );
     699
     700        // Create autosaves response.
     701        $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . $post_id . '/autosaves' );
     702        $request->add_header( 'content-type', 'application/json' );
     703        $request->set_body( wp_json_encode( $autosave_data ) );
     704
     705        $response = rest_get_server()->dispatch( $request );
     706        $data     = $response->get_data();
     707
     708        $this->assertSame( 400, $response->get_status(), 'Response status is not 400.' );
     709        $this->assertSame( 'rest_autosave_no_changes', $data['code'], 'Response "code" is not "rest_autosave_no_changes"' );
     710    }
    677711}
Note: See TracChangeset for help on using the changeset viewer.