Completed
Push — master ( a7cd2a...eabd6c )
by Stephen
38:42
created

WP_Customize_Setting::__construct()   D

Complexity

Conditions 10
Paths 72

Size

Total Lines 38
Code Lines 20

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 38
rs 4.8196
cc 10
eloc 20
nc 72
nop 3

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
 */
19
class WP_Customize_Setting {
20
	/**
21
	 * @access public
22
	 * @var WP_Customize_Manager
23
	 */
24
	public $manager;
25
26
	/**
27
	 * Unique string identifier for the setting.
28
	 *
29
	 * @access public
30
	 * @var string
31
	 */
32
	public $id;
33
34
	/**
35
	 * @access public
36
	 * @var string
37
	 */
38
	public $type = 'theme_mod';
39
40
	/**
41
	 * Capability required to edit this setting.
42
	 *
43
	 * @var string
44
	 */
45
	public $capability = 'edit_theme_options';
46
47
	/**
48
	 * Feature a theme is required to support to enable this setting.
49
	 *
50
	 * @access public
51
	 * @var string
52
	 */
53
	public $theme_supports  = '';
54
	public $default         = '';
55
	public $transport       = 'refresh';
56
57
	/**
58
	 * Server-side sanitization callback for the setting's value.
59
	 *
60
	 * @var callback
61
	 */
62
	public $sanitize_callback    = '';
63
	public $sanitize_js_callback = '';
64
65
	/**
66
	 * Whether or not the setting is initially dirty when created.
67
	 *
68
	 * This is used to ensure that a setting will be sent from the pane to the
69
	 * preview when loading the Customizer. Normally a setting only is synced to
70
	 * the preview if it has been changed. This allows the setting to be sent
71
	 * from the start.
72
	 *
73
	 * @since 4.2.0
74
	 * @access public
75
	 * @var bool
76
	 */
77
	public $dirty = false;
78
79
	/**
80
	 * @var array
81
	 */
82
	protected $id_data = array();
83
84
	/**
85
	 * Whether or not preview() was called.
86
	 *
87
	 * @since 4.4.0
88
	 * @access protected
89
	 * @var bool
90
	 */
91
	protected $is_previewed = false;
92
93
	/**
94
	 * Cache of multidimensional values to improve performance.
95
	 *
96
	 * @since 4.4.0
97
	 * @access protected
98
	 * @var array
99
	 * @static
100
	 */
101
	protected static $aggregated_multidimensionals = array();
102
103
	/**
104
	 * Whether the multidimensional setting is aggregated.
105
	 *
106
	 * @since 4.4.0
107
	 * @access protected
108
	 * @var bool
109
	 */
110
	protected $is_multidimensional_aggregated = false;
111
112
	/**
113
	 * Constructor.
114
	 *
115
	 * Any supplied $args override class property defaults.
116
	 *
117
	 * @since 3.4.0
118
	 *
119
	 * @param WP_Customize_Manager $manager
120
	 * @param string               $id      An specific ID of the setting. Can be a
121
	 *                                      theme mod or option name.
122
	 * @param array                $args    Setting arguments.
123
	 */
124
	public function __construct( $manager, $id, $args = array() ) {
125
		$keys = array_keys( get_object_vars( $this ) );
126
		foreach ( $keys as $key ) {
127
			if ( isset( $args[ $key ] ) ) {
128
				$this->$key = $args[ $key ];
129
			}
130
		}
131
132
		$this->manager = $manager;
133
		$this->id = $id;
134
135
		// Parse the ID for array keys.
136
		$this->id_data['keys'] = preg_split( '/\[/', str_replace( ']', '', $this->id ) );
137
		$this->id_data['base'] = array_shift( $this->id_data['keys'] );
138
139
		// Rebuild the ID.
140
		$this->id = $this->id_data[ 'base' ];
141
		if ( ! empty( $this->id_data[ 'keys' ] ) ) {
142
			$this->id .= '[' . implode( '][', $this->id_data['keys'] ) . ']';
143
		}
144
145
		if ( $this->sanitize_callback ) {
146
			add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback, 10, 2 );
147
		}
148
		if ( $this->sanitize_js_callback ) {
149
			add_filter( "customize_sanitize_js_{$this->id}", $this->sanitize_js_callback, 10, 2 );
150
		}
151
152
		if ( 'option' === $this->type || 'theme_mod' === $this->type ) {
153
			// Other setting types can opt-in to aggregate multidimensional explicitly.
154
			$this->aggregate_multidimensional();
155
156
			// Allow option settings to indicate whether they should be autoloaded.
157
			if ( 'option' === $this->type && isset( $args['autoload'] ) ) {
158
				self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['autoload'] = $args['autoload'];
159
			}
160
		}
161
	}
