Customize: Introduce settings_previewed
arg and getter on WP_Customize_Manager
which controls whether WP_Customize_Setting::preview()
should be called on settings.
The `settings_previewed` property eliminates the need for the Customizer components from having to look at global `doing_ajax` state. This is in particular needed when saving settings, as some settings will short-circuit the update operation if they detect no changes are introduced. This is also needed for low-level integrations with the Customizer, such as in REST API endpoints under development. Props stubgo, westonruter, utkarshpatel for testing. See #38900. Fixes #39221. git-svn-id: https://develop.svn.wordpress.org/trunk@41205 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
57e57505ba
commit
9c1005410f
@ -173,6 +173,14 @@ final class WP_Customize_Manager {
|
|||||||
*/
|
*/
|
||||||
protected $messenger_channel;
|
protected $messenger_channel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether settings should be previewed.
|
||||||
|
*
|
||||||
|
* @since 4.9.0
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $settings_previewed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsanitized values for Customize Settings parsed from $_POST['customized'].
|
* Unsanitized values for Customize Settings parsed from $_POST['customized'].
|
||||||
*
|
*
|
||||||
@ -213,15 +221,16 @@ final class WP_Customize_Manager {
|
|||||||
* @param array $args {
|
* @param array $args {
|
||||||
* Args.
|
* Args.
|
||||||
*
|
*
|
||||||
* @type string $changeset_uuid Changeset UUID, the post_name for the customize_changeset post containing the customized state. Defaults to new UUID.
|
* @type string $changeset_uuid Changeset UUID, the post_name for the customize_changeset post containing the customized state. Defaults to new UUID.
|
||||||
* @type string $theme Theme to be previewed (for theme switch). Defaults to customize_theme or theme query params.
|
* @type string $theme Theme to be previewed (for theme switch). Defaults to customize_theme or theme query params.
|
||||||
* @type string $messenger_channel Messenger channel. Defaults to customize_messenger_channel query param.
|
* @type string $messenger_channel Messenger channel. Defaults to customize_messenger_channel query param.
|
||||||
|
* @type bool $settings_previewed If settings should be previewed. Defaults to true.
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
public function __construct( $args = array() ) {
|
public function __construct( $args = array() ) {
|
||||||
|
|
||||||
$args = array_merge(
|
$args = array_merge(
|
||||||
array_fill_keys( array( 'changeset_uuid', 'theme', 'messenger_channel' ), null ),
|
array_fill_keys( array( 'changeset_uuid', 'theme', 'messenger_channel', 'settings_previewed' ), null ),
|
||||||
$args
|
$args
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -242,9 +251,14 @@ final class WP_Customize_Manager {
|
|||||||
$args['messenger_channel'] = sanitize_key( wp_unslash( $_REQUEST['customize_messenger_channel'] ) );
|
$args['messenger_channel'] = sanitize_key( wp_unslash( $_REQUEST['customize_messenger_channel'] ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! isset( $args['settings_previewed'] ) ) {
|
||||||
|
$args['settings_previewed'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
$this->original_stylesheet = get_stylesheet();
|
$this->original_stylesheet = get_stylesheet();
|
||||||
$this->theme = wp_get_theme( $args['theme'] );
|
$this->theme = wp_get_theme( $args['theme'] );
|
||||||
$this->messenger_channel = $args['messenger_channel'];
|
$this->messenger_channel = $args['messenger_channel'];
|
||||||
|
$this->settings_previewed = ! empty( $args['settings_previewed'] );
|
||||||
$this->_changeset_uuid = $args['changeset_uuid'];
|
$this->_changeset_uuid = $args['changeset_uuid'];
|
||||||
|
|
||||||
require_once( ABSPATH . WPINC . '/class-wp-customize-setting.php' );
|
require_once( ABSPATH . WPINC . '/class-wp-customize-setting.php' );
|
||||||
@ -621,6 +635,18 @@ final class WP_Customize_Manager {
|
|||||||
do_action( 'stop_previewing_theme', $this );
|
do_action( 'stop_previewing_theme', $this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether settings are or will be previewed.
|
||||||
|
*
|
||||||
|
* @since 4.9.0
|
||||||
|
* @see WP_Customize_Setting::preview()
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function settings_previewed() {
|
||||||
|
return $this->settings_previewed;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the changeset UUID.
|
* Get the changeset UUID.
|
||||||
*
|
*
|
||||||
@ -728,15 +754,7 @@ final class WP_Customize_Manager {
|
|||||||
*/
|
*/
|
||||||
do_action( 'customize_register', $this );
|
do_action( 'customize_register', $this );
|
||||||
|
|
||||||
/*
|
if ( $this->settings_previewed() ) {
|
||||||
* Note that settings must be previewed here even outside the customizer preview
|
|
||||||
* and also in the customizer pane itself. This is to enable loading an existing
|
|
||||||
* changeset into the customizer. Previewing the settings only has to be prevented
|
|
||||||
* in the case of a customize_save action because then update_option()
|
|
||||||
* may short-circuit because it will detect that there are no changes to
|
|
||||||
* make.
|
|
||||||
*/
|
|
||||||
if ( ! $this->doing_ajax( 'customize_save' ) ) {
|
|
||||||
foreach ( $this->settings as $setting ) {
|
foreach ( $this->settings as $setting ) {
|
||||||
$setting->preview();
|
$setting->preview();
|
||||||
}
|
}
|
||||||
|
@ -526,13 +526,10 @@ final class WP_Customize_Nav_Menus {
|
|||||||
$nav_menus_setting_ids[] = $setting_id;
|
$nav_menus_setting_ids[] = $setting_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->manager->add_dynamic_settings( $nav_menus_setting_ids );
|
$settings = $this->manager->add_dynamic_settings( $nav_menus_setting_ids );
|
||||||
if ( ! $this->manager->doing_ajax( 'customize_save' ) ) {
|
if ( $this->manager->settings_previewed() ) {
|
||||||
foreach ( $nav_menus_setting_ids as $setting_id ) {
|
foreach ( $settings as $setting ) {
|
||||||
$setting = $this->manager->get_setting( $setting_id );
|
$setting->preview();
|
||||||
if ( $setting ) {
|
|
||||||
$setting->preview();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,12 +211,7 @@ final class WP_Customize_Widgets {
|
|||||||
|
|
||||||
$settings = $this->manager->add_dynamic_settings( array_unique( $widget_setting_ids ) );
|
$settings = $this->manager->add_dynamic_settings( array_unique( $widget_setting_ids ) );
|
||||||
|
|
||||||
/*
|
if ( $this->manager->settings_previewed() ) {
|
||||||
* Preview settings right away so that widgets and sidebars will get registered properly.
|
|
||||||
* But don't do this if a customize_save because this will cause WP to think there is nothing
|
|
||||||
* changed that needs to be saved.
|
|
||||||
*/
|
|
||||||
if ( ! $this->manager->doing_ajax( 'customize_save' ) ) {
|
|
||||||
foreach ( $settings as $setting ) {
|
foreach ( $settings as $setting ) {
|
||||||
$setting->preview();
|
$setting->preview();
|
||||||
}
|
}
|
||||||
@ -506,7 +501,7 @@ final class WP_Customize_Widgets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! $this->manager->doing_ajax( 'customize_save' ) ) {
|
if ( $this->manager->settings_previewed() ) {
|
||||||
foreach ( $new_setting_ids as $new_setting_id ) {
|
foreach ( $new_setting_ids as $new_setting_id ) {
|
||||||
$this->manager->get_setting( $new_setting_id )->preview();
|
$this->manager->get_setting( $new_setting_id )->preview();
|
||||||
}
|
}
|
||||||
|
@ -2816,8 +2816,24 @@ function _wp_customize_include() {
|
|||||||
$messenger_channel = sanitize_key( $input_vars['customize_messenger_channel'] );
|
$messenger_channel = sanitize_key( $input_vars['customize_messenger_channel'] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that settings must be previewed even outside the customizer preview
|
||||||
|
* and also in the customizer pane itself. This is to enable loading an existing
|
||||||
|
* changeset into the customizer. Previewing the settings only has to be prevented
|
||||||
|
* here in the case of a customize_save action because this will cause WP to think
|
||||||
|
* there is nothing changed that needs to be saved.
|
||||||
|
*/
|
||||||
|
$is_customize_save_action = (
|
||||||
|
wp_doing_ajax()
|
||||||
|
&&
|
||||||
|
isset( $_REQUEST['action'] )
|
||||||
|
&&
|
||||||
|
'customize_save' === wp_unslash( $_REQUEST['action'] )
|
||||||
|
);
|
||||||
|
$settings_previewed = ! $is_customize_save_action;
|
||||||
|
|
||||||
require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
|
require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
|
||||||
$GLOBALS['wp_customize'] = new WP_Customize_Manager( compact( 'changeset_uuid', 'theme', 'messenger_channel' ) );
|
$GLOBALS['wp_customize'] = new WP_Customize_Manager( compact( 'changeset_uuid', 'theme', 'messenger_channel', 'settings_previewed' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2849,7 +2865,10 @@ function _wp_customize_publish_changeset( $new_status, $old_status, $changeset_p
|
|||||||
|
|
||||||
if ( empty( $wp_customize ) ) {
|
if ( empty( $wp_customize ) ) {
|
||||||
require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
|
require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
|
||||||
$wp_customize = new WP_Customize_Manager( array( 'changeset_uuid' => $changeset_post->post_name ) );
|
$wp_customize = new WP_Customize_Manager( array(
|
||||||
|
'changeset_uuid' => $changeset_post->post_name,
|
||||||
|
'settings_previewed' => false,
|
||||||
|
) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! did_action( 'customize_register' ) ) {
|
if ( ! did_action( 'customize_register' ) ) {
|
||||||
|
@ -215,6 +215,20 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
|
|||||||
$this->assertTrue( $show_admin_bar );
|
$this->assertTrue( $show_admin_bar );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test WP_Customize_Manager::settings_previewed().
|
||||||
|
*
|
||||||
|
* @ticket 39221
|
||||||
|
* @covers WP_Customize_Manager::settings_previewed()
|
||||||
|
*/
|
||||||
|
function test_settings_previewed() {
|
||||||
|
$wp_customize = new WP_Customize_Manager( array( 'settings_previewed' => false ) );
|
||||||
|
$this->assertSame( false, $wp_customize->settings_previewed() );
|
||||||
|
|
||||||
|
$wp_customize = new WP_Customize_Manager();
|
||||||
|
$this->assertSame( true, $wp_customize->settings_previewed() );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test WP_Customize_Manager::changeset_uuid().
|
* Test WP_Customize_Manager::changeset_uuid().
|
||||||
*
|
*
|
||||||
@ -1291,6 +1305,54 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
|
|||||||
$this->assertEquals( 'Unfiltered<script>evil</script>', get_option( 'scratchpad' ) );
|
$this->assertEquals( 'Unfiltered<script>evil</script>', get_option( 'scratchpad' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test saving settings by publishing a changeset outside of Customizer entirely.
|
||||||
|
*
|
||||||
|
* Widgets get their settings registered and previewed early in the admin,
|
||||||
|
* so this ensures that the previewing is bypassed when in the context of
|
||||||
|
* publishing
|
||||||
|
*
|
||||||
|
* @ticket 39221
|
||||||
|
* @covers _wp_customize_publish_changeset()
|
||||||
|
* @see WP_Customize_Widgets::schedule_customize_register()
|
||||||
|
* @see WP_Customize_Widgets::customize_register()
|
||||||
|
*/
|
||||||
|
function test_wp_customize_publish_changeset() {
|
||||||
|
global $wp_customize;
|
||||||
|
$wp_customize = null;
|
||||||
|
|
||||||
|
// Set the admin current screen to cause WP_Customize_Widgets::schedule_customize_register() to do early setting registration.
|
||||||
|
set_current_screen( 'edit' );
|
||||||
|
$this->assertTrue( is_admin() );
|
||||||
|
|
||||||
|
$old_sidebars_widgets = get_option( 'sidebars_widgets' );
|
||||||
|
$new_sidebars_widgets = $old_sidebars_widgets;
|
||||||
|
$this->assertGreaterThan( 2, count( $new_sidebars_widgets['sidebar-1'] ) );
|
||||||
|
$new_sidebar_1 = array_reverse( $new_sidebars_widgets['sidebar-1'] );
|
||||||
|
|
||||||
|
$post_id = $this->factory()->post->create( array(
|
||||||
|
'post_type' => 'customize_changeset',
|
||||||
|
'post_status' => 'draft',
|
||||||
|
'post_name' => wp_generate_uuid4(),
|
||||||
|
'post_content' => wp_json_encode( array(
|
||||||
|
'sidebars_widgets[sidebar-1]' => array(
|
||||||
|
'value' => $new_sidebar_1,
|
||||||
|
),
|
||||||
|
) ),
|
||||||
|
) );
|
||||||
|
|
||||||
|
// Save the updated sidebar widgets into the options table by publishing the changeset.
|
||||||
|
wp_publish_post( $post_id );
|
||||||
|
|
||||||
|
// Make sure previewing filters were never added, since WP_Customize_Manager should be constructed with settings_previewed=false.
|
||||||
|
$this->assertFalse( has_filter( 'option_sidebars_widgets' ) );
|
||||||
|
$this->assertFalse( has_filter( 'default_option_sidebars_widgets' ) );
|
||||||
|
|
||||||
|
// Ensure that the value has actually been written to the DB.
|
||||||
|
$updated_sidebars_widgets = get_option( 'sidebars_widgets' );
|
||||||
|
$this->assertEquals( $new_sidebar_1, $updated_sidebars_widgets['sidebar-1'] );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that save_changeset_post method bails updating an underlying changeset which is invalid.
|
* Ensure that save_changeset_post method bails updating an underlying changeset which is invalid.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user