[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * WordPress Customize Setting classes 4 * 5 * @package WordPress 6 * @subpackage Customize 7 * @since 3.4.0 8 */ 9 10 /** 11 * Customize Setting class. 12 * 13 * Handles saving and sanitizing of settings. 14 * 15 * @since 3.4.0 16 * 17 * @see WP_Customize_Manager 18 * @link https://developer.wordpress.org/themes/customize-api 19 */ 20 #[AllowDynamicProperties] 21 class WP_Customize_Setting { 22 /** 23 * Customizer bootstrap instance. 24 * 25 * @since 3.4.0 26 * @var WP_Customize_Manager 27 */ 28 public $manager; 29 30 /** 31 * Unique string identifier for the setting. 32 * 33 * @since 3.4.0 34 * @var string 35 */ 36 public $id; 37 38 /** 39 * Type of customize settings. 40 * 41 * @since 3.4.0 42 * @var string 43 */ 44 public $type = 'theme_mod'; 45 46 /** 47 * Capability required to edit this setting. 48 * 49 * @since 3.4.0 50 * @var string|array 51 */ 52 public $capability = 'edit_theme_options'; 53 54 /** 55 * Theme features required to support the setting. 56 * 57 * @since 3.4.0 58 * @var string|string[] 59 */ 60 public $theme_supports = ''; 61 62 /** 63 * The default value for the setting. 64 * 65 * @since 3.4.0 66 * @var string 67 */ 68 public $default = ''; 69 70 /** 71 * Options for rendering the live preview of changes in Customizer. 72 * 73 * Set this value to 'postMessage' to enable a custom JavaScript handler to render changes to this setting 74 * as opposed to reloading the whole page. 75 * 76 * @since 3.4.0 77 * @var string 78 */ 79 public $transport = 'refresh'; 80 81 /** 82 * Server-side validation callback for the setting's value. 83 * 84 * @since 4.6.0 85 * @var callable 86 */ 87 public $validate_callback = ''; 88 89 /** 90 * Callback to filter a Customize setting value in un-slashed form. 91 * 92 * @since 3.4.0 93 * @var callable 94 */ 95 public $sanitize_callback = ''; 96 97 /** 98 * Callback to convert a Customize PHP setting value to a value that is JSON serializable. 99 * 100 * @since 3.4.0 101 * @var callable 102 */ 103 public $sanitize_js_callback = ''; 104 105 /** 106 * Whether or not the setting is initially dirty when created. 107 * 108 * This is used to ensure that a setting will be sent from the pane to the 109 * preview when loading the Customizer. Normally a setting only is synced to 110 * the preview if it has been changed. This allows the setting to be sent 111 * from the start. 112 * 113 * @since 4.2.0 114 * @var bool 115 */ 116 public $dirty = false; 117 118 /** 119 * ID Data. 120 * 121 * @since 3.4.0 122 * @var array 123 */ 124 protected $id_data = array(); 125 126 /** 127 * Whether or not preview() was called. 128 * 129 * @since 4.4.0 130 * @var bool 131 */ 132 protected $is_previewed = false; 133 134 /** 135 * Cache of multidimensional values to improve performance. 136 * 137 * @since 4.4.0 138 * @var array 139 */ 140 protected static $aggregated_multidimensionals = array(); 141 142 /** 143 * Whether the multidimensional setting is aggregated. 144 * 145 * @since 4.4.0 146 * @var bool 147 */ 148 protected $is_multidimensional_aggregated = false; 149 150 /** 151 * Constructor. 152 * 153 * Any supplied $args override class property defaults. 154 * 155 * @since 3.4.0 156 * 157 * @param WP_Customize_Manager $manager Customizer bootstrap instance. 158 * @param string $id A specific ID of the setting. 159 * Can be a theme mod or option name. 160 * @param array $args { 161 * Optional. Array of properties for the new Setting object. Default empty array. 162 * 163 * @type string $type Type of the setting. Default 'theme_mod'. 164 * @type string $capability Capability required for the setting. Default 'edit_theme_options' 165 * @type string|string[] $theme_supports Theme features required to support the panel. Default is none. 166 * @type string $default Default value for the setting. Default is empty string. 167 * @type string $transport Options for rendering the live preview of changes in Customizer. 168 * Using 'refresh' makes the change visible by reloading the whole preview. 169 * Using 'postMessage' allows a custom JavaScript to handle live changes. 170 * Default is 'refresh'. 171 * @type callable $validate_callback Server-side validation callback for the setting's value. 172 * @type callable $sanitize_callback Callback to filter a Customize setting value in un-slashed form. 173 * @type callable $sanitize_js_callback Callback to convert a Customize PHP setting value to a value that is 174 * JSON serializable. 175 * @type bool $dirty Whether or not the setting is initially dirty when created. 176 * } 177 */ 178 public function __construct( $manager, $id, $args = array() ) { 179 $keys = array_keys( get_object_vars( $this ) ); 180 foreach ( $keys as $key ) { 181 if ( isset( $args[ $key ] ) ) { 182 $this->$key = $args[ $key ]; 183 } 184 } 185 186 $this->manager = $manager; 187 $this->id = $id; 188 189 // Parse the ID for array keys. 190 $this->id_data['keys'] = preg_split( '/\[/', str_replace( ']', '', $this->id ) ); 191 $this->id_data['base'] = array_shift( $this->id_data['keys'] ); 192 193 // Rebuild the ID. 194 $this->id = $this->id_data['base']; 195 if ( ! empty( $this->id_data['keys'] ) ) { 196 $this->id .= '[' . implode( '][', $this->id_data['keys'] ) . ']'; 197 } 198 199 if ( $this->validate_callback ) { 200 add_filter( "customize_validate_{$this->id}", $this->validate_callback, 10, 3 ); 201 } 202 if ( $this->sanitize_callback ) { 203 add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback, 10, 2 ); 204 } 205 if ( $this->sanitize_js_callback ) { 206 add_filter( "customize_sanitize_js_{$this->id}", $this->sanitize_js_callback, 10, 2 ); 207 } 208 209 if ( 'option' === $this->type || 'theme_mod' === $this->type ) { 210 // Other setting types can opt-in to aggregate multidimensional explicitly. 211 $this->aggregate_multidimensional(); 212 213 // Allow option settings to indicate whether they should be autoloaded. 214 if ( 'option' === $this->type && isset( $args['autoload'] ) ) { 215 self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['autoload'] = $args['autoload']; 216 } 217 } 218 } 219 220 /** 221 * Get parsed ID data for multidimensional setting. 222 * 223 * @since 4.4.0 224 * 225 * @return array { 226 * ID data for multidimensional setting. 227 * 228 * @type string $base ID base 229 * @type array $keys Keys for multidimensional array. 230 * } 231 */ 232 final public function id_data() { 233 return $this->id_data; 234 } 235 236 /** 237 * Set up the setting for aggregated multidimensional values. 238 * 239 * When a multidimensional setting gets aggregated, all of its preview and update 240 * calls get combined into one call, greatly improving performance. 241 * 242 * @since 4.4.0 243 */ 244 protected function aggregate_multidimensional() { 245 $id_base = $this->id_data['base']; 246 if ( ! isset( self::$aggregated_multidimensionals[ $this->type ] ) ) { 247 self::$aggregated_multidimensionals[ $this->type ] = array(); 248 } 249 if ( ! isset( self::$aggregated_multidimensionals[ $this->type ][ $id_base ] ) ) { 250 self::$aggregated_multidimensionals[ $this->type ][ $id_base ] = array( 251 'previewed_instances' => array(), // Calling preview() will add the $setting to the array. 252 'preview_applied_instances' => array(), // Flags for which settings have had their values applied. 253 'root_value' => $this->get_root_value( array() ), // Root value for initial state, manipulated by preview and update calls. 254 ); 255 } 256 257 if ( ! empty( $this->id_data['keys'] ) ) { 258 // Note the preview-applied flag is cleared at priority 9 to ensure it is cleared before a deferred-preview runs. 259 add_action( "customize_post_value_set_{$this->id}", array( $this, '_clear_aggregated_multidimensional_preview_applied_flag' ), 9 ); 260 $this->is_multidimensional_aggregated = true; 261 } 262 } 263 264 /** 265 * Reset `$aggregated_multidimensionals` static variable. 266 * 267 * This is intended only for use by unit tests. 268 * 269 * @since 4.5.0 270 * @ignore 271 */ 272 public static function reset_aggregated_multidimensionals() { 273 self::$aggregated_multidimensionals = array(); 274 } 275 276 /** 277 * The ID for the current site when the preview() method was called. 278 * 279 * @since 4.2.0 280 * @var int 281 */ 282 protected $_previewed_blog_id; 283 284 /** 285 * Return true if the current site is not the same as the previewed site. 286 * 287 * @since 4.2.0 288 * 289 * @return bool If preview() has been called. 290 */ 291 public function is_current_blog_previewed() { 292 if ( ! isset( $this->_previewed_blog_id ) ) { 293 return false; 294 } 295 return ( get_current_blog_id() === $this->_previewed_blog_id ); 296 } 297 298 /** 299 * Original non-previewed value stored by the preview method. 300 * 301 * @see WP_Customize_Setting::preview() 302 * @since 4.1.1 303 * @var mixed 304 */ 305 protected $_original_value; 306 307 /** 308 * Add filters to supply the setting's value when accessed. 309 * 310 * If the setting already has a pre-existing value and there is no incoming 311 * post value for the setting, then this method will short-circuit since 312 * there is no change to preview. 313 * 314 * @since 3.4.0 315 * @since 4.4.0 Added boolean return value. 316 * 317 * @return bool False when preview short-circuits due no change needing to be previewed. 318 */ 319 public function preview() { 320 if ( ! isset( $this->_previewed_blog_id ) ) { 321 $this->_previewed_blog_id = get_current_blog_id(); 322 } 323 324 // Prevent re-previewing an already-previewed setting. 325 if ( $this->is_previewed ) { 326 return true; 327 } 328 329 $id_base = $this->id_data['base']; 330 $is_multidimensional = ! empty( $this->id_data['keys'] ); 331 $multidimensional_filter = array( $this, '_multidimensional_preview_filter' ); 332 333 /* 334 * Check if the setting has a pre-existing value (an isset check), 335 * and if doesn't have any incoming post value. If both checks are true, 336 * then the preview short-circuits because there is nothing that needs 337 * to be previewed. 338 */ 339 $undefined = new stdClass(); 340 $needs_preview = ( $undefined !== $this->post_value( $undefined ) ); 341 $value = null; 342 343 // Since no post value was defined, check if we have an initial value set. 344 if ( ! $needs_preview ) { 345 if ( $this->is_multidimensional_aggregated ) { 346 $root = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 347 $value = $this->multidimensional_get( $root, $this->id_data['keys'], $undefined ); 348 } else { 349 $default = $this->default; 350 $this->default = $undefined; // Temporarily set default to undefined so we can detect if existing value is set. 351 $value = $this->value(); 352 $this->default = $default; 353 } 354 $needs_preview = ( $undefined === $value ); // Because the default needs to be supplied. 355 } 356 357 // If the setting does not need previewing now, defer to when it has a value to preview. 358 if ( ! $needs_preview ) { 359 if ( ! has_action( "customize_post_value_set_{$this->id}", array( $this, 'preview' ) ) ) { 360 add_action( "customize_post_value_set_{$this->id}", array( $this, 'preview' ) ); 361 } 362 return false; 363 } 364 365 switch ( $this->type ) { 366 case 'theme_mod': 367 if ( ! $is_multidimensional ) { 368 add_filter( "theme_mod_{$id_base}", array( $this, '_preview_filter' ) ); 369 } else { 370 if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) { 371 // Only add this filter once for this ID base. 372 add_filter( "theme_mod_{$id_base}", $multidimensional_filter ); 373 } 374 self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'][ $this->id ] = $this; 375 } 376 break; 377 case 'option': 378 if ( ! $is_multidimensional ) { 379 add_filter( "pre_option_{$id_base}", array( $this, '_preview_filter' ) ); 380 } else { 381 if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) { 382 // Only add these filters once for this ID base. 383 add_filter( "option_{$id_base}", $multidimensional_filter ); 384 add_filter( "default_option_{$id_base}", $multidimensional_filter ); 385 } 386 self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'][ $this->id ] = $this; 387 } 388 break; 389 default: 390 /** 391 * Fires when the WP_Customize_Setting::preview() method is called for settings 392 * not handled as theme_mods or options. 393 * 394 * The dynamic portion of the hook name, `$this->id`, refers to the setting ID. 395 * 396 * @since 3.4.0 397 * 398 * @param WP_Customize_Setting $setting WP_Customize_Setting instance. 399 */ 400 do_action( "customize_preview_{$this->id}", $this ); 401 402 /** 403 * Fires when the WP_Customize_Setting::preview() method is called for settings 404 * not handled as theme_mods or options. 405 * 406 * The dynamic portion of the hook name, `$this->type`, refers to the setting type. 407 * 408 * @since 4.1.0 409 * 410 * @param WP_Customize_Setting $setting WP_Customize_Setting instance. 411 */ 412 do_action( "customize_preview_{$this->type}", $this ); 413 } 414 415 $this->is_previewed = true; 416 417 return true; 418 } 419 420 /** 421 * Clear out the previewed-applied flag for a multidimensional-aggregated value whenever its post value is updated. 422 * 423 * This ensures that the new value will get sanitized and used the next time 424 * that `WP_Customize_Setting::_multidimensional_preview_filter()` 425 * is called for this setting. 426 * 427 * @since 4.4.0 428 * 429 * @see WP_Customize_Manager::set_post_value() 430 * @see WP_Customize_Setting::_multidimensional_preview_filter() 431 */ 432 final public function _clear_aggregated_multidimensional_preview_applied_flag() { 433 unset( self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['preview_applied_instances'][ $this->id ] ); 434 } 435 436 /** 437 * Callback function to filter non-multidimensional theme mods and options. 438 * 439 * If switch_to_blog() was called after the preview() method, and the current 440 * site is now not the same site, then this method does a no-op and returns 441 * the original value. 442 * 443 * @since 3.4.0 444 * 445 * @param mixed $original Old value. 446 * @return mixed New or old value. 447 */ 448 public function _preview_filter( $original ) { 449 if ( ! $this->is_current_blog_previewed() ) { 450 return $original; 451 } 452 453 $undefined = new stdClass(); // Symbol hack. 454 $post_value = $this->post_value( $undefined ); 455 if ( $undefined !== $post_value ) { 456 $value = $post_value; 457 } else { 458 /* 459 * Note that we don't use $original here because preview() will 460 * not add the filter in the first place if it has an initial value 461 * and there is no post value. 462 */ 463 $value = $this->default; 464 } 465 return $value; 466 } 467 468 /** 469 * Callback function to filter multidimensional theme mods and options. 470 * 471 * For all multidimensional settings of a given type, the preview filter for 472 * the first setting previewed will be used to apply the values for the others. 473 * 474 * @since 4.4.0 475 * 476 * @see WP_Customize_Setting::$aggregated_multidimensionals 477 * @param mixed $original Original root value. 478 * @return mixed New or old value. 479 */ 480 final public function _multidimensional_preview_filter( $original ) { 481 if ( ! $this->is_current_blog_previewed() ) { 482 return $original; 483 } 484 485 $id_base = $this->id_data['base']; 486 487 // If no settings have been previewed yet (which should not be the case, since $this is), just pass through the original value. 488 if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) { 489 return $original; 490 } 491 492 foreach ( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] as $previewed_setting ) { 493 // Skip applying previewed value for any settings that have already been applied. 494 if ( ! empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['preview_applied_instances'][ $previewed_setting->id ] ) ) { 495 continue; 496 } 497 498 // Do the replacements of the posted/default sub value into the root value. 499 $value = $previewed_setting->post_value( $previewed_setting->default ); 500 $root = self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['root_value']; 501 $root = $previewed_setting->multidimensional_replace( $root, $previewed_setting->id_data['keys'], $value ); 502 self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['root_value'] = $root; 503 504 // Mark this setting having been applied so that it will be skipped when the filter is called again. 505 self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['preview_applied_instances'][ $previewed_setting->id ] = true; 506 } 507 508 return self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 509 } 510 511 /** 512 * Checks user capabilities and theme supports, and then saves 513 * the value of the setting. 514 * 515 * @since 3.4.0 516 * 517 * @return void|false Void on success, false if cap check fails 518 * or value isn't set or is invalid. 519 */ 520 final public function save() { 521 $value = $this->post_value(); 522 523 if ( ! $this->check_capabilities() || ! isset( $value ) ) { 524 return false; 525 } 526 527 $id_base = $this->id_data['base']; 528 529 /** 530 * Fires when the WP_Customize_Setting::save() method is called. 531 * 532 * The dynamic portion of the hook name, `$id_base` refers to 533 * the base slug of the setting name. 534 * 535 * @since 3.4.0 536 * 537 * @param WP_Customize_Setting $setting WP_Customize_Setting instance. 538 */ 539 do_action( "customize_save_{$id_base}", $this ); 540 541 $this->update( $value ); 542 } 543 544 /** 545 * Fetch and sanitize the $_POST value for the setting. 546 * 547 * During a save request prior to save, post_value() provides the new value while value() does not. 548 * 549 * @since 3.4.0 550 * 551 * @param mixed $default_value A default value which is used as a fallback. Default null. 552 * @return mixed The default value on failure, otherwise the sanitized and validated value. 553 */ 554 final public function post_value( $default_value = null ) { 555 return $this->manager->post_value( $this, $default_value ); 556 } 557 558 /** 559 * Sanitize an input. 560 * 561 * @since 3.4.0 562 * 563 * @param string|array $value The value to sanitize. 564 * @return string|array|null|WP_Error Sanitized value, or `null`/`WP_Error` if invalid. 565 */ 566 public function sanitize( $value ) { 567 568 /** 569 * Filters a Customize setting value in un-slashed form. 570 * 571 * @since 3.4.0 572 * 573 * @param mixed $value Value of the setting. 574 * @param WP_Customize_Setting $setting WP_Customize_Setting instance. 575 */ 576 return apply_filters( "customize_sanitize_{$this->id}", $value, $this ); 577 } 578 579 /** 580 * Validates an input. 581 * 582 * @since 4.6.0 583 * 584 * @see WP_REST_Request::has_valid_params() 585 * 586 * @param mixed $value Value to validate. 587 * @return true|WP_Error True if the input was validated, otherwise WP_Error. 588 */ 589 public function validate( $value ) { 590 if ( is_wp_error( $value ) ) { 591 return $value; 592 } 593 if ( is_null( $value ) ) { 594 return new WP_Error( 'invalid_value', __( 'Invalid value.' ) ); 595 } 596 597 $validity = new WP_Error(); 598 599 /** 600 * Validates a Customize setting value. 601 * 602 * Plugins should amend the `$validity` object via its `WP_Error::add()` method. 603 * 604 * The dynamic portion of the hook name, `$this->ID`, refers to the setting ID. 605 * 606 * @since 4.6.0 607 * 608 * @param WP_Error $validity Filtered from `true` to `WP_Error` when invalid. 609 * @param mixed $value Value of the setting. 610 * @param WP_Customize_Setting $setting WP_Customize_Setting instance. 611 */ 612 $validity = apply_filters( "customize_validate_{$this->id}", $validity, $value, $this ); 613 614 if ( is_wp_error( $validity ) && ! $validity->has_errors() ) { 615 $validity = true; 616 } 617 return $validity; 618 } 619 620 /** 621 * Get the root value for a setting, especially for multidimensional ones. 622 * 623 * @since 4.4.0 624 * 625 * @param mixed $default_value Value to return if root does not exist. 626 * @return mixed 627 */ 628 protected function get_root_value( $default_value = null ) { 629 $id_base = $this->id_data['base']; 630 if ( 'option' === $this->type ) { 631 return get_option( $id_base, $default_value ); 632 } elseif ( 'theme_mod' === $this->type ) { 633 return get_theme_mod( $id_base, $default_value ); 634 } else { 635 /* 636 * Any WP_Customize_Setting subclass implementing aggregate multidimensional 637 * will need to override this method to obtain the data from the appropriate 638 * location. 639 */ 640 return $default_value; 641 } 642 } 643 644 /** 645 * Set the root value for a setting, especially for multidimensional ones. 646 * 647 * @since 4.4.0 648 * 649 * @param mixed $value Value to set as root of multidimensional setting. 650 * @return bool Whether the multidimensional root was updated successfully. 651 */ 652 protected function set_root_value( $value ) { 653 $id_base = $this->id_data['base']; 654 if ( 'option' === $this->type ) { 655 $autoload = true; 656 if ( isset( self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['autoload'] ) ) { 657 $autoload = self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['autoload']; 658 } 659 return update_option( $id_base, $value, $autoload ); 660 } elseif ( 'theme_mod' === $this->type ) { 661 set_theme_mod( $id_base, $value ); 662 return true; 663 } else { 664 /* 665 * Any WP_Customize_Setting subclass implementing aggregate multidimensional 666 * will need to override this method to obtain the data from the appropriate 667 * location. 668 */ 669 return false; 670 } 671 } 672 673 /** 674 * Save the value of the setting, using the related API. 675 * 676 * @since 3.4.0 677 * 678 * @param mixed $value The value to update. 679 * @return bool The result of saving the value. 680 */ 681 protected function update( $value ) { 682 $id_base = $this->id_data['base']; 683 if ( 'option' === $this->type || 'theme_mod' === $this->type ) { 684 if ( ! $this->is_multidimensional_aggregated ) { 685 return $this->set_root_value( $value ); 686 } else { 687 $root = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 688 $root = $this->multidimensional_replace( $root, $this->id_data['keys'], $value ); 689 self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value'] = $root; 690 return $this->set_root_value( $root ); 691 } 692 } else { 693 /** 694 * Fires when the WP_Customize_Setting::update() method is called for settings 695 * not handled as theme_mods or options. 696 * 697 * The dynamic portion of the hook name, `$this->type`, refers to the type of setting. 698 * 699 * @since 3.4.0 700 * 701 * @param mixed $value Value of the setting. 702 * @param WP_Customize_Setting $setting WP_Customize_Setting instance. 703 */ 704 do_action( "customize_update_{$this->type}", $value, $this ); 705 706 return has_action( "customize_update_{$this->type}" ); 707 } 708 } 709 710 /** 711 * Deprecated method. 712 * 713 * @since 3.4.0 714 * @deprecated 4.4.0 Deprecated in favor of update() method. 715 */ 716 protected function _update_theme_mod() { 717 _deprecated_function( __METHOD__, '4.4.0', __CLASS__ . '::update()' ); 718 } 719 720 /** 721 * Deprecated method. 722 * 723 * @since 3.4.0 724 * @deprecated 4.4.0 Deprecated in favor of update() method. 725 */ 726 protected function _update_option() { 727 _deprecated_function( __METHOD__, '4.4.0', __CLASS__ . '::update()' ); 728 } 729 730 /** 731 * Fetch the value of the setting. 732 * 733 * @since 3.4.0 734 * 735 * @return mixed The value. 736 */ 737 public function value() { 738 $id_base = $this->id_data['base']; 739 $is_core_type = ( 'option' === $this->type || 'theme_mod' === $this->type ); 740 741 if ( ! $is_core_type && ! $this->is_multidimensional_aggregated ) { 742 743 // Use post value if previewed and a post value is present. 744 if ( $this->is_previewed ) { 745 $value = $this->post_value( null ); 746 if ( null !== $value ) { 747 return $value; 748 } 749 } 750 751 $value = $this->get_root_value( $this->default ); 752 753 /** 754 * Filters a Customize setting value not handled as a theme_mod or option. 755 * 756 * The dynamic portion of the hook name, `$id_base`, refers to 757 * the base slug of the setting name, initialized from `$this->id_data['base']`. 758 * 759 * For settings handled as theme_mods or options, see those corresponding 760 * functions for available hooks. 761 * 762 * @since 3.4.0 763 * @since 4.6.0 Added the `$this` setting instance as the second parameter. 764 * 765 * @param mixed $default_value The setting default value. Default empty. 766 * @param WP_Customize_Setting $setting The setting instance. 767 */ 768 $value = apply_filters( "customize_value_{$id_base}", $value, $this ); 769 } elseif ( $this->is_multidimensional_aggregated ) { 770 $root_value = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value']; 771 $value = $this->multidimensional_get( $root_value, $this->id_data['keys'], $this->default ); 772 773 // Ensure that the post value is used if the setting is previewed, since preview filters aren't applying on cached $root_value. 774 if ( $this->is_previewed ) { 775 $value = $this->post_value( $value ); 776 } 777 } else { 778 $value = $this->get_root_value( $this->default ); 779 } 780 return $value; 781 } 782 783 /** 784 * Sanitize the setting's value for use in JavaScript. 785 * 786 * @since 3.4.0 787 * 788 * @return mixed The requested escaped value. 789 */ 790 public function js_value() { 791 792 /** 793 * Filters a Customize setting value for use in JavaScript. 794 * 795 * The dynamic portion of the hook name, `$this->id`, refers to the setting ID. 796 * 797 * @since 3.4.0 798 * 799 * @param mixed $value The setting value. 800 * @param WP_Customize_Setting $setting WP_Customize_Setting instance. 801 */ 802 $value = apply_filters( "customize_sanitize_js_{$this->id}", $this->value(), $this ); 803 804 if ( is_string( $value ) ) { 805 return html_entity_decode( $value, ENT_QUOTES, 'UTF-8' ); 806 } 807 808 return $value; 809 } 810 811 /** 812 * Retrieves the data to export to the client via JSON. 813 * 814 * @since 4.6.0 815 * 816 * @return array Array of parameters passed to JavaScript. 817 */ 818 public function json() { 819 return array( 820 'value' => $this->js_value(), 821 'transport' => $this->transport, 822 'dirty' => $this->dirty, 823 'type' => $this->type, 824 ); 825 } 826 827 /** 828 * Validate user capabilities whether the theme supports the setting. 829 * 830 * @since 3.4.0 831 * 832 * @return bool False if theme doesn't support the setting or user can't change setting, otherwise true. 833 */ 834 final public function check_capabilities() { 835 if ( $this->capability && ! current_user_can( $this->capability ) ) { 836 return false; 837 } 838 839 if ( $this->theme_supports && ! current_theme_supports( ...(array) $this->theme_supports ) ) { 840 return false; 841 } 842 843 return true; 844 } 845 846 /** 847 * Multidimensional helper function. 848 * 849 * @since 3.4.0 850 * 851 * @param array $root 852 * @param array $keys 853 * @param bool $create Default false. 854 * @return array|void Keys are 'root', 'node', and 'key'. 855 */ 856 final protected function multidimensional( &$root, $keys, $create = false ) { 857 if ( $create && empty( $root ) ) { 858 $root = array(); 859 } 860 861 if ( ! isset( $root ) || empty( $keys ) ) { 862 return; 863 } 864 865 $last = array_pop( $keys ); 866 $node = &$root; 867 868 foreach ( $keys as $key ) { 869 if ( $create && ! isset( $node[ $key ] ) ) { 870 $node[ $key ] = array(); 871 } 872 873 if ( ! is_array( $node ) || ! isset( $node[ $key ] ) ) { 874 return; 875 } 876 877 $node = &$node[ $key ]; 878 } 879 880 if ( $create ) { 881 if ( ! is_array( $node ) ) { 882 // Account for an array overriding a string or object value. 883 $node = array(); 884 } 885 if ( ! isset( $node[ $last ] ) ) { 886 $node[ $last ] = array(); 887 } 888 } 889 890 if ( ! isset( $node[ $last ] ) ) { 891 return; 892 } 893 894 return array( 895 'root' => &$root, 896 'node' => &$node, 897 'key' => $last, 898 ); 899 } 900 901 /** 902 * Will attempt to replace a specific value in a multidimensional array. 903 * 904 * @since 3.4.0 905 * 906 * @param array $root 907 * @param array $keys 908 * @param mixed $value The value to update. 909 * @return mixed 910 */ 911 final protected function multidimensional_replace( $root, $keys, $value ) { 912 if ( ! isset( $value ) ) { 913 return $root; 914 } elseif ( empty( $keys ) ) { // If there are no keys, we're replacing the root. 915 return $value; 916 } 917 918 $result = $this->multidimensional( $root, $keys, true ); 919 920 if ( isset( $result ) ) { 921 $result['node'][ $result['key'] ] = $value; 922 } 923 924 return $root; 925 } 926 927 /** 928 * Will attempt to fetch a specific value from a multidimensional array. 929 * 930 * @since 3.4.0 931 * 932 * @param array $root 933 * @param array $keys 934 * @param mixed $default_value A default value which is used as a fallback. Default null. 935 * @return mixed The requested value or the default value. 936 */ 937 final protected function multidimensional_get( $root, $keys, $default_value = null ) { 938 if ( empty( $keys ) ) { // If there are no keys, test the root. 939 return isset( $root ) ? $root : $default_value; 940 } 941 942 $result = $this->multidimensional( $root, $keys ); 943 return isset( $result ) ? $result['node'][ $result['key'] ] : $default_value; 944 } 945 946 /** 947 * Will attempt to check if a specific value in a multidimensional array is set. 948 * 949 * @since 3.4.0 950 * 951 * @param array $root 952 * @param array $keys 953 * @return bool True if value is set, false if not. 954 */ 955 final protected function multidimensional_isset( $root, $keys ) { 956 $result = $this->multidimensional_get( $root, $keys ); 957 return isset( $result ); 958 } 959 } 960 961 /** 962 * WP_Customize_Filter_Setting class. 963 */ 964 require_once ABSPATH . WPINC . '/customize/class-wp-customize-filter-setting.php'; 965 966 /** 967 * WP_Customize_Header_Image_Setting class. 968 */ 969 require_once ABSPATH . WPINC . '/customize/class-wp-customize-header-image-setting.php'; 970 971 /** 972 * WP_Customize_Background_Image_Setting class. 973 */ 974 require_once ABSPATH . WPINC . '/customize/class-wp-customize-background-image-setting.php'; 975 976 /** 977 * WP_Customize_Nav_Menu_Item_Setting class. 978 */ 979 require_once ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-item-setting.php'; 980 981 /** 982 * WP_Customize_Nav_Menu_Setting class. 983 */ 984 require_once ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-setting.php';
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |