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