Make WordPress Core


Ignore:
Timestamp:
09/26/2023 03:30:34 PM (9 months ago)
Author:
adamsilverstein
Message:

Revisions: framework for storing post meta revisions.

Enable the storing of post meta in revisions including autosaves and previews:

Add a new argument revisions_enabled to the register_meta function which enables storing meta in revisions.

Add a new wp_post_revision_meta_keys filter which developers can use to control which meta is revisioned - it passes an array of the meta keys with revisions enabled as well as the post type.

Meta keys with revisions enabled are also stored for autosaves, and are restored when a revision or autosave is restored. In addition, meta values are now stored with the autosave revision used for previews. Changes to meta can now be previewed correctly without overwriting the published meta (see #20299) or passing data as a query variable, as the editor currently does to preview changes to the featured image.

Changes to meta with revisions enabled are considered when determining if a new revision should be created. A new revision is created if the meta value has changed since the last revision.

Revisions are now saved on the wp_after_insert_post hook instead of post_updated. The wp_after_insert_post action is fired after post meta has been saved by the REST API which enables attaching meta to the revision. To ensure backwards compatibility with existing action uses, wp_save_post_revision_on_insert function exits early if plugins have removed the previous do_action( 'post_updated', 'wp_save_post_revision' ) call.

Props: alexkingorg, johnbillion, markjaquith, WraithKenny, kovshenin, azaozz, tv-productions, p51labs, mattheu, mikeschroder, Mamaduka, ellatrix, timothyblynjacobs, jakemgold, bookwyrm, ryanduff, mintindeed, wonderboymusic, sanchothefat, westonruter, spacedmonkey, hellofromTonya, drewapicture, adamsilverstein, swisspiddy.
Fixes #20564, #20299.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/rest-api/rest-post-meta-fields.php

    r56559 r56714  
    1818            array(
    1919                'show_in_rest' => true,
    20                 'supports'     => array( 'custom-fields' ),
     20                'supports'     => array( 'custom-fields', 'revisions' ),
    2121            )
    2222        );
     
    158158            array(
    159159                'show_in_rest' => true,
    160                 'supports'     => array( 'custom-fields' ),
     160                'supports'     => array( 'custom-fields', 'revisions' ),
    161161            )
    162162        );
     
    13771377     */
    13781378    public function test_update_value_return_success_with_same_value( $meta_key, $meta_value ) {
    1379         add_post_meta( self::$post_id, $meta_key, $meta_value );
    1380 
    13811379        $this->grant_write_permission();
    13821380
     
    13931391
    13941392        $this->assertSame( 200, $response->get_status() );
     1393
     1394        // Verify the returned meta value is correct.
     1395        $data = $response->get_data();
     1396        $this->assertArrayHasKey( 'meta', $data );
     1397        $this->assertArrayHasKey( $meta_key, $data['meta'] );
     1398        $this->assertSame( $meta_value, $data['meta'][ $meta_key ] );
    13951399    }
    13961400
     
    31133117        return $query;
    31143118    }
     3119
     3120
     3121    /**
     3122     * Test that single post meta is revisioned when saving to the posts REST API endpoint.
     3123     *
     3124     * @ticket 20564
     3125     */
     3126    public function test_revisioned_single_post_meta_with_posts_endpoint() {
     3127        $this->grant_write_permission();
     3128
     3129        register_post_meta(
     3130            'post',
     3131            'foo',
     3132            array(
     3133                'single'            => true,
     3134                'show_in_rest'      => true,
     3135                'revisions_enabled' => true,
     3136            )
     3137        );
     3138
     3139        $post_id = self::$post_id;
     3140
     3141        // Update the post, saving the meta.
     3142        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
     3143        $request->set_body_params(
     3144            array(
     3145                'title' => 'Revision 1',
     3146                'meta'  => array(
     3147                    'foo' => 'bar',
     3148                ),
     3149            )
     3150        );
     3151        $response = rest_get_server()->dispatch( $request );
     3152        $this->assertSame( 200, $response->get_status() );
     3153
     3154        // Get the last revision.
     3155        $revisions   = wp_get_post_revisions( $post_id, array( 'posts_per_page' => 1 ) );
     3156        $revision_id = array_shift( $revisions )->ID;
     3157
     3158        // @todo Ensure the revisions endpoint returns the correct meta values
     3159        // Check that the revisions endpoint returns the correct meta value.
     3160        $request  = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/revisions/%d', $post_id, $revision_id ) );
     3161        $response = rest_get_server()->dispatch( $request );
     3162        $this->assertSame( 200, $response->get_status() );
     3163        $data = $response->get_data();
     3164        $this->assertSame( 'bar', $response->get_data()['meta']['foo'] );
     3165
     3166        // Check that the post meta is set correctly.
     3167        $this->assertSame( 'bar', get_post_meta( $revision_id, 'foo', true ) );
     3168
     3169        // Create two more revisions with different meta values for the foo key.
     3170        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
     3171        $request->set_body_params(
     3172            array(
     3173                'title' => 'Revision 2',
     3174                'meta'  => array(
     3175                    'foo' => 'baz',
     3176                ),
     3177            )
     3178        );
     3179        $response = rest_get_server()->dispatch( $request );
     3180        $this->assertSame( 200, $response->get_status() );
     3181
     3182        // Get the last revision.
     3183        $revisions     = wp_get_post_revisions( $post_id, array( 'posts_per_page' => 1 ) );
     3184        $revision_id_2 = array_shift( $revisions )->ID;
     3185
     3186        // Check that the revision has the correct meta value.
     3187        $request  = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/revisions/%d', $post_id, $revision_id_2 ) );
     3188        $response = rest_get_server()->dispatch( $request );
     3189        $this->assertSame( 200, $response->get_status() );
     3190        $this->assertSame( 'baz', $response->get_data()['meta']['foo'] );
     3191
     3192        // Check that the post meta is set correctly.
     3193        $this->assertSame( 'baz', get_post_meta( $revision_id_2, 'foo', true ) );
     3194
     3195        // One more revision!
     3196        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
     3197        $request->set_body_params(
     3198            array(
     3199                'title' => 'Revision 3',
     3200                'meta'  => array(
     3201                    'foo' => 'qux',
     3202                ),
     3203            )
     3204        );
     3205        $response = rest_get_server()->dispatch( $request );
     3206        $this->assertSame( 200, $response->get_status() );
     3207
     3208        // Get the last revision.
     3209        $revisions     = wp_get_post_revisions( $post_id, array( 'posts_per_page' => 1 ) );
     3210        $revision_id_3 = array_shift( $revisions )->ID;
     3211
     3212        // Check that the revision has the correct meta value.
     3213        $request  = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/revisions/%d', $post_id, $revision_id_3 ) );
     3214        $response = rest_get_server()->dispatch( $request );
     3215        $this->assertSame( 200, $response->get_status() );
     3216        $this->assertSame( 'qux', $response->get_data()['meta']['foo'] );
     3217
     3218        // Check that the post meta is set correctly.
     3219        $this->assertSame( 'qux', get_post_meta( $revision_id_3, 'foo', true ) );
     3220
     3221        // Restore Revision 3 and verify the post gets the correct meta value.
     3222        wp_restore_post_revision( $revision_id_3 );
     3223        $this->assertSame( 'qux', get_post_meta( $post_id, 'foo', true ) );
     3224
     3225        // Restore Revision 2 and verify the post gets the correct meta value.
     3226        wp_restore_post_revision( $revision_id_2 );
     3227        $this->assertSame( 'baz', get_post_meta( $post_id, 'foo', true ) );
     3228    }
     3229
     3230    /**
     3231     * Test that multi-post meta is revisioned when saving to the posts REST API endpoint.
     3232     *
     3233     * @ticket 20564
     3234     */
     3235    public function test_revisioned_multiple_post_meta_with_posts_endpoint() {
     3236        $this->grant_write_permission();
     3237
     3238        register_post_meta(
     3239            'post',
     3240            'foo',
     3241            array(
     3242                'single'            => false,
     3243                'show_in_rest'      => true,
     3244                'revisions_enabled' => true,
     3245            )
     3246        );
     3247
     3248        $post_id = self::$post_id;
     3249
     3250        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
     3251        $request->set_body_params(
     3252            array(
     3253                'title' => 'Revision 1',
     3254                'meta'  => array(
     3255                    'foo' => array(
     3256                        'bar',
     3257                        'bat',
     3258                        'baz',
     3259                    ),
     3260                ),
     3261            )
     3262        );
     3263        $response = rest_get_server()->dispatch( $request );
     3264        $this->assertSame( 200, $response->get_status() );
     3265
     3266        // Log the current post meta.
     3267        $meta = get_post_meta( $post_id );
     3268
     3269        // Update the post.
     3270        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
     3271        $request->set_body_params(
     3272            array(
     3273                'title' => 'Revision 1 update',
     3274            )
     3275        );
     3276        $response = rest_get_server()->dispatch( $request );
     3277        $this->assertSame( 200, $response->get_status() );
     3278
     3279        // Get the last revision.
     3280        $revisions     = wp_get_post_revisions( $post_id, array( 'posts_per_page' => 1 ) );
     3281        $revision_id_1 = array_shift( $revisions )->ID;
     3282
     3283        // Check that the revision has the correct meta value.
     3284        $request  = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/revisions/%d', $post_id, $revision_id_1 ) );
     3285        $response = rest_get_server()->dispatch( $request );
     3286        $this->assertSame( 200, $response->get_status() );
     3287
     3288        $this->assertSame(
     3289            array( 'bar', 'bat', 'baz' ),
     3290            $response->get_data()['meta']['foo']
     3291        );
     3292        $this->assertSame(
     3293            array( 'bar', 'bat', 'baz' ),
     3294            get_post_meta( $revision_id_1, 'foo' )
     3295        );
     3296
     3297        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
     3298        $request->set_body_params(
     3299            array(
     3300                'title' => 'Revision 2',
     3301                'meta'  => array(
     3302                    'foo' => array(
     3303                        'car',
     3304                        'cat',
     3305                    ),
     3306                ),
     3307            )
     3308        );
     3309        $response = rest_get_server()->dispatch( $request );
     3310        $this->assertSame( 200, $response->get_status() );
     3311
     3312        // Get the last revision.
     3313        $revisions     = wp_get_post_revisions( $post_id, array( 'posts_per_page' => 1 ) );
     3314        $revision_id_2 = array_shift( $revisions )->ID;
     3315
     3316        // Check that the revision has the correct meta value.
     3317        $request  = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/revisions/%d', $post_id, $revision_id_2 ) );
     3318        $response = rest_get_server()->dispatch( $request );
     3319        $this->assertSame( 200, $response->get_status() );
     3320
     3321        $this->assertSame(
     3322            array( 'car', 'cat' ),
     3323            $response->get_data()['meta']['foo']
     3324        );
     3325        $this->assertSame( array( 'car', 'cat' ), get_post_meta( $revision_id_2, 'foo' ) );
     3326
     3327        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
     3328        $request->set_body_params(
     3329            array(
     3330                'title' => 'Revision 3',
     3331                'meta'  => array(
     3332                    'foo' => null,
     3333                ),
     3334            )
     3335        );
     3336        $response = rest_get_server()->dispatch( $request );
     3337        $this->assertSame( 200, $response->get_status() );
     3338
     3339        // Get the last revision.
     3340        $revisions     = wp_get_post_revisions( $post_id, array( 'posts_per_page' => 1 ) );
     3341        $revision_id_3 = array_shift( $revisions )->ID;
     3342
     3343        // Check that the revision has the correct meta value.
     3344        $request  = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/revisions/%d', $post_id, $revision_id_3 ) );
     3345        $response = rest_get_server()->dispatch( $request );
     3346        $this->assertSame( 200, $response->get_status() );
     3347
     3348        $this->assertSame(
     3349            array(),
     3350            $response->get_data()['meta']['foo']
     3351        );
     3352        $this->assertSame( array(), get_post_meta( $revision_id_3, 'foo' ) );
     3353
     3354        // Restore Revision 3 and verify the post gets the correct meta value.
     3355        wp_restore_post_revision( $revision_id_3 );
     3356        $this->assertSame( array(), get_post_meta( $post_id, 'foo' ) );
     3357
     3358        // Restore Revision 2 and verify the post gets the correct meta value.
     3359        wp_restore_post_revision( $revision_id_2 );
     3360        $this->assertSame( array( 'car', 'cat' ), get_post_meta( $post_id, 'foo' ) );
     3361    }
     3362
     3363    /**
     3364     * Test post meta revisions with a custom post type and the page post type.
     3365     *
     3366     * @group revision
     3367     * @dataProvider test_revisioned_single_post_meta_with_posts_endpoint_page_and_cpt_data_provider
     3368     */
     3369    public function test_revisioned_single_post_meta_with_posts_endpoint_page_and_cpt( $passed, $expected, $post_type ) {
     3370
     3371        $this->grant_write_permission();
     3372
     3373        // Create the custom meta.
     3374        register_post_meta(
     3375            $post_type,
     3376            'foo',
     3377            array(
     3378                'show_in_rest'      => true,
     3379                'revisions_enabled' => true,
     3380                'single'            => true,
     3381                'type'              => 'string',
     3382            )
     3383        );
     3384
     3385        // Set up a new post.
     3386        $post_id = $this->factory->post->create(
     3387            array(
     3388                'post_content' => 'initial content',
     3389                'post_type'    => $post_type,
     3390                'meta_input'   => array(
     3391                    'foo' => 'foo',
     3392                ),
     3393            )
     3394        );
     3395
     3396        $plural_mapping = array(
     3397            'page' => 'pages',
     3398            'cpt'  => 'cpt',
     3399        );
     3400        $request        = new WP_REST_Request( 'GET', sprintf( '/wp/v2/%s', $plural_mapping[ $post_type ] ) );
     3401
     3402        $response = rest_get_server()->dispatch( $request );
     3403
     3404        $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/%s/%d', $plural_mapping[ $post_type ], $post_id ) );
     3405        $request->set_body_params(
     3406            array(
     3407                'title' => 'Revision 1',
     3408                'meta'  => array(
     3409                    'foo' => $passed,
     3410                ),
     3411            )
     3412        );
     3413
     3414        $response = rest_get_server()->dispatch( $request );
     3415        $this->assertSame( 200, $response->get_status() );
     3416
     3417        // Update the post.
     3418        $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/%s/%d', $plural_mapping[ $post_type ], $post_id ) );
     3419        $request->set_body_params(
     3420            array(
     3421                'title' => 'Revision 1 update',
     3422            )
     3423        );
     3424        $response = rest_get_server()->dispatch( $request );
     3425        $this->assertSame( 200, $response->get_status() );
     3426
     3427        // Get the last revision.
     3428        $revisions = wp_get_post_revisions( $post_id, array( 'posts_per_page' => 1 ) );
     3429
     3430        $revision_id_1 = array_shift( $revisions )->ID;
     3431
     3432        // Check that the revision has the correct meta value.
     3433        $request  = new WP_REST_Request( 'GET', sprintf( '/wp/v2/%s/%d/revisions/%d', $plural_mapping[ $post_type ], $post_id, $revision_id_1 ) );
     3434        $response = rest_get_server()->dispatch( $request );
     3435        $this->assertSame( 200, $response->get_status() );
     3436
     3437        $this->assertSame(
     3438            $passed,
     3439            $response->get_data()['meta']['foo']
     3440        );
     3441
     3442        $this->assertSame(
     3443            array( $passed ),
     3444            get_post_meta( $revision_id_1, 'foo' )
     3445        );
     3446
     3447        unregister_post_meta( $post_type, 'foo' );
     3448        wp_delete_post( $post_id, true );
     3449    }
     3450
     3451    /**
     3452     * Provide data for the meta revision checks.
     3453     */
     3454    public function test_revisioned_single_post_meta_with_posts_endpoint_page_and_cpt_data_provider() {
     3455        return array(
     3456            array(
     3457                'Test string',
     3458                'Test string',
     3459                'cpt',
     3460            ),
     3461            array(
     3462                'Test string',
     3463                'Test string',
     3464                'page',
     3465            ),
     3466            array(
     3467                'Test string',
     3468                false,
     3469                'cpt',
     3470            ),
     3471
     3472        );
     3473    }
    31153474}
Note: See TracChangeset for help on using the changeset viewer.