162
163
	/**
164
	 * Get parsed ID data for multidimensional setting.
165
	 *
166
	 * @since 4.4.0
167
	 * @access public
168
	 *
169
	 * @return array {
170
	 *     ID data for multidimensional setting.
171
	 *
172
	 *     @type string $base ID base
173
	 *     @type array  $keys Keys for multidimensional array.
174
	 * }
175
	 */
176
	final public function id_data() {
177
		return $this->id_data;
178
	}
179
180
	/**
181
	 * Set up the setting for aggregated multidimensional values.
182
	 *
183
	 * When a multidimensional setting gets aggregated, all of its preview and update
184
	 * calls get combined into one call, greatly improving performance.
185
	 *
186
	 * @since 4.4.0
187
	 * @access protected
188
	 */
189
	protected function aggregate_multidimensional() {
190
		$id_base = $this->id_data['base'];
191
		if ( ! isset( self::$aggregated_multidimensionals[ $this->type ] ) ) {
192
			self::$aggregated_multidimensionals[ $this->type ] = array();
193
		}
194
		if ( ! isset( self::$aggregated_multidimensionals[ $this->type ][ $id_base ] ) ) {
195
			self::$aggregated_multidimensionals[ $this->type ][ $id_base ] = array(
196
				'previewed_instances'       => array(), // Calling preview() will add the $setting to the array.
197
				'preview_applied_instances' => array(), // Flags for which settings have had their values applied.
198
				'root_value'                => $this->get_root_value( array() ), // Root value for initial state, manipulated by preview and update calls.
199
			);
200
		}
201
202
		if ( ! empty( $this->id_data['keys'] ) ) {
203
			// Note the preview-applied flag is cleared at priority 9 to ensure it is cleared before a deferred-preview runs.
204
			add_action( "customize_post_value_set_{$this->id}", array( $this, '_clear_aggregated_multidimensional_preview_applied_flag' ), 9 );
205
			$this->is_multidimensional_aggregated = true;
206
		}
207
	}
208
209
	/**
210
	 * The ID for the current site when the preview() method was called.
211
	 *
212
	 * @since 4.2.0
213
	 * @access protected
214
	 * @var int
215
	 */
216
	protected $_previewed_blog_id;
217
218
	/**
219
	 * Return true if the current site is not the same as the previewed site.
220
	 *
221
	 * @since 4.2.0
222
	 * @access public
223
	 *
224
	 * @return bool If preview() has been called.
225
	 */
226
	public function is_current_blog_previewed() {
227
		if ( ! isset( $this->_previewed_blog_id ) ) {
228
			return false;
229
		}
230
		return ( get_current_blog_id() === $this->_previewed_blog_id );
231
	}
232
233
	/**
234
	 * Original non-previewed value stored by the preview method.
235
	 *
236
	 * @see WP_Customize_Setting::preview()
237
	 * @since 4.1.1
238
	 * @var mixed
239
	 */
240
	protected $_original_value;
241
242
	/**
243
	 * Add filters to supply the setting's value when accessed.
244
	 *
245
	 * If the setting already has a pre-existing value and there is no incoming
246
	 * post value for the setting, then this method will short-circuit since
247
	 * there is no change to preview.
248
	 *
249
	 * @since 3.4.0
250
	 * @since 4.4.0 Added boolean return value.
251
	 * @access public
252
	 *
253
	 * @return bool False when preview short-circuits due no change needing to be previewed.
254
	 */
