Ticket #32103: 32103.wip3.diff
File 32103.wip3.diff, 30.5 KB (added by , 9 years ago) |
---|
-
src/wp-includes/class-wp-customize-manager.php
diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php index 1505b60..e07bb8a 100644
final class WP_Customize_Manager { 899 899 do_action( 'customize_save', $this ); 900 900 901 901 foreach ( $this->settings as $setting ) { 902 /* 903 * Note that aggregated multidimensional settings will only be 904 * prepared for saving with this call. They will actually be saved 905 * in the finalize_multidimensional_update() call below. 906 */ 902 907 $setting->save(); 903 908 } 909 foreach ( $this->settings as $setting ) { 910 $setting->finalize_multidimensional_update(); 911 } 904 912 905 913 /** 906 914 * Fires after Customize settings have been saved. -
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..9469f28 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 * @todo Do we need this? We can look at $aggregated_multidimensionals anyway 98 * @since 4.4.0 99 * @access protected 100 * @var bool 101 */ 102 protected $is_multidimensional_aggregated = false; 103 104 /** 85 105 * Constructor. 86 106 * 87 107 * Any supplied $args override class property defaults. … … class WP_Customize_Setting { 96 116 public function __construct( $manager, $id, $args = array() ) { 97 117 $keys = array_keys( get_object_vars( $this ) ); 98 118 foreach ( $keys as $key ) { 99 if ( isset( $args[ $key ] ) ) 119 if ( isset( $args[ $key ] ) ) { 100 120 $this->$key = $args[ $key ]; 121 } 101 122 } 102 123 103 124 $this->manager = $manager; 104 125 $this->id = $id; 105 126 106 127 // 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'] );128 $this->id_data['keys'] = preg_split( '/\[/', str_replace( ']', '', $this->id ) ); 129 $this->id_data['base'] = array_shift( $this->id_data['keys'] ); 109 130 110 131 // Rebuild the ID. 111 132 $this->id = $this->id_data[ 'base' ]; 112 if ( ! empty( $this->id_data[ 'keys' ] ) ) 113 $this->id .= '[' . implode( '][', $this->id_data[ 'keys' ] ) . ']'; 133 if ( ! empty( $this->id_data[ 'keys' ] ) ) { 134 $this->id .= '[' . implode( '][', $this->id_data['keys'] ) . ']'; 135 } 114 136 115 if ( $this->sanitize_callback ) 137 if ( $this->sanitize_callback ) { 116 138 add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback, 10, 2 ); 117 118 if ( $this->sanitize_js_callback ) 139 } 140 if ( $this->sanitize_js_callback ) { 119 141 add_filter( "customize_sanitize_js_{$this->id}", $this->sanitize_js_callback, 10, 2 ); 142 } 143 144 if ( 'option' === $this->type || 'theme_mod' === $this->type ) { 145 // Other setting types can opt-in to aggregate multidimensional explicitly. 146 $this->aggregate_multidimensional(); 147 } 148 } 149 150 /** 151 * Get parsed ID data for multidimensional setting. 152 * 153 * @since 4.4.0 154 * @access public 155 * 156 * @return array { 157 * ID data for multidimensional setting. 158 * 159 * @type string $base ID base 160 * @type array $keys Keys for multidimensional array. 161 * } 162 */ 163 final public function id_data() { 164 return $this->id_data; 165 } 166 167 /** 168 * Set up the setting for aggregated multidimensional values. 169 * 170 * When a multidimensional setting gets aggregated, all of its preview and update 171 * calls get combined into one call, greatly improving performance. 172 * 173 * @since 4.4.0 174 * @access protected 175 */ 176 protected function aggregate_multidimensional() { 177 if ( empty( $this->id_data['keys'] ) ) { 178 return; 179 } 180 181 $id_base = $this->id_data['base']; 182 if ( ! isset( self::$aggregated_multidimensionals[ $this->type ] ) ) { 183 self::$aggregated_multidimensionals[ $this->type ] = array(); 184 } 185 if ( ! isset( self::$aggregated_multidimensionals[ $this->type ][ $id_base ] ) ) { 186 self::$aggregated_multidimensionals[ $this->type ][ $id_base ] = array( 187 'previewed_instances' => array(), // Calling preview() will add the $setting to the array. 188 'preview_applied_instances' => array(), // Flags for which settings have had their values applied. 189 'updated_instances' => array(), // Keep track of which settings have had update() called; will determine whether 190 'root_value' => $this->get_root_value( array() ), // Root value for initial state, manipulated by preview and update calls. 191 ); 192 } 193 $this->is_multidimensional_aggregated = true; 120 194 } 121 195 122 196 /** … … class WP_Customize_Setting { 153 227 protected $_original_value; 154 228 155 229 /** 156 * Set up filters for the setting so that the preview request 157 * will render the drafted changes. 230 * Add filters to supply the setting's value when accessed. 231 * 232 * If the setting already has a pre-existing value and there is no incoming 233 * post value for the setting, then this method will short-circuit since 234 * there is no change to preview. 158 235 * 159 236 * @since 3.4.0 237 * @since 4.4.0 Added boolean return value. 238 * @access public 239 * 240 * @return bool False when preview short-circuits due no change needing to be previewed. 160 241 */ 161 242 public function preview() { 162 if ( ! isset( $this->_original_value ) ) {163 $this->_original_value = $this->value();164 }165 243 if ( ! isset( $this->_previewed_blog_id ) ) { 166 244 $this->_previewed_blog_id = get_current_blog_id(); 167 245 } 246 $id_base = $this->id_data['base']; 247 $is_multidimensional = ! empty( $this->id_data['keys'] ); 248 $multidimensional_filter = array( $this, '_multidimensional_preview_filter' ); 168 249 169 switch( $this->type ) { 250 /* 251 * Check if the setting has a pre-existing value (an isset check), 252 * and if doesn't have any incoming post value. If both checks are true, 253 * then the preview short-circuits because there is nothing that needs 254 * to be previewed. 255 */ 256 $undefined = new stdClass(); 257 $needs_preview = ( $undefined !== $this->post_value( $undefined ) ); 258 $value = null; 259 260 // Since no post value was defined, check if we have an initial value set. 261 if ( ! $needs_preview ) { 262 if ( $this->is_multidimensional_aggregated ) { 263 $root = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 264 $value = $this->multidimensional_get( $root, $this->id_data['keys'], $undefined ); 265 } else { 266 $default = $this->default; 267 $this->default = $undefined; // Temporarily set default to undefined so we can detect if existing value is set. 268 $value = $this->value(); 269 $this->default = $default; 270 } 271 $needs_preview = ( $undefined === $value ); // Because the default needs to be supplied. 272 } 273 274 if ( ! $needs_preview ) { 275 return false; 276 } 277 278 switch ( $this->type ) { 170 279 case 'theme_mod' : 171 add_filter( 'theme_mod_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) ); 280 if ( ! $is_multidimensional ) { 281 add_filter( "theme_mod_{$id_base}", array( $this, '_preview_filter' ) ); 282 } else { 283 if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) { 284 // Only add this filter once for this ID base. 285 add_filter( "theme_mod_{$id_base}", $multidimensional_filter ); 286 } 287 self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'][ $this->id ] = $this; 288 } 172 289 break; 173 290 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' ) ); 291 if ( ! $is_multidimensional ) { 292 add_filter( "pre_option_{$id_base}", array( $this, '_preview_filter' ) ); 293 } else { 294 if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) { 295 // Only add these filters once for this ID base. 296 add_filter( "option_{$id_base}", $multidimensional_filter ); 297 add_filter( "default_option_{$id_base}", $multidimensional_filter ); 298 } 299 self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'][ $this->id ] = $this; 179 300 } 180 301 break; 181 302 default : … … class WP_Customize_Setting { 204 325 */ 205 326 do_action( "customize_preview_{$this->type}", $this ); 206 327 } 328 return true; 207 329 } 208 330 209 331 /** 210 * Callback function to filter thetheme mods and options.332 * Callback function to filter non-multidimensional theme mods and options. 211 333 * 212 334 * If switch_to_blog() was called after the preview() method, and the current 213 335 * blog is now not the same blog, then this method does a no-op and returns 214 336 * the original value. 215 337 * 216 338 * @since 3.4.0 217 * @uses WP_Customize_Setting::multidimensional_replace()218 339 * 219 340 * @param mixed $original Old value. 220 341 * @return mixed New or old value. … … class WP_Customize_Setting { 224 345 return $original; 225 346 } 226 347 227 $undefined = new stdClass(); // symbol hack348 $undefined = new stdClass(); // Symbol hack. 228 349 $post_value = $this->post_value( $undefined ); 229 if ( $undefined === $post_value ) { 230 $value = $this->_original_value; 231 } else { 350 if ( $undefined !== $post_value ) { 232 351 $value = $post_value; 352 } else { 353 /* 354 * Note that we don't use $original here because preview() will 355 * not add the filter in the first place if it has an initial value 356 * and there is no post value. 357 */ 358 $value = $this->default; 359 } 360 return $value; 361 } 362 363 /** 364 * Callback function to filter multidimensional theme mods and options. 365 * 366 * For all multidimensional settings of a given type, the preview filter for 367 * the first setting previewed will be used to apply the values for the others. 368 * 369 * @since 4.4.0 370 * @access public 371 * 372 * @see WP_Customize_Setting::$aggregated_multidimensionals 373 * @param mixed $original Original root value. 374 * @return mixed New or old value. 375 */ 376 public function _multidimensional_preview_filter( $original ) { 377 if ( ! $this->is_current_blog_previewed() ) { 378 return $original; 379 } 380 381 $id_base = $this->id_data['base']; 382 383 // If no settings have been previewed yet (which should not be the case, since $this is), just pass through the original value. 384 if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) { 385 return $original; 233 386 } 234 387 235 return $this->multidimensional_replace( $original, $this->id_data['keys'], $value ); 388 foreach ( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] as $previewed_setting ) { 389 // Skip applying previewed value for any settings that have already been applied. 390 if ( ! empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['preview_applied_instances'][ $previewed_setting->id ] ) ) { 391 continue; 392 } 393 394 // Do the replacements of the posted/default sub value into the root value. 395 $value = $previewed_setting->post_value( $previewed_setting->default ); 396 $root = self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['root_value']; 397 $root = $previewed_setting->multidimensional_replace( $root, $previewed_setting->id_data['keys'], $value ); 398 self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['root_value'] = $root; 399 400 // Mark this setting having been applied so that it will be skipped when the filter is called again. 401 self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['preview_applied_instances'][ $previewed_setting->id ] = true; 402 } 403 404 return self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 236 405 } 237 406 238 407 /** … … class WP_Customize_Setting { 299 468 } 300 469 301 470 /** 471 * Get the root value for a setting, especially for multidimensional ones. 472 * 473 * @since 4.4.0 474 * @access protected 475 * 476 * @param mixed $default Value to return if root does not exist. 477 * @return mixed 478 */ 479 protected function get_root_value( $default = null ) { 480 $id_base = $this->id_data['base']; 481 if ( 'option' === $this->type ) { 482 return get_option( $id_base, $default ); 483 } else if ( 'theme_mod' ) { 484 return get_theme_mod( $id_base, $default ); 485 } else { 486 /* 487 * Any WP_Customize_Setting subclass implementing aggregate multidimensional 488 * will need to override this method to obtain the data from the appropriate 489 * location. 490 */ 491 return $default; 492 } 493 } 494 495 /** 496 * Set the root value for a setting, especially for multidimensional ones. 497 * 498 * @since 4.4.0 499 * @access protected 500 * 501 * @param mixed $value Value to set as root of multidimensional setting. 502 * @return bool Whether the multidimensional root was updated successfully. 503 */ 504 protected function set_root_value( $value ) { 505 $id_base = $this->id_data['base']; 506 if ( 'option' === $this->type ) { 507 return update_option( $id_base, $value ); 508 } else if ( 'theme_mod' ) { 509 set_theme_mod( $id_base, $value ); 510 return true; 511 } else { 512 /* 513 * Any WP_Customize_Setting subclass implementing aggregate multidimensional 514 * will need to override this method to obtain the data from the appropriate 515 * location. 516 */ 517 return false; 518 } 519 } 520 521 /** 302 522 * Save the value of the setting, using the related API. 303 523 * 304 524 * @since 3.4.0 … … class WP_Customize_Setting { 307 527 * @return bool The result of saving the value. 308 528 */ 309 529 protected function update( $value ) { 310 switch ( $this->type ) { 311 case 'theme_mod' : 312 $this->_update_theme_mod( $value ); 530 $id_base = $this->id_data['base']; 531 if ( 'option' === $this->type || 'theme_mod' === $this->type ) { 532 if ( ! $this->is_multidimensional_aggregated ) { 533 return $this->set_root_value( $value ); 534 } else { 535 $root = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 536 $root = $this->multidimensional_replace( $root, $this->id_data['keys'], $value ); 537 self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value'] = $root; 538 self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['updated_instances'] = $this; // Mark this setting as updated. 539 // @todo Should actually just go ahead and call set set_root_value() and skip the whole finalize logic? 313 540 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}" ); 541 } 542 } else { 543 /** 544 * Fires when the {@see WP_Customize_Setting::update()} method is called for settings 545 * not handled as theme_mods or options. 546 * 547 * The dynamic portion of the hook name, `$this->type`, refers to the type of setting. 548 * 549 * @since 3.4.0 550 * 551 * @param mixed $value Value of the setting. 552 * @param WP_Customize_Setting $this WP_Customize_Setting instance. 553 */ 554 do_action( "customize_update_{$this->type}", $value, $this ); 555 556 return has_action( "customize_update_{$this->type}" ); 334 557 } 335 558 } 336 559 337 560 /** 338 * Update the theme mod from the value of the parameter.561 * Deprecated method. 339 562 * 340 563 * @since 3.4.0 341 * 342 * @param mixed $value The value to update. 564 * @deprecated 4.4.0 Deprecated in favor of update() method. 343 565 */ 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 ); 355 } 566 protected function _update_theme_mod() { 567 _deprecated_function( __METHOD__, '4.4.0' ); 356 568 } 357 569 358 570 /** 359 * Update the option from the value of the setting.571 * Deprecated method. 360 572 * 361 573 * @since 3.4.0 574 * @deprecated 4.4.0 Deprecated in favor of update() method. 575 */ 576 protected function _update_option() { 577 _deprecated_function( __METHOD__, '4.4.0' ); 578 } 579 580 /** 581 * Finalize/commit the updates for multidimensional settings. 362 582 * 363 * @param mixed $value The value to update. 364 * @return bool The result of saving the value. 583 * @see WP_Customize_Manager::save() 584 * @since 4.4.0 585 * @access public 365 586 */ 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 ); 587 final public function finalize_multidimensional_update() { 588 if ( ! $this->is_multidimensional_aggregated ) { 589 return; 590 } 591 $id_base = $this->id_data['base']; 370 592 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 ); 593 // Abort finalizing a multidimensional if none have been updated. 594 if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['updated_instances'] ) ) { 595 return; 596 } 597 598 if ( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['update_finalized'] ) { 599 return; 600 } 601 // @todo We should make sure we don't inject the default values into the array. Should be OK since preview() would not have applied. 602 $this->set_root_value( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value'] ); 603 self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['update_finalized'] = true; 376 604 } 377 605 378 606 /** … … class WP_Customize_Setting { 383 611 * @return mixed The value. 384 612 */ 385 613 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 ); 614 $id_base = $this->id_data['base']; 615 $is_core_type = ( 'option' === $this->type || 'theme_mod' === $this->type ); 616 617 if ( ! $is_core_type && ! $this->is_multidimensional_aggregated ) { 618 $value = $this->get_root_value( $this->default ); // @todo Should $this->default be used here? 619 620 /** 621 * Filter a Customize setting value not handled as a theme_mod or option. 622 * 623 * The dynamic portion of the hook name, `$this->id_date['base']`, refers to 624 * the base slug of the setting name. 625 * 626 * For settings handled as theme_mods or options, see those corresponding 627 * functions for available hooks. 628 * 629 * @since 3.4.0 630 * 631 * @param mixed $default The setting default value. Default empty. 632 */ 633 $value = apply_filters( "customize_value_{$id_base}", $value ); 634 } else if ( $this->is_multidimensional_aggregated ) { 635 $root_value = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 636 $value = $this->multidimensional_get( $root_value, $this->id_data['keys'], $this->default ); 637 } else { 638 $value = $this->get_root_value( $this->default ); 410 639 } 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 ); 640 return $value; 419 641 } 420 642 421 643 /** … … class WP_Customize_Setting { 520 742 * @param $root 521 743 * @param $keys 522 744 * @param mixed $value The value to update. 523 * @return 745 * @return mixed 524 746 */ 525 747 final protected function multidimensional_replace( $root, $keys, $value ) { 526 748 if ( ! isset( $value ) ) … … class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { 853 1075 } 854 1076 855 1077 /** 856 * Get the instance data for a given widgetsetting.1078 * Get the instance data for a given nav_menu_item setting. 857 1079 * 858 1080 * @since 4.3.0 859 1081 * @access public … … class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { 987 1209 * Handle previewing the setting. 988 1210 * 989 1211 * @since 4.3.0 1212 * @since 4.4.0 Added boolean return value. 990 1213 * @access public 991 1214 * 992 1215 * @see WP_Customize_Manager::post_value() 1216 * 1217 * @return bool False if method short-circuited due to no-op. 993 1218 */ 994 1219 public function preview() { 995 1220 if ( $this->is_previewed ) { 996 return; 1221 return false; 1222 } 1223 1224 $undefined = new stdClass(); 1225 $is_placeholder = ( $this->post_id < 0 ); 1226 $is_dirty = ( $undefined !== $this->post_value( $undefined ) ); 1227 if ( ! $is_placeholder && ! $is_dirty ) { 1228 return false; 997 1229 } 998 1230 999 1231 $this->is_previewed = true; … … class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { 1009 1241 } 1010 1242 1011 1243 // @todo Add get_post_metadata filters for plugins to add their data. 1244 1245 return true; 1012 1246 } 1013 1247 1014 1248 /** … … class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { 1621 1855 * Handle previewing the setting. 1622 1856 * 1623 1857 * @since 4.3.0 1858 * @since 4.4.0 Added boolean return value 1624 1859 * @access public 1625 1860 * 1626 1861 * @see WP_Customize_Manager::post_value() 1862 * 1863 * @return bool False if method short-circuited due to no-op. 1627 1864 */ 1628 1865 public function preview() { 1629 1866 if ( $this->is_previewed ) { 1630 return; 1867 return false; 1868 } 1869 1870 $undefined = new stdClass(); 1871 $is_placeholder = ( $this->term_id < 0 ); 1872 $is_dirty = ( $undefined !== $this->post_value( $undefined ) ); 1873 if ( ! $is_placeholder && ! $is_dirty ) { 1874 return false; 1631 1875 } 1632 1876 1633 1877 $this->is_previewed = true; … … class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { 1638 1882 add_filter( 'wp_get_nav_menu_object', array( $this, 'filter_wp_get_nav_menu_object' ), 10, 2 ); 1639 1883 add_filter( 'default_option_nav_menu_options', array( $this, 'filter_nav_menu_options' ) ); 1640 1884 add_filter( 'option_nav_menu_options', array( $this, 'filter_nav_menu_options' ) ); 1885 1886 return true; 1641 1887 } 1642 1888 1643 1889 /** -
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