WordPress.org

Make WordPress Core

Ticket #20564: 20564.18.diff

File 20564.18.diff, 12.9 KB (added by adamsilverstein, 6 years ago)

refresh against trunk

  • src/wp-admin/includes/post.php

     
    15231523                $new_autosave['ID'] = $old_autosave->ID;
    15241524                $new_autosave['post_author'] = $post_author;
    15251525
     1526                // Auto-save revisioned meta fields.
     1527                foreach ( _wp_post_revision_meta_keys() as $meta_key ) {
     1528                        if ( isset( $_POST[ $meta_key ] )
     1529                                && '' !== $_POST[ $meta_key ]
     1530                                && get_post_meta( $new_autosave['ID'], $meta_key, true ) != wp_unslash( $_POST[ $meta_key ] ) )
     1531                        {
     1532                                /*
     1533                                 * Use the underlying delete_metadata() and add_metadata() functions
     1534                                 * vs delete_post_meta() and add_post_meta() to make sure we're working
     1535                                 * with the actual revision meta.
     1536                                 */
     1537                                delete_metadata( 'post', $new_autosave['ID'], $meta_key );
     1538                                if ( ! empty( $_POST[ $meta_key ] ) ) {
     1539                                        add_metadata( 'post', $new_autosave['ID'], $meta_key, $_POST[ $meta_key ] );
     1540                                }
     1541                        }
     1542                }
     1543
    15261544                // If the new autosave has the same content as the post, delete the autosave.
    15271545                $post = get_post( $post_id );
    15281546                $autosave_is_different = false;
  • src/wp-includes/revision.php

     
    7070}
    7171
    7272/**
     73 * Determine which post meta fields should be revisioned.
     74 *
     75 * @access private
     76 * @since 4.0.0
     77 *
     78 * @return array An array of meta keys to be revisioned.
     79 */
     80function _wp_post_revision_meta_keys() {
     81        /**
     82         * Filter the list of post meta keys to be revisioned.
     83         *
     84         * @since 4.0.0
     85         *
     86         * @param array $keys An array of default meta fields to be revisioned.
     87         */
     88        return apply_filters( 'wp_post_revision_meta_keys', array() );
     89}
     90
     91/**
    7392 * Saves an already existing post as a post revision.
    7493 *
    7594 * Typically used immediately after post updates.
     
    127146                if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', $check_for_changes = true, $last_revision, $post ) ) {
    128147                        $post_has_changed = false;
    129148
     149                        // Check whether revisioned post fields have been changed.
    130150                        foreach ( array_keys( _wp_post_revision_fields() ) as $field ) {
    131151                                if ( normalize_whitespace( $post->$field ) != normalize_whitespace( $last_revision->$field ) ) {
    132152                                        $post_has_changed = true;
     
    133153                                        break;
    134154                                }
    135155                        }
    136                         //don't save revision if post unchanged
     156
     157                        // Check whether revisioned post meta fields have changed.
     158                        foreach ( _wp_post_revision_meta_keys() as $meta_key ) {
     159                                if ( get_post_meta( $post->ID, $meta_key ) != get_post_meta( $last_revision->ID, $meta_key ) ) {
     160                                        $post_has_changed = true;
     161                                        break;
     162                                }
     163                        }
     164
     165                        // Don't save revision if the post is unchanged.
    137166                        if( ! $post_has_changed )
    138167                                return;
    139168                }
     
    253282        if ( isset($post['post_type']) && 'revision' == $post['post_type'] )
    254283                return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) );
    255284
     285        $post_id = (int) $post['ID'];
    256286        $post = _wp_post_revision_fields( $post, $autosave );
    257287        $post = wp_slash($post); //since data is from db
    258288
     
    271301                do_action( '_wp_put_post_revision', $revision_id );
    272302        }
    273303
     304        // Save revisioned meta fields.
     305        foreach ( _wp_post_revision_meta_keys() as $meta_key ) {
     306                $meta_value = get_post_meta( $post_id, $meta_key );
     307
     308                // Don't save blank meta values
     309                if( '' == $meta_value ) {
     310                        continue;
     311                }
     312                /*
     313                 * Use the underlying add_metadata() function vs add_post_meta()
     314                 * to ensure metadata is added to the revision post and not its parent.
     315                 */
     316                add_metadata( 'post', $revision_id, $meta_key, $meta_value );
     317        }
     318        // Save the revisioned meta keys so we know which meta keys were revisioned
     319        add_metadata( 'post', $revision_id, '_wp_post_revision_meta_keys',  _wp_post_revision_meta_keys() );
     320
    274321        return $revision_id;
    275322}
    276323
     
    336383
    337384        $update['ID'] = $revision['post_parent'];
    338385
     386        // Restore revisioned meta fields; first get the keys for this revision
     387        $metas_revisioned =  wp_unslash( get_metadata( 'post', $revision_id, '_wp_post_revision_meta_keys' ) );
     388
     389        if ( ! empty( $metas_revisioned[0] ) ) {
     390                foreach ( $metas_revisioned[0] as $meta_key ) {
     391                        // Clear any existing metas
     392                        delete_post_meta( $revision['ID'], $meta_key );
     393                        // Get the stored meta, not stored === blank
     394                        $meta_values = get_post_meta( $revision['ID'], $meta_key, true );
     395
     396                        foreach( $meta_values as $meta_value ) {
     397                                add_post_meta( $update['ID'], $meta_key, $meta_value );
     398                        }
     399                }
     400        }
    339401        $update = wp_slash( $update ); //since data is from db
    340402
    341403        $post_id = wp_update_post( $update );
     
    503565        $post->post_excerpt = $preview->post_excerpt;
    504566
    505567        add_filter( 'get_the_terms', '_wp_preview_terms_filter', 10, 3 );
     568        add_filter( 'get_post_metadata', '_wp_preview_meta_filter', 10, 4 );
    506569
    507570        return $post;
    508571}
     
    526589}
    527590
    528591/**
     592 * Filters post meta retrieval to get values from the actual autosave post,
     593 * and not its parent.
     594 *
     595 * Filters revisioned meta keys only.
     596 *
     597 * @access private
     598 * @since 4.0.0
     599 *
     600 * @param mixed  $value     Meta value to filter.
     601 * @param int    $object_id Object ID.
     602 * @param string $meta_key  Meta key to filter a value for.
     603 * @param bool   $single    Whether to return a single value. Default false.
     604 * @return mixed Original meta value if the meta key isn't revisioned, the object doesn't exist,
     605 *               the post type is a revisionm or the post ID doesn't match the object ID.
     606 *               Otherwise, the revisioned meta value is returned for the preview.
     607 */
     608function _wp_preview_meta_filter( $value, $object_id, $meta_key, $single ) {
     609        $post = get_post();
     610        if ( empty( $post )
     611                || $post->ID != $object_id
     612                || ! in_array( $meta_key, _wp_post_revision_meta_keys() )
     613                || 'revision' == $post->post_type )
     614        {
     615                return $value;
     616        }
     617
     618        // Grab the autosave.
     619        $preview = wp_get_post_autosave( $post->ID );
     620        if ( ! is_object( $preview ) ) {
     621                return $value;
     622        }
     623
     624        return get_post_meta( $preview->ID, $meta_key, $single );
     625}
     626
     627/**
    529628 * Filters terms lookup to set the post format.
    530629 *
    531630 * @since 3.6.0
  • tests/phpunit/tests/post/revisions.php

     
    367367                $this->assertEquals( 100, $ok );
    368368                $this->assertEquals( 0, $reversed );
    369369        }
     370
     371        /**
     372         * Test the revisions system for storage of meta values
     373         * @ticket 20564
     374         */
     375        function test_revisions_stores_meta_values() {
     376                // Set up a new post
     377                $original_post_id = $post_id = $this->factory->post->create();
     378                // And update to store an initial revision
     379                wp_update_post( array( 'post_content'   => 'some initial content', 'ID' => $post_id ) );
     380
     381                // One revision so far
     382                $revisions = wp_get_post_revisions( $post_id );
     383                $this->assertCount( 1, $revisions );
     384                /**
     385                 * First set up a meta value
     386                 */
     387
     388                // Store a custom meta value, which is not revisioned by default
     389                update_post_meta( $post_id, 'meta_revision_test', 'original' );
     390
     391                // Update the post, storing a revision
     392                wp_update_post( array( 'post_content'   => 'some more content', 'ID' => $post_id ) );
     393
     394                $revisions = wp_get_post_revisions( $post_id );
     395                $this->assertCount( 2, $revisions );
     396
     397
     398                //  Next, store some updated meta values for the same key
     399                update_post_meta( $post_id, 'meta_revision_test', 'update1' );
     400
     401                // Save the post, changing content to force a revision
     402                wp_update_post( array( 'post_content'   => 'some updated content', 'ID' => $post_id ) );
     403
     404                $revisions = wp_get_post_revisions( $post_id );
     405                $this->assertCount( 3, $revisions );
     406
     407
     408                /**
     409                 * Now restore the original revision
     410                 */
     411
     412                // Restore the previous revision
     413                $revisions = (Array)wp_get_post_revisions( $post_id );
     414                // Go back two to load the previous revision
     415                array_shift( $revisions );
     416                $last_revision = array_shift( $revisions );
     417                // Restore!
     418                wp_restore_post_revision( $last_revision->ID );
     419
     420                wp_update_post( array( 'ID' => $post_id ) );
     421                $revisions = wp_get_post_revisions( $post_id );
     422                $this->assertCount( 4, $revisions );
     423
     424                /**
     425                 * Check the meta values to verify they are NOT revisioned - they are not revisioned by default
     426                 */
     427
     428                // Custom post meta should NOT be restored, orignal value should not be restored, value still 'update1'
     429                $this->assertEquals( 'update1', get_post_meta( $post_id, 'meta_revision_test', true ) );
     430
     431                update_post_meta( $post_id, 'meta_revision_test', 'update2' );
     432
     433
     434                /*
     435                 * Now test the revisioning of custom meta when enabled by the wp_post_revision_meta_keys filter
     436                 */
     437
     438                // Add the custom field to be revised via the wp_post_revision_meta_keys filter
     439                add_filter( 'wp_post_revision_meta_keys', function( $keys ) {
     440                        $keys[] = 'meta_revision_test';
     441                        return $keys;
     442                });
     443
     444                // Save the post, changing content to force a revision
     445                wp_update_post( array( 'post_content'   => 'more updated content', 'ID' => $post_id ) );
     446
     447                $revisions = wp_get_post_revisions( $post_id );
     448                $this->assertCount( 5, $revisions );
     449
     450                // Store custom meta values, which should now be revisioned
     451                update_post_meta( $post_id, 'meta_revision_test', 'update3' );
     452
     453                /**
     454                 * Save the post again, custom meta should now be revisioned
     455                 *
     456                 * Note that a revision is saved even though there is no change
     457                 * in post content, becaused the revisioned post_meta has changed
     458                 *
     459                 */
     460                wp_update_post( array( 'ID' => $post_id ) );
     461
     462                // This revision contains the existing post meta ('update3')
     463                $revisions = wp_get_post_revisions( $post_id );
     464                $this->assertCount( 6, $revisions );
     465
     466                // Verify that previous post meta is set
     467                $this->assertEquals( 'update3', get_post_meta( $post_id, 'meta_revision_test', true ) );
     468
     469                // Retore the previous revision
     470                $revisions = wp_get_post_revisions( $post_id );
     471
     472                // Go back two to load the previous revision
     473                array_shift( $revisions );
     474                $last_revision = array_shift( $revisions );
     475                wp_restore_post_revision( $last_revision->ID );
     476
     477                // Verify that previous post meta is restored
     478                $this->assertEquals( 'update2', get_post_meta( $post_id, 'meta_revision_test', true ) );
     479
     480                // Try storing a blank meta
     481                update_post_meta( $post_id, 'meta_revision_test', '' );
     482                wp_update_post( array( 'ID' => $post_id ) );
     483
     484                update_post_meta( $post_id, 'meta_revision_test', 'update 4' );
     485                wp_update_post( array( 'ID' => $post_id ) );
     486
     487                // Retore the previous revision
     488                $revisions = wp_get_post_revisions( $post_id );
     489                array_shift( $revisions );
     490                $last_revision = array_shift( $revisions );
     491                wp_restore_post_revision( $last_revision->ID );
     492
     493                // Verify that previous post meta is restored
     494                $this->assertEquals( '', get_post_meta( $post_id, 'meta_revision_test', true ) );
     495
     496                // Test not tracking a key
     497                remove_all_filters( 'wp_post_revision_meta_keys' );
     498
     499                // Should no longer be revisioned
     500                update_post_meta( $post_id, 'meta_revision_test', 'update 5' );
     501                wp_update_post( array( 'ID' => $post_id, 'post_content' => 'changed content' ) );
     502                update_post_meta( $post_id, 'meta_revision_test', 'update 6' );
     503                wp_update_post( array( 'ID' => $post_id, 'post_content' => 'go updated content' ) );
     504                // Retore the previous revision
     505                $revisions = wp_get_post_revisions( $post_id );
     506                array_shift( $revisions );
     507                $last_revision = array_shift( $revisions );
     508                wp_restore_post_revision( $last_revision->ID );
     509
     510                // Verify that previous post meta is NOT restored
     511                $this->assertEquals( 'update 6', get_post_meta( $post_id, 'meta_revision_test', true ) );
     512
     513                // Add the custom field to be revised via the wp_post_revision_meta_keys filter
     514                add_filter( 'wp_post_revision_meta_keys', function( $keys ) {
     515                        $keys[] = 'meta_revision_test';
     516                        return $keys;
     517                });
     518
     519                /**
     520                 * Test the revisioning of multiple meta keys
     521                 */
     522
     523                // Add three values for meta
     524                update_post_meta( $post_id, 'meta_revision_test', 'update 7' );
     525                add_post_meta( $post_id, 'meta_revision_test', 'update 7 number 2' );
     526                add_post_meta( $post_id, 'meta_revision_test', 'update 7 number 3' );
     527                wp_update_post( array( 'ID' => $post_id ) );
     528
     529                // Update all three values
     530                update_post_meta( $post_id, 'meta_revision_test', 'update 8', 'update 7' );
     531                update_post_meta( $post_id, 'meta_revision_test', 'update 8 number 2', 'update 7 number 2'  );
     532                update_post_meta( $post_id, 'meta_revision_test', 'update 8 number 3', 'update 7 number 3'  );
     533                wp_update_post( array( 'ID' => $post_id ) );
     534
     535                // Retore the previous revision
     536                $revisions = wp_get_post_revisions( $post_id );
     537                array_shift( $revisions );
     538                $last_revision = array_shift( $revisions );
     539                wp_restore_post_revision( $last_revision->ID );
     540
     541                $this->assertEquals( array( 'update 7', 'update 7 number 2', 'update 7 number 3' ), get_post_meta( $post_id, 'meta_revision_test' ) );
     542
     543                // Cleanup!
     544                wp_delete_post( $original_post_id );
     545
     546        }
    370547}