255
	public function preview() {
256
		if ( ! isset( $this->_previewed_blog_id ) ) {
257
			$this->_previewed_blog_id = get_current_blog_id();
0 ignored issues
show
Documentation Bug introduced by
It seems like get_current_blog_id() can also be of type double. However, the property $_previewed_blog_id is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
258
		}
259
260
		// Prevent re-previewing an already-previewed setting.
261
		if ( $this->is_previewed ) {
262
			return true;
263
		}
264
265
		$id_base = $this->id_data['base'];
266
		$is_multidimensional = ! empty( $this->id_data['keys'] );
267
		$multidimensional_filter = array( $this, '_multidimensional_preview_filter' );
268
269
		/*
270
		 * Check if the setting has a pre-existing value (an isset check),
271
		 * and if doesn't have any incoming post value. If both checks are true,
272
		 * then the preview short-circuits because there is nothing that needs
273
		 * to be previewed.
274
		 */
275
		$undefined = new stdClass();
276
		$needs_preview = ( $undefined !== $this->post_value( $undefined ) );
277
		$value = null;
0 ignored issues
show
Unused Code introduced by
$value is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
278
279
		// Since no post value was defined, check if we have an initial value set.
280
		if ( ! $needs_preview ) {
281
			if ( $this->is_multidimensional_aggregated ) {
282
				$root = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value'];
283
				$value = $this->multidimensional_get( $root, $this->id_data['keys'], $undefined );
284
			} else {
285
				$default = $this->default;
286
				$this->default = $undefined; // Temporarily set default to undefined so we can detect if existing value is set.
0 ignored issues
show
Documentation Bug introduced by
It seems like $undefined of type object<stdClass> is incompatible with the declared type string of property $default.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
287
				$value = $this->value();
288
				$this->default = $default;
289
			}
290
			$needs_preview = ( $undefined === $value ); // Because the default needs to be supplied.
291
		}
292
293
		// If the setting does not need previewing now, defer to when it has a value to preview.
294
		if ( ! $needs_preview ) {
295
			if ( ! has_action( "customize_post_value_set_{$this->id}", array( $this, 'preview' ) ) ) {
296
				add_action( "customize_post_value_set_{$this->id}", array( $this, 'preview' ) );
297
			}
298
			return false;
299
		}
300
301
		switch ( $this->type ) {
302 View Code Duplication
			case 'theme_mod' :
303
				if ( ! $is_multidimensional ) {
304
					add_filter( "theme_mod_{$id_base}", array( $this, '_preview_filter' ) );
305
				} else {
306
					if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) {
307
						// Only add this filter once for this ID base.
308
						add_filter( "theme_mod_{$id_base}", $multidimensional_filter );
309
					}
310
					self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'][ $this->id ] = $this;
311
				}
312
				break;
313 View Code Duplication
			case 'option' :
314
				if ( ! $is_multidimensional ) {
315
					add_filter( "pre_option_{$id_base}", array( $this, '_preview_filter' ) );
316
				} else {
317
					if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) {
318
						// Only add these filters once for this ID base.
319
						add_filter( "option_{$id_base}", $multidimensional_filter );
320
						add_filter( "default_option_{$id_base}", $multidimensional_filter );
321
					}
322
					self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'][ $this->id ] = $this;
323
				}
324
				break;
325
			default :
326
327
				/**
328
				 * Fires when the {@see WP_Customize_Setting::preview()} method is called for settings
329
				 * not handled as theme_mods or options.
330
				 *
331
				 * The dynamic portion of the hook name, `$this->id`, refers to the setting ID.
332
				 *
333
				 * @since 3.4.0
334
				 *
335
				 * @param WP_Customize_Setting $this {@see WP_Customize_Setting} instance.
336
				 */
337
				do_action( "customize_preview_{$this->id}", $this );
338
339
				/**
340
				 * Fires when the {@see WP_Customize_Setting::preview()} method is called for settings
341
				 * not handled as theme_mods or options.
342
				 *
343
				 * The dynamic portion of the hook name, `$this->type`, refers to the setting type.
344
				 *
345
				 * @since 4.1.0
346
				 *
347
				 * @param WP_Customize_Setting $this {@see WP_Customize_Setting} instance.
348
				 */
