web/wp-includes/class-wp-customize-setting.php
changeset 194 32102edaa81b
child 204 09a1c134465b
equal deleted inserted replaced
193:2f6f6f7551ca 194:32102edaa81b
       
     1 <?php
       
     2 /**
       
     3  * Customize Setting Class
       
     4  *
       
     5  * @package WordPress
       
     6  * @subpackage Customize
       
     7  * @since 3.4.0
       
     8  */
       
     9 
       
    10 class WP_Customize_Setting {
       
    11 	public $manager;
       
    12 	public $id;
       
    13 
       
    14 	public $type            = 'theme_mod';
       
    15 	public $capability      = 'edit_theme_options';
       
    16 	public $theme_supports  = '';
       
    17 	public $default         = '';
       
    18 	public $transport       = 'refresh';
       
    19 
       
    20 	public $sanitize_callback    = '';
       
    21 	public $sanitize_js_callback = '';
       
    22 
       
    23 	protected $id_data = array();
       
    24 	private $_post_value; // Cached, sanitized $_POST value.
       
    25 
       
    26 	/**
       
    27 	 * Constructor.
       
    28 	 *
       
    29 	 * @since 3.4.0
       
    30 	 *
       
    31 	 * @param string $id An specific ID of the setting. Can be a
       
    32 	 *                   theme mod or option name.
       
    33 	 * @param array $args Setting arguments.
       
    34 	 */
       
    35 	function __construct( $manager, $id, $args = array() ) {
       
    36 		$keys = array_keys( get_class_vars( __CLASS__ ) );
       
    37 		foreach ( $keys as $key ) {
       
    38 			if ( isset( $args[ $key ] ) )
       
    39 				$this->$key = $args[ $key ];
       
    40 		}
       
    41 
       
    42 		$this->manager = $manager;
       
    43 		$this->id = $id;
       
    44 
       
    45 		// Parse the ID for array keys.
       
    46 		$this->id_data[ 'keys' ] = preg_split( '/\[/', str_replace( ']', '', $this->id ) );
       
    47 		$this->id_data[ 'base' ] = array_shift( $this->id_data[ 'keys' ] );
       
    48 
       
    49 		// Rebuild the ID.
       
    50 		$this->id = $this->id_data[ 'base' ];
       
    51 		if ( ! empty( $this->id_data[ 'keys' ] ) )
       
    52 			$this->id .= '[' . implode( '][', $this->id_data[ 'keys' ] ) . ']';
       
    53 
       
    54 		if ( $this->sanitize_callback )
       
    55 			add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback, 10, 2 );
       
    56 
       
    57 		if ( $this->sanitize_js_callback )
       
    58 			add_filter( "customize_sanitize_js_{$this->id}", $this->sanitize_js_callback, 10, 2 );
       
    59 
       
    60 		return $this;
       
    61 	}
       
    62 
       
    63 	/**
       
    64 	 * Handle previewing the setting.
       
    65 	 *
       
    66 	 * @since 3.4.0
       
    67 	 */
       
    68 	public function preview() {
       
    69 		switch( $this->type ) {
       
    70 			case 'theme_mod' :
       
    71 				add_filter( 'theme_mod_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
       
    72 				break;
       
    73 			case 'option' :
       
    74 				if ( empty( $this->id_data[ 'keys' ] ) )
       
    75 					add_filter( 'pre_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
       
    76 				else {
       
    77 					add_filter( 'option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
       
    78 					add_filter( 'default_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
       
    79 				}
       
    80 				break;
       
    81 			default :
       
    82 				do_action( 'customize_preview_' . $this->id );
       
    83 		}
       
    84 	}
       
    85 
       
    86 	/**
       
    87 	 * Callback function to filter the theme mods and options.
       
    88 	 *
       
    89 	 * @since 3.4.0
       
    90 	 *
       
    91 	 * @param mixed Old value.
       
    92 	 * @return mixed New or old value.
       
    93 	 */
       
    94 	public function _preview_filter( $original ) {
       
    95 		return $this->multidimensional_replace( $original, $this->id_data[ 'keys' ], $this->post_value() );
       
    96 	}
       
    97 
       
    98 	/**
       
    99 	 * Set the value of the parameter for a specific theme.
       
   100 	 *
       
   101 	 * @since 3.4.0
       
   102 	 *
       
   103 	 * @return bool False if cap check fails or value isn't set.
       
   104 	 */
       
   105 	public final function save() {
       
   106 		$value = $this->post_value();
       
   107 
       
   108 		if ( ! $this->check_capabilities() || ! isset( $value ) )
       
   109 			return false;
       
   110 
       
   111 		do_action( 'customize_save_' . $this->id_data[ 'base' ] );
       
   112 
       
   113 		$this->update( $value );
       
   114 	}
       
   115 
       
   116 	/**
       
   117 	 * Fetches, validates, and sanitizes the $_POST value.
       
   118 	 *
       
   119 	 * @since 3.4.0
       
   120 	 *
       
   121 	 * @param $default mixed A default value which is used as a fallback. Default is null.
       
   122 	 * @return mixed Either the default value on failure or sanitized value.
       
   123 	 */
       
   124 	public final function post_value( $default = null ) {
       
   125 		if ( isset( $this->_post_value ) )
       
   126 			return $this->_post_value;
       
   127 
       
   128 		$result = $this->manager->post_value( $this );
       
   129 
       
   130 		if ( isset( $result ) )
       
   131 			return $this->_post_value = $result;
       
   132 		else
       
   133 			return $default;
       
   134 	}
       
   135 
       
   136 	/**
       
   137 	 * Sanitize an input.
       
   138 	 *
       
   139 	 * @since 3.4.0
       
   140 	 *
       
   141 	 * @param $value mixed The value to sanitize.
       
   142 	 * @return mixed Null if an input isn't valid, otherwise the sanitized value.
       
   143 	 */
       
   144 	public function sanitize( $value ) {
       
   145 		$value = stripslashes_deep( $value );
       
   146 		return apply_filters( "customize_sanitize_{$this->id}", $value, $this );
       
   147 	}
       
   148 
       
   149 	/**
       
   150 	 * Set the value of the parameter for a specific theme.
       
   151 	 *
       
   152 	 * @since 3.4.0
       
   153 	 *
       
   154 	 * @param $value mixed The value to update.
       
   155 	 * @return mixed The result of saving the value.
       
   156 	 */
       
   157 	protected function update( $value ) {
       
   158 		switch( $this->type ) {
       
   159 			case 'theme_mod' :
       
   160 				return $this->_update_theme_mod( $value );
       
   161 				break;
       
   162 			case 'option' :
       
   163 				return $this->_update_option( $value );
       
   164 				break;
       
   165 			default :
       
   166 				return do_action( 'customize_update_' . $this->type, $value );
       
   167 		}
       
   168 	}
       
   169 
       
   170 	/**
       
   171 	 * Update the theme mod from the value of the parameter.
       
   172 	 *
       
   173 	 * @since 3.4.0
       
   174 	 *
       
   175 	 * @param $value mixed The value to update.
       
   176 	 * @return mixed The result of saving the value.
       
   177 	 */
       
   178 	protected function _update_theme_mod( $value ) {
       
   179 		// Handle non-array theme mod.
       
   180 		if ( empty( $this->id_data[ 'keys' ] ) )
       
   181 			return set_theme_mod( $this->id_data[ 'base' ], $value );
       
   182 
       
   183 		// Handle array-based theme mod.
       
   184 		$mods = get_theme_mod( $this->id_data[ 'base' ] );
       
   185 		$mods = $this->multidimensional_replace( $mods, $this->id_data[ 'keys' ], $value );
       
   186 		if ( isset( $mods ) )
       
   187 			return set_theme_mod( $this->id_data[ 'base' ], $mods );
       
   188 	}
       
   189 
       
   190 	/**
       
   191 	 * Update the theme mod from the value of the parameter.
       
   192 	 *
       
   193 	 * @since 3.4.0
       
   194 	 *
       
   195 	 * @param $value mixed The value to update.
       
   196 	 * @return mixed The result of saving the value.
       
   197 	 */
       
   198 	protected function _update_option( $value ) {
       
   199 		// Handle non-array option.
       
   200 		if ( empty( $this->id_data[ 'keys' ] ) )
       
   201 			return update_option( $this->id_data[ 'base' ], $value );
       
   202 
       
   203 		// Handle array-based options.
       
   204 		$options = get_option( $this->id_data[ 'base' ] );
       
   205 		$options = $this->multidimensional_replace( $options, $this->id_data[ 'keys' ], $value );
       
   206 		if ( isset( $options ) )
       
   207 			return update_option( $this->id_data[ 'base' ], $options );
       
   208 	}
       
   209 
       
   210 	/**
       
   211 	 * Fetch the value of the parameter for a specific theme.
       
   212 	 *
       
   213 	 * @since 3.4.0
       
   214 	 *
       
   215 	 * @return mixed The requested value.
       
   216 	 */
       
   217 	public function value() {
       
   218 		switch( $this->type ) {
       
   219 			case 'theme_mod' :
       
   220 				$function = 'get_theme_mod';
       
   221 				break;
       
   222 			case 'option' :
       
   223 				$function = 'get_option';
       
   224 				break;
       
   225 			default :
       
   226 				return apply_filters( 'customize_value_' . $this->id_data[ 'base' ], $this->default );
       
   227 		}
       
   228 
       
   229 		// Handle non-array value
       
   230 		if ( empty( $this->id_data[ 'keys' ] ) )
       
   231 			return $function( $this->id_data[ 'base' ], $this->default );
       
   232 
       
   233 		// Handle array-based value
       
   234 		$values = $function( $this->id_data[ 'base' ] );
       
   235 		return $this->multidimensional_get( $values, $this->id_data[ 'keys' ], $this->default );
       
   236 	}
       
   237 
       
   238 	/**
       
   239 	 * Escape the parameter's value for use in JavaScript.
       
   240 	 *
       
   241 	 * @since 3.4.0
       
   242 	 *
       
   243 	 * @return mixed The requested escaped value.
       
   244 	 */
       
   245 	public function js_value() {
       
   246 		$value = apply_filters( "customize_sanitize_js_{$this->id}", $this->value(), $this );
       
   247 
       
   248 		if ( is_string( $value ) )
       
   249 			return html_entity_decode( $value, ENT_QUOTES, 'UTF-8');
       
   250 
       
   251 		return $value;
       
   252 	}
       
   253 
       
   254 	/**
       
   255 	 * Check if the theme supports the setting and check user capabilities.
       
   256 	 *
       
   257 	 * @since 3.4.0
       
   258 	 *
       
   259 	 * @return bool False if theme doesn't support the setting or user can't change setting, otherwise true.
       
   260 	 */
       
   261 	public final function check_capabilities() {
       
   262 		if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) )
       
   263 			return false;
       
   264 
       
   265 		if ( $this->theme_supports && ! call_user_func_array( 'current_theme_supports', (array) $this->theme_supports ) )
       
   266 			return false;
       
   267 
       
   268 		return true;
       
   269 	}
       
   270 
       
   271 	/**
       
   272 	 * Multidimensional helper function.
       
   273 	 *
       
   274 	 * @since 3.4.0
       
   275 	 *
       
   276 	 * @param $root
       
   277 	 * @param $keys
       
   278 	 * @param bool $create Default is false.
       
   279 	 * @return null|array
       
   280 	 */
       
   281 	final protected function multidimensional( &$root, $keys, $create = false ) {
       
   282 		if ( $create && empty( $root ) )
       
   283 			$root = array();
       
   284 
       
   285 		if ( ! isset( $root ) || empty( $keys ) )
       
   286 			return;
       
   287 
       
   288 		$last = array_pop( $keys );
       
   289 		$node = &$root;
       
   290 
       
   291 		foreach ( $keys as $key ) {
       
   292 			if ( $create && ! isset( $node[ $key ] ) )
       
   293 				$node[ $key ] = array();
       
   294 
       
   295 			if ( ! is_array( $node ) || ! isset( $node[ $key ] ) )
       
   296 				return;
       
   297 
       
   298 			$node = &$node[ $key ];
       
   299 		}
       
   300 
       
   301 		if ( $create && ! isset( $node[ $last ] ) )
       
   302 			$node[ $last ] = array();
       
   303 
       
   304 		if ( ! isset( $node[ $last ] ) )
       
   305 			return;
       
   306 
       
   307 		return array(
       
   308 			'root' => &$root,
       
   309 			'node' => &$node,
       
   310 			'key'  => $last,
       
   311 		);
       
   312 	}
       
   313 
       
   314 	/**
       
   315 	 * Will attempt to replace a specific value in a multidimensional array.
       
   316 	 *
       
   317 	 * @since 3.4.0
       
   318 	 *
       
   319 	 * @param $root
       
   320 	 * @param $keys
       
   321 	 * @param mixed $value The value to update.
       
   322 	 * @return
       
   323 	 */
       
   324 	final protected function multidimensional_replace( $root, $keys, $value ) {
       
   325 		if ( ! isset( $value ) )
       
   326 			return $root;
       
   327 		elseif ( empty( $keys ) ) // If there are no keys, we're replacing the root.
       
   328 			return $value;
       
   329 
       
   330 		$result = $this->multidimensional( $root, $keys, true );
       
   331 
       
   332 		if ( isset( $result ) )
       
   333 			$result['node'][ $result['key'] ] = $value;
       
   334 
       
   335 		return $root;
       
   336 	}
       
   337 
       
   338 	/**
       
   339 	 * Will attempt to fetch a specific value from a multidimensional array.
       
   340 	 *
       
   341 	 * @since 3.4.0
       
   342 	 *
       
   343 	 * @param $root
       
   344 	 * @param $keys
       
   345 	 * @param $default A default value which is used as a fallback. Default is null.
       
   346 	 * @return mixed The requested value or the default value.
       
   347 	 */
       
   348 	final protected function multidimensional_get( $root, $keys, $default = null ) {
       
   349 		if ( empty( $keys ) ) // If there are no keys, test the root.
       
   350 			return isset( $root ) ? $root : $default;
       
   351 
       
   352 		$result = $this->multidimensional( $root, $keys );
       
   353 		return isset( $result ) ? $result['node'][ $result['key'] ] : $default;
       
   354 	}
       
   355 
       
   356 	/**
       
   357 	 * Will attempt to check if a specific value in a multidimensional array is set.
       
   358 	 *
       
   359 	 * @since 3.4.0
       
   360 	 *
       
   361 	 * @param $root
       
   362 	 * @param $keys
       
   363 	 * @return bool True if value is set, false if not.
       
   364 	 */
       
   365 	final protected function multidimensional_isset( $root, $keys ) {
       
   366 		$result = $this->multidimensional_get( $root, $keys );
       
   367 		return isset( $result );
       
   368 	}
       
   369 }
       
   370 
       
   371 /**
       
   372  * A setting that is used to filter a value, but will not save the results.
       
   373  *
       
   374  * Results should be properly handled using another setting or callback.
       
   375  */
       
   376 class WP_Customize_Filter_Setting extends WP_Customize_Setting {
       
   377 	public function update() {}
       
   378 }
       
   379 
       
   380 /**
       
   381  * A setting that is used to filter a value, but will not save the results.
       
   382  *
       
   383  * Results should be properly handled using another setting or callback.
       
   384  */
       
   385 final class WP_Customize_Header_Image_Setting extends WP_Customize_Setting {
       
   386 	public $id = 'header_image_data';
       
   387 
       
   388 	public function update( $value ) {
       
   389 		global $custom_image_header;
       
   390 
       
   391 		// If the value doesn't exist (removed or random),
       
   392 		// use the header_image value.
       
   393 		if ( ! $value )
       
   394 			$value = $this->manager->get_setting('header_image')->post_value();
       
   395 
       
   396 		if ( is_array( $value ) && isset( $value['choice'] ) )
       
   397 			$custom_image_header->set_header_image( $value['choice'] );
       
   398 		else
       
   399 			$custom_image_header->set_header_image( $value );
       
   400 	}
       
   401 }
       
   402 
       
   403 final class WP_Customize_Background_Image_Setting extends WP_Customize_Setting {
       
   404 	public $id = 'background_image_thumb';
       
   405 
       
   406 	public function update( $value ) {
       
   407 		remove_theme_mod( 'background_image_thumb' );
       
   408 	}
       
   409 }