wp/wp-includes/class-wp-customize-setting.php
changeset 5 5e2f62d02dcd
parent 0 d970ebf37754
child 7 cf61fcea0001
--- a/wp/wp-includes/class-wp-customize-setting.php	Mon Jun 08 16:11:51 2015 +0000
+++ b/wp/wp-includes/class-wp-customize-setting.php	Tue Jun 09 03:35:32 2015 +0200
@@ -1,40 +1,95 @@
 <?php
 /**
- * Customize Setting Class.
+ * WordPress Customize Setting classes
  *
  * @package WordPress
  * @subpackage Customize
  * @since 3.4.0
  */
+
+/**
+ * Customize Setting class.
+ *
+ * Handles saving and sanitizing of settings.
+ *
+ * @since 3.4.0
+ *
+ * @see WP_Customize_Manager
+ */
 class WP_Customize_Setting {
+	/**
+	 * @access public
+	 * @var WP_Customize_Manager
+	 */
 	public $manager;
+
+	/**
+	 * @access public
+	 * @var string
+	 */
 	public $id;
 
-	public $type            = 'theme_mod';
-	public $capability      = 'edit_theme_options';
+	/**
+	 * @access public
+	 * @var string
+	 */
+	public $type = 'theme_mod';
+
+	/**
+	 * Capability required to edit this setting.
+	 *
+	 * @var string
+	 */
+	public $capability = 'edit_theme_options';
+
+	/**
+	 * Feature a theme is required to support to enable this setting.
+	 *
+	 * @access public
+	 * @var string
+	 */
 	public $theme_supports  = '';
 	public $default         = '';
 	public $transport       = 'refresh';
 
+	/**
+	 * Server-side sanitization callback for the setting's value.
+	 *
+	 * @var callback
+	 */
 	public $sanitize_callback    = '';
 	public $sanitize_js_callback = '';
 
+	/**
+	 * Whether or not the setting is initially dirty when created.
+	 *
+	 * This is used to ensure that a setting will be sent from the pane to the
+	 * preview when loading the Customizer. Normally a setting only is synced to
+	 * the preview if it has been changed. This allows the setting to be sent
+	 * from the start.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 * @var bool
+	 */
+	public $dirty = false;
+
 	protected $id_data = array();
-	private $_post_value; // Cached, sanitized $_POST value.
 
 	/**
 	 * Constructor.
 	 *
+	 * Any supplied $args override class property defaults.
+	 *
 	 * @since 3.4.0
 	 *
 	 * @param WP_Customize_Manager $manager
-	 * @param string $id An specific ID of the setting. Can be a
-	 *                   theme mod or option name.
-	 * @param array $args Setting arguments.
-	 * @return WP_Customize_Setting
+	 * @param string               $id      An specific ID of the setting. Can be a
+	 *                                      theme mod or option name.
+	 * @param array                $args    Setting arguments.
 	 */
-	function __construct( $manager, $id, $args = array() ) {
-		$keys = array_keys( get_class_vars( __CLASS__ ) );
+	public function __construct( $manager, $id, $args = array() ) {
+		$keys = array_keys( get_object_vars( $this ) );
 		foreach ( $keys as $key ) {
 			if ( isset( $args[ $key ] ) )
 				$this->$key = $args[ $key ];
@@ -57,16 +112,54 @@
 
 		if ( $this->sanitize_js_callback )
 			add_filter( "customize_sanitize_js_{$this->id}", $this->sanitize_js_callback, 10, 2 );
+	}
 
-		return $this;
+	/**
+	 * The ID for the current blog when the preview() method was called.
+	 *
+	 * @since 4.2.0
+	 * @access protected
+	 * @var int
+	 */
+	protected $_previewed_blog_id;
+
+	/**
+	 * Return true if the current blog is not the same as the previewed blog.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 *
+	 * @return bool|null Returns null if preview() has not been called yet.
+	 */
+	public function is_current_blog_previewed() {
+		if ( ! isset( $this->_previewed_blog_id ) ) {
+			return null;
+		}
+		return ( get_current_blog_id() === $this->_previewed_blog_id );
 	}
 
 	/**
+	 * Original non-previewed value stored by the preview method.
+	 *
+	 * @see WP_Customize_Setting::preview()
+	 * @since 4.1.1
+	 * @var mixed
+	 */
+	protected $_original_value;
+
+	/**
 	 * Handle previewing the setting.
 	 *
 	 * @since 3.4.0
 	 */
 	public function preview() {
+		if ( ! isset( $this->_original_value ) ) {
+			$this->_original_value = $this->value();
+		}
+		if ( ! isset( $this->_previewed_blog_id ) ) {
+			$this->_previewed_blog_id = get_current_blog_id();
+		}
+
 		switch( $this->type ) {
 			case 'theme_mod' :
 				add_filter( 'theme_mod_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
@@ -80,13 +173,40 @@
 				}
 				break;
 			default :
-				do_action( 'customize_preview_' . $this->id );
+
+				/**
+				 * Fires when the {@see WP_Customize_Setting::preview()} method is called for settings
+				 * not handled as theme_mods or options.
+				 *
+				 * The dynamic portion of the hook name, `$this->id`, refers to the setting ID.
+				 *
+				 * @since 3.4.0
+				 *
+				 * @param WP_Customize_Setting $this {@see WP_Customize_Setting} instance.
+				 */
+				do_action( "customize_preview_{$this->id}", $this );
+
+				/**
+				 * Fires when the {@see WP_Customize_Setting::preview()} method is called for settings
+				 * not handled as theme_mods or options.
+				 *
+				 * The dynamic portion of the hook name, `$this->type`, refers to the setting type.
+				 *
+				 * @since 4.1.0
+				 *
+				 * @param WP_Customize_Setting $this {@see WP_Customize_Setting} instance.
+				 */
+				do_action( "customize_preview_{$this->type}", $this );
 		}
 	}
 
 	/**
 	 * Callback function to filter the theme mods and options.
 	 *
+	 * If switch_to_blog() was called after the preview() method, and the current
+	 * blog is now not the same blog, then this method does a no-op and returns
+	 * the original value.
+	 *
 	 * @since 3.4.0
 	 * @uses WP_Customize_Setting::multidimensional_replace()
 	 *
@@ -94,45 +214,60 @@
 	 * @return mixed New or old value.
 	 */
 	public function _preview_filter( $original ) {
-		return $this->multidimensional_replace( $original, $this->id_data[ 'keys' ], $this->post_value() );
+		if ( ! $this->is_current_blog_previewed() ) {
+			return $original;
+		}
+
+		$undefined = new stdClass(); // symbol hack
+		$post_value = $this->post_value( $undefined );
+		if ( $undefined === $post_value ) {
+			$value = $this->_original_value;
+		} else {
+			$value = $post_value;
+		}
+
+		return $this->multidimensional_replace( $original, $this->id_data['keys'], $value );
 	}
 
 	/**
-	 * Set the value of the parameter for a specific theme.
+	 * Check user capabilities and theme supports, and then save
+	 * the value of the setting.
 	 *
 	 * @since 3.4.0
 	 *
-	 * @return bool False if cap check fails or value isn't set.
+	 * @return false|null False if cap check fails or value isn't set.
 	 */
-	public final function save() {
+	final public function save() {
 		$value = $this->post_value();
 
 		if ( ! $this->check_capabilities() || ! isset( $value ) )
 			return false;
 
-		do_action( 'customize_save_' . $this->id_data[ 'base' ] );
+		/**
+		 * Fires when the WP_Customize_Setting::save() method is called.
+		 *
+		 * The dynamic portion of the hook name, `$this->id_data['base']` refers to
+		 * the base slug of the setting name.
+		 *
+		 * @since 3.4.0
+		 *
+		 * @param WP_Customize_Setting $this {@see WP_Customize_Setting} instance.
+		 */
+		do_action( 'customize_save_' . $this->id_data[ 'base' ], $this );
 
 		$this->update( $value );
 	}
 
 	/**
-	 * Fetches, validates, and sanitizes the $_POST value.
+	 * Fetch and sanitize the $_POST value for the setting.
 	 *
 	 * @since 3.4.0
 	 *
 	 * @param mixed $default A default value which is used as a fallback. Default is null.
 	 * @return mixed The default value on failure, otherwise the sanitized value.
 	 */
-	public final function post_value( $default = null ) {
-		if ( isset( $this->_post_value ) )
-			return $this->_post_value;
-
-		$result = $this->manager->post_value( $this );
-
-		if ( isset( $result ) )
-			return $this->_post_value = $result;
-		else
-			return $default;
+	final public function post_value( $default = null ) {
+		return $this->manager->post_value( $this, $default );
 	}
 
 	/**
@@ -145,11 +280,20 @@
 	 */
 	public function sanitize( $value ) {
 		$value = wp_unslash( $value );
+
+		/**
+		 * Filter a Customize setting value in un-slashed form.
+		 *
+		 * @since 3.4.0
+		 *
+		 * @param mixed                $value Value of the setting.
+		 * @param WP_Customize_Setting $this  WP_Customize_Setting instance.
+		 */
 		return apply_filters( "customize_sanitize_{$this->id}", $value, $this );
 	}
 
 	/**
-	 * Set the value of the parameter for a specific theme.
+	 * Save the value of the setting, using the related API.
 	 *
 	 * @since 3.4.0
 	 *
@@ -160,12 +304,24 @@
 		switch( $this->type ) {
 			case 'theme_mod' :
 				return $this->_update_theme_mod( $value );
-				break;
+
 			case 'option' :
 				return $this->_update_option( $value );
-				break;
+
 			default :
-				return do_action( 'customize_update_' . $this->type, $value );
+
+				/**
+				 * Fires when the {@see WP_Customize_Setting::update()} method is called for settings
+				 * not handled as theme_mods or options.
+				 *
+				 * The dynamic portion of the hook name, `$this->type`, refers to the type of setting.
+				 *
+				 * @since 3.4.0
+				 *
+				 * @param mixed                $value Value of the setting.
+				 * @param WP_Customize_Setting $this  WP_Customize_Setting instance.
+				 */
+				return do_action( 'customize_update_' . $this->type, $value, $this );
 		}
 	}
 
@@ -190,12 +346,12 @@
 	}
 
 	/**
-	 * Update the theme mod from the value of the parameter.
+	 * Update the option from the value of the setting.
 	 *
 	 * @since 3.4.0
 	 *
 	 * @param mixed $value The value to update.
-	 * @return mixed The result of saving the value.
+	 * @return bool|null The result of saving the value.
 	 */
 	protected function _update_option( $value ) {
 		// Handle non-array option.
@@ -210,13 +366,14 @@
 	}
 
 	/**
-	 * Fetch the value of the parameter for a specific theme.
+	 * Fetch the value of the setting.
 	 *
 	 * @since 3.4.0
 	 *
-	 * @return mixed The requested value.
+	 * @return mixed The value.
 	 */
 	public function value() {
+		// Get the callback that corresponds to the setting type.
 		switch( $this->type ) {
 			case 'theme_mod' :
 				$function = 'get_theme_mod';
@@ -225,6 +382,20 @@
 				$function = 'get_option';
 				break;
 			default :
+
+				/**
+				 * Filter a Customize setting value not handled as a theme_mod or option.
+				 *
+				 * The dynamic portion of the hook name, `$this->id_date['base']`, refers to
+				 * the base slug of the setting name.
+				 *
+				 * For settings handled as theme_mods or options, see those corresponding
+				 * functions for available hooks.
+				 *
+				 * @since 3.4.0
+				 *
+				 * @param mixed $default The setting default value. Default empty.
+				 */
 				return apply_filters( 'customize_value_' . $this->id_data[ 'base' ], $this->default );
 		}
 
@@ -238,13 +409,24 @@
 	}
 
 	/**
-	 * Escape the parameter's value for use in JavaScript.
+	 * Sanitize the setting's value for use in JavaScript.
 	 *
 	 * @since 3.4.0
 	 *
 	 * @return mixed The requested escaped value.
 	 */
 	public function js_value() {
+
+		/**
+		 * Filter a Customize setting value for use in JavaScript.
+		 *
+		 * The dynamic portion of the hook name, `$this->id`, refers to the setting ID.
+		 *
+		 * @since 3.4.0
+		 *
+		 * @param mixed                $value The setting value.
+		 * @param WP_Customize_Setting $this  {@see WP_Customize_Setting} instance.
+		 */
 		$value = apply_filters( "customize_sanitize_js_{$this->id}", $this->value(), $this );
 
 		if ( is_string( $value ) )
@@ -254,13 +436,13 @@
 	}
 
 	/**
-	 * Check if the theme supports the setting and check user capabilities.
+	 * Validate user capabilities whether the theme supports the setting.
 	 *
 	 * @since 3.4.0
 	 *
 	 * @return bool False if theme doesn't support the setting or user can't change setting, otherwise true.
 	 */
-	public final function check_capabilities() {
+	final public function check_capabilities() {
 		if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) )
 			return false;
 
@@ -300,8 +482,15 @@
 			$node = &$node[ $key ];
 		}
 
-		if ( $create && ! isset( $node[ $last ] ) )
-			$node[ $last ] = array();
+		if ( $create ) {
+			if ( ! is_array( $node ) ) {
+				// account for an array overriding a string or object value
+				$node = array();
+			}
+			if ( ! isset( $node[ $last ] ) ) {
+				$node[ $last ] = array();
+			}
+		}
 
 		if ( ! isset( $node[ $last ] ) )
 			return;
@@ -344,7 +533,7 @@
 	 *
 	 * @param $root
 	 * @param $keys
-	 * @param $default A default value which is used as a fallback. Default is null.
+	 * @param mixed $default A default value which is used as a fallback. Default is null.
 	 * @return mixed The requested value or the default value.
 	 */
 	final protected function multidimensional_get( $root, $keys, $default = null ) {
@@ -375,9 +564,9 @@
  *
  * Results should be properly handled using another setting or callback.
  *
- * @package WordPress
- * @subpackage Customize
  * @since 3.4.0
+ *
+ * @see WP_Customize_Setting
  */
 class WP_Customize_Filter_Setting extends WP_Customize_Setting {
 
@@ -392,9 +581,9 @@
  *
  * Results should be properly handled using another setting or callback.
  *
- * @package WordPress
- * @subpackage Customize
  * @since 3.4.0
+ *
+ * @see WP_Customize_Setting
  */
 final class WP_Customize_Header_Image_Setting extends WP_Customize_Setting {
 	public $id = 'header_image_data';
@@ -420,16 +609,17 @@
 }
 
 /**
- * @package WordPress
- * @subpackage Customize
+ * Customizer Background Image Setting class.
+ *
  * @since 3.4.0
+ *
+ * @see WP_Customize_Setting
  */
 final class WP_Customize_Background_Image_Setting extends WP_Customize_Setting {
 	public $id = 'background_image_thumb';
 
 	/**
 	 * @since 3.4.0
-	 * @uses remove_theme_mod()
 	 *
 	 * @param $value
 	 */