349
				do_action( "customize_preview_{$this->type}", $this );
350
		}
351
352
		$this->is_previewed = true;
353
354
		return true;
355
	}
356
357
	/**
358
	 * Clear out the previewed-applied flag for a multidimensional-aggregated value whenever its post value is updated.
359
	 *
360
	 * This ensures that the new value will get sanitized and used the next time
361
	 * that `WP_Customize_Setting::_multidimensional_preview_filter()`
362
	 * is called for this setting.
363
	 *
364
	 * @since 4.4.0
365
	 * @access private
366
	 * @see WP_Customize_Manager::set_post_value()
367
	 * @see WP_Customize_Setting::_multidimensional_preview_filter()
368
	 */
369
	final public function _clear_aggregated_multidimensional_preview_applied_flag() {
370
		unset( self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['preview_applied_instances'][ $this->id ] );
371
	}
372
373
	/**
374
	 * Callback function to filter non-multidimensional theme mods and options.
375
	 *
376
	 * If switch_to_blog() was called after the preview() method, and the current
377
	 * site is now not the same site, then this method does a no-op and returns
378
	 * the original value.
379
	 *
380
	 * @since 3.4.0
381
	 *
382
	 * @param mixed $original Old value.
383
	 * @return mixed New or old value.
384
	 */
385
	public function _preview_filter( $original ) {
386
		if ( ! $this->is_current_blog_previewed() ) {
387
			return $original;
388
		}
389
390
		$undefined = new stdClass(); // Symbol hack.
391
		$post_value = $this->post_value( $undefined );
392
		if ( $undefined !== $post_value ) {
393
			$value = $post_value;
394
		} else {
395
			/*
396
			 * Note that we don't use $original here because preview() will
397
			 * not add the filter in the first place if it has an initial value
398
			 * and there is no post value.
399
			 */
400
			$value = $this->default;
401
		}
402
		return $value;
403
	}
404
405
	/**
406
	 * Callback function to filter multidimensional theme mods and options.
407
	 *
408
	 * For all multidimensional settings of a given type, the preview filter for
409
	 * the first setting previewed will be used to apply the values for the others.
410
	 *
411
	 * @since 4.4.0
412
	 * @access private
413
	 *
414
	 * @see WP_Customize_Setting::$aggregated_multidimensionals
415
	 * @param mixed $original Original root value.
416
	 * @return mixed New or old value.
417
	 */
418
	final public function _multidimensional_preview_filter( $original ) {
419
		if ( ! $this->is_current_blog_previewed() ) {
420
			return $original;
421
		}
422
423
		$id_base = $this->id_data['base'];
424
425
		// If no settings have been previewed yet (which should not be the case, since $this is), just pass through the original value.
426
		if ( empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] ) ) {
427
			return $original;
428
		}
429
430
		foreach ( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['previewed_instances'] as $previewed_setting ) {
431
			// Skip applying previewed value for any settings that have already been applied.
432
			if ( ! empty( self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['preview_applied_instances'][ $previewed_setting->id ] ) ) {
433
				continue;
434
			}
435
436
			// Do the replacements of the posted/default sub value into the root value.
437
			$value = $previewed_setting->post_value( $previewed_setting->default );
438
			$root = self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['root_value'];
439
			$root = $previewed_setting->multidimensional_replace( $root, $previewed_setting->id_data['keys'], $value );
440
			self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['root_value'] = $root;
441
442
			// Mark this setting having been applied so that it will be skipped when the filter is called again.
443
			self::$aggregated_multidimensionals[ $previewed_setting->type ][ $id_base ]['preview_applied_instances'][ $previewed_setting->id ] = true;
444
		}
445
446
		return self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value'];
447
	}
448
449
	/**
450
	 * Check user capabilities and theme supports, and then save
451
	 * the value of the setting.
452
	 *
453
	 * @since 3.4.0
454
	 *
455
	 * @return false|void False if cap check fails or value isn't set.
456
	 */
