~canonical-sysadmins/wordpress/4.7.2

« back to all changes in this revision

Viewing changes to wp-includes/class-wp-customize-setting.php

  • Committer: Jacek Nykis
  • Date: 2015-01-05 16:17:05 UTC
  • Revision ID: jacek.nykis@canonical.com-20150105161705-w544l1h5mcg7u4w9
Initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * Customize Setting Class.
 
4
 *
 
5
 * Handles saving and sanitizing of settings.
 
6
 *
 
7
 * @package WordPress
 
8
 * @subpackage Customize
 
9
 * @since 3.4.0
 
10
 */
 
11
class WP_Customize_Setting {
 
12
        /**
 
13
         * @access public
 
14
         * @var WP_Customize_Manager
 
15
         */
 
16
        public $manager;
 
17
 
 
18
        /**
 
19
         * @access public
 
20
         * @var string
 
21
         */
 
22
        public $id;
 
23
 
 
24
        /**
 
25
         * @access public
 
26
         * @var string
 
27
         */
 
28
        public $type = 'theme_mod';
 
29
 
 
30
        /**
 
31
         * Capability required to edit this setting.
 
32
         *
 
33
         * @var string
 
34
         */
 
35
        public $capability = 'edit_theme_options';
 
36
 
 
37
        /**
 
38
         * Feature a theme is required to support to enable this setting.
 
39
         *
 
40
         * @access public
 
41
         * @var string
 
42
         */
 
43
        public $theme_supports  = '';
 
44
        public $default         = '';
 
45
        public $transport       = 'refresh';
 
46
 
 
47
        /**
 
48
         * Server-side sanitization callback for the setting's value.
 
49
         *
 
50
         * @var callback
 
51
         */
 
52
        public $sanitize_callback    = '';
 
53
        public $sanitize_js_callback = '';
 
54
 
 
55
        protected $id_data = array();
 
56
 
 
57
        /**
 
58
         * Cached and sanitized $_POST value for the setting.
 
59
         *
 
60
         * @access private
 
61
         * @var mixed
 
62
         */
 
63
        private $_post_value;
 
64
 
 
65
        /**
 
66
         * Constructor.
 
67
         *
 
68
         * Any supplied $args override class property defaults.
 
69
         *
 
70
         * @since 3.4.0
 
71
         *
 
72
         * @param WP_Customize_Manager $manager
 
73
         * @param string               $id      An specific ID of the setting. Can be a
 
74
         *                                      theme mod or option name.
 
75
         * @param array                $args    Setting arguments.
 
76
         * @return WP_Customize_Setting $setting
 
77
         */
 
78
        public function __construct( $manager, $id, $args = array() ) {
 
79
                $keys = array_keys( get_object_vars( $this ) );
 
80
                foreach ( $keys as $key ) {
 
81
                        if ( isset( $args[ $key ] ) )
 
82
                                $this->$key = $args[ $key ];
 
83
                }
 
84
 
 
85
                $this->manager = $manager;
 
86
                $this->id = $id;
 
87
 
 
88
                // Parse the ID for array keys.
 
89
                $this->id_data[ 'keys' ] = preg_split( '/\[/', str_replace( ']', '', $this->id ) );
 
90
                $this->id_data[ 'base' ] = array_shift( $this->id_data[ 'keys' ] );
 
91
 
 
92
                // Rebuild the ID.
 
93
                $this->id = $this->id_data[ 'base' ];
 
94
                if ( ! empty( $this->id_data[ 'keys' ] ) )
 
95
                        $this->id .= '[' . implode( '][', $this->id_data[ 'keys' ] ) . ']';
 
96
 
 
97
                if ( $this->sanitize_callback )
 
98
                        add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback, 10, 2 );
 
99
 
 
100
                if ( $this->sanitize_js_callback )
 
101
                        add_filter( "customize_sanitize_js_{$this->id}", $this->sanitize_js_callback, 10, 2 );
 
102
 
 
103
                return $this;
 
104
        }
 
105
 
 
106
        /**
 
107
         * Handle previewing the setting.
 
108
         *
 
109
         * @since 3.4.0
 
110
         */
 
