Ticket #32103: 32103.4.diff
File 32103.4.diff, 28.5 KB (added by , 9 years ago) |
---|
-
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 6630157..01b84c8 100644
class WP_Customize_Setting { 82 82 protected $id_data = array(); 83 83 84 84 /** 85 * Cache of multidimensional values to improve performance. 86 * 87 * @since 4.4.0 88 * @access protected 89 * @var array 90 * @static 91 */ 92 protected static $aggregated_multidimensionals = array(); 93 94 /** 95 * Whether the multidimensional setting is aggregated. 96 * 97 * @since 4.4.0 98 * @access protected 99 * @var bool 100 */ 101 protected $is_multidimensional_aggregated = false; 102 103 /** 85 104 * Constructor. 86 105 * 87 106 * Any supplied $args override class property defaults. … … class WP_Customize_Setting { 96 115 public function __construct( $manager, $id, $args = array() ) { 97 116 $keys = array_keys( get_object_vars( $this ) ); 98 117 foreach ( $keys as $key ) { 99 if ( isset( $args[ $key ] ) ) 118 if ( isset( $args[ $key ] ) ) { 100 119 $this->$key = $args[ $key ]; 120 } 101 121 } 102 122 103 123 $this->manager = $manager; 104 124 $this->id = $id; 105 125 106 126 // Parse the ID for array keys. 107 $this->id_data[ 'keys'] = preg_split( '/\[/', str_replace( ']', '', $this->id ) );108 $this->id_data[ 'base' ] = array_shift( $this->id_data[ 'keys'] );127 $this->id_data['keys'] = preg_split( '/\[/', str_replace( ']', '', $this->id ) ); 128 $this->id_data['base'] = array_shift( $this->id_data['keys'] ); 109 129 110 130 // Rebuild the ID. 111 131 $this->id = $this->id_data[ 'base' ]; 112 if ( ! empty( $this->id_data[ 'keys' ] ) ) 113 $this->id .= '[' . implode( '][', $this->id_data[ 'keys' ] ) . ']'; 132 if ( ! empty( $this->id_data[ 'keys' ] ) ) { 133 $this->id .= '[' . implode( '][', $this->id_data['keys'] ) . ']'; 134 } 114 135 115 if ( $this->sanitize_callback ) 136 if ( $this->sanitize_callback ) { 116 137 add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback, 10, 2 ); 117 118 if ( $this->sanitize_js_callback ) 138 } 139 if ( $this->sanitize_js_callback ) { 119 140 add_filter( "customize_sanitize_js_{$this->id}", $this->sanitize_js_callback, 10, 2 ); 141 } 142 143 if ( 'option' === $this->type || 'theme_mod' === $this->type ) { 144 // Other setting types can opt-in to aggregate multidimensional explicitly. 145 $this->aggregate_multidimensional(); 146 } 147 } 148 149 /** 150 * Get parsed ID data for multidimensional setting. 151 * 152 * @since 4.4.0 153 * @access public 154 * 155 * @return array { 156 * ID data for multidimensional setting. 157 * 158 * @type string $base ID base 159 * @type array $keys Keys for multidimensional array. 160 * } 161 */ 162 final public function id_data() { 163 return $this->id_data; 164 } 165 166 /** 167 * Set up the setting for aggregated multidimensional values. 168 * 169 * When a multidimensional setting gets aggregated, all of its preview and update 170 * calls get combined into one call, greatly improving performance. 171 * 172 * @since 4.4.0 173 * @access protected 174 */ 175 protected function aggregate_multidimensional() { 176 if ( empty( $this->id_data['keys'] ) ) { 177 return; 178 } 179 180 $id_base = $this->id_data['base']; 181 if ( ! isset( self::$aggregated_multidimensionals[ $this->type ] ) ) { 182 self::$aggregated_multidimensionals[ $this->type ] = array(); 183 } 184 if ( ! isset( self::$aggregated_multidimensionals[ $this->type ][ $id_base ] ) ) { 185 self::$aggregated_multidimensionals[ $this->type ][ $id_base ] = array( 186 'previewed_instances' => array(), // Calling preview() will add the $setting to the array. 187 'preview_applied_instances' => array(), // Flags for which settings have had their values applied. 188 'root_value' => $this->get_root_value( array() ), // Root value for initial state, manipulated by preview and update calls. 189 ); 190 } 191 $this->is_multidimensional_aggregated = true; 120 192 } 121 193 122 194 /** … … class WP_Customize_Setting { 153 225 protected $_original_value; 154 226 155 227 /** 156 * Set up filters for the setting so that the preview request 157 * will render the drafted changes. 228 * Add filters to supply the setting's value when accessed. 229 * 230 * If the setting already has a pre-existing value and there is no incoming 231 * post value for the setting, then this method will short-circuit since 232 * there is no change to preview. 158 233 * 159 234 * @since 3.4.0 235 * @since 4.4.0 Added boolean return value. 236 * @access public 237 * 238 * @return bool False when preview short-circuits due no change needing to be previewed. 160 239 */ 161 240 public function preview() { 162 if ( ! isset( $this->_original_value ) ) {163 $this->_original_value = $this->value();164 }165 241 if ( ! isset( $this->_previewed_blog_id ) ) { 166 242 $this->_previewed_blog_id = get_current_blog_id(); 167 243 } 244 $id_base = $this->id_data['base']; 245 $is_multidimensional = ! empty( $this->id_data['keys'] ); 246 $multidimensional_filter = array( $this, '_multidimensional_preview_filter' ); 168 247 169 switch( $this->type ) { 248 /* 249 * Check if the setting has a pre-existing value (an isset check), 250 * and if doesn't have any incoming post value. If both checks are true, 251 * then the preview short-circuits because there is nothing that needs 252 * to be previewed. 253 */ 254 $undefined = new stdClass(); 255 $needs_preview = ( $undefined !== $this->post_value( $undefined ) ); 256 $value = null; 257 258 // Since no post value was defined, check if we have an initial value set. 259 if ( ! $needs_preview ) { 260 if ( $this->is_multidimensional_aggregated ) { 261 $root = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 262 $value = $this->multidimensional_get( $root, $this->id_data['keys'], $undefined ); 263 } else { 264 $default = $this->default; 265 $this->default = $undefined; // Temporarily set default to undefined so we can detect if existing value is set. 266 $value = $this->value(); 267 $this->default = $default; 268 } 269 $needs_preview = ( $undefined === $value ); // Because the default needs to be supplied. 270 } 271 272 if ( ! $needs_preview ) { 273 return false; 274 } 275 276 switch ( $this->type ) { 170 277 case 'theme_mod' : 171 add_filter( 'theme_mod_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) ); 278 if ( ! $is_multidimensional ) { 279 add_filter( "theme_mod_{$id_base}", array( $this, '_preview_filter' ) ); 280 } else { 281 if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) { 282 // Only add this filter once for this ID base. 283 add_filter( "theme_mod_{$id_base}", $multidimensional_filter ); 284 } 285 self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'][ $this->id ] = $this; 286 } 172 287 break; 173 288 case 'option' : 174 if ( empty( $this->id_data[ 'keys' ] ) ) 175 add_filter( 'pre_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) ); 176 else { 177 add_filter( 'option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) ); 178 add_filter( 'default_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) ); 289 if ( ! $is_multidimensional ) { 290 add_filter( "pre_option_{$id_base}", array( $this, '_preview_filter' ) ); 291 } else { 292 if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) { 293 // Only add these filters once for this ID base. 294 add_filter( "option_{$id_base}", $multidimensional_filter ); 295 add_filter( "default_option_{$id_base}", $multidimensional_filter ); 296 } 297 self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'][ $this->id ] = $this; 179 298 } 180 299 break; 181 300 default : … … class WP_Customize_Setting { 204 323 */ 205 324 do_action( "customize_preview_{$this->type}", $this ); 206 325 } 326 return true; 207 327 } 208 328 209 329 /** 210 * Callback function to filter thetheme mods and options.330 * Callback function to filter non-multidimensional theme mods and options. 211 331 * 212 332 * If switch_to_blog() was called after the preview() method, and the current 213 333 * blog is now not the same blog, then this method does a no-op and returns 214 334 * the original value. 215 335 * 216 336 * @since 3.4.0 217 * @uses WP_Customize_Setting::multidimensional_replace()218 337 * 219 338 * @param mixed $original Old value. 220 339 * @return mixed New or old value. … … class WP_Customize_Setting { 224 343 return $original; 225 344 } 226 345 227 $undefined = new stdClass(); // symbol hack346 $undefined = new stdClass(); // Symbol hack. 228 347 $post_value = $this->post_value( $undefined ); 229 if ( $undefined === $post_value ) { 230 $value = $this->_original_value; 231 } else { 348 if ( $undefined !== $post_value ) { 232 349 $value = $post_value; 350 } else { 351 /* 352 * Note that we don't use $original here because preview() will 353 * not add the filter in the first place if it has an initial value 354 * and there is no post value. 355 */ 356 $value = $this->default; 233 357 } 358 return $value; 359 } 360 361 /** 362 * Callback function to filter multidimensional theme mods and options. 363 * 364 * For all multidimensional settings of a given type, the preview filter for 365 * the first setting previewed will be used to apply the values for the others. 366 * 367 * @since 4.4.0 368 * @access public 369 * 370 * @see WP_Customize_Setting::$aggregated_multidimensionals 371 * @param mixed $original Original root value. 372 * @return mixed New or old value. 373 */ 374 public function _multidimensional_preview_filter( $original ) { 375 if ( ! $this->is_current_blog_previewed() ) { 376 return $original; 377 } 378 379 $id_base = $this->id_data['base']; 380 381 // If no settings have been previewed yet (which should not be the case, since $this is), just pass through the original value. 382 if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) { 383 return $original; 384 } 385 386 foreach ( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] as $previewed_setting ) { 387 // Skip applying previewed value for any settings that have already been applied. 388 if ( ! empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['preview_applied_instances'][ $previewed_setting->id ] ) ) { 389 continue; 390 } 391 392 // Do the replacements of the posted/default sub value into the root value. 393 $value = $previewed_setting->post_value( $previewed_setting->default ); 394 $root = self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['root_value']; 395 $root = $previewed_setting->multidimensional_replace( $root, $previewed_setting->id_data['keys'], $value ); 396 self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['root_value'] = $root; 234 397 235 return $this->multidimensional_replace( $original, $this->id_data['keys'], $value ); 398 // Mark this setting having been applied so that it will be skipped when the filter is called again. 399 self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['preview_applied_instances'][ $previewed_setting->id ] = true; 400 } 401 402 return self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 236 403 } 237 404 238 405 /** … … class WP_Customize_Setting { 299 466 } 300 467 301 468 /** 302 * Save the value of the setting, using the related API.469 * Get the root value for a setting, especially for multidimensional ones. 303 470 * 304 * @since 3.4.0 471 * @since 4.4.0 472 * @access protected 305 473 * 306 * @param mixed $ value The value to update.307 * @return bool The result of saving the value.474 * @param mixed $default Value to return if root does not exist. 475 * @return mixed 308 476 */ 309 protected function update( $value ) { 310 switch ( $this->type ) { 311 case 'theme_mod' : 312 $this->_update_theme_mod( $value ); 313 return true; 314 315 case 'option' : 316 return $this->_update_option( $value ); 317 318 default : 319 320 /** 321 * Fires when the {@see WP_Customize_Setting::update()} method is called for settings 322 * not handled as theme_mods or options. 323 * 324 * The dynamic portion of the hook name, `$this->type`, refers to the type of setting. 325 * 326 * @since 3.4.0 327 * 328 * @param mixed $value Value of the setting. 329 * @param WP_Customize_Setting $this WP_Customize_Setting instance. 330 */ 331 do_action( "customize_update_{$this->type}", $value, $this ); 332 333 return has_action( "customize_update_{$this->type}" ); 477 protected function get_root_value( $default = null ) { 478 $id_base = $this->id_data['base']; 479 if ( 'option' === $this->type ) { 480 return get_option( $id_base, $default ); 481 } else if ( 'theme_mod' ) { 482 return get_theme_mod( $id_base, $default ); 483 } else { 484 /* 485 * Any WP_Customize_Setting subclass implementing aggregate multidimensional 486 * will need to override this method to obtain the data from the appropriate 487 * location. 488 */ 489 return $default; 334 490 } 335 491 } 336 492 337 493 /** 338 * Update the theme mod from the value of the parameter.494 * Set the root value for a setting, especially for multidimensional ones. 339 495 * 340 * @since 3.4.0 496 * @since 4.4.0 497 * @access protected 341 498 * 342 * @param mixed $value The value to update. 499 * @param mixed $value Value to set as root of multidimensional setting. 500 * @return bool Whether the multidimensional root was updated successfully. 343 501 */ 344 protected function _update_theme_mod( $value ) { 345 // Handle non-array theme mod. 346 if ( empty( $this->id_data[ 'keys' ] ) ) { 347 set_theme_mod( $this->id_data[ 'base' ], $value ); 348 return; 349 } 350 // Handle array-based theme mod. 351 $mods = get_theme_mod( $this->id_data[ 'base' ] ); 352 $mods = $this->multidimensional_replace( $mods, $this->id_data[ 'keys' ], $value ); 353 if ( isset( $mods ) ) { 354 set_theme_mod( $this->id_data[ 'base' ], $mods ); 502 protected function set_root_value( $value ) { 503 $id_base = $this->id_data['base']; 504 if ( 'option' === $this->type ) { 505 return update_option( $id_base, $value ); 506 } else if ( 'theme_mod' ) { 507 set_theme_mod( $id_base, $value ); 508 return true; 509 } else { 510 /* 511 * Any WP_Customize_Setting subclass implementing aggregate multidimensional 512 * will need to override this method to obtain the data from the appropriate 513 * location. 514 */ 515 return false; 355 516 } 356 517 } 357 518 358 519 /** 359 * Update the option from the value of the setting.520 * Save the value of the setting, using the related API. 360 521 * 361 522 * @since 3.4.0 362 523 * 363 524 * @param mixed $value The value to update. 364 525 * @return bool The result of saving the value. 365 526 */ 366 protected function _update_option( $value ) { 367 // Handle non-array option. 368 if ( empty( $this->id_data[ 'keys' ] ) ) 369 return update_option( $this->id_data[ 'base' ], $value ); 527 protected function update( $value ) { 528 $id_base = $this->id_data['base']; 529 if ( 'option' === $this->type || 'theme_mod' === $this->type ) { 530 if ( ! $this->is_multidimensional_aggregated ) { 531 return $this->set_root_value( $value ); 532 } else { 533 $root = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 534 $root = $this->multidimensional_replace( $root, $this->id_data['keys'], $value ); 535 self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value'] = $root; 536 return $this->set_root_value( $root ); 537 } 538 } else { 539 /** 540 * Fires when the {@see WP_Customize_Setting::update()} method is called for settings 541 * not handled as theme_mods or options. 542 * 543 * The dynamic portion of the hook name, `$this->type`, refers to the type of setting. 544 * 545 * @since 3.4.0 546 * 547 * @param mixed $value Value of the setting. 548 * @param WP_Customize_Setting $this WP_Customize_Setting instance. 549 */ 550 do_action( "customize_update_{$this->type}", $value, $this ); 551 552 return has_action( "customize_update_{$this->type}" ); 553 } 554 } 555 556 /** 557 * Deprecated method. 558 * 559 * @since 3.4.0 560 * @deprecated 4.4.0 Deprecated in favor of update() method. 561 */ 562 protected function _update_theme_mod() { 563 _deprecated_function( __METHOD__, '4.4.0', __CLASS__ . '::update()' ); 564 } 370 565 371 // Handle array-based options. 372 $options = get_option( $this->id_data[ 'base' ] ); 373 $options = $this->multidimensional_replace( $options, $this->id_data[ 'keys' ], $value ); 374 if ( isset( $options ) ) 375 return update_option( $this->id_data[ 'base' ], $options ); 566 /** 567 * Deprecated method. 568 * 569 * @since 3.4.0 570 * @deprecated 4.4.0 Deprecated in favor of update() method. 571 */ 572 protected function _update_option() { 573 _deprecated_function( __METHOD__, '4.4.0', __CLASS__ . '::update()' ); 376 574 } 377 575 378 576 /** … … class WP_Customize_Setting { 383 581 * @return mixed The value. 384 582 */ 385 583 public function value() { 386 // Get the callback that corresponds to the setting type. 387 switch( $this->type ) { 388 case 'theme_mod' : 389 $function = 'get_theme_mod'; 390 break; 391 case 'option' : 392 $function = 'get_option'; 393 break; 394 default : 395 396 /** 397 * Filter a Customize setting value not handled as a theme_mod or option. 398 * 399 * The dynamic portion of the hook name, `$this->id_date['base']`, refers to 400 * the base slug of the setting name. 401 * 402 * For settings handled as theme_mods or options, see those corresponding 403 * functions for available hooks. 404 * 405 * @since 3.4.0 406 * 407 * @param mixed $default The setting default value. Default empty. 408 */ 409 return apply_filters( 'customize_value_' . $this->id_data[ 'base' ], $this->default ); 584 $id_base = $this->id_data['base']; 585 $is_core_type = ( 'option' === $this->type || 'theme_mod' === $this->type ); 586 587 if ( ! $is_core_type && ! $this->is_multidimensional_aggregated ) { 588 $value = $this->get_root_value( $this->default ); 589 590 /** 591 * Filter a Customize setting value not handled as a theme_mod or option. 592 * 593 * The dynamic portion of the hook name, `$this->id_date['base']`, refers to 594 * the base slug of the setting name. 595 * 596 * For settings handled as theme_mods or options, see those corresponding 597 * functions for available hooks. 598 * 599 * @since 3.4.0 600 * 601 * @param mixed $default The setting default value. Default empty. 602 */ 603 $value = apply_filters( "customize_value_{$id_base}", $value ); 604 } else if ( $this->is_multidimensional_aggregated ) { 605 $root_value = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 606 $value = $this->multidimensional_get( $root_value, $this->id_data['keys'], $this->default ); 607 } else { 608 $value = $this->get_root_value( $this->default ); 410 609 } 411 412 // Handle non-array value 413 if ( empty( $this->id_data[ 'keys' ] ) ) 414 return $function( $this->id_data[ 'base' ], $this->default ); 415 416 // Handle array-based value 417 $values = $function( $this->id_data[ 'base' ] ); 418 return $this->multidimensional_get( $values, $this->id_data[ 'keys' ], $this->default ); 610 return $value; 419 611 } 420 612 421 613 /** … … class WP_Customize_Setting { 520 712 * @param $root 521 713 * @param $keys 522 714 * @param mixed $value The value to update. 523 * @return 715 * @return mixed 524 716 */ 525 717 final protected function multidimensional_replace( $root, $keys, $value ) { 526 718 if ( ! isset( $value ) ) … … class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { 853 1045 } 854 1046 855 1047 /** 856 * Get the instance data for a given widgetsetting.1048 * Get the instance data for a given nav_menu_item setting. 857 1049 * 858 1050 * @since 4.3.0 859 1051 * @access public … … class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { 987 1179 * Handle previewing the setting. 988 1180 * 989 1181 * @since 4.3.0 1182 * @since 4.4.0 Added boolean return value. 990 1183 * @access public 991 1184 * 992 1185 * @see WP_Customize_Manager::post_value() 1186 * 1187 * @return bool False if method short-circuited due to no-op. 993 1188 */ 994 1189 public function preview() { 995 1190 if ( $this->is_previewed ) { 996 return; 1191 return false; 1192 } 1193 1194 $undefined = new stdClass(); 1195 $is_placeholder = ( $this->post_id < 0 ); 1196 $is_dirty = ( $undefined !== $this->post_value( $undefined ) ); 1197 if ( ! $is_placeholder && ! $is_dirty ) { 1198 return false; 997 1199 } 998 1200 999 1201 $this->is_previewed = true; … … class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { 1009 1211 } 1010 1212 1011 1213 // @todo Add get_post_metadata filters for plugins to add their data. 1214 1215 return true; 1012 1216 } 1013 1217 1014 1218 /** … … class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { 1621 1825 * Handle previewing the setting. 1622 1826 * 1623 1827 * @since 4.3.0 1828 * @since 4.4.0 Added boolean return value 1624 1829 * @access public 1625 1830 * 1626 1831 * @see WP_Customize_Manager::post_value() 1832 * 1833 * @return bool False if method short-circuited due to no-op. 1627 1834 */ 1628 1835 public function preview() { 1629 1836 if ( $this->is_previewed ) { 1630 return; 1837 return false; 1838 } 1839 1840 $undefined = new stdClass(); 1841 $is_placeholder = ( $this->term_id < 0 ); 1842 $is_dirty = ( $undefined !== $this->post_value( $undefined ) ); 1843 if ( ! $is_placeholder && ! $is_dirty ) { 1844 return false; 1631 1845 } 1632 1846 1633 1847 $this->is_previewed = true; … … class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { 1638 1852 add_filter( 'wp_get_nav_menu_object', array( $this, 'filter_wp_get_nav_menu_object' ), 10, 2 ); 1639 1853 add_filter( 'default_option_nav_menu_options', array( $this, 'filter_nav_menu_options' ) ); 1640 1854 add_filter( 'option_nav_menu_options', array( $this, 'filter_nav_menu_options' ) ); 1855 1856 return true; 1641 1857 } 1642 1858 1643 1859 /** -
tests/phpunit/tests/customize/setting.php
diff --git tests/phpunit/tests/customize/setting.php tests/phpunit/tests/customize/setting.php index 069a8ae..600fb3f 100644
class Tests_WP_Customize_Setting extends WP_UnitTestCase { 102 102 $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) ); 103 103 $this->assertEquals( $this->undefined, call_user_func( $type_options['getter'], $name, $this->undefined ) ); 104 104 $this->assertEquals( $default, $setting->value() ); 105 $ setting->preview();105 $this->assertTrue( $setting->preview(), 'Preview should not no-op since setting has no existing value.' ); 106 106 $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 ) ); 107 107 $this->assertEquals( $default, $setting->value() ); 108 108 … … class Tests_WP_Customize_Setting extends WP_UnitTestCase { 114 114 $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) ); 115 115 $this->assertEquals( $initial_value, call_user_func( $type_options['getter'], $name ) ); 116 116 $this->assertEquals( $initial_value, $setting->value() ); 117 $ setting->preview();117 $this->assertFalse( $setting->preview(), 'Preview should no-op since setting value was extant and no post value was present.' ); 118 118 $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods) 119 119 $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods) 120 120 $this->assertEquals( $initial_value, call_user_func( $type_options['getter'], $name ) ); 121 121 $this->assertEquals( $initial_value, $setting->value() ); 122 122 123 // @todo What if we call the setter after preview() is called? If no post_value, should the new set value be stored? If that happens, then the following 3 assertions should be inverted124 123 $overridden_value = "overridden_value_$name"; 125 124 call_user_func( $type_options['setter'], $name, $overridden_value ); 126 $this->assertEquals( $initial_value, call_user_func( $type_options['getter'], $name ) ); 127 $this->assertEquals( $initial_value, $setting->value() ); 128 $this->assertNotEquals( $overridden_value, $setting->value() ); 125 $message = 'Initial value should be overridden because initial preview() was no-op due to setting having existing value and/or post value was absent.'; 126 $this->assertEquals( $overridden_value, call_user_func( $type_options['getter'], $name ), $message ); 127 $this->assertEquals( $overridden_value, $setting->value(), $message ); 128 $this->assertNotEquals( $initial_value, $setting->value(), $message ); 129 129 130 130 // Non-multidimensional: Test unset setting being overridden by a post value 131 131 $name = "unset_{$type}_overridden"; … … class Tests_WP_Customize_Setting extends WP_UnitTestCase { 133 133 $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) ); 134 134 $this->assertEquals( $this->undefined, call_user_func( $type_options['getter'], $name, $this->undefined ) ); 135 135 $this->assertEquals( $default, $setting->value() ); 136 $ setting->preview(); // activate post_data136 $this->assertTrue( $setting->preview(), 'Preview applies because setting has post_data_overrides.' ); // activate post_data 137 137 $this->assertEquals( $this->post_data_overrides[ $name ], call_user_func( $type_options['getter'], $name, $this->undefined ) ); 138 138 $this->assertEquals( $this->post_data_overrides[ $name ], $setting->value() ); 139 139 … … class Tests_WP_Customize_Setting extends WP_UnitTestCase { 145 145 $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) ); 146 146 $this->assertEquals( $initial_value, call_user_func( $type_options['getter'], $name, $this->undefined ) ); 147 147 $this->assertEquals( $initial_value, $setting->value() ); 148 $ setting->preview(); // activate post_data148 $this->assertTrue( $setting->preview(), 'Preview applies because setting has post_data_overrides.' ); // activate post_data 149 149 $this->assertEquals( 0, did_action( "customize_preview_{$setting->id}" ) ); // only applicable for custom types (not options or theme_mods) 150 150 $this->assertEquals( 0, did_action( "customize_preview_{$setting->type}" ) ); // only applicable for custom types (not options or theme_mods) 151 151 $this->assertEquals( $this->post_data_overrides[ $name ], call_user_func( $type_options['getter'], $name, $this->undefined ) ); … … class Tests_WP_Customize_Setting extends WP_UnitTestCase { 167 167 $setting = new WP_Customize_Setting( $this->manager, $name, compact( 'type', 'default' ) ); 168 168 $this->assertEquals( $this->undefined, call_user_func( $type_options['getter'], $base_name, $this->undefined ) ); 169 169 $this->assertEquals( $default, $setting->value() ); 170 $ setting->preview();170 $this->assertTrue( $setting->preview() ); 171 171 $base_value = call_user_func( $type_options['getter'], $base_name, $this->undefined ); 172 172 $this->assertArrayHasKey( 'foo', $base_value ); 173 173 $this->assertEquals( $default, $base_value['foo'] ); … … class Tests_WP_Customize_Setting extends WP_UnitTestCase { 311 311 $this->assertEquals( $initial_value, $this->custom_type_getter( $name, $this->undefined ) ); 312 312 $this->assertEquals( $initial_value, $setting->value() ); 313 313 $setting->preview(); 314 $this->assertEquals( 1, did_action( "customize_preview_{$setting->id}" ));315 $this->assertEquals( 2, did_action( "customize_preview_{$setting->type}" ) );314 $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.' ); 315 $this->assertEquals( 1, did_action( "customize_preview_{$setting->type}" ) ); 316 316 $this->assertEquals( $initial_value, $this->custom_type_getter( $name, $this->undefined ) ); // should be same as above 317 317 $this->assertEquals( $initial_value, $setting->value() ); // should be same as above 318 318 … … class Tests_WP_Customize_Setting extends WP_UnitTestCase { 325 325 $this->assertEquals( $this->undefined, $this->custom_type_getter( $name, $this->undefined ) ); 326 326 $this->assertEquals( $default, $setting->value() ); 327 327 $setting->preview(); 328 $this->assertEquals( 1, did_action( "customize_preview_{$setting->id}" ) );329 $this->assertEquals( 3, did_action( "customize_preview_{$setting->type}" ) );328 $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}" ) ); 330 330 $this->assertEquals( $post_data_overrides[ $name ], $this->custom_type_getter( $name, $this->undefined ) ); 331 331 $this->assertEquals( $post_data_overrides[ $name ], $setting->value() ); 332 332 … … class Tests_WP_Customize_Setting extends WP_UnitTestCase { 342 342 $this->assertEquals( $initial_value, $setting->value() ); 343 343 $setting->preview(); 344 344 $this->assertEquals( 1, did_action( "customize_preview_{$setting->id}" ) ); 345 $this->assertEquals( 4, did_action( "customize_preview_{$setting->type}" ) );345 $this->assertEquals( 3, did_action( "customize_preview_{$setting->type}" ) ); 346 346 $this->assertEquals( $post_data_overrides[ $name ], $this->custom_type_getter( $name, $this->undefined ) ); 347 347 $this->assertEquals( $post_data_overrides[ $name ], $setting->value() ); 348 348