457
	final public function save() {
458
		$value = $this->post_value();
459
460
		if ( ! $this->check_capabilities() || ! isset( $value ) )
461
			return false;
462
463
		/**
464
		 * Fires when the WP_Customize_Setting::save() method is called.
465
		 *
466
		 * The dynamic portion of the hook name, `$this->id_data['base']` refers to
467
		 * the base slug of the setting name.
468
		 *
469
		 * @since 3.4.0
470
		 *
471
		 * @param WP_Customize_Setting $this {@see WP_Customize_Setting} instance.
472
		 */
473
		do_action( 'customize_save_' . $this->id_data[ 'base' ], $this );
474
475
		$this->update( $value );
476
	}
477
478
	/**
479
	 * Fetch and sanitize the $_POST value for the setting.
480
	 *
481
	 * @since 3.4.0
482
	 *
483
	 * @param mixed $default A default value which is used as a fallback. Default is null.
484
	 * @return mixed The default value on failure, otherwise the sanitized value.
485
	 */
486
	final public function post_value( $default = null ) {
487
		return $this->manager->post_value( $this, $default );
488
	}
489
490
	/**
491
	 * Sanitize an input.
492
	 *
493
	 * @since 3.4.0
494
	 *
495
	 * @param string|array $value The value to sanitize.
496
	 * @return string|array|null Null if an input isn't valid, otherwise the sanitized value.
497
	 */
498
	public function sanitize( $value ) {
499
500
		/**
501
		 * Filter a Customize setting value in un-slashed form.
502
		 *
503
		 * @since 3.4.0
504
		 *
505
		 * @param mixed                $value Value of the setting.
506
		 * @param WP_Customize_Setting $this  WP_Customize_Setting instance.
507
		 */
508
		return apply_filters( "customize_sanitize_{$this->id}", $value, $this );
509
	}
510
511
	/**
512
	 * Get the root value for a setting, especially for multidimensional ones.
513
	 *
514
	 * @since 4.4.0
515
	 * @access protected
516
	 *
517
	 * @param mixed $default Value to return if root does not exist.
518
	 * @return mixed
519
	 */
520
	protected function get_root_value( $default = null ) {
521
		$id_base = $this->id_data['base'];
522
		if ( 'option' === $this->type ) {
523
			return get_option( $id_base, $default );
524
		} else if ( 'theme_mod' ) {
525
			return get_theme_mod( $id_base, $default );
526
		} else {
527
			/*
528
			 * Any WP_Customize_Setting subclass implementing aggregate multidimensional
529
			 * will need to override this method to obtain the data from the appropriate
530
			 * location.
531
			 */
532
			return $default;
533
		}
534
	}
535
536
	/**
537
	 * Set the root value for a setting, especially for multidimensional ones.
538
	 *
539
	 * @since 4.4.0
540
	 * @access protected
541
	 *
542
	 * @param mixed $value Value to set as root of multidimensional setting.
543
	 * @return bool Whether the multidimensional root was updated successfully.
544
	 */
545
	protected function set_root_value( $value ) {
546
		$id_base = $this->id_data['base'];
547
		if ( 'option' === $this->type ) {
548
			$autoload = true;
549
			if ( isset( self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['autoload'] ) ) {
550
				$autoload = self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['autoload'];
551
			}
552
			return update_option( $id_base, $value, $autoload );
553
		} else if ( 'theme_mod' ) {
554
			set_theme_mod( $id_base, $value );
555
			return true;
556
		} else {
557
			/*
558
			 * Any WP_Customize_Setting subclass implementing aggregate multidimensional
559
			 * will need to override this method to obtain the data from the appropriate
560
			 * location.
561
			 */
562
			return false;
563
		}
564
	}
565
566
	/**
567
	 * Save the value of the setting, using the related API.
568
	 *
569
	 * @since 3.4.0
570
	 *
571
	 * @param mixed $value The value to update.
572
	 * @return bool The result of saving the value.
573
	 */
