1 <?php |
1 <?php |
2 /** |
2 /** |
3 * Customize Setting Class. |
3 * WordPress Customize Setting classes |
4 * |
4 * |
5 * @package WordPress |
5 * @package WordPress |
6 * @subpackage Customize |
6 * @subpackage Customize |
7 * @since 3.4.0 |
7 * @since 3.4.0 |
8 */ |
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 */ |
9 class WP_Customize_Setting { |
19 class WP_Customize_Setting { |
|
20 /** |
|
21 * @access public |
|
22 * @var WP_Customize_Manager |
|
23 */ |
10 public $manager; |
24 public $manager; |
|
25 |
|
26 /** |
|
27 * @access public |
|
28 * @var string |
|
29 */ |
11 public $id; |
30 public $id; |
12 |
31 |
13 public $type = 'theme_mod'; |
32 /** |
14 public $capability = 'edit_theme_options'; |
33 * @access public |
|
34 * @var string |
|
35 */ |
|
36 public $type = 'theme_mod'; |
|
37 |
|
38 /** |
|
39 * Capability required to edit this setting. |
|
40 * |
|
41 * @var string |
|
42 */ |
|
43 public $capability = 'edit_theme_options'; |
|
44 |
|
45 /** |
|
46 * Feature a theme is required to support to enable this setting. |
|
47 * |
|
48 * @access public |
|
49 * @var string |
|
50 */ |
15 public $theme_supports = ''; |
51 public $theme_supports = ''; |
16 public $default = ''; |
52 public $default = ''; |
17 public $transport = 'refresh'; |
53 public $transport = 'refresh'; |
18 |
54 |
|
55 /** |
|
56 * Server-side sanitization callback for the setting's value. |
|
57 * |
|
58 * @var callback |
|
59 */ |
19 public $sanitize_callback = ''; |
60 public $sanitize_callback = ''; |
20 public $sanitize_js_callback = ''; |
61 public $sanitize_js_callback = ''; |
21 |
62 |
|
63 /** |
|
64 * Whether or not the setting is initially dirty when created. |
|
65 * |
|
66 * This is used to ensure that a setting will be sent from the pane to the |
|
67 * preview when loading the Customizer. Normally a setting only is synced to |
|
68 * the preview if it has been changed. This allows the setting to be sent |
|
69 * from the start. |
|
70 * |
|
71 * @since 4.2.0 |
|
72 * @access public |
|
73 * @var bool |
|
74 */ |
|
75 public $dirty = false; |
|
76 |
22 protected $id_data = array(); |
77 protected $id_data = array(); |
23 private $_post_value; // Cached, sanitized $_POST value. |
|
24 |
78 |
25 /** |
79 /** |
26 * Constructor. |
80 * Constructor. |
27 * |
81 * |
|
82 * Any supplied $args override class property defaults. |
|
83 * |
28 * @since 3.4.0 |
84 * @since 3.4.0 |
29 * |
85 * |
30 * @param WP_Customize_Manager $manager |
86 * @param WP_Customize_Manager $manager |
31 * @param string $id An specific ID of the setting. Can be a |
87 * @param string $id An specific ID of the setting. Can be a |
32 * theme mod or option name. |
88 * theme mod or option name. |
33 * @param array $args Setting arguments. |
89 * @param array $args Setting arguments. |
34 * @return WP_Customize_Setting |
90 */ |
35 */ |
91 public function __construct( $manager, $id, $args = array() ) { |
36 function __construct( $manager, $id, $args = array() ) { |
92 $keys = array_keys( get_object_vars( $this ) ); |
37 $keys = array_keys( get_class_vars( __CLASS__ ) ); |
|
38 foreach ( $keys as $key ) { |
93 foreach ( $keys as $key ) { |
39 if ( isset( $args[ $key ] ) ) |
94 if ( isset( $args[ $key ] ) ) |
40 $this->$key = $args[ $key ]; |
95 $this->$key = $args[ $key ]; |
41 } |
96 } |
42 |
97 |
55 if ( $this->sanitize_callback ) |
110 if ( $this->sanitize_callback ) |
56 add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback, 10, 2 ); |
111 add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback, 10, 2 ); |
57 |
112 |
58 if ( $this->sanitize_js_callback ) |
113 if ( $this->sanitize_js_callback ) |
59 add_filter( "customize_sanitize_js_{$this->id}", $this->sanitize_js_callback, 10, 2 ); |
114 add_filter( "customize_sanitize_js_{$this->id}", $this->sanitize_js_callback, 10, 2 ); |
60 |
115 } |
61 return $this; |
116 |
62 } |
117 /** |
|
118 * The ID for the current blog when the preview() method was called. |
|
119 * |
|
120 * @since 4.2.0 |
|
121 * @access protected |
|
122 * @var int |
|
123 */ |
|
124 protected $_previewed_blog_id; |
|
125 |
|
126 /** |
|
127 * Return true if the current blog is not the same as the previewed blog. |
|
128 * |
|
129 * @since 4.2.0 |
|
130 * @access public |
|
131 * |
|
132 * @return bool|null Returns null if preview() has not been called yet. |
|
133 */ |
|
134 public function is_current_blog_previewed() { |
|
135 if ( ! isset( $this->_previewed_blog_id ) ) { |
|
136 return null; |
|
137 } |
|
138 return ( get_current_blog_id() === $this->_previewed_blog_id ); |
|
139 } |
|
140 |
|
141 /** |
|
142 * Original non-previewed value stored by the preview method. |
|
143 * |
|
144 * @see WP_Customize_Setting::preview() |
|
145 * @since 4.1.1 |
|
146 * @var mixed |
|
147 */ |
|
148 protected $_original_value; |
63 |
149 |
64 /** |
150 /** |
65 * Handle previewing the setting. |
151 * Handle previewing the setting. |
66 * |
152 * |
67 * @since 3.4.0 |
153 * @since 3.4.0 |
68 */ |
154 */ |
69 public function preview() { |
155 public function preview() { |
|
156 if ( ! isset( $this->_original_value ) ) { |
|
157 $this->_original_value = $this->value(); |
|
158 } |
|
159 if ( ! isset( $this->_previewed_blog_id ) ) { |
|
160 $this->_previewed_blog_id = get_current_blog_id(); |
|
161 } |
|
162 |
70 switch( $this->type ) { |
163 switch( $this->type ) { |
71 case 'theme_mod' : |
164 case 'theme_mod' : |
72 add_filter( 'theme_mod_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) ); |
165 add_filter( 'theme_mod_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) ); |
73 break; |
166 break; |
74 case 'option' : |
167 case 'option' : |
78 add_filter( 'option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) ); |
171 add_filter( 'option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) ); |
79 add_filter( 'default_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) ); |
172 add_filter( 'default_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) ); |
80 } |
173 } |
81 break; |
174 break; |
82 default : |
175 default : |
83 do_action( 'customize_preview_' . $this->id ); |
176 |
|
177 /** |
|
178 * Fires when the {@see WP_Customize_Setting::preview()} method is called for settings |
|
179 * not handled as theme_mods or options. |
|
180 * |
|
181 * The dynamic portion of the hook name, `$this->id`, refers to the setting ID. |
|
182 * |
|
183 * @since 3.4.0 |
|
184 * |
|
185 * @param WP_Customize_Setting $this {@see WP_Customize_Setting} instance. |
|
186 */ |
|
187 do_action( "customize_preview_{$this->id}", $this ); |
|
188 |
|
189 /** |
|
190 * Fires when the {@see WP_Customize_Setting::preview()} method is called for settings |
|
191 * not handled as theme_mods or options. |
|
192 * |
|
193 * The dynamic portion of the hook name, `$this->type`, refers to the setting type. |
|
194 * |
|
195 * @since 4.1.0 |
|
196 * |
|
197 * @param WP_Customize_Setting $this {@see WP_Customize_Setting} instance. |
|
198 */ |
|
199 do_action( "customize_preview_{$this->type}", $this ); |
84 } |
200 } |
85 } |
201 } |
86 |
202 |
87 /** |
203 /** |
88 * Callback function to filter the theme mods and options. |
204 * Callback function to filter the theme mods and options. |
|
205 * |
|
206 * If switch_to_blog() was called after the preview() method, and the current |
|
207 * blog is now not the same blog, then this method does a no-op and returns |
|
208 * the original value. |
89 * |
209 * |
90 * @since 3.4.0 |
210 * @since 3.4.0 |
91 * @uses WP_Customize_Setting::multidimensional_replace() |
211 * @uses WP_Customize_Setting::multidimensional_replace() |
92 * |
212 * |
93 * @param mixed $original Old value. |
213 * @param mixed $original Old value. |
94 * @return mixed New or old value. |
214 * @return mixed New or old value. |
95 */ |
215 */ |
96 public function _preview_filter( $original ) { |
216 public function _preview_filter( $original ) { |
97 return $this->multidimensional_replace( $original, $this->id_data[ 'keys' ], $this->post_value() ); |
217 if ( ! $this->is_current_blog_previewed() ) { |
98 } |
218 return $original; |
99 |
219 } |
100 /** |
220 |
101 * Set the value of the parameter for a specific theme. |
221 $undefined = new stdClass(); // symbol hack |
102 * |
222 $post_value = $this->post_value( $undefined ); |
103 * @since 3.4.0 |
223 if ( $undefined === $post_value ) { |
104 * |
224 $value = $this->_original_value; |
105 * @return bool False if cap check fails or value isn't set. |
225 } else { |
106 */ |
226 $value = $post_value; |
107 public final function save() { |
227 } |
|
228 |
|
229 return $this->multidimensional_replace( $original, $this->id_data['keys'], $value ); |
|
230 } |
|
231 |
|
232 /** |
|
233 * Check user capabilities and theme supports, and then save |
|
234 * the value of the setting. |
|
235 * |
|
236 * @since 3.4.0 |
|
237 * |
|
238 * @return false|null False if cap check fails or value isn't set. |
|
239 */ |
|
240 final public function save() { |
108 $value = $this->post_value(); |
241 $value = $this->post_value(); |
109 |
242 |
110 if ( ! $this->check_capabilities() || ! isset( $value ) ) |
243 if ( ! $this->check_capabilities() || ! isset( $value ) ) |
111 return false; |
244 return false; |
112 |
245 |
113 do_action( 'customize_save_' . $this->id_data[ 'base' ] ); |
246 /** |
|
247 * Fires when the WP_Customize_Setting::save() method is called. |
|
248 * |
|
249 * The dynamic portion of the hook name, `$this->id_data['base']` refers to |
|
250 * the base slug of the setting name. |
|
251 * |
|
252 * @since 3.4.0 |
|
253 * |
|
254 * @param WP_Customize_Setting $this {@see WP_Customize_Setting} instance. |
|
255 */ |
|
256 do_action( 'customize_save_' . $this->id_data[ 'base' ], $this ); |
114 |
257 |
115 $this->update( $value ); |
258 $this->update( $value ); |
116 } |
259 } |
117 |
260 |
118 /** |
261 /** |
119 * Fetches, validates, and sanitizes the $_POST value. |
262 * Fetch and sanitize the $_POST value for the setting. |
120 * |
263 * |
121 * @since 3.4.0 |
264 * @since 3.4.0 |
122 * |
265 * |
123 * @param mixed $default A default value which is used as a fallback. Default is null. |
266 * @param mixed $default A default value which is used as a fallback. Default is null. |
124 * @return mixed The default value on failure, otherwise the sanitized value. |
267 * @return mixed The default value on failure, otherwise the sanitized value. |
125 */ |
268 */ |
126 public final function post_value( $default = null ) { |
269 final public function post_value( $default = null ) { |
127 if ( isset( $this->_post_value ) ) |
270 return $this->manager->post_value( $this, $default ); |
128 return $this->_post_value; |
|
129 |
|
130 $result = $this->manager->post_value( $this ); |
|
131 |
|
132 if ( isset( $result ) ) |
|
133 return $this->_post_value = $result; |
|
134 else |
|
135 return $default; |
|
136 } |
271 } |
137 |
272 |
138 /** |
273 /** |
139 * Sanitize an input. |
274 * Sanitize an input. |
140 * |
275 * |
143 * @param mixed $value The value to sanitize. |
278 * @param mixed $value The value to sanitize. |
144 * @return mixed Null if an input isn't valid, otherwise the sanitized value. |
279 * @return mixed Null if an input isn't valid, otherwise the sanitized value. |
145 */ |
280 */ |
146 public function sanitize( $value ) { |
281 public function sanitize( $value ) { |
147 $value = wp_unslash( $value ); |
282 $value = wp_unslash( $value ); |
|
283 |
|
284 /** |
|
285 * Filter a Customize setting value in un-slashed form. |
|
286 * |
|
287 * @since 3.4.0 |
|
288 * |
|
289 * @param mixed $value Value of the setting. |
|
290 * @param WP_Customize_Setting $this WP_Customize_Setting instance. |
|
291 */ |
148 return apply_filters( "customize_sanitize_{$this->id}", $value, $this ); |
292 return apply_filters( "customize_sanitize_{$this->id}", $value, $this ); |
149 } |
293 } |
150 |
294 |
151 /** |
295 /** |
152 * Set the value of the parameter for a specific theme. |
296 * Save the value of the setting, using the related API. |
153 * |
297 * |
154 * @since 3.4.0 |
298 * @since 3.4.0 |
155 * |
299 * |
156 * @param mixed $value The value to update. |
300 * @param mixed $value The value to update. |
157 * @return mixed The result of saving the value. |
301 * @return mixed The result of saving the value. |
158 */ |
302 */ |
159 protected function update( $value ) { |
303 protected function update( $value ) { |
160 switch( $this->type ) { |
304 switch( $this->type ) { |
161 case 'theme_mod' : |
305 case 'theme_mod' : |
162 return $this->_update_theme_mod( $value ); |
306 return $this->_update_theme_mod( $value ); |
163 break; |
307 |
164 case 'option' : |
308 case 'option' : |
165 return $this->_update_option( $value ); |
309 return $this->_update_option( $value ); |
166 break; |
310 |
167 default : |
311 default : |
168 return do_action( 'customize_update_' . $this->type, $value ); |
312 |
|
313 /** |
|
314 * Fires when the {@see WP_Customize_Setting::update()} method is called for settings |
|
315 * not handled as theme_mods or options. |
|
316 * |
|
317 * The dynamic portion of the hook name, `$this->type`, refers to the type of setting. |
|
318 * |
|
319 * @since 3.4.0 |
|
320 * |
|
321 * @param mixed $value Value of the setting. |
|
322 * @param WP_Customize_Setting $this WP_Customize_Setting instance. |
|
323 */ |
|
324 return do_action( 'customize_update_' . $this->type, $value, $this ); |
169 } |
325 } |
170 } |
326 } |
171 |
327 |
172 /** |
328 /** |
173 * Update the theme mod from the value of the parameter. |
329 * Update the theme mod from the value of the parameter. |
188 if ( isset( $mods ) ) |
344 if ( isset( $mods ) ) |
189 return set_theme_mod( $this->id_data[ 'base' ], $mods ); |
345 return set_theme_mod( $this->id_data[ 'base' ], $mods ); |
190 } |
346 } |
191 |
347 |
192 /** |
348 /** |
193 * Update the theme mod from the value of the parameter. |
349 * Update the option from the value of the setting. |
194 * |
350 * |
195 * @since 3.4.0 |
351 * @since 3.4.0 |
196 * |
352 * |
197 * @param mixed $value The value to update. |
353 * @param mixed $value The value to update. |
198 * @return mixed The result of saving the value. |
354 * @return bool|null The result of saving the value. |
199 */ |
355 */ |
200 protected function _update_option( $value ) { |
356 protected function _update_option( $value ) { |
201 // Handle non-array option. |
357 // Handle non-array option. |
202 if ( empty( $this->id_data[ 'keys' ] ) ) |
358 if ( empty( $this->id_data[ 'keys' ] ) ) |
203 return update_option( $this->id_data[ 'base' ], $value ); |
359 return update_option( $this->id_data[ 'base' ], $value ); |
208 if ( isset( $options ) ) |
364 if ( isset( $options ) ) |
209 return update_option( $this->id_data[ 'base' ], $options ); |
365 return update_option( $this->id_data[ 'base' ], $options ); |
210 } |
366 } |
211 |
367 |
212 /** |
368 /** |
213 * Fetch the value of the parameter for a specific theme. |
369 * Fetch the value of the setting. |
214 * |
370 * |
215 * @since 3.4.0 |
371 * @since 3.4.0 |
216 * |
372 * |
217 * @return mixed The requested value. |
373 * @return mixed The value. |
218 */ |
374 */ |
219 public function value() { |
375 public function value() { |
|
376 // Get the callback that corresponds to the setting type. |
220 switch( $this->type ) { |
377 switch( $this->type ) { |
221 case 'theme_mod' : |
378 case 'theme_mod' : |
222 $function = 'get_theme_mod'; |
379 $function = 'get_theme_mod'; |
223 break; |
380 break; |
224 case 'option' : |
381 case 'option' : |
225 $function = 'get_option'; |
382 $function = 'get_option'; |
226 break; |
383 break; |
227 default : |
384 default : |
|
385 |
|
386 /** |
|
387 * Filter a Customize setting value not handled as a theme_mod or option. |
|
388 * |
|
389 * The dynamic portion of the hook name, `$this->id_date['base']`, refers to |
|
390 * the base slug of the setting name. |
|
391 * |
|
392 * For settings handled as theme_mods or options, see those corresponding |
|
393 * functions for available hooks. |
|
394 * |
|
395 * @since 3.4.0 |
|
396 * |
|
397 * @param mixed $default The setting default value. Default empty. |
|
398 */ |
228 return apply_filters( 'customize_value_' . $this->id_data[ 'base' ], $this->default ); |
399 return apply_filters( 'customize_value_' . $this->id_data[ 'base' ], $this->default ); |
229 } |
400 } |
230 |
401 |
231 // Handle non-array value |
402 // Handle non-array value |
232 if ( empty( $this->id_data[ 'keys' ] ) ) |
403 if ( empty( $this->id_data[ 'keys' ] ) ) |
236 $values = $function( $this->id_data[ 'base' ] ); |
407 $values = $function( $this->id_data[ 'base' ] ); |
237 return $this->multidimensional_get( $values, $this->id_data[ 'keys' ], $this->default ); |
408 return $this->multidimensional_get( $values, $this->id_data[ 'keys' ], $this->default ); |
238 } |
409 } |
239 |
410 |
240 /** |
411 /** |
241 * Escape the parameter's value for use in JavaScript. |
412 * Sanitize the setting's value for use in JavaScript. |
242 * |
413 * |
243 * @since 3.4.0 |
414 * @since 3.4.0 |
244 * |
415 * |
245 * @return mixed The requested escaped value. |
416 * @return mixed The requested escaped value. |
246 */ |
417 */ |
247 public function js_value() { |
418 public function js_value() { |
|
419 |
|
420 /** |
|
421 * Filter a Customize setting value for use in JavaScript. |
|
422 * |
|
423 * The dynamic portion of the hook name, `$this->id`, refers to the setting ID. |
|
424 * |
|
425 * @since 3.4.0 |
|
426 * |
|
427 * @param mixed $value The setting value. |
|
428 * @param WP_Customize_Setting $this {@see WP_Customize_Setting} instance. |
|
429 */ |
248 $value = apply_filters( "customize_sanitize_js_{$this->id}", $this->value(), $this ); |
430 $value = apply_filters( "customize_sanitize_js_{$this->id}", $this->value(), $this ); |
249 |
431 |
250 if ( is_string( $value ) ) |
432 if ( is_string( $value ) ) |
251 return html_entity_decode( $value, ENT_QUOTES, 'UTF-8'); |
433 return html_entity_decode( $value, ENT_QUOTES, 'UTF-8'); |
252 |
434 |
253 return $value; |
435 return $value; |
254 } |
436 } |
255 |
437 |
256 /** |
438 /** |
257 * Check if the theme supports the setting and check user capabilities. |
439 * Validate user capabilities whether the theme supports the setting. |
258 * |
440 * |
259 * @since 3.4.0 |
441 * @since 3.4.0 |
260 * |
442 * |
261 * @return bool False if theme doesn't support the setting or user can't change setting, otherwise true. |
443 * @return bool False if theme doesn't support the setting or user can't change setting, otherwise true. |
262 */ |
444 */ |
263 public final function check_capabilities() { |
445 final public function check_capabilities() { |
264 if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) ) |
446 if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) ) |
265 return false; |
447 return false; |
266 |
448 |
267 if ( $this->theme_supports && ! call_user_func_array( 'current_theme_supports', (array) $this->theme_supports ) ) |
449 if ( $this->theme_supports && ! call_user_func_array( 'current_theme_supports', (array) $this->theme_supports ) ) |
268 return false; |
450 return false; |