<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[35724] trunk: 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.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/35724">35724</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/35724","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>westonruter</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2015-11-21 02:51:57 +0000 (Sat, 21 Nov 2015)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>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 <a href="https://core.trac.wordpress.org/changeset/35007">[35007]</a>.
See <a href="https://core.trac.wordpress.org/ticket/32103">#32103</a>.
Fixes <a href="https://core.trac.wordpress.org/ticket/34738">#34738</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesclasswpcustomizemanagerphp">trunk/src/wp-includes/class-wp-customize-manager.php</a></li>
<li><a href="#trunksrcwpincludesclasswpcustomizesettingphp">trunk/src/wp-includes/class-wp-customize-setting.php</a></li>
<li><a href="#trunksrcwpincludesclasswpcustomizewidgetsphp">trunk/src/wp-includes/class-wp-customize-widgets.php</a></li>
<li><a href="#trunksrcwpincludescustomizeclasswpcustomizenavmenuitemsettingphp">trunk/src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php</a></li>
<li><a href="#trunksrcwpincludescustomizeclasswpcustomizenavmenusettingphp">trunk/src/wp-includes/customize/class-wp-customize-nav-menu-setting.php</a></li>
<li><a href="#trunktestsphpunittestscustomizemanagerphp">trunk/tests/phpunit/tests/customize/manager.php</a></li>
<li><a href="#trunktestsphpunittestscustomizesettingphp">trunk/tests/phpunit/tests/customize/setting.php</a></li>
<li><a href="#trunktestsphpunittestscustomizewidgetsphp">trunk/tests/phpunit/tests/customize/widgets.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesclasswpcustomizemanagerphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-customize-manager.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-customize-manager.php      2015-11-20 18:55:31 UTC (rev 35723)
+++ trunk/src/wp-includes/class-wp-customize-manager.php        2015-11-21 02:51:57 UTC (rev 35724)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -659,6 +659,36 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public function set_post_value( $setting_id, $value ) {
</span><span class="cx" style="display: block; padding: 0 10px">                $this->unsanitized_post_values();
</span><span class="cx" style="display: block; padding: 0 10px">                $this->_post_values[ $setting_id ] = $value;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               /**
+                * Announce when a specific setting's unsanitized post value has been set.
+                *
+                * Fires when the {@see WP_Customize_Manager::set_post_value()} method is called.
+                *
+                * The dynamic portion of the hook name, `$setting_id`, refers to the setting ID.
+                *
+                * @since 4.4.0
+                *
+                * @param mixed                $value Unsanitized setting post value.
+                * @param WP_Customize_Manager $this  WP_Customize_Manager instance.
+                */
+               do_action( "customize_post_value_set_{$setting_id}", $value, $this );
+
+               /**
+                * Announce when any setting's unsanitized post value has been set.
+                *
+                * Fires when the {@see WP_Customize_Manager::set_post_value()} method is called.
+                *
+                * This is useful for <code>WP_Customize_Setting</code> instances to watch
+                * in order to update a cached previewed value.
+                *
+                * @since 4.4.0
+                *
+                * @param string               $setting_id Setting ID.
+                * @param mixed                $value      Unsanitized setting post value.
+                * @param WP_Customize_Manager $this       WP_Customize_Manager instance.
+                */
+               do_action( 'customize_post_value_set', $setting_id, $value, $this );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span></span></pre></div>
<a id="trunksrcwpincludesclasswpcustomizesettingphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-customize-setting.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-customize-setting.php      2015-11-20 18:55:31 UTC (rev 35723)
+++ trunk/src/wp-includes/class-wp-customize-setting.php        2015-11-21 02:51:57 UTC (rev 35724)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -82,6 +82,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">        protected $id_data = array();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Whether or not preview() was called.
+        *
+        * @since 4.4.0
+        * @access protected
+        * @var bool
+        */
+       protected $is_previewed = false;
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Cache of multidimensional values to improve performance.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 4.4.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -191,6 +200,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! empty( $this->id_data['keys'] ) ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        // Note the preview-applied flag is cleared at priority 9 to ensure it is cleared before a deferred-preview runs.
+                       add_action( "customize_post_value_set_{$this->id}", array( $this, '_clear_aggregated_multidimensional_preview_applied_flag' ), 9 );
</ins><span class="cx" style="display: block; padding: 0 10px">                         $this->is_multidimensional_aggregated = true;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -245,6 +256,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! isset( $this->_previewed_blog_id ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->_previewed_blog_id = get_current_blog_id();
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               // Prevent re-previewing an already-previewed setting.
+               if ( $this->is_previewed ) {
+                       return true;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 $id_base = $this->id_data['base'];
</span><span class="cx" style="display: block; padding: 0 10px">                $is_multidimensional = ! empty( $this->id_data['keys'] );
</span><span class="cx" style="display: block; padding: 0 10px">                $multidimensional_filter = array( $this, '_multidimensional_preview_filter' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -273,7 +290,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $needs_preview = ( $undefined === $value ); // Because the default needs to be supplied.
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // If the setting does not need previewing now, defer to when it has a value to preview.
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( ! $needs_preview ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        if ( ! has_action( "customize_post_value_set_{$this->id}", array( $this, 'preview' ) ) ) {
+                               add_action( "customize_post_value_set_{$this->id}", array( $this, 'preview' ) );
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                         return false;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -327,10 +348,29 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                 */
</span><span class="cx" style="display: block; padding: 0 10px">                                do_action( "customize_preview_{$this->type}", $this );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               $this->is_previewed = true;
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 return true;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Clear out the previewed-applied flag for a multidimensional-aggregated value whenever its post value is updated.
+        *
+        * This ensures that the new value will get sanitized and used the next time
+        * that <code>WP_Customize_Setting::_multidimensional_preview_filter()</code>
+        * is called for this setting.
+        *
+        * @since 4.4.0
+        * @access private
+        * @see WP_Customize_Manager::set_post_value()
+        * @see WP_Customize_Setting::_multidimensional_preview_filter()
+        */
+       final public function _clear_aggregated_multidimensional_preview_applied_flag() {
+               unset( self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['preview_applied_instances'][ $this->id ] );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Callback function to filter non-multidimensional theme mods and options.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * If switch_to_blog() was called after the preview() method, and the current
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -369,13 +409,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * the first setting previewed will be used to apply the values for the others.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 4.4.0
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * @access public
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  * @access private
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @see WP_Customize_Setting::$aggregated_multidimensionals
</span><span class="cx" style="display: block; padding: 0 10px">         * @param mixed $original Original root value.
</span><span class="cx" style="display: block; padding: 0 10px">         * @return mixed New or old value.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        public function _multidimensional_preview_filter( $original ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ final public function _multidimensional_preview_filter( $original ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( ! $this->is_current_blog_previewed() ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        return $original;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span></span></pre></div>
<a id="trunksrcwpincludesclasswpcustomizewidgetsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-customize-widgets.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-customize-widgets.php      2015-11-20 18:55:31 UTC (rev 35723)
+++ trunk/src/wp-includes/class-wp-customize-widgets.php        2015-11-21 02:51:57 UTC (rev 35724)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1380,7 +1380,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                 * in place from WP_Customize_Setting::preview() will use this value
</span><span class="cx" style="display: block; padding: 0 10px">                 * instead of the default widget instance value (an empty array).
</span><span class="cx" style="display: block; padding: 0 10px">                 */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->manager->set_post_value( $setting_id, $instance );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->manager->set_post_value( $setting_id, $this->sanitize_widget_js_instance( $instance ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // Obtain the widget control with the updated instance in place.
</span><span class="cx" style="display: block; padding: 0 10px">                ob_start();
</span></span></pre></div>
<a id="trunksrcwpincludescustomizeclasswpcustomizenavmenuitemsettingphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php      2015-11-20 18:55:31 UTC (rev 35723)
+++ trunk/src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php        2015-11-21 02:51:57 UTC (rev 35724)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -120,15 +120,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public $original_nav_menu_term_id;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * Whether or not preview() was called.
-        *
-        * @since 4.3.0
-        * @access protected
-        * @var bool
-        */
-       protected $is_previewed = false;
-
-       /**
</del><span class="cx" style="display: block; padding: 0 10px">          * Whether or not update() was called.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 4.3.0
</span></span></pre></div>
<a id="trunksrcwpincludescustomizeclasswpcustomizenavmenusettingphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/customize/class-wp-customize-nav-menu-setting.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/customize/class-wp-customize-nav-menu-setting.php   2015-11-20 18:55:31 UTC (rev 35723)
+++ trunk/src/wp-includes/customize/class-wp-customize-nav-menu-setting.php     2015-11-21 02:51:57 UTC (rev 35724)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -89,15 +89,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public $previous_term_id;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * Whether or not preview() was called.
-        *
-        * @since 4.3.0
-        * @access protected
-        * @var bool
-        */
-       protected $is_previewed = false;
-
-       /**
</del><span class="cx" style="display: block; padding: 0 10px">          * Whether or not update() was called.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 4.3.0
</span></span></pre></div>
<a id="trunktestsphpunittestscustomizemanagerphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/customize/manager.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/customize/manager.php   2015-11-20 18:55:31 UTC (rev 35723)
+++ trunk/tests/phpunit/tests/customize/manager.php     2015-11-21 02:51:57 UTC (rev 35724)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -32,8 +32,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        function setUp() {
</span><span class="cx" style="display: block; padding: 0 10px">                parent::setUp();
</span><span class="cx" style="display: block; padding: 0 10px">                require_once( ABSPATH . WPINC . '/class-wp-customize-manager.php' );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $GLOBALS['wp_customize'] = new WP_Customize_Manager();
-               $this->manager = $GLOBALS['wp_customize'];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->manager = $this->instantiate();
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->undefined = new stdClass();
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -66,7 +65,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        define( 'DOING_AJAX', true );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $manager = $this->instantiate();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $manager = $this->manager;
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertTrue( $manager->doing_ajax() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $_REQUEST['action'] = 'customize_save';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -82,7 +81,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->markTestSkipped( 'Cannot test when DOING_AJAX' );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $manager = $this->instantiate();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $manager = $this->manager;
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertFalse( $manager->doing_ajax() );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -92,7 +91,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 30988
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        function test_unsanitized_post_values() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $manager = $this->instantiate();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $manager = $this->manager;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $customized = array(
</span><span class="cx" style="display: block; padding: 0 10px">                        'foo' => 'bar',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -114,7 +113,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="cx" style="display: block; padding: 0 10px">                $_POST['customized'] = wp_slash( wp_json_encode( $posted_settings ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $manager = $this->instantiate();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $manager = $this->manager;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $manager->add_setting( 'foo', array( 'default' => 'foo_default' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $foo_setting = $manager->get_setting( 'foo' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -127,12 +126,71 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Test WP_Customize_Manager::set_post_value().
+        *
+        * @see WP_Customize_Manager::set_post_value()
+        */
+       function test_set_post_value() {
+               $this->manager->add_setting( 'foo', array(
+                       'sanitize_callback' => array( $this, 'sanitize_foo_for_test_set_post_value' ),
+               ) );
+               $setting = $this->manager->get_setting( 'foo' );
+
+               $this->assertEmpty( $this->captured_customize_post_value_set_actions );
+               add_action( 'customize_post_value_set', array( $this, 'capture_customize_post_value_set_actions' ), 10, 3 );
+               add_action( 'customize_post_value_set_foo', array( $this, 'capture_customize_post_value_set_actions' ), 10, 2 );
+               $this->manager->set_post_value( $setting->id, '123abc' );
+               $this->assertCount( 2, $this->captured_customize_post_value_set_actions );
+               $this->assertEquals( 'customize_post_value_set_foo', $this->captured_customize_post_value_set_actions[0]['action'] );
+               $this->assertEquals( 'customize_post_value_set', $this->captured_customize_post_value_set_actions[1]['action'] );
+               $this->assertEquals( array( '123abc', $this->manager ), $this->captured_customize_post_value_set_actions[0]['args'] );
+               $this->assertEquals( array( $setting->id, '123abc', $this->manager ), $this->captured_customize_post_value_set_actions[1]['args'] );
+
+               $unsanitized = $this->manager->unsanitized_post_values();
+               $this->assertArrayHasKey( $setting->id, $unsanitized );
+
+               $this->assertEquals( '123abc', $unsanitized[ $setting->id ] );
+               $this->assertEquals( 123, $setting->post_value() );
+       }
+
+       /**
+        * Sanitize a value for Tests_WP_Customize_Manager::test_set_post_value().
+        *
+        * @see Tests_WP_Customize_Manager::test_set_post_value()
+        *
+        * @param mixed $value Value.
+        * @return int Value.
+        */
+       function sanitize_foo_for_test_set_post_value( $value ) {
+               return intval( $value );
+       }
+
+       /**
+        * Store data coming from customize_post_value_set action calls.
+        *
+        * @see Tests_WP_Customize_Manager::capture_customize_post_value_set_actions()
+        * @var array
+        */
+       protected $captured_customize_post_value_set_actions = array();
+
+       /**
+        * Capture the actions fired when calling WP_Customize_Manager::set_post_value().
+        *
+        * @see Tests_WP_Customize_Manager::test_set_post_value()
+        */
+       function capture_customize_post_value_set_actions() {
+               $action = current_action();
+               $args = func_get_args();
+               $this->captured_customize_post_value_set_actions[] = compact( 'action', 'args' );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Test the WP_Customize_Manager::add_dynamic_settings() method.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 30936
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        function test_add_dynamic_settings() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $manager = $this->instantiate();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $manager = $this->manager;
</ins><span class="cx" style="display: block; padding: 0 10px">                 $setting_ids = array( 'foo', 'bar' );
</span><span class="cx" style="display: block; padding: 0 10px">                $manager->add_setting( 'foo', array( 'default' => 'foo_default' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEmpty( $manager->get_setting( 'bar' ), 'Expected there to not be a bar setting up front.' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -162,7 +220,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                add_action( 'customize_register', array( $this, 'action_customize_register_for_dynamic_settings' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $manager = $this->instantiate();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $manager = $this->manager;
</ins><span class="cx" style="display: block; padding: 0 10px">                 $manager->add_setting( 'foo', array( 'default' => 'foo_default' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEmpty( $manager->get_setting( 'bar' ), 'Expected dynamic setting "bar" to not be registered.' );
</span></span></pre></div>
<a id="trunktestsphpunittestscustomizesettingphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/customize/setting.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/customize/setting.php   2015-11-20 18:55:31 UTC (rev 35723)
+++ trunk/tests/phpunit/tests/customize/setting.php     2015-11-21 02:51:57 UTC (rev 35724)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -94,9 +94,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">        function test_preview_standard_types_non_multidimensional() {
</span><span class="cx" style="display: block; padding: 0 10px">                $_POST['customized'] = wp_slash( wp_json_encode( $this->post_data_overrides ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Try non-multidimensional settings
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Try non-multidimensional settings.
</ins><span class="cx" style="display: block; padding: 0 10px">                 foreach ( $this->standard_type_configs as $type => $type_options ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Non-multidimensional: See what effect the preview filter has on a non-existent setting (default value should be seen)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Non-multidimensional: See what effect the preview filter has on a non-existent setting (default value should be seen).
</ins><span class="cx" style="display: block; padding: 0 10px">                         $name = "unset_{$type}_without_post_value";
</span><span class="cx" style="display: block; padding: 0 10px">                        $default = "default_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -106,7 +106,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $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 ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $default, $setting->value() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Non-multidimensional: See what effect the preview has on an extant setting (default value should not be seen)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Non-multidimensional: See what effect the preview has on an extant setting (default value should not be seen).
</ins><span class="cx" style="display: block; padding: 0 10px">                         $name = "set_{$type}_without_post_value";
</span><span class="cx" style="display: block; padding: 0 10px">                        $default = "default_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                        $initial_value = "initial_value_{$name}";
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -115,11 +115,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $initial_value, call_user_func( $type_options['getter'], $name ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $initial_value, $setting->value() );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertFalse( $setting->preview(), 'Preview should no-op since setting value was extant and no post value was present.' );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods)
-                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // Only applicable for custom types (not options or theme_mods).
+                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // Only applicable for custom types (not options or theme_mods).
</ins><span class="cx" style="display: block; padding: 0 10px">                         $this->assertEquals( $initial_value, call_user_func( $type_options['getter'], $name ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $initial_value, $setting->value() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        // Non-multidimensional: Try updating a value that had a no-op preview.
</ins><span class="cx" style="display: block; padding: 0 10px">                         $overridden_value = "overridden_value_$name";
</span><span class="cx" style="display: block; padding: 0 10px">                        call_user_func( $type_options['setter'], $name, $overridden_value );
</span><span class="cx" style="display: block; padding: 0 10px">                        $message = 'Initial value should be overridden because initial preview() was no-op due to setting having existing value and/or post value was absent.';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -127,17 +128,26 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $overridden_value, $setting->value(), $message );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertNotEquals( $initial_value, $setting->value(), $message );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Non-multidimensional: Test unset setting being overridden by a post value
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Non-multidimensional: Ensure that setting a post value *after* preview() is called results in the post value being seen (deferred preview).
+                       $post_value = "post_value_for_{$setting->id}_set_after_preview_called";
+                       $this->assertEquals( 0, did_action( "customize_post_value_set_{$setting->id}" ) );
+                       $this->manager->set_post_value( $setting->id, $post_value );
+                       $this->assertEquals( 1, did_action( "customize_post_value_set_{$setting->id}" ) );
+                       $this->assertNotEquals( $overridden_value, $setting->value() );
+                       $this->assertEquals( $post_value, call_user_func( $type_options['getter'], $name ) );
+                       $this->assertEquals( $post_value, $setting->value() );
+
+                       // Non-multidimensional: Test unset setting being overridden by a post value.
</ins><span class="cx" style="display: block; padding: 0 10px">                         $name = "unset_{$type}_overridden";
</span><span class="cx" style="display: block; padding: 0 10px">                        $default = "default_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $this->undefined, call_user_func( $type_options['getter'], $name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $default, $setting->value() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $this->assertTrue( $setting->preview(), 'Preview applies because setting has post_data_overrides.' ); // activate post_data
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $this->assertTrue( $setting->preview(), 'Preview applies because setting has post_data_overrides.' ); // Activate post_data.
</ins><span class="cx" style="display: block; padding: 0 10px">                         $this->assertEquals( $this->post_data_overrides[ $name ], call_user_func( $type_options['getter'], $name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $this->post_data_overrides[ $name ], $setting->value() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Non-multidimensional: Test set setting being overridden by a post value
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Non-multidimensional: Test set setting being overridden by a post value.
</ins><span class="cx" style="display: block; padding: 0 10px">                         $name = "set_{$type}_overridden";
</span><span class="cx" style="display: block; padding: 0 10px">                        $default = "default_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                        $initial_value = "initial_value_{$name}";
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -145,9 +155,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $initial_value, call_user_func( $type_options['getter'], $name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $initial_value, $setting->value() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $this->assertTrue( $setting->preview(), 'Preview applies because setting has post_data_overrides.' ); // activate post_data
-                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods)
-                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $this->assertTrue( $setting->preview(), 'Preview applies because setting has post_data_overrides.' ); // Activate post_data.
+                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // Only applicable for custom types (not options or theme_mods).
+                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // Only applicable for custom types (not options or theme_mods).
</ins><span class="cx" style="display: block; padding: 0 10px">                         $this->assertEquals( $this->post_data_overrides[ $name ], call_user_func( $type_options['getter'], $name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $this->post_data_overrides[ $name ], $setting->value() );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -155,24 +165,26 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="cx" style="display: block; padding: 0 10px">         * Run assertions on multidimensional standard settings.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         *
+        * @see WP_Customize_Setting::preview()
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><span class="cx" style="display: block; padding: 0 10px">        function test_preview_standard_types_multidimensional() {
</span><span class="cx" style="display: block; padding: 0 10px">                $_POST['customized'] = wp_slash( wp_json_encode( $this->post_data_overrides ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                foreach ( $this->standard_type_configs as $type => $type_options ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Multidimensional: See what effect the preview filter has on a non-existent setting (default value should be seen)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Multidimensional: See what effect the preview filter has on a non-existent setting (default value should be seen).
</ins><span class="cx" style="display: block; padding: 0 10px">                         $base_name = "unset_{$type}_multi";
</span><span class="cx" style="display: block; padding: 0 10px">                        $name = $base_name . '[foo]';
</span><span class="cx" style="display: block; padding: 0 10px">                        $default = "default_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $this->undefined, call_user_func( $type_options['getter'], $base_name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $default, $setting->value() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $this->assertTrue( $setting->preview() );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $this->assertTrue( $setting->preview(), "Preview for $setting->id should apply because setting is not in DB." );
</ins><span class="cx" style="display: block; padding: 0 10px">                         $base_value = call_user_func( $type_options['getter'], $base_name, $this->undefined );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertArrayHasKey( 'foo', $base_value );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $default, $base_value['foo'] );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Multidimensional: See what effect the preview has on an extant setting (default value should not be seen)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Multidimensional: See what effect the preview has on an extant setting (default value should not be seen) without post value.
</ins><span class="cx" style="display: block; padding: 0 10px">                         $base_name = "set_{$type}_multi";
</span><span class="cx" style="display: block; padding: 0 10px">                        $name = $base_name . '[foo]';
</span><span class="cx" style="display: block; padding: 0 10px">                        $default = "default_value_{$name}";
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -183,28 +195,35 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $base_value = call_user_func( $type_options['getter'], $base_name, array() );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $initial_value, $base_value['foo'] );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $initial_value, $setting->value() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $setting->preview();
-                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods)
-                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $this->assertFalse( $setting->preview(), "Preview for $setting->id should no-op because setting is in DB and post value is absent." );
+                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // Only applicable for custom types (not options or theme_mods).
+                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // Only applicable for custom types (not options or theme_mods).
</ins><span class="cx" style="display: block; padding: 0 10px">                         $base_value = call_user_func( $type_options['getter'], $base_name, array() );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $initial_value, $base_value['foo'] );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $initial_value, $setting->value() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Multidimensional: Test unset setting being overridden by a post value
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Multidimensional: Ensure that setting a post value *after* preview() is called results in the post value being seen (deferred preview).
+                       $override_value = "post_value_for_{$setting->id}_set_after_preview_called";
+                       $this->manager->set_post_value( $setting->id, $override_value );
+                       $base_value = call_user_func( $type_options['getter'], $base_name, array() );
+                       $this->assertEquals( $override_value, $base_value['foo'] );
+                       $this->assertEquals( $override_value, $setting->value() );
+
+                       // Multidimensional: Test unset setting being overridden by a post value.
</ins><span class="cx" style="display: block; padding: 0 10px">                         $base_name = "unset_{$type}_multi_overridden";
</span><span class="cx" style="display: block; padding: 0 10px">                        $name = $base_name . '[foo]';
</span><span class="cx" style="display: block; padding: 0 10px">                        $default = "default_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $this->undefined, call_user_func( $type_options['getter'], $base_name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $default, $setting->value() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $setting->preview();
-                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods)
-                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $this->assertTrue( $setting->preview(), "Preview for $setting->id should apply because a post value is present." );
+                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // Only applicable for custom types (not options or theme_mods).
+                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // Only applicable for custom types (not options or theme_mods).
</ins><span class="cx" style="display: block; padding: 0 10px">                         $base_value = call_user_func( $type_options['getter'], $base_name, $this->undefined );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertArrayHasKey( 'foo', $base_value );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $this->post_data_overrides[ $name ], $base_value['foo'] );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Multidimemsional: Test set setting being overridden by a post value
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Multidimensional: Test set setting being overridden by a post value.
</ins><span class="cx" style="display: block; padding: 0 10px">                         $base_name = "set_{$type}_multi_overridden";
</span><span class="cx" style="display: block; padding: 0 10px">                        $name = $base_name . '[foo]';
</span><span class="cx" style="display: block; padding: 0 10px">                        $default = "default_value_{$name}";
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -213,20 +232,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        call_user_func( $type_options['setter'], $base_name, $base_initial_value );
</span><span class="cx" style="display: block; padding: 0 10px">                        $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $base_value = call_user_func( $type_options['getter'], $base_name, $this->undefined );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $this->arrayHasKey( 'foo', $base_value );
-                       $this->arrayHasKey( 'bar', $base_value );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $this->assertArrayHasKey( 'foo', $base_value );
+                       $this->assertArrayHasKey( 'bar', $base_value );
</ins><span class="cx" style="display: block; padding: 0 10px">                         $this->assertEquals( $base_initial_value['foo'], $base_value['foo'] );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        $getter = call_user_func( $type_options['getter'], $base_name, $this->undefined );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $base_initial_value['bar'], $getter['bar'] );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $initial_value, $setting->value() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $setting->preview();
-                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods)
-                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $this->assertTrue( $setting->preview(), "Preview for $setting->id should apply because post value is present." );
+                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // Only applicable for custom types (not options or theme_mods).
+                       $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // Only applicable for custom types (not options or theme_mods).
</ins><span class="cx" style="display: block; padding: 0 10px">                         $base_value = call_user_func( $type_options['getter'], $base_name, $this->undefined );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertArrayHasKey( 'foo', $base_value );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $this->post_data_overrides[ $name ], $base_value['foo'] );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $this->arrayHasKey( 'bar', call_user_func( $type_options['getter'], $base_name, $this->undefined ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $this->assertArrayHasKey( 'bar', call_user_func( $type_options['getter'], $base_name, $this->undefined ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        $getter = call_user_func( $type_options['getter'], $base_name, $this->undefined );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $base_initial_value['bar'], $getter['bar'] );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -272,7 +291,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->custom_type_data_previewed[ $setting->id ] = $previewed_value;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ /**
+        * Run assertions on custom settings.
+        *
+        * @see WP_Customize_Setting::preview()
+        */
</ins><span class="cx" style="display: block; padding: 0 10px">         function test_preview_custom_type() {
</span><span class="cx" style="display: block; padding: 0 10px">                $type = 'custom_type';
</span><span class="cx" style="display: block; padding: 0 10px">                $post_data_overrides = array(
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -286,63 +309,69 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                add_action( "customize_preview_{$type}", array( $this, 'custom_type_preview' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Custom type not existing and no post value override
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Custom type not existing and no post value override.
</ins><span class="cx" style="display: block; padding: 0 10px">                 $name = "unset_{$type}_without_post_value";
</span><span class="cx" style="display: block; padding: 0 10px">                $default = "default_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need.
</ins><span class="cx" style="display: block; padding: 0 10px">                 add_filter( "customize_value_{$name}", array( $this, 'custom_type_value_filter' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $this->undefined, $this->custom_type_getter( $name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $default, $setting->value() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $setting->preview();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertTrue( $setting->preview() );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertEquals( 1, did_action( "customize_preview_{$setting->id}" ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( 1, did_action( "customize_preview_{$setting->type}" ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $this->undefined, $this->custom_type_getter( $name, $this->undefined ) ); // Note: for a non-custom type this is $default
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertEquals( $default, $setting->value() ); // should be same as above
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertEquals( $default, $setting->value() ); // Should be same as above.
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Custom type existing and no post value override
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Custom type existing and no post value override.
</ins><span class="cx" style="display: block; padding: 0 10px">                 $name = "set_{$type}_without_post_value";
</span><span class="cx" style="display: block; padding: 0 10px">                $default = "default_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                $initial_value = "initial_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                $this->custom_type_setter( $name, $initial_value );
</span><span class="cx" style="display: block; padding: 0 10px">                $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need.
</ins><span class="cx" style="display: block; padding: 0 10px">                 add_filter( "customize_value_{$name}", array( $this, 'custom_type_value_filter' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $initial_value, $this->custom_type_getter( $name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $initial_value, $setting->value() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $setting->preview();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertFalse( $setting->preview(), "Preview for $setting->id should not apply because existing type without an override." );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $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.' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( 1, did_action( "customize_preview_{$setting->type}" ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertEquals( $initial_value, $this->custom_type_getter( $name, $this->undefined ) ); // should be same as above
-               $this->assertEquals( $initial_value, $setting->value() ); // should be same as above
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertEquals( $initial_value, $this->custom_type_getter( $name, $this->undefined ) ); // Should be same as above.
+               $this->assertEquals( $initial_value, $setting->value() ); // Should be same as above.
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Custom type not existing and with a post value override
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Custom type deferred preview (setting post value after preview ran).
+               $override_value = "custom_type_value_{$name}_override_deferred_preview";
+               $this->manager->set_post_value( $setting->id, $override_value );
+               $this->assertEquals( $override_value, $this->custom_type_getter( $name, $this->undefined ) ); // Should be same as above.
+               $this->assertEquals( $override_value, $setting->value() ); // Should be same as above.
+
+               // Custom type not existing and with a post value override.
</ins><span class="cx" style="display: block; padding: 0 10px">                 $name = "unset_{$type}_with_post_value";
</span><span class="cx" style="display: block; padding: 0 10px">                $default = "default_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need.
</ins><span class="cx" style="display: block; padding: 0 10px">                 add_filter( "customize_value_{$name}", array( $this, 'custom_type_value_filter' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $this->undefined, $this->custom_type_getter( $name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $default, $setting->value() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $setting->preview();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertTrue( $setting->preview() );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $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.' );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertEquals( 2, did_action( "customize_preview_{$setting->type}" ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertEquals( 3, did_action( "customize_preview_{$setting->type}" ) );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertEquals( $post_data_overrides[ $name ], $this->custom_type_getter( $name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $post_data_overrides[ $name ], $setting->value() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Custom type not existing and with a post value override
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Custom type not existing and with a post value override.
</ins><span class="cx" style="display: block; padding: 0 10px">                 $name = "set_{$type}_with_post_value";
</span><span class="cx" style="display: block; padding: 0 10px">                $default = "default_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                $initial_value = "initial_value_{$name}";
</span><span class="cx" style="display: block; padding: 0 10px">                $this->custom_type_setter( $name, $initial_value );
</span><span class="cx" style="display: block; padding: 0 10px">                $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Note: #29316 will allow us to have one filter for all settings of a given type, which is what we need.
</ins><span class="cx" style="display: block; padding: 0 10px">                 add_filter( "customize_value_{$name}", array( $this, 'custom_type_value_filter' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $initial_value, $this->custom_type_getter( $name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $initial_value, $setting->value() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $setting->preview();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertTrue( $setting->preview() );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertEquals( 1, did_action( "customize_preview_{$setting->id}" ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertEquals( 3, did_action( "customize_preview_{$setting->type}" ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertEquals( 4, did_action( "customize_preview_{$setting->type}" ) );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertEquals( $post_data_overrides[ $name ], $this->custom_type_getter( $name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $post_data_overrides[ $name ], $setting->value() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -361,7 +390,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $this->undefined, get_option( $name, $this->undefined ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $default, $setting->value() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $setting->preview();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertTrue( $setting->preview() );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertEquals( $default, get_option( $name, $this->undefined ), sprintf( 'Expected get_option(%s) to return setting default: %s.', $name, $default ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $default, $setting->value() );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -438,7 +467,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->manager->set_post_value( $name, $post_value );
</span><span class="cx" style="display: block; padding: 0 10px">                $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertFalse( $setting->is_current_blog_previewed() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $setting->preview();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertTrue( $setting->preview() );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertTrue( $setting->is_current_blog_previewed() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $post_value, $setting->value() );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -462,7 +491,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->manager->set_post_value( $name, $post_value );
</span><span class="cx" style="display: block; padding: 0 10px">                $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertFalse( $setting->is_current_blog_previewed() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $setting->preview();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertTrue( $setting->preview() );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertTrue( $setting->is_current_blog_previewed() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $blog_id = self::factory()->blog->create();
</span></span></pre></div>
<a id="trunktestsphpunittestscustomizewidgetsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/customize/widgets.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/customize/widgets.php   2015-11-20 18:55:31 UTC (rev 35723)
+++ trunk/tests/phpunit/tests/customize/widgets.php     2015-11-21 02:51:57 UTC (rev 35724)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -291,4 +291,57 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertFalse( $this->manager->widgets->is_panel_active() );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertFalse( $this->manager->get_panel( 'widgets' )->active() );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * @ticket 34738
+        * @see WP_Customize_Widgets::call_widget_update()
+        */
+       function test_call_widget_update() {
+
+               $widget_number = 2;
+               $widget_id = "search-{$widget_number}";
+               $setting_id = "widget_search[{$widget_number}]";
+               $instance = array(
+                       'title' => 'Buscar',
+               );
+
+               $_POST = wp_slash( array(
+                       'action' => 'update-widget',
+                       'wp_customize' => 'on',
+                       'nonce' => wp_create_nonce( 'update-widget' ),
+                       'theme' => $this->manager->get_stylesheet(),
+                       'customized' => '{}',
+                       'widget-search' => array(
+                               2 => $instance,
+                       ),
+                       'widget-id' => $widget_id,
+                       'id_base' => 'search',
+                       'widget-width' => '250',
+                       'widget-height' => '200',
+                       'widget_number' => strval( $widget_number ),
+                       'multi_number' => '',
+                       'add_new' => '',
+               ) );
+
+               $this->do_customize_boot_actions();
+
+               $this->assertArrayNotHasKey( $setting_id, $this->manager->unsanitized_post_values() );
+               $result = $this->manager->widgets->call_widget_update( $widget_id );
+
+               $this->assertInternalType( 'array', $result );
+               $this->assertArrayHasKey( 'instance', $result );
+               $this->assertArrayHasKey( 'form', $result );
+               $this->assertEquals( $instance, $result['instance'] );
+               $this->assertContains( sprintf( 'value="%s"', esc_attr( $instance['title'] ) ), $result['form'] );
+
+               $post_values = $this->manager->unsanitized_post_values();
+               $this->assertArrayHasKey( $setting_id, $post_values );
+               $post_value = $post_values[ $setting_id ];
+               $this->assertInternalType( 'array', $post_value );
+               $this->assertArrayHasKey( 'title', $post_value );
+               $this->assertArrayHasKey( 'encoded_serialized_instance', $post_value );
+               $this->assertArrayHasKey( 'instance_hash_key', $post_value );
+               $this->assertArrayHasKey( 'is_widget_customizer_js_value', $post_value );
+               $this->assertEquals( $post_value, $this->manager->widgets->sanitize_widget_js_instance( $instance ) );
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre>
</div>
</div>

</body>
</html>