574
	protected function update( $value ) {
575
		$id_base = $this->id_data['base'];
576
		if ( 'option' === $this->type || 'theme_mod' === $this->type ) {
577
			if ( ! $this->is_multidimensional_aggregated ) {
578
				return $this->set_root_value( $value );
579
			} else {
580
				$root = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value'];
581
				$root = $this->multidimensional_replace( $root, $this->id_data['keys'], $value );
582
				self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value'] = $root;
583
				return $this->set_root_value( $root );
584
			}
585
		} else {
586
			/**
587
			 * Fires when the {@see WP_Customize_Setting::update()} method is called for settings
588
			 * not handled as theme_mods or options.
589
			 *
590
			 * The dynamic portion of the hook name, `$this->type`, refers to the type of setting.
591
			 *
592
			 * @since 3.4.0
593
			 *
594
			 * @param mixed                $value Value of the setting.
595
			 * @param WP_Customize_Setting $this  WP_Customize_Setting instance.
596
			 */
597
			do_action( "customize_update_{$this->type}", $value, $this );
598
599
			return has_action( "customize_update_{$this->type}" );
600
		}
601
	}
602
603
	/**
604
	 * Deprecated method.
605
	 *
606
	 * @since 3.4.0
607
	 * @deprecated 4.4.0 Deprecated in favor of update() method.
608
	 */
609
	protected function _update_theme_mod() {
610
		_deprecated_function( __METHOD__, '4.4.0', __CLASS__ . '::update()' );
611
	}
612
613
	/**
614
	 * Deprecated method.
615
	 *
616
	 * @since 3.4.0
617
	 * @deprecated 4.4.0 Deprecated in favor of update() method.
618
	 */
619
	protected function _update_option() {
620
		_deprecated_function( __METHOD__, '4.4.0', __CLASS__ . '::update()' );
621
	}
622
623
	/**
624
	 * Fetch the value of the setting.
625
	 *
626
	 * @since 3.4.0
627
	 *
628
	 * @return mixed The value.
629
	 */
630
	public function value() {
631
		$id_base = $this->id_data['base'];
632
		$is_core_type = ( 'option' === $this->type || 'theme_mod' === $this->type );
633
634
		if ( ! $is_core_type && ! $this->is_multidimensional_aggregated ) {
635
			$value = $this->get_root_value( $this->default );
636
637
			/**
638
			 * Filter a Customize setting value not handled as a theme_mod or option.
639
			 *
640
			 * The dynamic portion of the hook name, `$this->id_date['base']`, refers to
641
			 * the base slug of the setting name.
642
			 *
643
			 * For settings handled as theme_mods or options, see those corresponding
644
			 * functions for available hooks.
645
			 *
646
			 * @since 3.4.0
647
			 *
648
			 * @param mixed $default The setting default value. Default empty.
649
			 */
650
			$value = apply_filters( "customize_value_{$id_base}", $value );
651
		} else if ( $this->is_multidimensional_aggregated ) {
652
			$root_value = self::$aggregated_multidimensionals[ $this->type ][ $id_base ]['root_value'];
653
			$value = $this->multidimensional_get( $root_value, $this->id_data['keys'], $this->default );
654
		} else {
655
			$value = $this->get_root_value( $this->default );
656
		}
657
		return $value;
658
	}
659
660
	/**
661
	 * Sanitize the setting's value for use in JavaScript.
662
	 *
663
	 * @since 3.4.0
664
	 *
665
	 * @return mixed The requested escaped value.
666
	 */
667
	public function js_value() {
668
669
		/**
670
		 * Filter a Customize setting value for use in JavaScript.
671
		 *
672
		 * The dynamic portion of the hook name, `$this->id`, refers to the setting ID.
673
		 *
674
		 * @since 3.4.0
675
		 *
676
		 * @param mixed                $value The setting value.
677
		 * @param WP_Customize_Setting $this  {@see WP_Customize_Setting} instance.
678
		 */
679
		$value = apply_filters( "customize_sanitize_js_{$this->id}", $this->value(), $this );
680
681
		if ( is_string( $value ) )
682
			return html_entity_decode( $value, ENT_QUOTES, 'UTF-8');
683
684
		return $value;
685
	}
686
687
	/**
688
	 * Validate user capabilities whether the theme supports the setting.
689
	 *
690
	 * @since 3.4.0
691
	 *
692
	 * @return bool False if theme doesn't support the setting or user can't change setting, otherwise true.
693
	 */
