Make WordPress Core

Changeset 41205


Ignore:
Timestamp:
08/02/2017 05:34:32 AM (7 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.