WordPress.org

Make WordPress Core

Changeset 35724


Ignore:
Timestamp:
11/21/2015 02:51:57 AM (4 years ago)
Author:
westonruter
Message:

Customize: Ensure that a setting (especially a multidimensional one) can still be previewed when the post value to preview is set after preview() is invoked.

  • Introduce customize_post_value_set_{$setting_id} and customize_post_value_set actions which are done when WP_Customize_Manager::set_post_value() is called.
  • Clear the preview_applied flag for aggregated multidimensional settings when a post value is set. This ensures the new value is used instead of a previously-cached previewed value.
  • Move $is_preview property from subclasses to WP_Customize_Setting parent class.
  • Deferred preview: Ensure that when preview() short-circuits due to not being applicable that it will be called again later when the post value is set.
  • Populate post value for updated-widget with the (unsanitized) JS-value in WP_Customize_Widgets::call_widget_update() so that value will be properly sanitized when accessed in WP_Customize_Manager::post_value().

Includes unit tests with assertions to check the reported issues and validate the fixes.

Fixes defect introduced in [35007].
See #32103.
Fixes #34738.

Location:
trunk
Files:
8 edited

Legend:

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

    r35718 r35724  
    660660        $this->unsanitized_post_values();
    661661        $this->_post_values[ $setting_id ] = $value;
     662
     663        /**
     664         * Announce when a specific setting's unsanitized post value has been set.
     665         *
     666         * Fires when the {@see WP_Customize_Manager::set_post_value()} method is called.
     667         *
     668         * The dynamic portion of the hook name, `$setting_id`, refers to the setting ID.
     669         *
     670         * @since 4.4.0
     671         *
     672         * @param mixed                $value Unsanitized setting post value.
     673         * @param WP_Customize_Manager $this  WP_Customize_Manager instance.
     674         */
     675        do_action( "customize_post_value_set_{$setting_id}", $value, $this );
     676
     677        /**
     678         * Announce when any setting's unsanitized post value has been set.
     679         *
     680         * Fires when the {@see WP_Customize_Manager::set_post_value()} method is called.
     681         *
     682         * This is useful for <code>WP_Customize_Setting</code> instances to watch
     683         * in order to update a cached previewed value.
     684         *
     685         * @since 4.4.0
     686         *
     687         * @param string               $setting_id Setting ID.
     688         * @param mixed                $value      Unsanitized setting post value.
     689         * @param WP_Customize_Manager $this       WP_Customize_Manager instance.
     690         */
     691        do_action( 'customize_post_value_set', $setting_id, $value, $this );
    662692    }
    663693
  • trunk/src/wp-includes/class-wp-customize-setting.php

    r35383 r35724  
    8383
    8484    /**
     85     * Whether or not preview() was called.
     86     *
     87     * @since 4.4.0
     88     * @access protected
     89     * @var bool
     90     */
     91    protected $is_previewed = false;
     92
     93    /**
    8594     * Cache of multidimensional values to improve performance.
    8695     *
     
    192201
    193202        if ( ! empty( $this->id_data['keys'] ) ) {
     203            // Note the preview-applied flag is cleared at priority 9 to ensure it is cleared before a deferred-preview runs.
     204            add_action( "customize_post_value_set_{$this->id}", array( $this, '_clear_aggregated_multidimensional_preview_applied_flag' ), 9 );
    194205            $this->is_multidimensional_aggregated = true;
    195206        }
     
    246257            $this->_previewed_blog_id = get_current_blog_id();
    247258        }
     259
     260        // Prevent re-previewing an already-previewed setting.
     261        if ( $this->is_previewed ) {
     262            return true;
     263        }
     264
    248265        $id_base = $this->id_data['base'];
    249266        $is_multidimensional = ! empty( $this->id_data['keys'] );
     
    274291        }
    275292
     293        // If the setting does not need previewing now, defer to when it has a value to preview.
    276294        if ( ! $needs_preview ) {
     295            if ( ! has_action( "customize_post_value_set_{$this->id}", array( $this, 'preview' ) ) ) {
     296                add_action( "customize_post_value_set_{$this->id}", array( $this, 'preview' ) );
     297            }
    277298            return false;
    278299        }
     
    328349                do_action( "customize_preview_{$this->type}", $this );
    329350        }
     351
     352        $this->is_previewed = true;
     353
    330354        return true;
     355    }
     356
     357    /**
     358     * Clear out the previewed-applied flag for a multidimensional-aggregated value whenever its post value is updated.
     359     *
     360     * This ensures that the new value will get sanitized and used the next time
     361     * that <code>WP_Customize_Setting::_multidimensional_preview_filter()</code>
     362     * is called for this setting.
     363     *
     364     * @since 4.4.0
     365     * @access private
     366     * @see WP_Customize_Manager::set_post_value()
     367     * @see WP_Customize_Setting::_multidimensional_preview_filter()
     368     */
     369    final public function _clear_aggregated_multidimensional_preview_applied_flag() {
     370        unset( self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['preview_applied_instances'][ $this->id ] );
    331371    }
    332372
     
    370410     *
    371411     * @since 4.4.0
    372      * @access public
     412     * @access private
    373413     *
    374414     * @see WP_Customize_Setting::$aggregated_multidimensionals
     
    376416     * @return mixed New or old value.
    377417     */
    378     public function _multidimensional_preview_filter( $original ) {
     418    final public function _multidimensional_preview_filter( $original ) {
    379419        if ( ! $this->is_current_blog_previewed() ) {
    380420            return $original;
  • trunk/src/wp-includes/class-wp-customize-widgets.php

    r35381 r35724  
    13811381         * instead of the default widget instance value (an empty array).
    13821382         */
    1383         $this->manager->set_post_value( $setting_id, $instance );
     1383        $this->manager->set_post_value( $setting_id, $this->sanitize_widget_js_instance( $instance ) );
    13841384
    13851385        // Obtain the widget control with the updated instance in place.
  • trunk/src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php

    r35580 r35724  
    119119     */
    120120    public $original_nav_menu_term_id;
    121 
    122     /**
    123      * Whether or not preview() was called.
    124      *
    125      * @since 4.3.0
    126      * @access protected
    127      * @var bool
    128      */
    129     protected $is_previewed = false;
    130121
    131122    /**
  • trunk/src/wp-includes/customize/class-wp-customize-nav-menu-setting.php

    r35385 r35724  
    9090
    9191    /**
    92      * Whether or not preview() was called.
    93      *
    94      * @since 4.3.0
    95      * @access protected
    96      * @var bool
    97      */
    98     protected $is_previewed = false;
    99 
    100     /**
    10192     * Whether or not update() was called.
    10293     *
  • trunk/tests/phpunit/tests/customize/manager.php

    r35635 r35724  
    3333        parent::setUp();
    3434        require_once( ABSPATH . WPINC . '/class-wp-customize-manager.php' );
    35         $GLOBALS['wp_customize'] = new WP_Customize_Manager();
    36         $this->manager = $GLOBALS['wp_customize'];
     35        $this->manager = $this->instantiate();
    3736        $this->undefined = new stdClass();
    3837    }
     
    6766        }
    6867
    69         $manager = $this->instantiate();
     68        $manager = $this->manager;
    7069        $this->assertTrue( $manager->doing_ajax() );
    7170
     
    8382        }
    8483
    85         $manager = $this->instantiate();
     84        $manager = $this->manager;
    8685        $this->assertFalse( $manager->doing_ajax() );
    8786    }
     
    9392     */
    9493    function test_unsanitized_post_values() {
    95         $manager = $this->instantiate();
     94        $manager = $this->manager;
    9695
    9796        $customized = array(
     
    115114        $_POST['customized'] = wp_slash( wp_json_encode( $posted_settings ) );
    116115
    117         $manager = $this->instantiate();
     116        $manager = $this->manager;
    118117
    119118        $manager->add_setting( 'foo', array( 'default' => 'foo_default' ) );
     
    128127
    129128    /**
     129     * Test WP_Customize_Manager::set_post_value().
     130     *
     131     * @see WP_Customize_Manager::set_post_value()
     132     */
     133    function test_set_post_value() {
     134        $this->manager->add_setting( 'foo', array(
     135            'sanitize_callback' => array( $this, 'sanitize_foo_for_test_set_post_value' ),
     136        ) );
     137        $setting = $this->manager->get_setting( 'foo' );
     138
     139        $this->assertEmpty( $this->captured_customize_post_value_set_actions );
     140        add_action( 'customize_post_value_set', array( $this, 'capture_customize_post_value_set_actions' ), 10, 3 );
     141        add_action( 'customize_post_value_set_foo', array( $this, 'capture_customize_post_value_set_actions' ), 10, 2 );
     142        $this->manager->set_post_value( $setting->id, '123abc' );
     143        $this->assertCount( 2, $this->captured_customize_post_value_set_actions );
     144        $this->assertEquals( 'customize_post_value_set_foo', $this->captured_customize_post_value_set_actions[0]['action'] );
     145        $this->assertEquals( 'customize_post_value_set', $this->captured_customize_post_value_set_actions[1]['action'] );
     146        $this->assertEquals( array( '123abc', $this->manager ), $this->captured_customize_post_value_set_actions[0]['args'] );
     147        $this->assertEquals( array( $setting->id, '123abc', $this->manager ), $this->captured_customize_post_value_set_actions[1]['args'] );
     148
     149        $unsanitized = $this->manager->unsanitized_post_values();
     150        $this->assertArrayHasKey( $setting->id, $unsanitized );
     151
     152        $this->assertEquals( '123abc', $unsanitized[ $setting->id ] );
     153        $this->assertEquals( 123, $setting->post_value() );
     154    }
     155
     156    /**
     157     * Sanitize a value for Tests_WP_Customize_Manager::test_set_post_value().
     158     *
     159     * @see Tests_WP_Customize_Manager::test_set_post_value()
     160     *
     161     * @param mixed $value Value.
     162     * @return int Value.
     163     */
     164    function sanitize_foo_for_test_set_post_value( $value ) {
     165        return intval( $value );
     166    }
     167
     168    /**
     169     * Store data coming from customize_post_value_set action calls.
     170     *
     171     * @see Tests_WP_Customize_Manager::capture_customize_post_value_set_actions()
     172     * @var array
     173     */
     174    protected $captured_customize_post_value_set_actions = array();
     175
     176    /**
     177     * Capture the actions fired when calling WP_Customize_Manager::set_post_value().
     178     *
     179     * @see Tests_WP_Customize_Manager::test_set_post_value()
     180     */
     181    function capture_customize_post_value_set_actions() {
     182        $action = current_action();
     183        $args = func_get_args();
     184        $this->captured_customize_post_value_set_actions[] = compact( 'action', 'args' );
     185    }
     186
     187    /**
    130188     * Test the WP_Customize_Manager::add_dynamic_settings() method.
    131189     *
     
    133191     */
    134192    function test_add_dynamic_settings() {
    135         $manager = $this->instantiate();
     193        $manager = $this->manager;
    136194        $setting_ids = array( 'foo', 'bar' );
    137195        $manager->add_setting( 'foo', array( 'default' => 'foo_default' ) );
     
    163221        add_action( 'customize_register', array( $this, 'action_customize_register_for_dynamic_settings' ) );
    164222
    165         $manager = $this->instantiate();
     223        $manager = $this->manager;
    166224        $manager->add_setting( 'foo', array( 'default' => 'foo_default' ) );
    167225
  • trunk/tests/phpunit/tests/customize/setting.php

    r35305 r35724  
    9595        $_POST['customized'] = wp_slash( wp_json_encode( $this->post_data_overrides ) );
    9696
    97         // Try non-multidimensional settings
     97        // Try non-multidimensional settings.
    9898        foreach ( $this->standard_type_configs as $type => $type_options ) {
    99             // Non-multidimensional: See what effect the preview filter has on a non-existent setting (default value should be seen)
     99            // Non-multidimensional: See what effect the preview filter has on a non-existent setting (default value should be seen).
    100100            $name = "unset_{$type}_without_post_value";
    101101            $default = "default_value_{$name}";
     
    107107            $this->assertEquals( $default, $setting->value() );
    108108
    109             // Non-multidimensional: See what effect the preview has on an extant setting (default value should not be seen)
     109            // Non-multidimensional: See what effect the preview has on an extant setting (default value should not be seen).
    110110            $name = "set_{$type}_without_post_value";
    111111            $default = "default_value_{$name}";
     
    116116            $this->assertEquals( $initial_value, $setting->value() );
    117117            $this->assertFalse( $setting->preview(), 'Preview should no-op since setting value was extant and no post value was present.' );
    118             $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods)
    119             $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods)
     118            $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // Only applicable for custom types (not options or theme_mods).
     119            $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // Only applicable for custom types (not options or theme_mods).
    120120            $this->assertEquals( $initial_value, call_user_func( $type_options['getter'], $name ) );
    121121            $this->assertEquals( $initial_value, $setting->value() );
    122122
     123            // Non-multidimensional: Try updating a value that had a no-op preview.
    123124            $overridden_value = "overridden_value_$name";
    124125            call_user_func( $type_options['setter'], $name, $overridden_value );
     
    128129            $this->assertNotEquals( $initial_value, $setting->value(), $message );
    129130
    130             // Non-multidimensional: Test unset setting being overridden by a post value
     131            // Non-multidimensional: Ensure that setting a post value *after* preview() is called results in the post value being seen (deferred preview).
     132            $post_value = "post_value_for_{$setting->id}_set_after_preview_called";
     133            $this->assertEquals( 0, did_action( "customize_post_value_set_{$setting->id}" ) );
     134            $this->manager->set_post_value( $setting->id, $post_value );
     135            $this->assertEquals( 1, did_action( "customize_post_value_set_{$setting->id}" ) );
     136            $this->assertNotEquals( $overridden_value, $setting->value() );
     137            $this->assertEquals( $post_value, call_user_func( $type_options['getter'], $name ) );
     138            $this->assertEquals( $post_value, $setting->value() );
     139
     140            // Non-multidimensional: Test unset setting being overridden by a post value.
    131141            $name = "unset_{$type}_overridden";
    132142            $default = "default_value_{$name}";
     
    134144            $this->assertEquals( $this->undefined, call_user_func( $type_options['getter'], $name, $this->undefined ) );
    135145            $this->assertEquals( $default, $setting->value() );
    136             $this->assertTrue( $setting->preview(), 'Preview applies because setting has post_data_overrides.' ); // activate post_data
     146            $this->assertTrue( $setting->preview(), 'Preview applies because setting has post_data_overrides.' ); // Activate post_data.
    137147            $this->assertEquals( $this->post_data_overrides[ $name ], call_user_func( $type_options['getter'], $name, $this->undefined ) );
    138148            $this->assertEquals( $this->post_data_overrides[ $name ], $setting->value() );
    139149
    140             // Non-multidimensional: Test set setting being overridden by a post value
     150            // Non-multidimensional: Test set setting being overridden by a post value.
    141151            $name = "set_{$type}_overridden";
    142152            $default = "default_value_{$name}";
     
    146156            $this->assertEquals( $initial_value, call_user_func( $type_options['getter'], $name, $this->undefined ) );
    147157            $this->assertEquals( $initial_value, $setting->value() );
    148             $this->assertTrue( $setting->preview(), 'Preview applies because setting has post_data_overrides.' ); // activate post_data
    149             $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods)
    150             $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods)
     158            $this->assertTrue( $setting->preview(), 'Preview applies because setting has post_data_overrides.' ); // Activate post_data.
     159            $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // Only applicable for custom types (not options or theme_mods).
     160            $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // Only applicable for custom types (not options or theme_mods).
    151161            $this->assertEquals( $this->post_data_overrides[ $name ], call_user_func( $type_options['getter'], $name, $this->undefined ) );
    152162            $this->assertEquals( $this->post_data_overrides[ $name ], $setting->value() );
     
    156166    /**
    157167     * Run assertions on multidimensional standard settings.
     168     *
     169     * @see WP_Customize_Setting::preview()
    158170     */
    159171    function test_preview_standard_types_multidimensional() {
     
    161173
    162174        foreach ( $this->standard_type_configs as $type => $type_options ) {
    163             // Multidimensional: See what effect the preview filter has on a non-existent setting (default value should be seen)
     175            // Multidimensional: See what effect the preview filter has on a non-existent setting (default value should be seen).
    164176            $base_name = "unset_{$type}_multi";
    165177            $name = $base_name . '[foo]';
     
    168180            $this->assertEquals( $this->undefined, call_user_func( $type_options['getter'], $base_name, $this->undefined ) );
    169181            $this->assertEquals( $default, $setting->value() );
    170             $this->assertTrue( $setting->preview() );
     182            $this->assertTrue( $setting->preview(), "Preview for $setting->id should apply because setting is not in DB." );
    171183            $base_value = call_user_func( $type_options['getter'], $base_name, $this->undefined );
    172184            $this->assertArrayHasKey( 'foo', $base_value );
    173185            $this->assertEquals( $default, $base_value['foo'] );
    174186
    175             // Multidimensional: See what effect the preview has on an extant setting (default value should not be seen)
     187            // Multidimensional: See what effect the preview has on an extant setting (default value should not be seen) without post value.
    176188            $base_name = "set_{$type}_multi";
    177189            $name = $base_name . '[foo]';
     
    184196            $this->assertEquals( $initial_value, $base_value['foo'] );
    185197            $this->assertEquals( $initial_value, $setting->value() );
    186             $setting->preview();
    187             $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods)
    188             $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods)
     198            $this->assertFalse( $setting->preview(), "Preview for $setting->id should no-op because setting is in DB and post value is absent." );
     199            $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // Only applicable for custom types (not options or theme_mods).
     200            $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // Only applicable for custom types (not options or theme_mods).
    189201            $base_value = call_user_func( $type_options['getter'], $base_name, array() );
    190202            $this->assertEquals( $initial_value, $base_value['foo'] );
    191203            $this->assertEquals( $initial_value, $setting->value() );
    192204
    193             // Multidimensional: Test unset setting being overridden by a post value
     205            // Multidimensional: Ensure that setting a post value *after* preview() is called results in the post value being seen (deferred preview).
     206            $override_value = "post_value_for_{$setting->id}_set_after_preview_called";
     207            $this->manager->set_post_value( $setting->id, $override_value );
     208            $base_value = call_user_func( $type_options['getter'], $base_name, array() );
     209            $this->assertEquals( $override_value, $base_value['foo'] );
     210            $this->assertEquals( $override_value, $setting->value() );
     211
     212            // Multidimensional: Test unset setting being overridden by a post value.
    194213            $base_name = "unset_{$type}_multi_overridden";
    195214            $name = $base_name . '[foo]';
     
    198217            $this->assertEquals( $this->undefined, call_user_func( $type_options['getter'], $base_name, $this->undefined ) );
    199218            $this->assertEquals( $default, $setting->value() );
    200             $setting->preview();
    201             $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods)
    202             $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods)
     219            $this->assertTrue( $setting->preview(), "Preview for $setting->id should apply because a post value is present." );
     220            $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // Only applicable for custom types (not options or theme_mods).
     221            $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // Only applicable for custom types (not options or theme_mods).
    203222            $base_value = call_user_func( $type_options['getter'], $base_name, $this->undefined );
    204223            $this->assertArrayHasKey( 'foo', $base_value );
    205224            $this->assertEquals( $this->post_data_overrides[ $name ], $base_value['foo'] );
    206225
    207             // Multidimemsional: Test set setting being overridden by a post value
     226            // Multidimensional: Test set setting being overridden by a post value.
    208227            $base_name = "set_{$type}_multi_overridden";
    209228            $name = $base_name . '[foo]';
     
    214233            $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
    215234            $base_value = call_user_func( $type_options['getter'], $base_name, $this->undefined );
    216             $this->arrayHasKey( 'foo', $base_value );
    217             $this->arrayHasKey( 'bar', $base_value );
     235            $this->assertArrayHasKey( 'foo', $base_value );
     236            $this->assertArrayHasKey( 'bar', $base_value );
    218237            $this->assertEquals( $base_initial_value['foo'], $base_value['foo'] );
    219238
     
    221240            $this->assertEquals( $base_initial_value['bar'], $getter['bar'] );
    222241            $this->assertEquals( $initial_value, $setting->value() );
    223             $setting->preview();
    224             $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods)
    225             $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods)
     242            $this->assertTrue( $setting->preview(), "Preview for $setting->id should apply because post value is present." );
     243            $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // Only applicable for custom types (not options or theme_mods).
     244            $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // Only applicable for custom types (not options or theme_mods).
    226245            $base_value = call_user_func( $type_options['getter'], $base_name, $this->undefined );
    227246            $this->assertArrayHasKey( 'foo', $base_value );
    228247            $this->assertEquals( $this->post_data_overrides[ $name ], $base_value['foo'] );
    229             $this->arrayHasKey( 'bar', call_user_func( $type_options['getter'], $base_name, $this->undefined ) );
     248            $this->assertArrayHasKey( 'bar', call_user_func( $type_options['getter'], $base_name, $this->undefined ) );
    230249
    231250            $getter = call_user_func( $type_options['getter'], $base_name, $this->undefined );
     
    273292        }
    274293    }
    275 
     294    /**
     295     * Run assertions on custom settings.
     296     *
     297     * @see WP_Customize_Setting::preview()
     298     */
    276299    function test_preview_custom_type() {
    277300        $type = 'custom_type';
     
    287310        add_action( "customize_preview_{$type}", array( $this, 'custom_type_preview' ) );
    288311
    289         // Custom type not existing and no post value override
     312        // Custom type not existing and no post value override.
    290313        $name = "unset_{$type}_without_post_value";
    291314        $default = "default_value_{$name}";
    292315        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
    293         // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need
     316        // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need.
    294317        add_filter( "customize_value_{$name}", array( $this, 'custom_type_value_filter' ) );
    295318        $this->assertEquals( $this->undefined, $this->custom_type_getter( $name, $this->undefined ) );
    296319        $this->assertEquals( $default, $setting->value() );
    297         $setting->preview();
     320        $this->assertTrue( $setting->preview() );
    298321        $this->assertEquals( 1, did_action( "customize_preview_{$setting->id}" ) );
    299322        $this->assertEquals( 1, did_action( "customize_preview_{$setting->type}" ) );
    300323        $this->assertEquals( $this->undefined, $this->custom_type_getter( $name, $this->undefined ) ); // Note: for a non-custom type this is $default
    301         $this->assertEquals( $default, $setting->value() ); // should be same as above
    302 
    303         // Custom type existing and no post value override
     324        $this->assertEquals( $default, $setting->value() ); // Should be same as above.
     325
     326        // Custom type existing and no post value override.
    304327        $name = "set_{$type}_without_post_value";
    305328        $default = "default_value_{$name}";
     
    307330        $this->custom_type_setter( $name, $initial_value );
    308331        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
    309         // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need
     332        // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need.
    310333        add_filter( "customize_value_{$name}", array( $this, 'custom_type_value_filter' ) );
    311334        $this->assertEquals( $initial_value, $this->custom_type_getter( $name, $this->undefined ) );
    312335        $this->assertEquals( $initial_value, $setting->value() );
    313         $setting->preview();
     336        $this->assertFalse( $setting->preview(), "Preview for $setting->id should not apply because existing type without an override." );
    314337        $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ), 'Zero preview actions because initial value is set with no incoming post value, so there is no preview to apply.' );
    315338        $this->assertEquals( 1, did_action( "customize_preview_{$setting->type}" ) );
    316         $this->assertEquals( $initial_value, $this->custom_type_getter( $name, $this->undefined ) ); // should be same as above
    317         $this->assertEquals( $initial_value, $setting->value() ); // should be same as above
    318 
    319         // Custom type not existing and with a post value override
     339        $this->assertEquals( $initial_value, $this->custom_type_getter( $name, $this->undefined ) ); // Should be same as above.
     340        $this->assertEquals( $initial_value, $setting->value() ); // Should be same as above.
     341
     342        // Custom type deferred preview (setting post value after preview ran).
     343        $override_value = "custom_type_value_{$name}_override_deferred_preview";
     344        $this->manager->set_post_value( $setting->id, $override_value );
     345        $this->assertEquals( $override_value, $this->custom_type_getter( $name, $this->undefined ) ); // Should be same as above.
     346        $this->assertEquals( $override_value, $setting->value() ); // Should be same as above.
     347
     348        // Custom type not existing and with a post value override.
    320349        $name = "unset_{$type}_with_post_value";
    321350        $default = "default_value_{$name}";
    322351        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
    323         // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need
     352        // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need.
    324353        add_filter( "customize_value_{$name}", array( $this, 'custom_type_value_filter' ) );
    325354        $this->assertEquals( $this->undefined, $this->custom_type_getter( $name, $this->undefined ) );
    326355        $this->assertEquals( $default, $setting->value() );
    327         $setting->preview();
     356        $this->assertTrue( $setting->preview() );
    328357        $this->assertEquals( 1, did_action( "customize_preview_{$setting->id}" ), 'One preview action now because initial value was not set and/or there is no incoming post value, so there is is a preview to apply.' );
    329         $this->assertEquals( 2, did_action( "customize_preview_{$setting->type}" ) );
     358        $this->assertEquals( 3, did_action( "customize_preview_{$setting->type}" ) );
    330359        $this->assertEquals( $post_data_overrides[ $name ], $this->custom_type_getter( $name, $this->undefined ) );
    331360        $this->assertEquals( $post_data_overrides[ $name ], $setting->value() );
    332361
    333         // Custom type not existing and with a post value override
     362        // Custom type not existing and with a post value override.
    334363        $name = "set_{$type}_with_post_value";
    335364        $default = "default_value_{$name}";
     
    337366        $this->custom_type_setter( $name, $initial_value );
    338367        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
    339         // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need
     368        // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need.
    340369        add_filter( "customize_value_{$name}", array( $this, 'custom_type_value_filter' ) );
    341370        $this->assertEquals( $initial_value, $this->custom_type_getter( $name, $this->undefined ) );
    342371        $this->assertEquals( $initial_value, $setting->value() );
    343         $setting->preview();
     372        $this->assertTrue( $setting->preview() );
    344373        $this->assertEquals( 1, did_action( "customize_preview_{$setting->id}" ) );
    345         $this->assertEquals( 3, did_action( "customize_preview_{$setting->type}" ) );
     374        $this->assertEquals( 4, did_action( "customize_preview_{$setting->type}" ) );
    346375        $this->assertEquals( $post_data_overrides[ $name ], $this->custom_type_getter( $name, $this->undefined ) );
    347376        $this->assertEquals( $post_data_overrides[ $name ], $setting->value() );
     
    362391        $this->assertEquals( $this->undefined, get_option( $name, $this->undefined ) );
    363392        $this->assertEquals( $default, $setting->value() );
    364         $setting->preview();
     393        $this->assertTrue( $setting->preview() );
    365394        $this->assertEquals( $default, get_option( $name, $this->undefined ), sprintf( 'Expected get_option(%s) to return setting default: %s.', $name, $default ) );
    366395        $this->assertEquals( $default, $setting->value() );
     
    439468        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type' ) );
    440469        $this->assertFalse( $setting->is_current_blog_previewed() );
    441         $setting->preview();
     470        $this->assertTrue( $setting->preview() );
    442471        $this->assertTrue( $setting->is_current_blog_previewed() );
    443472
     
    463492        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type' ) );
    464493        $this->assertFalse( $setting->is_current_blog_previewed() );
    465         $setting->preview();
     494        $this->assertTrue( $setting->preview() );
    466495        $this->assertTrue( $setting->is_current_blog_previewed() );
    467496
  • trunk/tests/phpunit/tests/customize/widgets.php

    r35242 r35724  
    292292        $this->assertFalse( $this->manager->get_panel( 'widgets' )->active() );
    293293    }
     294
     295    /**
     296     * @ticket 34738
     297     * @see WP_Customize_Widgets::call_widget_update()
     298     */
     299    function test_call_widget_update() {
     300
     301        $widget_number = 2;
     302        $widget_id = "search-{$widget_number}";
     303        $setting_id = "widget_search[{$widget_number}]";
     304        $instance = array(
     305            'title' => 'Buscar',
     306        );
     307
     308        $_POST = wp_slash( array(
     309            'action' => 'update-widget',
     310            'wp_customize' => 'on',
     311            'nonce' => wp_create_nonce( 'update-widget' ),
     312            'theme' => $this->manager->get_stylesheet(),
     313            'customized' => '{}',
     314            'widget-search' => array(
     315                2 => $instance,
     316            ),
     317            'widget-id' => $widget_id,
     318            'id_base' => 'search',
     319            'widget-width' => '250',
     320            'widget-height' => '200',
     321            'widget_number' => strval( $widget_number ),
     322            'multi_number' => '',
     323            'add_new' => '',
     324        ) );
     325
     326        $this->do_customize_boot_actions();
     327
     328        $this->assertArrayNotHasKey( $setting_id, $this->manager->unsanitized_post_values() );
     329        $result = $this->manager->widgets->call_widget_update( $widget_id );
     330
     331        $this->assertInternalType( 'array', $result );
     332        $this->assertArrayHasKey( 'instance', $result );
     333        $this->assertArrayHasKey( 'form', $result );
     334        $this->assertEquals( $instance, $result['instance'] );
     335        $this->assertContains( sprintf( 'value="%s"', esc_attr( $instance['title'] ) ), $result['form'] );
     336
     337        $post_values = $this->manager->unsanitized_post_values();
     338        $this->assertArrayHasKey( $setting_id, $post_values );
     339        $post_value = $post_values[ $setting_id ];
     340        $this->assertInternalType( 'array', $post_value );
     341        $this->assertArrayHasKey( 'title', $post_value );
     342        $this->assertArrayHasKey( 'encoded_serialized_instance', $post_value );
     343        $this->assertArrayHasKey( 'instance_hash_key', $post_value );
     344        $this->assertArrayHasKey( 'is_widget_customizer_js_value', $post_value );
     345        $this->assertEquals( $post_value, $this->manager->widgets->sanitize_widget_js_instance( $instance ) );
     346    }
    294347}
Note: See TracChangeset for help on using the changeset viewer.