Make WordPress Core

Changeset 56714

Timestamp:
09/26/2023 03:30:34 PM (10 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.

Location:
trunk
Files:
1 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/post.php

    r56712 r56714  
    19711971         *
    19721972         * @since 4.1.0
     1973
    19731974         *
    19741975         * @param array $new_autosave Post array - the autosave that is about to be saved.
     1976
    19751977         */
    1976         do_action( 'wp_creating_autosave', $new_autosave );
    1977 
     1978        do_action( 'wp_creating_autosave', $new_autosave, true );
    19781979        return wp_update_post( $new_autosave );
    19791980    }
     
    19831984
    19841985    // Otherwise create the new autosave as a special post revision.
    1985     return _wp_put_post_revision( $post_data, true );
     1986    $revision = _wp_put_post_revision( $post_data, true );
     1987
     1988    if ( ! is_wp_error( $revision ) && 0 !== $revision ) {
     1989
     1990        /** This action is documented in wp-admin/includes/post.php */
     1991        do_action( 'wp_creating_autosave', get_post( $revision, ARRAY_A ), false );
     1992    }
     1993
     1994    return $revision;
     1995}
     1996
     1997/**
     1998 * Autosave the revisioned meta fields.
     1999 *
     2000 * Iterates through the revisioned meta fields and checks each to see if they are set,
     2001 * and have a changed value. If so, the meta value is saved and attached to the autosave.
     2002 *
     2003 * @since 6.4.0
     2004 *
     2005 * @param array $new_autosave The new post data being autosaved.
     2006 */
     2007function wp_autosave_post_revisioned_meta_fields( $new_autosave ) {
     2008    /*
     2009     * The post data arrives as either $_POST['data']['wp_autosave'] or the $_POST
     2010     * itself. This sets $posted_data to the correct variable.
     2011     *
     2012     * Ignoring sanitization to avoid altering meta. Ignoring the nonce check because
     2013     * this is hooked on inner core hooks where a valid nonce was already checked.
     2014     *
     2015     * @phpcs:disable WordPress.Security
     2016     */
     2017    $posted_data = isset( $_POST['data']['wp_autosave'] ) ? $_POST['data']['wp_autosave'] : $_POST;
     2018    // phpcs:enable
     2019
     2020    $post_type = get_post_type( $new_autosave['post_parent'] );
     2021
     2022    /*
     2023     * Go thru the revisioned meta keys and save them as part of the autosave, if
     2024     * the meta key is part of the posted data, the meta value is not blank and
     2025     * the the meta value has changes from the last autosaved value.
     2026     */
     2027    foreach ( wp_post_revision_meta_keys( $post_type ) as $meta_key ) {
     2028
     2029        if (
     2030        isset( $posted_data[ $meta_key ] ) &&
     2031        get_post_meta( $new_autosave['ID'], $meta_key, true ) !== wp_unslash( $posted_data[ $meta_key ] )
     2032        ) {
     2033            /*
     2034             * Use the underlying delete_metadata() and add_metadata() functions
     2035             * vs delete_post_meta() and add_post_meta() to make sure we're working
     2036             * with the actual revision meta.
     2037             */
     2038            delete_metadata( 'post', $new_autosave['ID'], $meta_key );
     2039
     2040            /*
     2041             * One last check to ensure meta value not empty().
     2042             */
     2043            if ( ! empty( $posted_data[ $meta_key ] ) ) {
     2044                /*
     2045                 * Add the revisions meta data to the autosave.
     2046                 */
     2047                add_metadata( 'post', $new_autosave['ID'], $meta_key, $posted_data[ $meta_key ] );
     2048            }
     2049        }
     2050    }
    19862051}
    19872052
  • trunk/src/wp-includes/default-filters.php

    r56693 r56714  
    412412add_action( 'shutdown', 'wp_ob_end_flush_all', 1 );
    413413// Create a revision whenever a post is updated.
     414
    414415add_action( 'post_updated', 'wp_save_post_revision', 10, 1 );
    415416add_action( 'publish_post', '_publish_post_hook', 5, 1 );
     
    720721add_action( 'init', 'wp_create_initial_post_meta' );
    721722
     723
     724
     725
     726
     727
     728
     729
     730
     731
     732
     733
     734
    722735// Font management.
    723736add_action( 'wp_head', 'wp_print_font_faces', 50 );
  • trunk/src/wp-includes/meta.php

    r56191 r56714  
    13681368 * @since 5.3.0 Valid meta types expanded to include "array" and "object".
    13691369 * @since 5.5.0 The `$default` argument was added to the arguments array.
     1370
    13701371 *
    13711372 * @param string       $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
     
    13931394 *                                         When registering complex meta values this argument may optionally be an
    13941395 *                                         array with 'schema' or 'prepare_callback' keys instead of a boolean.
     1396
     1397
    13951398 * }
    13961399 * @param string|array $deprecated Deprecated. Use `$args` instead.
     
    14151418        'auth_callback'     => null,
    14161419        'show_in_rest'      => false,
     1420
    14171421    );
    14181422
     
    14611465
    14621466    $object_subtype = ! empty( $args['object_subtype'] ) ? $args['object_subtype'] : '';
     1467
     1468
     1469
     1470
     1471
     1472
     1473
     1474
     1475
     1476
     1477
    14631478
    14641479    // If `auth_callback` is not provided, fall back to `is_protected_meta()`.
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php

    r56586 r56714  
    235235            $autosave_id = wp_update_post( wp_slash( (array) $prepared_post ), true );
    236236        } else {
    237             // Non-draft posts: create or update the post autosave.
    238             $autosave_id = $this->create_post_autosave( (array) $prepared_post );
     237            // Non-draft posts: create or update the post autosave.
     238            $autosave_id = $this->create_post_autosave( (array) $prepared_post );
    239239        }
    240240
     
    349349     *
    350350     * @since 5.0.0
     351
    351352     *
    352353     * @param array $post_data Associative array containing the post data.
     354
    353355     * @return mixed The autosave revision ID or WP_Error.
    354356     */
    355     public function create_post_autosave( $post_data ) {
     357    public function create_post_autosave( $post_data ) {
    356358
    357359        $post_id = (int) $post_data['ID'];
     
    373375        }
    374376
     377
     378
     379
     380
     381
     382
     383
     384
     385
     386
     387
     388
     389
     390
     391
    375392        $user_id = get_current_user_id();
    376393
     
    391408
    392409            // wp_update_post() expects escaped array.
    393             return wp_update_post( wp_slash( $new_autosave ) );
    394         }
    395 
    396         // Create the new autosave as a special post revision.
    397         return _wp_put_post_revision( $post_data, true );
     410            $revision_id = wp_update_post( wp_slash( $new_autosave ) );
     411        } else {
     412            // Create the new autosave as a special post revision.
     413            $revision_id = _wp_put_post_revision( $post_data, true );
     414        }
     415
     416        if ( is_wp_error( $revision_id ) || 0 === $revision_id ) {
     417            return $revision_id;
     418        }
     419
     420        // Attached any passed meta values that have revisions enabled.
     421        if ( ! empty( $meta ) ) {
     422            foreach ( $revisioned_meta_keys as $meta_key ) {
     423                if ( isset( $meta[ $meta_key ] ) ) {
     424                    update_metadata( 'post', $revision_id, $meta_key, $meta[ $meta_key ] );
     425                }
     426            }
     427        }
     428
     429        return $revision_id;
    398430    }
    399431
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php

    r56586 r56714  
    2626
    2727    /**
     28
     29
     30
     31
     32
     33
     34
     35
    2836     * Parent controller.
    2937     *
     
    6169        $this->parent_base       = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
    6270        $this->namespace         = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2';
     71
    6372    }
    6473
     
    620629        }
    621630
     631
     632
     633
     634
    622635        $context  = ! empty( $request['context'] ) ? $request['context'] : 'view';
    623636        $data     = $this->add_additional_fields_to_object( $data, $request );
     
    752765            $schema['properties']['guid'] = $parent_schema['properties']['guid'];
    753766        }
     767
     768
    754769
    755770        $this->schema = $schema;
  • trunk/src/wp-includes/revision.php

    r56359 r56714  
    9797
    9898/**
     99
     100
     101
     102
     103
     104
     105
     106
     107
     108
     109
     110
     111
     112
     113
     114
     115
     116
     117
     118
     119
    99120 * Creates a revision for the current version of a post.
    100121 *
     
    109130function wp_save_post_revision( $post_id ) {
    110131    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
     132
     133
     134
     135
     136
    111137        return;
    112138    }
     
    362388         *
    363389         * @since 2.6.0
     390
    364391         *
    365392         * @param int $revision_id Post revision ID.
     393
    366394         */
    367         do_action( '_wp_put_post_revision', $revision_id );
     395        do_action( '_wp_put_post_revision', $revision_id );
    368396    }
    369397
    370398    return $revision_id;
     399
     400
     401
     402
     403
     404
     405
     406
     407
     408
     409
     410
     411
     412
     413
     414
     415
     416
     417
     418
     419
     420
    371421}
    372422
     
    451501    update_post_meta( $post_id, '_edit_last', get_current_user_id() );
    452502
     503
     504
     505
    453506    /**
    454507     * Fires after a post revision has been restored.
     
    462515
    463516    return $post_id;
     517
     518
     519
     520
     521
     522
     523
     524
     525
     526
     527
     528
     529
     530
     531
     532
     533
     534
     535
     536
     537
     538
     539
     540
     541
     542
     543
     544
     545
     546
     547
     548
     549
     550
     551
     552
     553
     554
     555
     556
     557
     558
     559
     560
     561
     562
     563
     564
     565
     566
     567
     568
     569
     570
     571
     572
     573
     574
     575
     576
     577
     578
     579
     580
     581
     582
     583
     584
     585
     586
     587
     588
     589
     590
     591
     592
     593
     594
     595
     596
     597
     598
     599
     600
     601
     602
     603
     604
     605
     606
     607
     608
     609
     610
     611
     612
     613
     614
     615
    464616}
    465617
     
    729881    add_filter( 'get_the_terms', '_wp_preview_terms_filter', 10, 3 );
    730882    add_filter( 'get_post_metadata', '_wp_preview_post_thumbnail_filter', 10, 3 );
     883
    731884
    732885    return $post;
     
    9471100    return true;
    9481101}
     1102
     1103
     1104
     1105
     1106
     1107
     1108
     1109
     1110
     1111
     1112
     1113
     1114
     1115
     1116
     1117
     1118
     1119
     1120
     1121
     1122
     1123
     1124
     1125
     1126
     1127
     1128
     1129
     1130
     1131
     1132
     1133
     1134
     1135
     1136
  • trunk/tests/phpunit/tests/meta/registerMeta.php

    r56548 r56714  
    9898                        'auth_callback'     => '__return_true',
    9999                        'show_in_rest'      => false,
     100
    100101                    ),
    101102                ),
     
    122123                        'auth_callback'     => '__return_true',
    123124                        'show_in_rest'      => false,
     125
    124126                    ),
    125127                ),
     
    176178                        'auth_callback'     => '__return_true',
    177179                        'show_in_rest'      => false,
     180
    178181                    ),
    179182                ),
     
    343346                        'auth_callback'     => '__return_true',
    344347                        'show_in_rest'      => false,
     348
    345349                    ),
    346350                ),
     
    396400                        'auth_callback'     => '__return_true',
    397401                        'show_in_rest'      => false,
     402
    398403                    ),
    399404                ),
     
    10821087        );
    10831088    }
     1089
     1090
     1091
     1092
     1093
     1094
     1095
     1096
     1097
     1098
     1099
     1100
     1101
     1102
     1103
     1104
     1105
     1106
     1107
     1108
     1109
     1110
     1111
     1112
     1113
     1114
     1115
     1116
     1117
     1118
     1119
    10841120}
  • trunk/tests/phpunit/tests/rest-api/rest-autosaves-controller.php

    r56548 r56714  
    216216            'date',
    217217            'date_gmt',
     218
     219
    218220            'modified',
    219221            'modified_gmt',
    220             'guid',
    221             'id',
    222222            'parent',
    223223            'slug',
     224
    224225            'title',
    225226            'excerpt',
     
    289290        $data       = $response->get_data();
    290291        $properties = $data['schema']['properties'];
    291         $this->assertCount( 13, $properties );
     292        $this->assertCount( 1, $properties );
    292293        $this->assertArrayHasKey( 'author', $properties );
    293294        $this->assertArrayHasKey( 'content', $properties );
     
    303304        $this->assertArrayHasKey( 'title', $properties );
    304305        $this->assertArrayHasKey( 'preview_link', $properties );
     306
    305307    }
    306308
  • trunk/tests/phpunit/tests/rest-api/rest-global-styles-revisions-controller.php

    r56105 r56714  
    133133        );
    134134
    135         wp_update_post( $new_styles_post, true, false );
     135        wp_update_post( $new_styles_post, true );
    136136
    137137        $new_styles_post = array(
     
    163163        );
    164164
    165         wp_update_post( $new_styles_post, true, false );
     165        wp_update_post( $new_styles_post, true );
    166166
    167167        $new_styles_post = array(
     
    193193        );
    194194
    195         wp_update_post( $new_styles_post, true, false );
     195        wp_update_post( $new_styles_post, true );
    196196        wp_set_current_user( 0 );
    197197    }
     
    327327        );
    328328
    329         wp_update_post( $updated_styles_post, true, false );
     329        wp_update_post( $updated_styles_post, true );
    330330
    331331        $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$global_styles_id . '/revisions' );
  • 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' ),
    2121            )
    2222        );
     
    158158            array(
    159159                'show_in_rest' => true,
    160                 'supports'     => array( 'custom-fields' ),
     160                'supports'     => array( 'custom-fields' ),
    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
     1395
     1396
     1397
     1398
    13951399    }
    13961400
     
    31133117        return $query;
    31143118    }
     3119
     3120
     3121
     3122
     3123
     3124
     3125
     3126
     3127
     3128
     3129
     3130
     3131
     3132
     3133
     3134
     3135
     3136
     3137
     3138
     3139
     3140
     3141
     3142
     3143
     3144
     3145
     3146
     3147
     3148
     3149
     3150
     3151
     3152
     3153
     3154
     3155
     3156
     3157
     3158
     3159
     3160
     3161
     3162
     3163
     3164
     3165
     3166
     3167
     3168
     3169
     3170
     3171
     3172
     3173
     3174
     3175
     3176
     3177
     3178
     3179
     3180
     3181
     3182
     3183
     3184
     3185
     3186
     3187
     3188
     3189
     3190
     3191
     3192
     3193
     3194
     3195
     3196
     3197
     3198
     3199
     3200
     3201
     3202
     3203
     3204
     3205
     3206
     3207
     3208
     3209
     3210
     3211
     3212
     3213
     3214
     3215
     3216
     3217
     3218
     3219
     3220
     3221
     3222
     3223
     3224
     3225
     3226
     3227
     3228
     3229
     3230
     3231
     3232
     3233
     3234
     3235
     3236
     3237
     3238
     3239
     3240
     3241
     3242
     3243
     3244
     3245
     3246
     3247
     3248
     3249
     3250
     3251
     3252
     3253
     3254
     3255
     3256
     3257
     3258
     3259
     3260
     3261
     3262
     3263
     3264
     3265
     3266
     3267
     3268
     3269
     3270
     3271
     3272
     3273
     3274
     3275
     3276
     3277
     3278
     3279
     3280
     3281
     3282
     3283
     3284
     3285
     3286
     3287
     3288
     3289
     3290
     3291
     3292
     3293
     3294
     3295
     3296
     3297
     3298
     3299
     3300
     3301
     3302
     3303
     3304
     3305
     3306
     3307
     3308
     3309
     3310
     3311
     3312
     3313
     3314
     3315
     3316
     3317
     3318
     3319
     3320
     3321
     3322
     3323
     3324
     3325
     3326
     3327
     3328
     3329
     3330
     3331
     3332
     3333
     3334
     3335
     3336
     3337
     3338
     3339
     3340
     3341
     3342
     3343
     3344
     3345
     3346
     3347
     3348
     3349
     3350
     3351
     3352
     3353
     3354
     3355
     3356
     3357
     3358
     3359
     3360
     3361
     3362
     3363
     3364
     3365
     3366
     3367
     3368
     3369
     3370
     3371
     3372
     3373
     3374
     3375
     3376
     3377
     3378
     3379
     3380
     3381
     3382
     3383
     3384
     3385
     3386
     3387
     3388
     3389
     3390
     3391
     3392
     3393
     3394
     3395
     3396
     3397
     3398
     3399
     3400
     3401
     3402
     3403
     3404
     3405
     3406
     3407
     3408
     3409
     3410
     3411
     3412
     3413
     3414
     3415
     3416
     3417
     3418
     3419
     3420
     3421
     3422
     3423
     3424
     3425
     3426
     3427
     3428
     3429
     3430
     3431
     3432
     3433
     3434
     3435
     3436
     3437
     3438
     3439
     3440
     3441
     3442
     3443
     3444
     3445
     3446
     3447
     3448
     3449
     3450
     3451
     3452
     3453
     3454
     3455
     3456
     3457
     3458
     3459
     3460
     3461
     3462
     3463
     3464
     3465
     3466
     3467
     3468
     3469
     3470
     3471
     3472
     3473
    31153474}
  • trunk/tests/phpunit/tests/rest-api/rest-revisions-controller.php

    r55457 r56714  
    180180            'guid',
    181181            'id',
     182
    182183            'parent',
    183184            'slug',
     
    336337        $data       = $response->get_data();
    337338        $properties = $data['schema']['properties'];
    338         $this->assertCount( 12, $properties );
     339        $this->assertCount( 1, $properties );
    339340        $this->assertArrayHasKey( 'author', $properties );
    340341        $this->assertArrayHasKey( 'content', $properties );
     
    349350        $this->assertArrayHasKey( 'slug', $properties );
    350351        $this->assertArrayHasKey( 'title', $properties );
     352
    351353    }
    352354
  • trunk/tests/phpunit/tests/user/wpRegisterPersistedPreferencesMeta.php

    r56547 r56714  
    5353                    ),
    5454                ),
     55
    5556            ),
    5657            $wp_meta_keys['user'][''][ $meta_key ],
  • trunk/tests/qunit/fixtures/wp-api-generated.js

    r56642 r56714  
    1178311783            "rendered": ""
    1178411784        },
     11785
     11786
     11787
    1178511788        "_links": {
    1178611789            "parent": [
     
    1181111814        "excerpt": {
    1181211815            "rendered": "<p>REST API Client Fixture: Post</p>\n"
     11816
     11817
     11818
    1181311819        },
    1181411820        "_links": {
     
    1184211848    "excerpt": {
    1184311849        "rendered": "<p>REST API Client Fixture: Post</p>\n"
     11850
     11851
     11852
    1184411853    }
    1184511854};
     
    1186611875        "excerpt": {
    1186711876            "rendered": ""
     11877
     11878
     11879
    1186811880        },
    1186911881        "_links": {
     
    1189711909    "excerpt": {
    1189811910        "rendered": ""
     11911
     11912
     11913
    1189911914    }
    1190011915};
     
    1204312058            "rendered": ""
    1204412059        },
     12060
     12061
     12062
    1204512063        "_links": {
    1204612064            "parent": [
     
    1207112089        "excerpt": {
    1207212090            "rendered": "<p>REST API Client Fixture: Page</p>\n"
     12091
     12092
     12093
    1207312094        },
    1207412095        "_links": {
     
    1210212123    "excerpt": {
    1210312124        "rendered": "<p>REST API Client Fixture: Page</p>\n"
     12125
     12126
     12127
    1210412128    }
    1210512129};
     
    1212612150        "excerpt": {
    1212712151            "rendered": ""
     12152
     12153
     12154
    1212812155        },
    1212912156        "_links": {
     
    1215712184    "excerpt": {
    1215812185        "rendered": ""
     12186
     12187
     12188
    1215912189    }
    1216012190};
Note: See TracChangeset for help on using the changeset viewer.