111
        public function preview() {
 
112
                switch( $this->type ) {
 
113
                        case 'theme_mod' :
 
114
                                add_filter( 'theme_mod_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
 
115
                                break;
 
116
                        case 'option' :
 
117
                                if ( empty( $this->id_data[ 'keys' ] ) )
 
118
                                        add_filter( 'pre_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
 
119
                                else {
 
120
                                        add_filter( 'option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
 
121
                                        add_filter( 'default_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
 
122
                                }
 
123
                                break;
 
124
                        default :
 
125
 
 
126
                                /**
 
127
                                 * Fires when the WP_Customize_Setting::preview() method is called for settings
 
128
                                 * not handled as theme_mods or options.
 
129
                                 *
 
130
                                 * The dynamic portion of the hook name, $this->id, refers to the setting ID.
 
131
                                 *
 
132
                                 * @since 3.4.0
 
133
                                 *
 
134
                                 * @param WP_Customize_Setting $this WP_Customize_Setting instance.
 
135
                                 */
 
136
                                do_action( 'customize_preview_' . $this->id, $this );
 
137
                }
 
138
        }
 
139
 
 
140
        /**
 
141
         * Callback function to filter the theme mods and options.
 
142
         *
 
143
         * @since 3.4.0
 
144
         * @uses WP_Customize_Setting::multidimensional_replace()
 
145
         *
 
146
         * @param mixed $original Old value.
 
147
         * @return mixed New or old value.
 
148
         */
 
149
        public function _preview_filter( $original ) {
 
150
                return $this->multidimensional_replace( $original, $this->id_data[ 'keys' ], $this->post_value() );
 
151
        }
 
152
 
 
153
        /**
 
154
         * Check user capabilities and theme supports, and then save
 
155
         * the value of the setting.
 
156
         *
 
157
         * @since 3.4.0
 
158
         *
 
159
         * @return bool False if cap check fails or value isn't set.
 
160
         */
 
161
        public final function save() {
 
162
                $value = $this->post_value();
 
163
 
 
164
                if ( ! $this->check_capabilities() || ! isset( $value ) )
 
165
                        return false;
 
166
 
 
167
                /**
 
168
                 * Fires when the WP_Customize_Setting::save() method is called.
 
169
                 *
 
170
                 * The dynamic portion of the hook name, $this->id_data['base'] refers to
 
171
                 * the base slug of the setting name.
 
172
                 *
 
173
                 * @since 3.4.0
 
174
                 *
 
175
                 * @param WP_Customize_Setting $this WP_Customize_Setting instance.
 
176
                 */
 
177
                do_action( 'customize_save_' . $this->id_data[ 'base' ], $this );
 
178
 
 
179
                $this->update( $value );
 
180
        }
 
181
 
 
182
        /**
 
183
         * Fetch and sanitize the $_POST value for the setting.
 
184
         *
 
185
         * @since 3.4.0
 
186
         *
 
187
         * @param mixed $default A default value which is used as a fallback. Default is null.
 
188
         * @return mixed The default value on failure, otherwise the sanitized value.
 
189
         */
 
190
        public final function post_value( $default = null ) {
 
191
                // Check for a cached value
 
192
                if ( isset( $this->_post_value ) )
 
193
                        return $this->_post_value;
 
194
 
 
195
                // Call the manager for the post value
 
196
                $result = $this->manager->post_value( $this );
 
197
 
 
198
                if ( isset( $result ) )
 
199
                        return $this->_post_value = $result;
 
200
                else
 
201
                        return $default;
 
202
        }
 
203
 
 
204
        /**
 
205
         * Sanitize an input.
 
206
         *
 
207
         * @since 3.4.0
 
208
         *
 
209
         * @param mixed $value The value to sanitize.
 
210
         * @return mixed Null if an input isn't valid, otherwise the sanitized value.
 
211
         */
 
212
        public function sanitize( $value ) {
 
213
                $value = wp_unslash( $value );
 
214
 
 
215
                /**
 
216
                 * Filter a Customize setting value in un-slashed form.
 
217
                 *
 
218
                 * @since 3.4.0
 
219
                 *
 
220
                 * @param mixed                $value Value of the setting.
 
221
                 * @param WP_Customize_Setting $this  WP_Customize_Setting instance.
 
222
                 */
 
223
                return apply_filters( "customize_sanitize_{$this->id}", $value, $this );
 
224
        }
 
225
 
 
226
        /**
 
227
         * Save the value of the setting, using the related API.
 
228
         *
 
229
         * @since 3.4.0
 
230
         *
 
231
         * @param mixed $value The value to update.
 
232
         * @return mixed The result of saving the value.
 
233
         */
 
234
        protected function update( $value ) {
 
235
                switch( $this->type ) {
 
236
                        case 'theme_mod' :
 
237
                                return $this->_update_theme_mod( $value );
 
238
 
 
239
                        case 'option' :
 
240
                                return $this->_update_option( $value );
 
241
 
 
242
                        default :
 
243
 
 
244
                                /**
 
245
                                 * Fires when the WP_Customize_Setting::update() method is called for settings
 
246
                                 * not handled as theme_mods or options.
 
247
                                 *
 
248
                                 * The dynamic portion of the hook name, $this->type, refers to the type of setting.
 
249
                                 *
 
250
                                 * @since 3.4.0
 
251
                                 *
 
252
                                 * @param mixed                $value Value of the setting.
 
253
                                 * @param WP_Customize_Setting $this  WP_Customize_Setting instance.
 
254
                                 */
 
255
                                return do_action( 'customize_update_' . $this->type, $value, $this );
 
256
                }
 
257
        }
 
258
 
 
259
        /**
 
260
         * Update the theme mod from the value of the parameter.
 
261
         *
 
262
         * @since 3.4.0
 
263
         *
 
264
         * @param mixed $value The value to update.
 
265
         * @return mixed The result of saving the value.
 
266
         */
 
267
        protected function _update_theme_mod( $value ) {
 
268
                // Handle non-array theme mod.
 
269
                if ( empty( $this->id_data[ 'keys' ] ) )
 
270
                        return set_theme_mod( $this->id_data[ 'base' ], $value );
 
271
 
 
272
                // Handle array-based theme mod.
 
273
                $mods = get_theme_mod( $this->id_data[ 'base' ] );
 
274
                $mods = $this->multidimensional_replace( $mods, $this->id_data[ 'keys' ], $value );
 
275
                if ( isset( $mods ) )
 
276
                        return set_theme_mod( $this->id_data[ 'base' ], $mods );
 
277
        }
 
278
 
 
279
        /**
 
280
         * Update the option from the value of the setting.
 
281
         *
 
282
         * @since 3.4.0
 
283
         *
 
284
         * @param mixed $value The value to update.
 
285
         * @return mixed The result of saving the value.
 
286
         */
 
287
        protected function _update_option( $value ) {
 
288
                // Handle non-array option.
 
289
                if ( empty( $this->id_data[ 'keys' ] ) )
 
290
                        return update_option( $this->id_data[ 'base' ], $value );
 
291
 
 
292
                // Handle array-based options.
 
293
                $options = get_option( $this->id_data[ 'base' ] );
 
294
                $options = $this->multidimensional_replace( $options, $this->id_data[ 'keys' ], $value );
 
295
                if ( isset( $options ) )
 
296
                        return update_option( $this->id_data[ 'base' ], $options );
 
297
        }
 
298
 
 
299
        /**
 
300
         * Fetch the value of the setting.
 
301
         *
 
302
         * @since 3.4.0
 
303
         *
 
304
         * @return mixed The value.
 
305
         */
 
306
        public function value() {
 
307
                // Get the callback that corresponds to the setting type.
 
308
                switch( $this->type ) {
 
309
                        case 'theme_mod' :
 
310
                                $function = 'get_theme_mod';
 
311
                                break;
 
312
                        case 'option' :
 
313
                                $function = 'get_option';
 
314
                                break;
 
315
                        default :
 
316
 
 
317
                                /**
 
318
                                 * Filter a Customize setting value not handled as a theme_mod or option.
 
319
                                 *
 
320
                                 * The dynamic portion of the hook name, $this->id_date['base'], refers to
 
321
                                 * the base slug of the setting name.
 
322
                                 *
 
323
                                 * For settings handled as theme_mods or options, see those corresponding
 
324
                                 * functions for available hooks.
 
325
                                 *
 
326
                                 * @since 3.4.0
 
327
                                 *
 
328
                                 * @param mixed $default The setting default value. Default empty.
 
329
                                 */
 
330
                                return apply_filters( 'customize_value_' . $this->id_data[ 'base' ], $this->default );
 
331
                }
 
332
 
 
333
                // Handle non-array value
 
334
                if ( empty( $this->id_data[ 'keys' ] ) )
 
335
                        return $function( $this->id_data[ 'base' ], $this->default );
 
336
 
 
337
                // Handle array-based value
 
338
                $values = $function( $this->id_data[ 'base' ] );
 
339
                return $this->multidimensional_get( $values, $this->id_data[ 'keys' ], $this->default );
 
340
        }
 
341
 
 
342
        /**
 
343
         * Sanitize the setting's value for use in JavaScript.
 
344
         *
 
345
         * @since 3.4.0
 
346
         *
 
347
         * @return mixed The requested escaped value.
 
348
         */
 
349
        public function js_value() {
 
350
 
 
351
                /**
 
352
                 * Filter a Customize setting value for use in JavaScript.
 
353
                 *
 
354
                 * The dynamic portion of the hook name, $this->id, refers to the setting ID.
 
355
                 *
 
356
                 * @since 3.4.0
 
357
                 *
 
358
                 * @param mixed                $value The setting value.
 
359
                 * @param WP_Customize_Setting $this  WP_Customize_Setting instance.
 
360
                 */
 
361
                $value = apply_filters( "customize_sanitize_js_{$this->id}", $this->value(), $this );
 
362
 
 
363
                if ( is_string( $value ) )
 
364
                        return html_entity_decode( $value, ENT_QUOTES, 'UTF-8');
 
365
 
 
366
                return $value;
 
367
        }
 
368
 
 
369
        /**
 
370
         * Validate user capabilities whether the theme supports the setting.
 
371
         *
 
372
         * @since 3.4.0
 
373
         *
 
374
         * @return bool False if theme doesn't support the setting or user can't change setting, otherwise true.
 
375
         */
 
376
        public final function check_capabilities() {
 
377
                if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) )
 
378
                        return false;
 
379
 
 
380
                if ( $this->theme_supports && ! call_user_func_array( 'current_theme_supports', (array) $this->theme_supports ) )
 
381
                        return false;
 
382
 
 
383
                return true;
 
384
        }
 
385
 
 
386
        /**
 
387
         * Multidimensional helper function.
 
388
         *
 
389
         * @since 3.4.0
 
390
         *
 
391
         * @param $root
 
392
         * @param $keys
 
393
         * @param bool $create Default is false.
 
394
         * @return null|array Keys are 'root', 'node', and 'key'.
 
395
         */
 
396
        final protected function multidimensional( &$root, $keys, $create = false ) {
 
397
                if ( $create && empty( $root ) )
 
398
                        $root = array();
 
399
 
 
400
                if ( ! isset( $root ) || empty( $keys ) )
 
401
                        return;
 
402
 
 
403
                $last = array_pop( $keys );
 
404
                $node = &$root;
 
405
 
 
406
                foreach ( $keys as $key ) {
 
407
                        if ( $create && ! isset( $node[ $key ] ) )
 
408
                                $node[ $key ] = array();
 
409
 
 
410
                        if ( ! is_array( $node ) || ! isset( $node[ $key ] ) )
 
411
                                return;
 
412
 
 
413
                        $node = &$node[ $key ];
 
414
                }
 
415
 
 
416
                if ( $create && ! isset( $node[ $last ] ) )
 
417
                        $node[ $last ] = array();
 
418
 
 
419
                if ( ! isset( $node[ $last ] ) )
 
420
                        return;
 
421
 
 
422
                return array(
 
423
                        'root' => &$root,
 
424
                        'node' => &$node,
 
425
                        'key'  => $last,
 
426
                );
 
427
        }
 
428
 
 
429
        /**
 
430
         * Will attempt to replace a specific value in a multidimensional array.
 
431
         *
 
432
         * @since 3.4.0
 
433
         *
 
434
         * @param $root
 
435
         * @param $keys
 
436
         * @param mixed $value The value to update.
 
437
         * @return
 
438
         */
 
439
        final protected function multidimensional_replace( $root, $keys, $value ) {
 
440
                if ( ! isset( $value ) )
 
441
                        return $root;
 
442
                elseif ( empty( $keys ) ) // If there are no keys, we're replacing the root.
 
443
                        return $value;
 
444
 
 
445
                $result = $this->multidimensional( $root, $keys, true );
 
446
 
 
447
                if ( isset( $result ) )
 
448
                        $result['node'][ $result['key'] ] = $value;
 
449
 
 
450
                return $root;
 
451
        }
 
452
 
 
453
        /**
 
454
         * Will attempt to fetch a specific value from a multidimensional array.
 
455
         *
 
456
         * @since 3.4.0
 
457
         *
 
458
         * @param $root
 
459
         * @param $keys
 
460
         * @param $default A default value which is used as a fallback. Default is null.
 
461
         * @return mixed The requested value or the default value.
 
462
         */
 
463
        final protected function multidimensional_get( $root, $keys, $default = null ) {
 
464
                if ( empty( $keys ) ) // If there are no keys, test the root.
 
465
                        return isset( $root ) ? $root : $default;
 
466
 
 
467
                $result = $this->multidimensional( $root, $keys );
 
468
                return isset( $result ) ? $result['node'][ $result['key'] ] : $default;
 
469
        }
 
470
 
 
471
        /**
 
472
         * Will attempt to check if a specific value in a multidimensional array is set.
 
473
         *
 
474
         * @since 3.4.0
 
475
         *
 
476
         * @param $root
 
477
         * @param $keys
 
478
         * @return bool True if value is set, false if not.
 
479
         */
 
480
        final protected function multidimensional_isset( $root, $keys ) {
 
481
                $result = $this->multidimensional_get( $root, $keys );
 
482
                return isset( $result );
 
483
        }
 
484
}
 
485
 
 
486
/**
 
487
 * A setting that is used to filter a value, but will not save the results.
 
488
 *
 
489
 * Results should be properly handled using another setting or callback.
 
490
 *
 
491
 * @package WordPress
 
492
 * @subpackage Customize
 
493
 * @since 3.4.0
 
494
 */
 
495
class WP_Customize_Filter_Setting extends WP_Customize_Setting {
 
496
 
 
497
        /**
 
498
         * @since 3.4.0
 
499
         */
 
500
        public function update( $value ) {}
 
501
}
 
502
 
 
503
/**
 
504
 * A setting that is used to filter a value, but will not save the results.
 
505
 *
 
506
 * Results should be properly handled using another setting or callback.
 
507
 *
 
508
 * @package WordPress
 
509
 * @subpackage Customize
 
510
 * @since 3.4.0
 
511
 */
 
512
final class WP_Customize_Header_Image_Setting extends WP_Customize_Setting {
 
513
        public $id = 'header_image_data';
 
514
 
 
515
        /**
 
516
         * @since 3.4.0
 
517
         *
 
518
         * @param $value
 
519
         */
 
520
        public function update( $value ) {
 
521
                global $custom_image_header;
 
522
 
 
523
                // If the value doesn't exist (removed or random),
 
524
                // use the header_image value.
 
525
                if ( ! $value )
 
526
                        $value = $this->manager->get_setting('header_image')->post_value();
 
527
 
 
528
                if ( is_array( $value ) && isset( $value['choice'] ) )
 
529
                        $custom_image_header->set_header_image( $value['choice'] );
 
530
                else
 
531
                        $custom_image_header->set_header_image( $value );
 
532
        }
 
533
}
 
534
 
 
535
/**
 
536
 * Class WP_Customize_Background_Image_Setting
 
537
 *
 
538
 * @package WordPress
 
539
 * @subpackage Customize
 
540
 * @since 3.4.0
 
541
 */
 
542
final class WP_Customize_Background_Image_Setting extends WP_Customize_Setting {
 
543
        public $id = 'background_image_thumb';
 
544
 
 
545
        /**
 
546
         * @since 3.4.0
 
547
         * @uses remove_theme_mod()
 
548
         *
 
549
         * @param $value
 
550
         */
 
551
        public function update( $value ) {
 
552
                remove_theme_mod( 'background_image_thumb' );
 
553
        }
 
554
}