Make WordPress Core


Ignore:
Timestamp:
09/26/2017 07:37:02 AM (7 years ago)
Author:
westonruter
Message:

Customize: Extend changesets to support autosave revisions with restoration notifications, and introduce a new default linear history mode for saved changesets (with a filter for opt-in to changeset branching).

  • Autosaved changes made on top of auto-draft changesets get written on top of the auto-draft itself, similar to how autosaves for posts will overwrite post drafts.
  • Autosaved changes made to saved changesets (e.g. draft, future) will be placed into an autosave revision for that changeset and that user.
  • Opening the Customizer will now prompt the user to restore their most recent auto-draft changeset; if notification is dismissed or ignored then the auto-draft will be marked as dismissed and will not be prompted to user in a notification again.
  • Customizer will no longer automatically supply the changeset_uuid param in the customize.php URL when branching changesets are not active.
  • If user closes Customizer explicitly via clicking on X link, then autosave auto-draft/autosave will be dismissed so as to not be prompted again.
  • If there is a changeset already saved as a draft or future (UI is forthcoming) then this changeset will now be autoloaded for the user to keep making additional changes. This is the linear model for changesets.
  • To restore the previous behavior of the Customizer where each session started a new changeset, regardless of whether or not there was an existing changeset saved, there is now a customize_changeset_branching hook which can be filtered to return true.
  • wp.customize.requestChangesetUpdate() now supports a second with options including autosave, title, and date.
  • The window blur event for customize.php has been replaced with a visibilitychange event to reduce autosave requests when clicking into preview window.
  • Adds autosaved and branching args to WP_Customize_Manager.
  • The changeset_uuid param for WP_Customize_Manager is extended to recognize a false value which causes the Customizer to defer identifying the UUID until after_setup_theme in the new WP_Customize_Manager::establish_loaded_changeset() method.
  • A new customize_autosaved query parameter can now be supplied which is passed into the autosaved arg in WP_Customize_Manager; this option is an opt-in to source data from the autosave revision, allowing a user to restore autosaved changes.

