Make WordPress Core

Changeset 54130


Ignore:
Timestamp:
09/11/2022 10:33:29 PM (2 years ago)
Author:
antpb
Message:

Autosave/REST API: Block autosaving from overwriting changes when locked from editing.

Previously when a user was locked from editing a post in the block editor, autosave functionality was allowed to overwrite changes made by the editor that has taken control. This patch honors the lock status keeping autosave from conflicitng with other content editors.

Props jhart35, adamsilverstein, sathyapulse, chanthaboune, primetimejas, joemcgill, kadamwhite.
Fixes #55659.

Location:
trunk
Files:
2 edited

Legend:

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

    r51962 r54130  
    221221        $user_id           = get_current_user_id();
    222222
    223         if ( ( 'draft' === $post->post_status || 'auto-draft' === $post->post_status ) && $post->post_author == $user_id ) {
     223        // We need to check post lock to ensure the original author didn't leave their browser tab open.
     224        if ( ! function_exists( 'wp_check_post_lock' ) ) {
     225            require_once ABSPATH . 'wp-admin/includes/post.php';
     226        }
     227
     228        $post_lock = wp_check_post_lock( $post->ID );
     229        $is_draft  = 'draft' === $post->post_status || 'auto-draft' === $post->post_status;
     230
     231        if ( $is_draft && (int) $post->post_author === $user_id && ! $post_lock ) {
    224232            // Draft posts for the same author: autosaving updates the post and does not create a revision.
    225233            // Convert the post object to an array and add slashes, wp_update_post() expects escaped array.
  • trunk/tests/phpunit/tests/rest-api/rest-autosaves-controller.php

    r54058 r54130  
    608608        $this->assertNotEquals( 'garbage', get_post( self::$draft_page_id )->comment_status );
    609609    }
     610
     611    /**
     612     * Test ensuring that autosave from the original author doesn't overwrite changes after it has been taken over by a 2nd author.
     613     *
     614     * @ticket 55659
     615     */
     616    public function test_rest_autosave_draft_post_locked_to_different_author() {
     617
     618        // Create a post by the editor.
     619        $post_data = array(
     620            'post_content' => 'Test post content',
     621            'post_title'   => 'Test post title',
     622            'post_excerpt' => 'Test post excerpt',
     623            'post_author'  => self::$editor_id,
     624            'post_status'  => 'draft',
     625        );
     626        $post_id   = wp_insert_post( $post_data );
     627
     628        // Set the post lock to the contributor, simulating a takeover of the post.
     629        wp_set_current_user( self::$contributor_id );
     630        wp_set_post_lock( $post_id );
     631
     632        // Update the post with new data from the contributor.
     633        $updated_post_data = array(
     634            'ID'           => $post_id,
     635            'post_content' => 'New post content from the contributor',
     636            'post_title'   => 'New post title',
     637        );
     638        wp_update_post( $updated_post_data );
     639
     640        // Set the current user to the editor and initiate an autosave with some new data.
     641        wp_set_current_user( self::$editor_id );
     642        $autosave_data = array(
     643            'id'      => $post_id,
     644            'content' => 'Updated post content',
     645            'excerpt' => 'A new excerpt to test',
     646            'title'   => $post_data['post_title'],
     647        );
     648
     649        // Initiate an autosave via the REST API as Gutenberg does.
     650        $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' );
     651        $request->add_header( 'content-type', 'application/json' );
     652        $request->set_body( wp_json_encode( $autosave_data ) );
     653
     654        $response = rest_get_server()->dispatch( $request );
     655        $new_data = $response->get_data();
     656
     657        // The current version of our test post.
     658        $current_post = get_post( $post_id );
     659
     660        // The new data from the autosave should have its parent ID set to the original post ID.
     661        $this->assertSame( $post_id, $new_data['parent'] );
     662
     663        // The post title and content should still be the updated versions from the contributor.
     664        $this->assertSame( $current_post->post_title, $updated_post_data['post_title'] );
     665        $this->assertSame( $current_post->post_content, $updated_post_data['post_content'] );
     666
     667        // The excerpt should have stayed the same.
     668        $this->assertSame( $current_post->post_excerpt, $post_data['post_excerpt'] );
     669
     670        $autosave_post = wp_get_post_autosave( $post_id );
     671
     672        // Has changes.
     673        $this->assertSame( $autosave_data['content'], $autosave_post->post_content );
     674
     675        wp_delete_post( $post_id );
     676    }
    610677}
Note: See TracChangeset for help on using the changeset viewer.