WordPress.org

Make WordPress Core

Ticket #20564: 20564-10.diff

File 20564-10.diff, 11.7 KB (added by adamsilverstein, 5 years ago)

includes unit test

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

     
    13501350                $new_autosave['ID'] = $old_autosave->ID;
    13511351                $new_autosave['post_author'] = $post_author;
    13521352
     1353                // Auto-save revisioned meta fields.
     1354                foreach ( _wp_post_revision_meta_keys() as $meta_key ) {
     1355                        if ( isset( $_POST[ $meta_key ] ) && get_post_meta( $new_autosave['ID'], $meta_key, true ) != $_POST[ $meta_key ] ) {
     1356                                // Use the underlying delete_metadata and add_metadata vs delete_post_meta
     1357                                // and add_post_meta to make sure we're working with the actual revision meta.
     1358                                delete_metadata( 'post', $new_autosave['ID'], $meta_key );
     1359                                if ( ! empty( $_POST[ $meta_key ] ) )
     1360                                        add_metadata( 'post', $new_autosave['ID'], $meta_key, $_POST[ $meta_key ] );
     1361                        }
     1362                }
     1363
     1364                // Save the post format as part of the autosave if different.
     1365                if ( isset( $_POST['post_format'] ) && get_post_meta( $new_autosave['ID'], '_revision_post_format', true ) != $_POST['post_format'] ) {
     1366                        delete_metadata( 'post', $new_autosave['ID'], '_revision_post_format' );
     1367                        if ( ! empty( $_POST['post_format'] ) )
     1368                                update_metadata( 'post', $new_autosave['ID'], '_revision_post_format', $_POST['post_format'] );
     1369                }
     1370
    13531371                // If the new autosave is the same content as the post, delete the old autosave.
    13541372                $post = get_post( $post_id );
    13551373                $autosave_is_different = false;
  • src/wp-includes/js/autosave.js

     
    328328(function($){
    329329// Returns the data for saving in both localStorage and autosaves to the server
    330330wp.autosave.getPostData = function() {
    331         var ed = typeof tinymce != 'undefined' ? tinymce.activeEditor : null, post_name, parent_id, cats = [],
     331        var ed = typeof tinymce != 'undefined' ? tinymce.activeEditor : null, post_name, parent_id, post_format, cats = [],
    332332                data = {
    333333                        action: 'autosave',
    334334                        autosave: true,
     
    387387        if ( $('#auto_draft').val() == '1' )
    388388                data.auto_draft = '1';
    389389
     390        post_format = $('#post_format').val() || '';
     391        data['post_format'] = post_format == 'standard' ? '' : post_format;
     392
     393        // Add the post format selected on the edit screen.
     394        $('#post-formats-select').find('input[name="post_format"]').each( function(i, field) {
     395                data[ field.name ] = $(field).is(':checked') || '';
     396        });
     397
    390398        return data;
    391399};
    392400
  • src/wp-includes/revision.php

     
    2828        if ( !$fields ) {
    2929                // Allow these to be versioned
    3030                $fields = array(
    31                         'post_title' => __( 'Title' ),
     31                        'post_title'   => __( 'Title' ),
    3232                        'post_content' => __( 'Content' ),
    3333                        'post_excerpt' => __( 'Excerpt' ),
    3434                );
    3535
    36                 // Runs only once
    37                 $fields = apply_filters( '_wp_post_revision_fields', $fields );
     36                /**
     37                 * Filter the list of post fields that are revisioned.
     38                 *
     39                 * @since 3.6.0
     40                 *
     41                 * @param array $fields An array of fields to be be revisioned.
     42                 *
     43                 */
     44                $fields = apply_filters( '_wp_post_revision_fields', $fields ); // Runs only once
    3845
    3946                // WP uses these internally either in versioning or elsewhere - they cannot be versioned
    4047                foreach ( array( 'ID', 'post_name', 'post_parent', 'post_date', 'post_date_gmt', 'post_status', 'post_type', 'comment_count', 'post_author' ) as $protect )
     
    5966}
    6067
    6168/**
     69 * Determines which post meta fields are revisioned.
     70 *
     71 * @since 3.8.0
     72 *
     73 * @access private
     74 * @return array An array of meta keys that should be revisioned.
     75 *
     76 */
     77function _wp_post_revision_meta_keys() {
     78        // By default, revision the post format meta values
     79        $keys = array(
     80                '_wp_format_url',
     81                '_wp_format_quote',
     82                '_wp_format_quote_source',
     83                '_wp_format_image',
     84                '_wp_format_gallery',
     85                '_wp_format_audio',
     86                '_wp_format_video',
     87        );
     88
     89        /**
     90         * Filter the list of post meta keys that are revisioned.
     91         *
     92         * @since 3.8.0
     93         *
     94         * @param array $keys An array of fields to be be revisioned.
     95         *
     96         */
     97        return apply_filters( 'wp_post_revision_meta_keys', $keys );
     98}
     99
     100/**
    62101 * Saves an already existing post as a post revision.
    63102 *
    64103 * Typically used immediately after post updates.
     
    102141                if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', true, $last_revision, $post ) ) {
    103142                        $post_has_changed = false;
    104143
     144                        // Check whether revisioned fields have been changed
    105145                        foreach ( array_keys( _wp_post_revision_fields() ) as $field ) {
    106146                                if ( normalize_whitespace( $post->$field ) != normalize_whitespace( $last_revision->$field ) ) {
    107147                                        $post_has_changed = true;
    108148                                        break;
    109149                                }
    110150                        }
    111                         //don't save revision if post unchanged
     151
     152                        // Check whether revisioned meta fields have changed
     153                        foreach ( _wp_post_revision_meta_keys() as $meta_key ) {
     154                                if ( get_post_meta( $post->ID, $meta_key ) != get_post_meta( $last_revision->ID, $meta_key ) ) {
     155                                        $post_has_changed = true;
     156                                        break;
     157                                }
     158                        }
     159
     160                        // Check whether the post format has changed
     161                        if ( get_post_format( $post->ID ) != get_post_meta( $last_revision->ID, '_revision_post_format', true ) )
     162                                $post_has_changed = true;
     163
     164                        // Don't save revision if post unchanged
    112165                        if( ! $post_has_changed )
    113166                                return;
    114167                }
     
    240293        if ( $revision_id )
    241294                do_action( '_wp_put_post_revision', $revision_id );
    242295
    243         return $revision_id;
    244 }
     296        // Save revisioned meta fields.
     297        foreach ( _wp_post_revision_meta_keys() as $meta_key ) {
     298                $meta_value = get_post_meta( $post_id, $meta_key, true );
     299                if ( empty( $meta_value ) )
     300                        continue;
     301                // Use the underlying add_metadata vs add_post_meta to make sure
     302                // metadata is added to the revision post and not its parent.
     303                add_metadata( 'post', $revision_id, $meta_key, wp_slash( $meta_value ) );
     304        }
     305        // Save the post format
     306        if ( $post_format = get_post_format( $post_id ) )
     307                add_metadata( 'post', $revision_id, '_revision_post_format', $post_format );
    245308
     309                return $revision_id;
     310        }
     311
    246312/**
    247313 * Gets a post revision.
    248314 *
     
    308374
    309375        $update['ID'] = $revision['post_parent'];
    310376
     377        // Restore revisioned meta fields.
     378        foreach ( _wp_post_revision_meta_keys() as $meta_key ) {
     379                $meta_value = get_post_meta( $revision['ID'], $meta_key, true );
     380                if ( empty( $meta_value ) )
     381                        $meta_value = '';
     382                // Add slashes to data pulled from the db
     383                update_post_meta( $update['ID'], $meta_key, wp_slash( $meta_value ) );
     384        }
     385
    311386        $update = wp_slash( $update ); //since data is from db
     387        // Restore post format
     388        set_post_format( $update['ID'], get_post_meta( $revision['ID'], '_revision_post_format', true ) );
    312389
     390        // Restore revisioned meta fields.
     391        foreach ( _wp_post_revision_meta_keys() as $meta_key ) {
     392                delete_post_meta( $update['ID'], $meta_key );
     393                $meta_values = get_post_meta( $revision['ID'], $meta_key );
     394                if ( false === $meta_values )
     395                        continue;
     396
     397                foreach ( $meta_values as $meta_value )
     398                        add_post_meta( $update['ID'], $meta_key, $meta_value );
     399        }
     400
    313401        $post_id = wp_update_post( $update );
    314402        if ( ! $post_id || is_wp_error( $post_id ) )
    315403                return $post_id;
     
    449537        $post->post_excerpt = $preview->post_excerpt;
    450538
    451539        add_filter( 'get_the_terms', '_wp_preview_terms_filter', 10, 3 );
     540        add_filter( 'get_post_metadata', '_wp_preview_meta_filter', 10, 4 );
    452541
    453542        return $post;
    454543}
     
    472561}
    473562
    474563/**
     564 * Filters post meta retrieval to get values from the actual autosave post,
     565 * and not its parent. Filters revisioned meta keys only.
     566 *
     567 * @since 3.6.0
     568 * @access private
     569 */
     570function _wp_preview_meta_filter( $value, $object_id, $meta_key, $single ) {
     571        $post = get_post();
     572        if ( empty( $post ) || $post->ID != $object_id || ! in_array( $meta_key, _wp_post_revision_meta_keys() ) || 'revision' == $post->post_type )
     573                return $value;
     574        $preview = wp_get_post_autosave( $post->ID );
     575        if ( ! is_object( $preview ) )
     576                return $value;
     577        return get_post_meta( $preview->ID, $meta_key, $single );
     578}
     579
     580/**
    475581 * Filters terms lookup to set the post format.
    476582 *
    477583 * @since 3.6.0
  • tests/phpunit/tests/post/revisions.php

     
    338338                        $this->assertTrue( user_can( $author_user_id, 'read_post', $revision->ID ) );
    339339                }
    340340        }
     341
     342        /**
     343         * Test the revisions system for storage of meta values & post format
     344         * @ticket 20564
     345         */
     346        function test_revisions_stores_meta_values() {
     347                // Set up a new post
     348                $original_post_id = $post_id = $this->factory->post->create();
     349                // And update to store an initial revision
     350                wp_update_post( array( 'post_content'   => 'some initial content', 'ID' => $post_id ) );
     351
     352                /**
     353                 * First set up some meta values, one custom and one _wp_format_gallery (one of the default wp_post_revision_meta_keys)
     354                 */
     355
     356                // Store a custom meta value, which is not revisioned by default
     357                update_post_meta( $post_id, 'meta_revision_test', 'original' );
     358
     359                // Store a _wp_format_ meta, which is revisioned by defeault
     360                update_post_meta( $post_id, '_wp_format_gallery', 'active' );
     361
     362                // Update the post, storing a revision
     363                wp_update_post( array( 'post_content'   => 'some more content', 'ID' => $post_id ) );
     364
     365                /**
     366                 * Next, store some updated meta values for the same keys
     367                 */
     368
     369                update_post_meta( $post_id, 'meta_revision_test', 'update1' );
     370                update_post_meta( $post_id, '_wp_format_gallery', 'inactive' );
     371
     372                // Save the post, changing content to force a revision
     373                wp_update_post( array( 'post_content'   => 'some updated content', 'ID' => $post_id ) );
     374
     375                /**
     376                 * Now restore the original revision
     377                 */
     378
     379                // Get all the revisions
     380                $revisions = (Array)wp_get_post_revisions( $post_id );
     381
     382                // Go back two revisions (the 1st revision matches the current post)
     383                $last_revision = array_pop( $revisions );
     384                $last_revision = array_pop( $revisions );
     385
     386                // Restore!
     387                wp_restore_post_revision( $last_revision->ID );
     388
     389                /**
     390                 * Check the meta values to see if they are revisioned
     391                 */
     392
     393                // Custom post met should NOT be restored, orignal value should not be restored, value still 'update1'
     394                $this->assertEquals( 'update1', get_post_meta( $post_id, 'meta_revision_test', true ) );
     395
     396                // _wp_format_ metas should be revisioned, original value should be restored
     397                $this->assertEquals( 'active', get_post_meta( $post_id, '_wp_format_gallery', true ) );
     398
     399                /**
     400                 * Now test the revisioning of custom meta when enabled by the
     401                 */
     402
     403                // Add the custom field to be revised via the wp_post_revision_meta_keys filter wp_post_revision_meta_keys filter
     404                add_filter( 'wp_post_revision_meta_keys', function( $keys ) {
     405                        $keys[] =  'meta_revision_test';
     406                        return $keys;
     407                });
     408
     409                /**
     410                 * Save new meta in the revisioned field
     411                 */
     412
     413                // Save the post again, custom meta should now be revisioned - note no change in content, revision still saved
     414                wp_update_post( array( 'ID' => $post_id ) );
     415
     416                // Store custom meta values, which should now be revisioned
     417                update_post_meta( $post_id, 'meta_revision_test', 'update2' );
     418
     419                // Save the post again
     420                wp_update_post( array( 'ID' => $post_id ) );
     421
     422                // Retore the previous revision
     423                $revisions = wp_get_post_revisions( $post_id );
     424
     425                // Go back two
     426                $last_revision = array_pop( $revisions );
     427                $last_revision = array_pop( $revisions );
     428                wp_restore_post_revision( $last_revision->ID );
     429
     430                $this->assertEquals( 'update1', get_post_meta( $post_id, 'meta_revision_test', true ) );
     431
     432                // Cleanup!
     433                wp_delete_post( $original_post_id );
     434
     435
     436        }
    341437}