Make WordPress Core

Ticket #34738: 34738.1.diff

File 34738.1.diff, 36.4 KB (added by westonruter, 10 years ago)

Additional changes: https://github.com/xwp/wordpress-develop/compare/3ee37d1...c2fabed

  • src/wp-includes/class-wp-customize-manager.php

    diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php
    index c3b1f32..1835b05 100644
    final class WP_Customize_Manager { 
    659659        public function set_post_value( $setting_id, $value ) {
    660660                $this->unsanitized_post_values();
    661661                $this->_post_values[ $setting_id ] = $value;
     662
     663                /**
     664                 * Announce when a 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                 * This is useful for <code>WP_Customize_Setting</code> instances to watch
     669                 * in order to update a cached previewed value.
     670                 *
     671                 * @since 4.4.0
     672                 *
     673                 * @param string               $setting_id Setting ID.
     674                 * @param mixed                $value      Unsanitized setting post value.
     675                 * @param WP_Customize_Manager $this       WP_Customize_Manager instance.
     676                 */
     677                do_action( 'customize_post_value_set', $setting_id, $value, $this );
     678
     679                /**
     680                 * Announce when a specific setting's unsanitized post value has been set.
     681                 *
     682                 * Fires when the {@see WP_Customize_Manager::set_post_value()} method is called.
     683                 *
     684                 * The dynamic portion of the hook name, `$setting_id`, refers to the setting ID.
     685                 *
     686                 * @since 4.4.0
     687                 *
     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
    664694        /**
  • src/wp-includes/class-wp-customize-setting.php

    diff --git src/wp-includes/class-wp-customize-setting.php src/wp-includes/class-wp-customize-setting.php
    index 12f76d4..434dec7 100644
    class WP_Customize_Setting { 
    8282        protected $id_data = array();
    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         *
    8796         * @since 4.4.0
    class WP_Customize_Setting { 
    191200                }
    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                }
    196207        }
    class WP_Customize_Setting { 
    245256                if ( ! isset( $this->_previewed_blog_id ) ) {
    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'] );
    250267                $multidimensional_filter = array( $this, '_multidimensional_preview_filter' );
    class WP_Customize_Setting { 
    273290                        $needs_preview = ( $undefined === $value ); // Because the default needs to be supplied.
    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                }
    279300
    class WP_Customize_Setting { 
    327348                                 */
    328349                                do_action( "customize_preview_{$this->type}", $this );
    329350                }
     351
     352                $this->is_previewed = true;
     353
    330354                return true;
    331355        }
    332356
    333357        /**
     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 ] );
     371        }
     372
     373        /**
    334374         * Callback function to filter non-multidimensional theme mods and options.
    335375         *
    336376         * If switch_to_blog() was called after the preview() method, and the current
    class WP_Customize_Setting { 
    369409         * the first setting previewed will be used to apply the values for the others.
    370410         *
    371411         * @since 4.4.0
    372          * @access public
     412         * @access private
    373413         *
    374414         * @see WP_Customize_Setting::$aggregated_multidimensionals
    375415         * @param mixed $original Original root value.
    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;
    381421                }
  • src/wp-includes/class-wp-customize-widgets.php

    diff --git src/wp-includes/class-wp-customize-widgets.php src/wp-includes/class-wp-customize-widgets.php
    index 6ee6942..7639d50 100644
    final class WP_Customize_Widgets { 
    13801380                 * in place from WP_Customize_Setting::preview() will use this value
    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.
    13861386                ob_start();
  • src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php

    diff --git src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php
    index 2fa0b5c..073423e 100644
    class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { 
    120120        public $original_nav_menu_term_id;
    121121
    122122        /**
    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;
    130 
    131         /**
    132123         * Whether or not update() was called.
    133124         *
    134125         * @since 4.3.0
  • src/wp-includes/customize/class-wp-customize-nav-menu-setting.php

    diff --git src/wp-includes/customize/class-wp-customize-nav-menu-setting.php src/wp-includes/customize/class-wp-customize-nav-menu-setting.php
    index 766099e..5562a8d 100644
    class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { 
    8989        public $previous_term_id;
    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         *
    10394         * @since 4.3.0
  • tests/phpunit/tests/customize/manager.php

    diff --git tests/phpunit/tests/customize/manager.php tests/phpunit/tests/customize/manager.php
    index 481fe61..6813c4e 100644
    class Tests_WP_Customize_Manager extends WP_UnitTestCase { 
    3232        function setUp() {
    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        }
    3938
    class Tests_WP_Customize_Manager extends WP_UnitTestCase { 
    6665                        define( 'DOING_AJAX', true );
    6766                }
    6867
    69                 $manager = $this->instantiate();
     68                $manager = $this->manager;
    7069                $this->assertTrue( $manager->doing_ajax() );
    7170
    7271                $_REQUEST['action'] = 'customize_save';
    class Tests_WP_Customize_Manager extends WP_UnitTestCase { 
    8281                        $this->markTestSkipped( 'Cannot test when DOING_AJAX' );
    8382                }
    8483
    85                 $manager = $this->instantiate();
     84                $manager = $this->manager;
    8685                $this->assertFalse( $manager->doing_ajax() );
    8786        }
    8887
    class Tests_WP_Customize_Manager extends WP_UnitTestCase { 
    9291         * @ticket 30988
    9392         */
    9493        function test_unsanitized_post_values() {
    95                 $manager = $this->instantiate();
     94                $manager = $this->manager;
    9695
    9796                $customized = array(
    9897                        'foo' => 'bar',
    class Tests_WP_Customize_Manager extends WP_UnitTestCase { 
    114113                );
    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' ) );
    120119                $foo_setting = $manager->get_setting( 'foo' );
    class Tests_WP_Customize_Manager extends WP_UnitTestCase { 
    127126        }
    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', $this->captured_customize_post_value_set_actions[0]['action'] );
     145                $this->assertEquals( 'customize_post_value_set_foo', $this->captured_customize_post_value_set_actions[1]['action'] );
     146                $this->assertEquals( array( $setting->id, '123abc', $this->manager ), $this->captured_customize_post_value_set_actions[0]['args'] );
     147                $this->assertEquals( array( '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         *
    132190         * @ticket 30936
    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' ) );
    138196                $this->assertEmpty( $manager->get_setting( 'bar' ), 'Expected there to not be a bar setting up front.' );
    class Tests_WP_Customize_Manager extends WP_UnitTestCase { 
    162220
    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
    168226                $this->assertEmpty( $manager->get_setting( 'bar' ), 'Expected dynamic setting "bar" to not be registered.' );
  • tests/phpunit/tests/customize/setting.php

    diff --git tests/phpunit/tests/customize/setting.php tests/phpunit/tests/customize/setting.php
    index da789b1..6d46f3b 100644
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    9494        function test_preview_standard_types_non_multidimensional() {
    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}";
    102102                        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    106106                        $this->assertEquals( $default, call_user_func( $type_options['getter'], $name, $this->undefined ), sprintf( 'Expected %s(%s) to return setting default: %s.', $type_options['getter'], $name, $default ) );
    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}";
    112112                        $initial_value = "initial_value_{$name}";
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    115115                        $this->assertEquals( $initial_value, call_user_func( $type_options['getter'], $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 );
    125126                        $message = 'Initial value should be overridden because initial preview() was no-op due to setting having existing value and/or post value was absent.';
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    127128                        $this->assertEquals( $overridden_value, $setting->value(), $message );
    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}";
    133143                        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
    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}";
    143153                        $initial_value = "initial_value_{$name}";
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    145155                        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
    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() );
    153163                }
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    155165
    156166        /**
    157167         * Run assertions on multidimensional standard settings.
     168         *
     169         * @see WP_Customize_Setting::preview()
    158170         */
    159171        function test_preview_standard_types_multidimensional() {
    160172                $_POST['customized'] = wp_slash( wp_json_encode( $this->post_data_overrides ) );
    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]';
    166178                        $default = "default_value_{$name}";
    167179                        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
    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]';
    178190                        $default = "default_value_{$name}";
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    183195                        $base_value = call_user_func( $type_options['getter'], $base_name, array() );
    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]';
    196215                        $default = "default_value_{$name}";
    197216                        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
    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]';
    210229                        $default = "default_value_{$name}";
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    213232                        call_user_func( $type_options['setter'], $base_name, $base_initial_value );
    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
    220239                        $getter = call_user_func( $type_options['getter'], $base_name, $this->undefined );
    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 );
    232251                        $this->assertEquals( $base_initial_value['bar'], $getter['bar'] );
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    272291                        $this->custom_type_data_previewed[ $setting->id ] = $previewed_value;
    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';
    278301                $post_data_overrides = array(
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    286309
    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
     324                $this->assertEquals( $default, $setting->value() ); // Should be same as above.
    302325
    303                 // Custom type existing and no post value override
     326                // Custom type existing and no post value override.
    304327                $name = "set_{$type}_without_post_value";
    305328                $default = "default_value_{$name}";
    306329                $initial_value = "initial_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
     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.
    318341
    319                 // Custom type not existing and with a post value override
     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}";
    336365                $initial_value = "initial_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() );
    348377
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    361390                $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
    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() );
    367396        }
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    438467                $this->manager->set_post_value( $name, $post_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
    444473                $this->assertEquals( $post_value, $setting->value() );
    class Tests_WP_Customize_Setting extends WP_UnitTestCase { 
    462491                $this->manager->set_post_value( $name, $post_value );
    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
    468497                $blog_id = self::factory()->blog->create();
  • tests/phpunit/tests/customize/widgets.php

    diff --git tests/phpunit/tests/customize/widgets.php tests/phpunit/tests/customize/widgets.php
    index 6584341..1ba37bb 100644
    class Tests_WP_Customize_Widgets extends WP_UnitTestCase { 
    291291                $this->assertFalse( $this->manager->widgets->is_panel_active() );
    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}