PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/html/blog/wp-includes/class-wp-customize-setting.php

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