694 View Code Duplication
	final public function check_capabilities() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
695
		if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) )
696
			return false;
697
698
		if ( $this->theme_supports && ! call_user_func_array( 'current_theme_supports', (array) $this->theme_supports ) )
699
			return false;
700
701
		return true;
702
	}
703
704
	/**
705
	 * Multidimensional helper function.
706
	 *
707
	 * @since 3.4.0
708
	 *
709
	 * @param $root
710
	 * @param $keys
711
	 * @param bool $create Default is false.
712
	 * @return array|void Keys are 'root', 'node', and 'key'.
713
	 */
714
	final protected function multidimensional( &$root, $keys, $create = false ) {
715
		if ( $create && empty( $root ) )
716
			$root = array();
717
718
		if ( ! isset( $root ) || empty( $keys ) )
719
			return;
720
721
		$last = array_pop( $keys );
722
		$node = &$root;
723
724
		foreach ( $keys as $key ) {
725
			if ( $create && ! isset( $node[ $key ] ) )
726
				$node[ $key ] = array();
727
728
			if ( ! is_array( $node ) || ! isset( $node[ $key ] ) )
729
				return;
730
731
			$node = &$node[ $key ];
732
		}
733
734 View Code Duplication
		if ( $create ) {
735
			if ( ! is_array( $node ) ) {
736
				// account for an array overriding a string or object value
737
				$node = array();
738
			}
739
			if ( ! isset( $node[ $last ] ) ) {
740
				$node[ $last ] = array();
741
			}
742
		}
743
744
		if ( ! isset( $node[ $last ] ) )
745
			return;
746
747
		return array(
748
			'root' => &$root,
749
			'node' => &$node,
750
			'key'  => $last,
751
		);
752
	}
753
754
	/**
755
	 * Will attempt to replace a specific value in a multidimensional array.
756
	 *
757
	 * @since 3.4.0
758
	 *
759
	 * @param $root
760
	 * @param $keys
761
	 * @param mixed $value The value to update.
762
	 * @return mixed
763
	 */
764
	final protected function multidimensional_replace( $root, $keys, $value ) {
765
		if ( ! isset( $value ) )
766
			return $root;
767
		elseif ( empty( $keys ) ) // If there are no keys, we're replacing the root.
768
			return $value;
769
770
		$result = $this->multidimensional( $root, $keys, true );
771
772
		if ( isset( $result ) )
773
			$result['node'][ $result['key'] ] = $value;
774
775
		return $root;
776
	}
777
778
	/**
779
	 * Will attempt to fetch a specific value from a multidimensional array.
780
	 *
781
	 * @since 3.4.0
782
	 *
783
	 * @param $root
784
	 * @param $keys
785
	 * @param mixed $default A default value which is used as a fallback. Default is null.
786
	 * @return mixed The requested value or the default value.
787
	 */
788
	final protected function multidimensional_get( $root, $keys, $default = null ) {
789
		if ( empty( $keys ) ) // If there are no keys, test the root.
790
			return isset( $root ) ? $root : $default;
791
792
		$result = $this->multidimensional( $root, $keys );
793
		return isset( $result ) ? $result['node'][ $result['key'] ] : $default;
794
	}
795
796
	/**
797
	 * Will attempt to check if a specific value in a multidimensional array is set.
798
	 *
799
	 * @since 3.4.0
800
	 *
801
	 * @param $root
802
	 * @param $keys
803
	 * @return bool True if value is set, false if not.
804
	 */
805
	final protected function multidimensional_isset( $root, $keys ) {
806
		$result = $this->multidimensional_get( $root, $keys );
807
		return isset( $result );
808
	}
809
}
810
811
/** WP_Customize_Filter_Setting class */
812
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-filter-setting.php' );
813
814
/** WP_Customize_Header_Image_Setting class */
815
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-header-image-setting.php' );
816
817
/** WP_Customize_Background_Image_Setting class */
818
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-background-image-setting.php' );
819
820
/** WP_Customize_Nav_Menu_Item_Setting class */
821
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-item-setting.php' );
822
823
/** WP_Customize_Nav_Menu_Setting class */
824
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-setting.php' );
825