mirror of
https://github.com/WordPress/WordPress.git
synced 2025-02-16 11:35:48 +00:00
Customize: Allow starter content to apply in a new theme when switching from another theme containing changes.
* Ensure that starter content can apply from theme B after previewing starter content in theme A. * Introduce new `starter_content` flag in changeset setting params which is used to capture whether a value is starter content and thus can be overridden. * Create changeset up-front with `starter_content` flags instead of waiting for `AUTOSAVE_INTERVAL`. * Eliminate instantiation of settings for widget instances in favor of directly calling `sanitize_widget_js_instance`. This eliminates issues with looking for widgets before they are registered. * Ensure that non-placeholders (inline arrays instead of string references) can be supplied in starter content. * Re-use auto-draft posts as starter content across theme switches. * Introduce `starter_content` param for `WP_Customize_Manager::save_changeset_post()` which is `false` except when starter content is being loaded on a `fresh_site`. See #38114. Fixes #38541. Built from https://develop.svn.wordpress.org/trunk@39241 git-svn-id: http://core.svn.wordpress.org/trunk@39181 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
11998b4169
commit
8efc416f64
@ -523,8 +523,12 @@ final class WP_Customize_Manager {
|
||||
}
|
||||
}
|
||||
|
||||
// Import theme starter content for fresh installs when landing in the customizer and no existing changeset loaded.
|
||||
if ( get_option( 'fresh_site' ) && 'customize.php' === $pagenow && ! $this->changeset_post_id() ) {
|
||||
/*
|
||||
* Import theme starter content for fresh installs when landing in the customizer.
|
||||
* Import starter content at after_setup_theme:100 so that any
|
||||
* add_theme_support( 'starter-content' ) calls will have been made.
|
||||
*/
|
||||
if ( get_option( 'fresh_site' ) && 'customize.php' === $pagenow ) {
|
||||
add_action( 'after_setup_theme', array( $this, 'import_theme_starter_content' ), 100 );
|
||||
}
|
||||
|
||||
@ -885,7 +889,16 @@ final class WP_Customize_Manager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Import theme starter content into post values.
|
||||
* Starter content setting IDs.
|
||||
*
|
||||
* @since 4.7.0
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
protected $starter_content_settings_ids = array();
|
||||
|
||||
/**
|
||||
* Import theme starter content into the customized state.
|
||||
*
|
||||
* @since 4.7.0
|
||||
* @access public
|
||||
@ -897,6 +910,11 @@ final class WP_Customize_Manager {
|
||||
$starter_content = get_theme_starter_content();
|
||||
}
|
||||
|
||||
$changeset_data = array();
|
||||
if ( $this->changeset_post_id() ) {
|
||||
$changeset_data = $this->get_changeset_post_data( $this->changeset_post_id() );
|
||||
}
|
||||
|
||||
$sidebars_widgets = isset( $starter_content['widgets'] ) && ! empty( $this->widgets ) ? $starter_content['widgets'] : array();
|
||||
$posts = isset( $starter_content['posts'] ) && ! empty( $this->nav_menus ) ? $starter_content['posts'] : array();
|
||||
$options = isset( $starter_content['options'] ) ? $starter_content['options'] : array();
|
||||
@ -932,45 +950,113 @@ final class WP_Customize_Manager {
|
||||
$widget_id = sprintf( '%s-%d', $id_base, $max_widget_numbers[ $id_base ] );
|
||||
$setting_id = sprintf( 'widget_%s[%d]', $id_base, $max_widget_numbers[ $id_base ] );
|
||||
|
||||
$class = 'WP_Customize_Setting';
|
||||
|
||||
/** This filter is documented in wp-includes/class-wp-customize-manager.php */
|
||||
$args = apply_filters( 'customize_dynamic_setting_args', false, $setting_id );
|
||||
|
||||
if ( false !== $args ) {
|
||||
|
||||
/** This filter is documented in wp-includes/class-wp-customize-manager.php */
|
||||
$class = apply_filters( 'customize_dynamic_setting_class', $class, $setting_id, $args );
|
||||
|
||||
$setting = new $class( $this, $setting_id, $args );
|
||||
$setting_value = call_user_func( $setting->sanitize_js_callback, $instance, $setting );
|
||||
$setting_value = $this->widgets->sanitize_widget_js_instance( $instance );
|
||||
if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) {
|
||||
$this->set_post_value( $setting_id, $setting_value );
|
||||
$sidebar_widget_ids[] = $widget_id;
|
||||
$this->starter_content_settings_ids[] = $setting_id;
|
||||
}
|
||||
$sidebar_widget_ids[] = $widget_id;
|
||||
}
|
||||
|
||||
$this->set_post_value( sprintf( 'sidebars_widgets[%s]', $sidebar_id ), $sidebar_widget_ids );
|
||||
$setting_id = sprintf( 'sidebars_widgets[%s]', $sidebar_id );
|
||||
if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) {
|
||||
$this->set_post_value( $setting_id, $sidebar_widget_ids );
|
||||
$this->starter_content_settings_ids[] = $setting_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Posts & pages.
|
||||
if ( ! empty( $posts ) ) {
|
||||
$nav_menus_created_posts = array();
|
||||
if ( ! empty( $changeset_data['nav_menus_created_posts']['value'] ) ) {
|
||||
$nav_menus_created_posts = $changeset_data['nav_menus_created_posts']['value'];
|
||||
}
|
||||
|
||||
$existing_posts = array();
|
||||
if ( ! empty( $nav_menus_created_posts ) ) {
|
||||
$existing_posts_query = new WP_Query( array(
|
||||
'post__in' => $nav_menus_created_posts,
|
||||
'post_status' => 'auto-draft',
|
||||
'post_type' => 'any',
|
||||
'number' => -1,
|
||||
) );
|
||||
foreach ( $existing_posts_query->posts as $existing_post ) {
|
||||
$existing_posts[ $existing_post->post_type . ':' . $existing_post->post_name ] = $existing_post;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( array_keys( $posts ) as $post_symbol ) {
|
||||
if ( empty( $posts[ $post_symbol ]['post_type'] ) ) {
|
||||
continue;
|
||||
}
|
||||
$post_type = $posts[ $post_symbol ]['post_type'];
|
||||
if ( ! empty( $posts[ $post_symbol ]['post_name'] ) ) {
|
||||
$post_name = $posts[ $post_symbol ]['post_name'];
|
||||
} elseif ( ! empty( $posts[ $post_symbol ]['post_title'] ) ) {
|
||||
$post_name = sanitize_title( $posts[ $post_symbol ]['post_title'] );
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use existing auto-draft post if one already exists with the same type and name.
|
||||
if ( isset( $existing_posts[ $post_type . ':' . $post_name ] ) ) {
|
||||
$posts[ $post_symbol ]['ID'] = $existing_posts[ $post_type . ':' . $post_name ]->ID;
|
||||
continue;
|
||||
}
|
||||
|
||||
$r = $this->nav_menus->insert_auto_draft_post( $posts[ $post_symbol ] );
|
||||
if ( $r instanceof WP_Post ) {
|
||||
$posts[ $post_symbol ]['ID'] = $r->ID;
|
||||
}
|
||||
}
|
||||
$this->set_post_value( 'nav_menus_created_posts', wp_list_pluck( $posts, 'ID' ) ); // This is why nav_menus component is dependency for adding posts.
|
||||
|
||||
// The nav_menus_created_posts setting is why nav_menus component is dependency for adding posts.
|
||||
$setting_id = 'nav_menus_created_posts';
|
||||
if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) {
|
||||
$nav_menus_created_posts = array_unique( array_merge( $nav_menus_created_posts, wp_list_pluck( $posts, 'ID' ) ) );
|
||||
$this->set_post_value( $setting_id, array_values( $nav_menus_created_posts ) );
|
||||
$this->starter_content_settings_ids[] = $setting_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Nav menus.
|
||||
$placeholder_id = -1;
|
||||
$reused_nav_menu_setting_ids = array();
|
||||
foreach ( $nav_menus as $nav_menu_location => $nav_menu ) {
|
||||
$nav_menu_term_id = $placeholder_id--;
|
||||
$nav_menu_setting_id = sprintf( 'nav_menu[%d]', $nav_menu_term_id );
|
||||
|
||||
$nav_menu_term_id = null;
|
||||
$nav_menu_setting_id = null;
|
||||
$matches = array();
|
||||
|
||||
// Look for an existing placeholder menu with starter content to re-use.
|
||||
foreach ( $changeset_data as $setting_id => $setting_params ) {
|
||||
$can_reuse = (
|
||||
! empty( $setting_params['starter_content'] )
|
||||
&&
|
||||
! in_array( $setting_id, $reused_nav_menu_setting_ids, true )
|
||||
&&
|
||||
preg_match( '#^nav_menu\[(?P<nav_menu_id>-?\d+)\]$#', $setting_id, $matches )
|
||||
);
|
||||
if ( $can_reuse ) {
|
||||
$nav_menu_term_id = intval( $matches['nav_menu_id'] );
|
||||
$nav_menu_setting_id = $setting_id;
|
||||
$reused_nav_menu_setting_ids[] = $setting_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $nav_menu_term_id ) {
|
||||
while ( isset( $changeset_data[ sprintf( 'nav_menu[%d]', $placeholder_id ) ] ) ) {
|
||||
$placeholder_id--;
|
||||
}
|
||||
$nav_menu_term_id = $placeholder_id;
|
||||
$nav_menu_setting_id = sprintf( 'nav_menu[%d]', $placeholder_id );
|
||||
}
|
||||
|
||||
$this->set_post_value( $nav_menu_setting_id, array(
|
||||
'name' => isset( $nav_menu['name'] ) ? $nav_menu['name'] : $nav_menu_location,
|
||||
) );
|
||||
$this->starter_content_settings_ids[] = $nav_menu_setting_id;
|
||||
|
||||
// @todo Add support for menu_item_parent.
|
||||
$position = 0;
|
||||
@ -994,10 +1080,18 @@ final class WP_Customize_Manager {
|
||||
} else {
|
||||
$nav_menu_item['object_id'] = 0;
|
||||
}
|
||||
$this->set_post_value( $nav_menu_item_setting_id, $nav_menu_item );
|
||||
|
||||
if ( empty( $changeset_data[ $nav_menu_item_setting_id ] ) || ! empty( $changeset_data[ $nav_menu_item_setting_id ]['starter_content'] ) ) {
|
||||
$this->set_post_value( $nav_menu_item_setting_id, $nav_menu_item );
|
||||
$this->starter_content_settings_ids[] = $nav_menu_item_setting_id;
|
||||
}
|
||||
}
|
||||
|
||||
$this->set_post_value( sprintf( 'nav_menu_locations[%s]', $nav_menu_location ), $nav_menu_term_id );
|
||||
$setting_id = sprintf( 'nav_menu_locations[%s]', $nav_menu_location );
|
||||
if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) {
|
||||
$this->set_post_value( $setting_id, $nav_menu_term_id );
|
||||
$this->starter_content_settings_ids[] = $setting_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Options.
|
||||
@ -1005,7 +1099,11 @@ final class WP_Customize_Manager {
|
||||
if ( preg_match( '/^{{(?P<symbol>.+)}}$/', $value, $matches ) && isset( $posts[ $matches['symbol'] ] ) ) {
|
||||
$value = $posts[ $matches['symbol'] ]['ID'];
|
||||
}
|
||||
$this->set_post_value( $name, $value );
|
||||
|
||||
if ( empty( $changeset_data[ $name ] ) || ! empty( $changeset_data[ $name ]['starter_content'] ) ) {
|
||||
$this->set_post_value( $name, $value );
|
||||
$this->starter_content_settings_ids[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
// Theme mods.
|
||||
@ -1013,8 +1111,38 @@ final class WP_Customize_Manager {
|
||||
if ( preg_match( '/^{{(?P<symbol>.+)}}$/', $value, $matches ) && isset( $posts[ $matches['symbol'] ] ) ) {
|
||||
$value = $posts[ $matches['symbol'] ]['ID'];
|
||||
}
|
||||
$this->set_post_value( $name, $value );
|
||||
|
||||
if ( empty( $changeset_data[ $name ] ) || ! empty( $changeset_data[ $name ]['starter_content'] ) ) {
|
||||
$this->set_post_value( $name, $value );
|
||||
$this->starter_content_settings_ids[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $this->starter_content_settings_ids ) ) {
|
||||
if ( did_action( 'customize_register' ) ) {
|
||||
$this->_save_starter_content_changeset();
|
||||
} else {
|
||||
add_action( 'customize_register', array( $this, '_save_starter_content_changeset' ), 1000 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save starter content changeset.
|
||||
*
|
||||
* @since 4.7.0
|
||||
* @access private
|
||||
*/
|
||||
public function _save_starter_content_changeset() {
|
||||
|
||||
if ( empty( $this->starter_content_settings_ids ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->save_changeset_post( array(
|
||||
'data' => array_fill_keys( $this->starter_content_settings_ids, array( 'starter_content' => true ) ),
|
||||
'starter_content' => true,
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1823,11 +1951,12 @@ final class WP_Customize_Manager {
|
||||
* @param array $args {
|
||||
* Args for changeset post.
|
||||
*
|
||||
* @type array $data Optional additional changeset data. Values will be merged on top of any existing post values.
|
||||
* @type string $status Post status. Optional. If supplied, the save will be transactional and a post revision will be allowed.
|
||||
* @type string $title Post title. Optional.
|
||||
* @type string $date_gmt Date in GMT. Optional.
|
||||
* @type int $user_id ID for user who is saving the changeset. Optional, defaults to the current user ID.
|
||||
* @type array $data Optional additional changeset data. Values will be merged on top of any existing post values.
|
||||
* @type string $status Post status. Optional. If supplied, the save will be transactional and a post revision will be allowed.
|
||||
* @type string $title Post title. Optional.
|
||||
* @type string $date_gmt Date in GMT. Optional.
|
||||
* @type int $user_id ID for user who is saving the changeset. Optional, defaults to the current user ID.
|
||||
* @type bool $starter_content Whether the data is starter content. If false (default), then $starter_content will be cleared for any $data being saved.
|
||||
* }
|
||||
*
|
||||
* @return array|WP_Error Returns array on success and WP_Error with array data on error.
|
||||
@ -1841,6 +1970,7 @@ final class WP_Customize_Manager {
|
||||
'data' => array(),
|
||||
'date_gmt' => null,
|
||||
'user_id' => get_current_user_id(),
|
||||
'starter_content' => false,
|
||||
),
|
||||
$args
|
||||
);
|
||||
@ -1977,6 +2107,7 @@ final class WP_Customize_Manager {
|
||||
if ( ! isset( $data[ $changeset_setting_id ] ) ) {
|
||||
$data[ $changeset_setting_id ] = array();
|
||||
}
|
||||
|
||||
$data[ $changeset_setting_id ] = array_merge(
|
||||
$data[ $changeset_setting_id ],
|
||||
$setting_params,
|
||||
@ -1985,6 +2116,11 @@ final class WP_Customize_Manager {
|
||||
'user_id' => $args['user_id'],
|
||||
)
|
||||
);
|
||||
|
||||
// Clear starter_content flag in data if changeset is not explicitly being updated for starter content.
|
||||
if ( empty( $args['starter_content'] ) ) {
|
||||
unset( $data[ $changeset_setting_id ]['starter_content'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -696,6 +696,7 @@ final class WP_Customize_Nav_Menus {
|
||||
|
||||
$this->manager->add_setting( new WP_Customize_Filter_Setting( $this->manager, 'nav_menus_created_posts', array(
|
||||
'transport' => 'postMessage',
|
||||
'type' => 'option', // To prevent theme prefix in changeset.
|
||||
'default' => array(),
|
||||
'sanitize_callback' => array( $this, 'sanitize_nav_menus_created_posts' ),
|
||||
) ) );
|
||||
|
@ -1824,26 +1824,26 @@ function get_theme_starter_content() {
|
||||
$config = array();
|
||||
}
|
||||
|
||||
$core_content = array (
|
||||
$core_content = array(
|
||||
'widgets' => array(
|
||||
'text_business_info' => array ( 'text', array (
|
||||
'text_business_info' => array( 'text', array(
|
||||
'title' => _x( 'Find Us', 'Theme starter content' ),
|
||||
'text' => join( '', array (
|
||||
'text' => join( '', array(
|
||||
'<p><strong>' . _x( 'Address', 'Theme starter content' ) . '</strong><br />',
|
||||
_x( '123 Main Street', 'Theme starter content' ) . '<br />' . _x( 'New York, NY 10001', 'Theme starter content' ) . '</p>',
|
||||
'<p><strong>' . _x( 'Hours', 'Theme starter content' ) . '</strong><br />',
|
||||
_x( 'Monday—Friday: 9:00AM–5:00PM', 'Theme starter content' ) . '<br />' . _x( 'Saturday & Sunday: 11:00AM–3:00PM', 'Theme starter content' ) . '</p>'
|
||||
) ),
|
||||
) ),
|
||||
'search' => array ( 'search', array (
|
||||
'search' => array( 'search', array(
|
||||
'title' => _x( 'Site Search', 'Theme starter content' ),
|
||||
) ),
|
||||
'text_credits' => array ( 'text', array (
|
||||
'text_credits' => array( 'text', array(
|
||||
'title' => _x( 'Site Credits', 'Theme starter content' ),
|
||||
'text' => sprintf( _x( 'This site was created on %s', 'Theme starter content' ), get_date_from_gmt( current_time( 'mysql', 1 ), 'c' ) ),
|
||||
) ),
|
||||
),
|
||||
'nav_menus' => array (
|
||||
'nav_menus' => array(
|
||||
'page_home' => array(
|
||||
'type' => 'post_type',
|
||||
'object' => 'page',
|
||||
@ -1919,48 +1919,53 @@ function get_theme_starter_content() {
|
||||
|
||||
foreach ( $config as $type => $args ) {
|
||||
switch( $type ) {
|
||||
// Use options and theme_mods as-is
|
||||
// Use options and theme_mods as-is.
|
||||
case 'options' :
|
||||
case 'theme_mods' :
|
||||
$content[ $type ] = $config[ $type ];
|
||||
break;
|
||||
|
||||
// Widgets are an extra level down due to groupings
|
||||
// Widgets are grouped into sidebars.
|
||||
case 'widgets' :
|
||||
foreach ( $config[ $type ] as $group => $items ) {
|
||||
foreach ( $items as $id ) {
|
||||
if ( ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $id ] ) ) {
|
||||
$content[ $type ][ $group ][ $id ] = $core_content[ $type ][ $id ];
|
||||
foreach ( $config[ $type ] as $sidebar_id => $widgets ) {
|
||||
foreach ( $widgets as $widget ) {
|
||||
if ( is_array( $widget ) ) {
|
||||
$content[ $type ][ $sidebar_id ][] = $widget;
|
||||
} elseif ( is_string( $widget ) && ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $widget ] ) ) {
|
||||
$content[ $type ][ $sidebar_id ][] = $core_content[ $type ][ $widget ];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// And nav menus are yet another level down
|
||||
// And nav menu items are grouped into nav menus.
|
||||
case 'nav_menus' :
|
||||
foreach ( $config[ $type ] as $group => $args2 ) {
|
||||
// Menu groups need a name
|
||||
if ( empty( $args['name'] ) ) {
|
||||
$args2['name'] = $group;
|
||||
foreach ( $config[ $type ] as $nav_menu_location => $nav_menu ) {
|
||||
|
||||
// Ensure nav menus get a name.
|
||||
if ( empty( $nav_menu['name'] ) ) {
|
||||
$nav_menu['name'] = $nav_menu_location;
|
||||
}
|
||||
|
||||
$content[ $type ][ $group ]['name'] = $args2['name'];
|
||||
$content[ $type ][ $nav_menu_location ]['name'] = $nav_menu['name'];
|
||||
|
||||
// Do we need to check if this is empty?
|
||||
foreach ( $args2['items'] as $id ) {
|
||||
if ( ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $id ] ) ) {
|
||||
$content[ $type ][ $group ]['items'][ $id ] = $core_content[ $type ][ $id ];
|
||||
foreach ( $nav_menu['items'] as $nav_menu_item ) {
|
||||
if ( is_array( $nav_menu_item ) ) {
|
||||
$content[ $type ][ $nav_menu_location ]['items'][] = $nav_menu_item;
|
||||
} elseif ( is_string( $nav_menu_item ) && ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $nav_menu_item ] ) ) {
|
||||
$content[ $type ][ $nav_menu_location ]['items'][] = $core_content[ $type ][ $nav_menu_item ];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// Everything else should map at the next level
|
||||
// Everything else should map at the next level.
|
||||
default :
|
||||
foreach( $config[ $type ] as $id ) {
|
||||
if ( ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $id ] ) ) {
|
||||
$content[ $type ][ $id ] = $core_content[ $type ][ $id ];
|
||||
foreach( $config[ $type ] as $i => $item ) {
|
||||
if ( is_array( $item ) ) {
|
||||
$content[ $type ][ $i ] = $item;
|
||||
} elseif ( is_string( $item ) && ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $item ] ) ) {
|
||||
$content[ $type ][ $item ] = $core_content[ $type ][ $item ];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -4,7 +4,7 @@
|
||||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '4.7-beta3-39240';
|
||||
$wp_version = '4.7-beta3-39241';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
|
Loading…
x
Reference in New Issue
Block a user