Make WordPress Core

Changeset 41205


Ignore:
Timestamp:
08/02/2017 05:34:32 AM (9 years ago)
Author:
westonruter
Message:

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.

Location:
trunk
Files:
5 edited

Legend:

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

    r41162 r41205  
    175175
    176176        /**
     177         * Whether settings should be previewed.
     178         *
     179         * @since 4.9.0
     180         * @var bool
     181         */
     182        protected $settings_previewed;
     183
     184        /**
    177185         * Unsanitized values for Customize Settings parsed from $_POST['customized'].
    178186         *
     
    214222         *     Args.
    215223         *
    216          *     @type string $changeset_uuid    Changeset UUID, the post_name for the customize_changeset post containing the customized state. Defaults to new UUID.
    217          *     @type string $theme             Theme to be previewed (for theme switch). Defaults to customize_theme or theme query params.
    218          *     @type string $messenger_channel Messenger channel. Defaults to customize_messenger_channel query param.
     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.
    219228         * }
    220229         */
     
    222231
    223232                $args = array_merge(
    224                         array_fill_keys( array( 'changeset_uuid', 'theme', 'messenger_channel' ), null ),
     233                        array_fill_keys( array( 'changeset_uuid', 'theme', 'messenger_channel', 'settings_previewed' ), null ),
    225234                        $args
    226235                );
     
    243252                }
    244253
     254                if ( ! isset( $args['settings_previewed'] ) ) {
     255                        $args['settings_previewed'] = true;
     256                }
     257
    245258                $this->original_stylesheet = get_stylesheet();
    246259                $this->theme = wp_get_theme( $args['theme'] );
    247260                $this->messenger_channel = $args['messenger_channel'];
     261                $this->settings_previewed = ! empty( $args['settings_previewed'] );
    248262                $this->_changeset_uuid = $args['changeset_uuid'];
    249263
     
    623637
    624638        /**
     639         * Gets whether settings are or will be previewed.
     640         *
     641         * @since 4.9.0
     642         * @see WP_Customize_Setting::preview()
     643         *
     644         * @return bool
     645         */
     646        public function settings_previewed() {
     647                return $this->settings_previewed;
     648        }
     649
     650        /**
    625651         * Get the changeset UUID.
    626652         *
     
    729755                do_action( 'customize_register', $this );
    730756
    731                 /*
    732                  * Note that settings must be previewed here even outside the customizer preview
    733                  * and also in the customizer pane itself. This is to enable loading an existing
    734                  * changeset into the customizer. Previewing the settings only has to be prevented
    735                  * in the case of a customize_save action because then update_option()
    736                  * may short-circuit because it will detect that there are no changes to
    737                  * make.
    738                  */
    739                 if ( ! $this->doing_ajax( 'customize_save' ) ) {
     757                if ( $this->settings_previewed() ) {
    740758                        foreach ( $this->settings as $setting ) {
    741759                                $setting->preview();
  • trunk/src/wp-includes/class-wp-customize-nav-menus.php

    r41204 r41205  
    527527                        }
    528528                }
    529                 $this->manager->add_dynamic_settings( $nav_menus_setting_ids );
    530                 if ( ! $this->manager->doing_ajax( 'customize_save' ) ) {
    531                         foreach ( $nav_menus_setting_ids as $setting_id ) {
    532                                 $setting = $this->manager->get_setting( $setting_id );
    533                                 if ( $setting ) {
    534                                         $setting->preview();
    535                                 }
     529                $settings = $this->manager->add_dynamic_settings( $nav_menus_setting_ids );
     530                if ( $this->manager->settings_previewed() ) {
     531                        foreach ( $settings as $setting ) {
     532                                $setting->preview();
    536533                        }
    537534                }
  • trunk/src/wp-includes/class-wp-customize-widgets.php

    r41168 r41205  
    212212                $settings = $this->manager->add_dynamic_settings( array_unique( $widget_setting_ids ) );
    213213
    214                 /*
    215                  * Preview settings right away so that widgets and sidebars will get registered properly.
    216                  * But don't do this if a customize_save because this will cause WP to think there is nothing
    217                  * changed that needs to be saved.
    218                  */
    219                 if ( ! $this->manager->doing_ajax( 'customize_save' ) ) {
     214                if ( $this->manager->settings_previewed() ) {
    220215                        foreach ( $settings as $setting ) {
    221216                                $setting->preview();
     
    507502                }
    508503
    509                 if ( ! $this->manager->doing_ajax( 'customize_save' ) ) {
     504                if ( $this->manager->settings_previewed() ) {
    510505                        foreach ( $new_setting_ids as $new_setting_id ) {
    511506                                $this->manager->get_setting( $new_setting_id )->preview();
  • trunk/src/wp-includes/theme.php

    r41193 r41205  
    28172817        }
    28182818
     2819        /*
     2820         * Note that settings must be previewed even outside the customizer preview
     2821         * and also in the customizer pane itself. This is to enable loading an existing
     2822         * changeset into the customizer. Previewing the settings only has to be prevented
     2823         * here in the case of a customize_save action because this will cause WP to think
     2824         * there is nothing changed that needs to be saved.
     2825         */
     2826        $is_customize_save_action = (
     2827                wp_doing_ajax()
     2828                &&
     2829                isset( $_REQUEST['action'] )
     2830                &&
     2831                'customize_save' === wp_unslash( $_REQUEST['action'] )
     2832        );
     2833        $settings_previewed = ! $is_customize_save_action;
     2834
    28192835        require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
    2820         $GLOBALS['wp_customize'] = new WP_Customize_Manager( compact( 'changeset_uuid', 'theme', 'messenger_channel' ) );
     2836        $GLOBALS['wp_customize'] = new WP_Customize_Manager( compact( 'changeset_uuid', 'theme', 'messenger_channel', 'settings_previewed' ) );
    28212837}
    28222838
     
    28502866        if ( empty( $wp_customize ) ) {
    28512867                require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
    2852                 $wp_customize = new WP_Customize_Manager( array( 'changeset_uuid' => $changeset_post->post_name ) );
     2868                $wp_customize = new WP_Customize_Manager( array(
     2869                        'changeset_uuid' => $changeset_post->post_name,
     2870                        'settings_previewed' => false,
     2871                ) );
    28532872        }
    28542873
  • trunk/tests/phpunit/tests/customize/manager.php

    r41012 r41205  
    214214                $wp_customize->setup_theme();
    215215                $this->assertTrue( $show_admin_bar );
     216        }
     217
     218        /**
     219         * Test WP_Customize_Manager::settings_previewed().
     220         *
     221         * @ticket 39221
     222         * @covers WP_Customize_Manager::settings_previewed()
     223         */
     224        function test_settings_previewed() {
     225                $wp_customize = new WP_Customize_Manager( array( 'settings_previewed' => false ) );
     226                $this->assertSame( false, $wp_customize->settings_previewed() );
     227
     228                $wp_customize = new WP_Customize_Manager();
     229                $this->assertSame( true, $wp_customize->settings_previewed() );
    216230        }
    217231
     
    12931307
    12941308        /**
     1309         * Test saving settings by publishing a changeset outside of Customizer entirely.
     1310         *
     1311         * Widgets get their settings registered and previewed early in the admin,
     1312         * so this ensures that the previewing is bypassed when in the context of
     1313         * publishing
     1314         *
     1315         * @ticket 39221
     1316         * @covers _wp_customize_publish_changeset()
     1317         * @see WP_Customize_Widgets::schedule_customize_register()
     1318         * @see WP_Customize_Widgets::customize_register()
     1319         */
     1320        function test_wp_customize_publish_changeset() {
     1321                global $wp_customize;
     1322                $wp_customize = null;
     1323
     1324                // Set the admin current screen to cause WP_Customize_Widgets::schedule_customize_register() to do early setting registration.
     1325                set_current_screen( 'edit' );
     1326                $this->assertTrue( is_admin() );
     1327
     1328                $old_sidebars_widgets = get_option( 'sidebars_widgets' );
     1329                $new_sidebars_widgets = $old_sidebars_widgets;
     1330                $this->assertGreaterThan( 2, count( $new_sidebars_widgets['sidebar-1'] ) );
     1331                $new_sidebar_1 = array_reverse( $new_sidebars_widgets['sidebar-1'] );
     1332
     1333                $post_id = $this->factory()->post->create( array(
     1334                        'post_type' => 'customize_changeset',
     1335                        'post_status' => 'draft',
     1336                        'post_name' => wp_generate_uuid4(),
     1337                        'post_content' => wp_json_encode( array(
     1338                                'sidebars_widgets[sidebar-1]' => array(
     1339                                        'value' => $new_sidebar_1,
     1340                                ),
     1341                        ) ),
     1342                ) );
     1343
     1344                // Save the updated sidebar widgets into the options table by publishing the changeset.
     1345                wp_publish_post( $post_id );
     1346
     1347                // Make sure previewing filters were never added, since WP_Customize_Manager should be constructed with settings_previewed=false.
     1348                $this->assertFalse( has_filter( 'option_sidebars_widgets' ) );
     1349                $this->assertFalse( has_filter( 'default_option_sidebars_widgets' ) );
     1350
     1351                // Ensure that the value has actually been written to the DB.
     1352                $updated_sidebars_widgets = get_option( 'sidebars_widgets' );
     1353                $this->assertEquals( $new_sidebar_1, $updated_sidebars_widgets['sidebar-1'] );
     1354        }
     1355
     1356        /**
    12951357         * Ensure that save_changeset_post method bails updating an underlying changeset which is invalid.
    12961358         *
Note: See TracChangeset for help on using the changeset viewer.