Props westonruter, dlh, sayedwp, JoshuaWold, melchoyce.
See #39896.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-customize-manager.php

    r41586 r41597  
    175175
    176176    /**
    177      * Whether settings should be previewed.
     177     * Whether the autosave revision of the changeset should should be loaded.
    178178     *
    179179     * @since 4.9.0
    180180     * @var bool
    181181     */
    182     protected $settings_previewed;
     182    protected $autosaved = false;
     183
     184    /**
     185     * Whether the changeset branching is allowed.
     186     *
     187     * @since 4.9.0
     188     * @var bool
     189     */
     190    protected $branching = true;
     191
     192    /**
     193     * Whether settings should be previewed.
     194     *
     195     * @since 4.9.0
     196     * @var bool
     197     */
     198    protected $settings_previewed = true;
     199
     200    /**
     201     * Whether a starter content changeset was saved.
     202     *
     203     * @since 4.9.0
     204     * @var bool
     205     */
     206    protected $saved_starter_content_changeset = false;
    183207
    184208    /**
     
    222246     *     Args.
    223247     *
    224      *     @type string $changeset_uuid     Changeset UUID, the post_name for the customize_changeset post containing the customized state. Defaults to new UUID.
    225      *     @type string $theme              Theme to be previewed (for theme switch). Defaults to customize_theme or theme query params.
    226      *     @type string $messenger_channel  Messenger channel. Defaults to customize_messenger_channel query param.
    227      *     @type bool   $settings_previewed If settings should be previewed. Defaults to true.
     248     *     @type null|string|false $changeset_uuid     Changeset UUID, the `post_name` for the customize_changeset post containing the customized state.
     249     *                                                 Defaults to `null` resulting in a UUID to be immediately generated. If `false` is provided, then
     250     *                                                 then the changeset UUID will be determined during `after_setup_theme`: when the
     251     *                                                 `customize_changeset_branching` filter returns false, then the default UUID will be that
     252     *                                                 of the most recent `customize_changeset` post that has a status other than 'auto-draft',
     253     *                                                 'publish', or 'trash'. Otherwise, if changeset branching is enabled, then a random UUID will be used.
     254     *     @type string            $theme              Theme to be previewed (for theme switch). Defaults to customize_theme or theme query params.
     255     *     @type string            $messenger_channel  Messenger channel. Defaults to customize_messenger_channel query param.
     256     *     @type bool              $settings_previewed If settings should be previewed. Defaults to true.
     257     *     @type bool              $branching          If changeset branching is allowed; otherwise, changesets are linear. Defaults to true.
     258     *     @type bool              $autosaved          If data from a changeset's autosaved revision should be loaded if it exists. Defaults to false.
    228259     * }
    229260     */
     
    231262
    232263        $args = array_merge(
    233             array_fill_keys( array( 'changeset_uuid', 'theme', 'messenger_channel', 'settings_previewed' ), null ),
     264            array_fill_keys( array( 'changeset_uuid', 'theme', 'messenger_channel', 'settings_previewed', 'autosaved', 'branching' ), null ),
    234265            $args
    235266        );
     
    252283        }
    253284
    254         if ( ! isset( $args['settings_previewed'] ) ) {
    255             $args['settings_previewed'] = true;
    256         }
    257 
    258285        $this->original_stylesheet = get_stylesheet();
    259286        $this->theme = wp_get_theme( 0 === validate_file( $args['theme'] ) ? $args['theme'] : null );
    260287        $this->messenger_channel = $args['messenger_channel'];
    261         $this->settings_previewed = ! empty( $args['settings_previewed'] );
    262288        $this->_changeset_uuid = $args['changeset_uuid'];
     289
     290        foreach ( array( 'settings_previewed', 'autosaved', 'branching' ) as $key ) {
     291            if ( isset( $args[ $key ] ) ) {
     292                $this->$key = (bool) $args[ $key ];
     293            }
     294        }
    263295
    264296        require_once( ABSPATH . WPINC . '/class-wp-customize-setting.php' );
     
    344376        add_action( 'wp_ajax_customize_save',           array( $this, 'save' ) );
    345377        add_action( 'wp_ajax_customize_refresh_nonces', array( $this, 'refresh_nonces' ) );
     378        add_action( 'wp_ajax_dismiss_customize_changeset_autosave', array( $this, 'handle_dismiss_changeset_autosave_request' ) );
    346379
    347380        add_action( 'customize_register',                 array( $this, 'register_controls' ) );
     
    475508        }
    476509
    477         if ( ! wp_is_uuid( $this->_changeset_uuid ) ) {
     510        // If a changeset was provided is invalid.
     511        if ( isset( $this->_changeset_uuid ) && false !== $this->_changeset_uuid && ! wp_is_uuid( $this->_changeset_uuid ) ) {
    478512            $this->wp_die( -1, __( 'Invalid changeset UUID' ) );
    479513        }
     
    536570        }
    537571
     572        // Make sure changeset UUID is established immediately after the theme is loaded.
     573        add_action( 'after_setup_theme', array( $this, 'establish_loaded_changeset' ), 5 );
     574
    538575        /*
    539576         * Import theme starter content for fresh installations when landing in the customizer.
     
    546583
    547584        $this->start_previewing_theme();
     585    }
     586
     587    /**
     588     * Establish the loaded changeset.
     589     *
     590     * This method runs right at after_setup_theme and applies the 'customize_changeset_branching' filter to determine
     591     * whether concurrent changesets are allowed. Then if the Customizer is not initialized with a `changeset_uuid` param,
     592     * this method will determine which UUID should be used. If changeset branching is disabled, then the most saved
     593     * changeset will be loaded by default. Otherwise, if there are no existing saved changesets or if changeset branching is
     594     * enabled, then a new UUID will be generated.
     595     *
     596     * @since 4.9.0
     597     */
     598    public function establish_loaded_changeset() {
     599
     600        /**
     601         * Filters whether or not changeset branching is allowed.
     602         *
     603         * By default in core, when changeset branching is not allowed, changesets will operate
     604         * linearly in that only one saved changeset will exist at a time (with a 'draft' or
     605         * 'future' status). This makes the Customizer operate in a way that is similar to going to
     606         * "edit" to one existing post: all users will be making changes to the same post, and autosave
     607         * revisions will be made for that post.
     608         *
     609         * By contrast, when changeset branching is allowed, then the model is like users going
     610         * to "add new" for a page and each user makes changes independently of each other since
     611         * they are all operating on their own separate pages, each getting their own separate
     612         * initial auto-drafts and then once initially saved, autosave revisions on top of that
     613         * user's specific post.
     614         *
     615         * Since linear changesets are deemed to be more suitable for the majority of WordPress users,
     616         * they are the default. For WordPress sites that have heavy site management in the Customizer
     617         * by multiple users then branching changesets should be enabled by means of this filter.
     618         *
     619         * @since 4.9.0
     620         *
     621         * @param bool                 $allow_branching Whether branching is allowed. If `false`, the default,
     622         *                                              then only one saved changeset exists at a time.
     623         * @param WP_Customize_Manager $wp_customize    Manager instance.
     624         */
     625        $this->branching = apply_filters( 'customize_changeset_branching', $this->branching, $this );
     626
     627        if ( empty( $this->_changeset_uuid ) ) {
     628            $changeset_uuid = null;
     629
     630            if ( ! $this->branching ) {
     631                $unpublished_changeset_posts = $this->get_changeset_posts( array(
     632                    'post_status' => array_diff( get_post_stati(), array( 'auto-draft', 'publish', 'trash', 'inherit', 'private' ) ),
     633                    'exclude_restore_dismissed' => false,
     634                    'posts_per_page' => 1,
     635                    'order' => 'DESC',
     636                    'orderby' => 'date',
     637                ) );
     638                $unpublished_changeset_post = array_shift( $unpublished_changeset_posts );
     639                if ( ! empty( $unpublished_changeset_post ) && wp_is_uuid( $unpublished_changeset_post->post_name ) ) {
     640                    $changeset_uuid = $unpublished_changeset_post->post_name;
     641                }
     642            }
     643
     644            // If no changeset UUID has been set yet, then generate a new one.
     645            if ( empty( $changeset_uuid ) ) {
     646                $changeset_uuid = wp_generate_uuid4();
     647            }
     648
     649            $this->_changeset_uuid = $changeset_uuid;
     650        }
    548651    }
    549652
     
    653756     *
    654757     * @since 4.7.0
    655      *
     758     * @since 4.9.0 An exception is thrown if the changeset UUID has not been established yet.
     759     * @see WP_Customize_Manager::establish_loaded_changeset()
     760     *
     761     * @throws Exception When the UUID has not been set yet.
    656762     * @return string UUID.
    657763     */
    658764    public function changeset_uuid() {
     765        if ( empty( $this->_changeset_uuid ) ) {
     766            throw new Exception( 'Changeset UUID has not been set.' ); // @todo Replace this with a call to `WP_Customize_Manager::establish_loaded_changeset()` during 4.9-beta2.
     767        }
    659768        return $this->_changeset_uuid;
    660769    }
     
    826935
    827936    /**
     937     * Get changeset posts.
     938     *
     939     * @since 4.9.0
     940     *
     941     * @param array $args {
     942     *     Args to pass into `get_posts()` to query changesets.
     943     *
     944     *     @type int    $posts_per_page             Number of posts to return. Defaults to -1 (all posts).
     945     *     @type int    $author                     Post author. Defaults to current user.
     946     *     @type string $post_status                Status of changeset. Defaults to 'auto-draft'.
     947     *     @type bool   $exclude_restore_dismissed  Whether to exclude changeset auto-drafts that have been dismissed. Defaults to true.
     948     * }
     949     * @return WP_Post[] Auto-draft changesets.
     950     */
     951    protected function get_changeset_posts( $args = array() ) {
     952        $default_args = array(
     953            'exclude_restore_dismissed' => true,
     954            'posts_per_page' => -1,
     955            'post_type' => 'customize_changeset',
     956            'post_status' => 'auto-draft',
     957            'order' => 'DESC',
     958            'orderby' => 'date',
     959            'no_found_rows' => true,
     960            'cache_results' => true,
     961            'update_post_meta_cache' => false,
     962            'update_post_term_cache' => false,
     963            'lazy_load_term_meta' => false,
     964        );
     965        if ( get_current_user_id() ) {
     966            $default_args['author'] = get_current_user_id();
     967        }
     968        $args = array_merge( $default_args, $args );
     969
     970        if ( ! empty( $args['exclude_restore_dismissed'] ) ) {
     971            unset( $args['exclude_restore_dismissed'] );
     972            $args['meta_query'] = array(
     973                array(
     974                    'key' => '_customize_restore_dismissed',
     975                    'compare' => 'NOT EXISTS',
     976                ),
     977            );
     978        }
     979
     980        return get_posts( $args );
     981    }
     982
     983    /**
    828984     * Get the changeset post id for the loaded changeset.
    829985     *
     
    834990    public function changeset_post_id() {
    835991        if ( ! isset( $this->_changeset_post_id ) ) {
    836             $post_id = $this->find_changeset_post_id( $this->_changeset_uuid );
     992            $post_id = $this->find_changeset_post_id( $this->changeset_uuid() );
    837993            if ( ! $post_id ) {
    838994                $post_id = false;
     
    8621018            return new WP_Error( 'missing_post' );
    8631019        }
    864         if ( 'customize_changeset' !== $changeset_post->post_type ) {
     1020        if ( 'revision' === $changeset_post->post_type ) {
     1021            if ( 'customize_changeset' !== get_post_type( $changeset_post->post_parent ) ) {
     1022                return new WP_Error( 'wrong_post_type' );
     1023            }
     1024        } elseif ( 'customize_changeset' !== $changeset_post->post_type ) {
    8651025            return new WP_Error( 'wrong_post_type' );
    8661026        }
     
    8791039     *
    8801040     * @since 4.7.0
     1041     * @since 4.9.0 This will return the changeset's data with a user's autosave revision merged on top, if one exists and $autosaved is true.
    8811042     *
    8821043     * @return array Changeset data.
     
    8901051            $this->_changeset_data = array();
    8911052        } else {
    892             $data = $this->get_changeset_post_data( $changeset_post_id );
    893             if ( ! is_wp_error( $data ) ) {
    894                 $this->_changeset_data = $data;
    895             } else {
    896                 $this->_changeset_data = array();
     1053            if ( $this->autosaved ) {
     1054                $autosave_post = wp_get_post_autosave( $changeset_post_id );
     1055                if ( $autosave_post ) {
     1056                    $data = $this->get_changeset_post_data( $autosave_post->ID );
     1057                    if ( ! is_wp_error( $data ) ) {
     1058                        $this->_changeset_data = $data;
     1059                    }
     1060                }
     1061            }
     1062
     1063            // Load data from the changeset if it was not loaded from an autosave.
     1064            if ( ! isset( $this->_changeset_data ) ) {
     1065                $data = $this->get_changeset_post_data( $changeset_post_id );
     1066                if ( ! is_wp_error( $data ) ) {
     1067                    $this->_changeset_data = $data;
     1068                } else {
     1069                    $this->_changeset_data = array();
     1070                }
    8971071            }
    8981072        }
     
    13751549            'starter_content' => true,
    13761550        ) );
     1551        $this->saved_starter_content_changeset = true;
    13771552
    13781553        $this->pending_starter_content_settings_ids = array();
     
    17971972        $settings = array(
    17981973            'changeset' => array(
    1799                 'uuid' => $this->_changeset_uuid,
     1974                'uuid' => $this->changeset_uuid(),
     1975                'autosaved' => $this->autosaved,
    18001976            ),
    18011977            'timeouts' => array(
     
    20792255
    20802256        $changeset_post_id = $this->changeset_post_id();
    2081         if ( empty( $changeset_post_id ) ) {
     2257        $is_new_changeset = empty( $changeset_post_id );
     2258        if ( $is_new_changeset ) {
    20822259            if ( ! current_user_can( get_post_type_object( 'customize_changeset' )->cap->create_posts ) ) {
    20832260                wp_send_json_error( 'cannot_create_changeset_post' );
     
    21452322        }
    21462323
     2324        $autosave = ! empty( $_POST['customize_changeset_autosave'] );
     2325        if ( $autosave && ! defined( 'DOING_AUTOSAVE' ) ) { // Back-compat.
     2326            define( 'DOING_AUTOSAVE', true );
     2327        }
     2328
    21472329        $r = $this->save_changeset_post( array(
    21482330            'status' => $changeset_status,
     
    21502332            'date_gmt' => $changeset_date_gmt,
    21512333            'data' => $input_changeset_data,
     2334            'autosave' => $autosave,
    21522335        ) );
    21532336        if ( is_wp_error( $r ) ) {
     
    21632346        } else {
    21642347            $response = $r;
     2348
     2349            // Dismiss all other auto-draft changeset posts for this user (they serve like autosave revisions), as there should only be one.
     2350            if ( $is_new_changeset ) {
     2351                $changeset_autodraft_posts = $this->get_changeset_posts( array(
     2352                    'post_status' => 'auto-draft',
     2353                    'exclude_restore_dismissed' => true,
     2354                    'posts_per_page' => -1,
     2355                ) );
     2356                foreach ( $changeset_autodraft_posts as $autosave_autodraft_post ) {
     2357                    if ( $autosave_autodraft_post->ID !== $this->changeset_post_id() ) {
     2358                        update_post_meta( $autosave_autodraft_post->ID, '_customize_restore_dismissed', true );
     2359                    }
     2360                }
     2361            }
    21652362
    21662363            // Note that if the changeset status was publish, then it will get set to trash if revisions are not supported.
     
    22132410     *     @type int    $user_id         ID for user who is saving the changeset. Optional, defaults to the current user ID.
    22142411     *     @type bool   $starter_content Whether the data is starter content. If false (default), then $starter_content will be cleared for any $data being saved.
     2412     *     @type bool   $autosave        Whether this is a request to create an autosave revision.
    22152413     * }
    22162414     *
     
    22272425                'user_id' => get_current_user_id(),
    22282426                'starter_content' => false,
     2427                'autosave' => false,
    22292428            ),
    22302429            $args
     
    22762475        if ( ! empty( $is_future_dated ) && 'publish' === $args['status'] ) {
    22772476            $args['status'] = 'future';
     2477        }
     2478
     2479        // Validate autosave param. See _wp_post_revision_fields() for why these fields are disallowed.
     2480        if ( $args['autosave'] ) {
     2481            if ( $args['date_gmt'] ) {
     2482                return new WP_Error( 'illegal_autosave_with_date_gmt' );
     2483            } elseif ( $args['status'] ) {
     2484                return new WP_Error( 'illegal_autosave_with_status' );
     2485            } elseif ( $args['user_id'] && get_current_user_id() !== $args['user_id'] ) {
     2486                return new WP_Error( 'illegal_autosave_with_non_current_user' );
     2487            }
    22782488        }
    22792489
     
    25202730        // Note that updating a post with publish status will trigger WP_Customize_Manager::publish_changeset_values().
    25212731        if ( $changeset_post_id ) {
    2522             $post_array['edit_date'] = true; // Prevent date clearing.
    2523             $r = wp_update_post( wp_slash( $post_array ), true );
     2732            if ( $args['autosave'] && 'auto-draft' !== get_post_status( $changeset_post_id ) ) {
     2733                // See _wp_translate_postdata() for why this is required as it will use the edit_post meta capability.
     2734                add_filter( 'map_meta_cap', array( $this, 'grant_edit_post_capability_for_changeset' ), 10, 4 );
     2735                $post_array['post_ID'] = $post_array['ID'];
     2736                $post_array['post_type'] = 'customize_changeset';
     2737                $r = wp_create_post_autosave( wp_slash( $post_array ) );
     2738                remove_filter( 'map_meta_cap', array( $this, 'grant_edit_post_capability_for_changeset' ), 10 );
     2739            } else {
     2740                $post_array['edit_date'] = true; // Prevent date clearing.
     2741                $r = wp_update_post( wp_slash( $post_array ), true );
     2742
     2743                // Delete autosave revision when the changeset is updated.
     2744                $autosave_draft = wp_get_post_autosave( $changeset_post_id );
     2745                if ( $autosave_draft ) {
     2746                    wp_delete_post( $autosave_draft->ID, true );
     2747                }
     2748            }
    25242749        } else {
    25252750            $r = wp_insert_post( wp_slash( $post_array ), true );
     
    25452770
    25462771        return $response;
     2772    }
     2773
     2774    /**
     2775     * Re-map 'edit_post' meta cap for a customize_changeset post to be the same as 'customize' maps.
     2776     *
     2777     * There is essentially a "meta meta" cap in play here, where 'edit_post' meta cap maps to
     2778     * the 'customize' meta cap which then maps to 'edit_theme_options'. This is currently
     2779     * required in core for `wp_create_post_autosave()` because it will call
     2780     * `_wp_translate_postdata()` which in turn will check if a user can 'edit_post', but the
     2781     * the caps for the customize_changeset post type are all mapping to the meta capability.
     2782     * This should be able to be removed once #40922 is addressed in core.
     2783     *
     2784     * @since 4.9.0
     2785     * @link https://core.trac.wordpress.org/ticket/40922
     2786     * @see WP_Customize_Manager::save_changeset_post()
     2787     * @see _wp_translate_postdata()
     2788     *
     2789     * @param array  $caps    Returns the user's actual capabilities.
     2790     * @param string $cap     Capability name.
     2791     * @param int    $user_id The user ID.
     2792     * @param array  $args    Adds the context to the cap. Typically the object ID.
     2793     * @return array Capabilities.
     2794     */
     2795    public function grant_edit_post_capability_for_changeset( $caps, $cap, $user_id, $args ) {
     2796        if ( 'edit_post' === $cap && ! empty( $args[0] ) && 'customize_changeset' === get_post_type( $args[0] ) ) {
     2797            $post_type_obj = get_post_type_object( 'customize_changeset' );
     2798            $caps = map_meta_cap( $post_type_obj->cap->$cap, $user_id );
     2799        }
     2800        return $caps;
    25472801    }
    25482802
     
    27873041
    27883042    /**
     3043     * Delete a given auto-draft changeset or the autosave revision for a given changeset.
     3044     *
     3045     * @since 4.9.0
     3046     */
     3047    public function handle_dismiss_changeset_autosave_request() {
     3048        if ( ! $this->is_preview() ) {
     3049            wp_send_json_error( 'not_preview', 400 );
     3050        }
     3051
     3052        if ( ! check_ajax_referer( 'dismiss_customize_changeset_autosave', 'nonce', false ) ) {
     3053            wp_send_json_error( 'invalid_nonce', 403 );
     3054        }
     3055
     3056        $changeset_post_id = $this->changeset_post_id();
     3057        if ( empty( $changeset_post_id ) ) {
     3058            wp_send_json_error( 'missing_changeset', 404 );
     3059        }
     3060
     3061        if ( 'auto-draft' === get_post_status( $changeset_post_id ) ) {
     3062            if ( ! update_post_meta( $changeset_post_id, '_customize_restore_dismissed', true ) ) {
     3063                wp_send_json_error( 'auto_draft_dismissal_failure', 500 );
     3064            } else {
     3065                wp_send_json_success( 'auto_draft_dismissed' );
     3066            }
     3067        } else {
     3068            $revision = wp_get_post_autosave( $changeset_post_id );
     3069
     3070            if ( $revision ) {
     3071                if ( ! current_user_can( get_post_type_object( 'customize_changeset' )->cap->delete_post, $changeset_post_id ) ) {
     3072                    wp_send_json_error( 'cannot_delete_autosave_revision', 403 );
     3073                }
     3074
     3075                if ( ! wp_delete_post( $revision->ID, true ) ) {
     3076                    wp_send_json_error( 'autosave_revision_deletion_failure', 500 );
     3077                } else {
     3078                    wp_send_json_success( 'autosave_revision_deleted' );
     3079                }
     3080            } else {
     3081                wp_send_json_error( 'no_autosave_to_delete', 404 );
     3082            }
     3083        }
     3084        wp_send_json_error( 'unknown_error', 500 );
     3085    }
     3086
     3087    /**
    27893088     * Add a customize setting.
    27903089     *
     
    35283827            'save' => wp_create_nonce( 'save-customize_' . $this->get_stylesheet() ),
    35293828            'preview' => wp_create_nonce( 'preview-customize_' . $this->get_stylesheet() ),
     3829            'dismiss_autosave' => wp_create_nonce( 'dismiss_customize_changeset_autosave' ),
    35303830        );
    35313831
     
    35643864        }
    35653865
     3866        $autosave_revision_post = null;
     3867        $autosave_autodraft_post = null;
     3868        $changeset_post_id = $this->changeset_post_id();
     3869        if ( ! $this->saved_starter_content_changeset && ! $this->autosaved ) {
     3870            if ( $changeset_post_id ) {
     3871                $autosave_revision_post = wp_get_post_autosave( $changeset_post_id );
     3872            } else {
     3873                $autosave_autodraft_posts = $this->get_changeset_posts( array(
     3874                    'posts_per_page' => 1,
     3875                    'post_status' => 'auto-draft',
     3876                    'exclude_restore_dismissed' => true,
     3877                ) );
     3878                if ( ! empty( $autosave_autodraft_posts ) ) {
     3879                    $autosave_autodraft_post = array_shift( $autosave_autodraft_posts );
     3880                }
     3881            }
     3882        }
     3883
    35663884        // Prepare Customizer settings to pass to JavaScript.
    35673885        $settings = array(
    35683886            'changeset' => array(
    35693887                'uuid' => $this->changeset_uuid(),
    3570                 'status' => $this->changeset_post_id() ? get_post_status( $this->changeset_post_id() ) : '',
     3888                'branching' => $this->branching,
     3889                'autosaved' => $this->autosaved,
     3890                'hasAutosaveRevision' => ! empty( $autosave_revision_post ),
     3891                'latestAutoDraftUuid' => $autosave_autodraft_post ? $autosave_autodraft_post->post_name : null,
     3892                'status' => $changeset_post_id ? get_post_status( $changeset_post_id ) : '',
    35713893            ),
    35723894            'timeouts' => array(
Note: See TracChangeset for help on using the changeset viewer.