Customizer: Introduce an API to create WP_Customize_Settings for dynamically-created settings.

* Introduce WP_Customize_Manager::add_dynamic_settings() to register dynamically-created settings.
* Introduce `customize_dynamic_setting_args` filter to pass an array of args to a dynamic setting's constructor.
* Add unit tests for WP_Customize_Manager and WP_Customize_Widgets.
* See WP_Customize_Widgets as an example.

props westonruter.
fixes #30936.

git-svn-id: https://develop.svn.wordpress.org/trunk@31370 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Dominik Schilling (ocean90)
2015-02-08 23:10:05 +00:00
parent 76b84b9231
commit 2518bbbb1f
5 changed files with 607 additions and 273 deletions
+101 -6
View File
@@ -65,7 +65,7 @@ final class WP_Customize_Manager {
/**
* Unsanitized values for Customize Settings parsed from $_POST['customized'].
*
* @var array|false
* @var array
*/
private $_post_values;
@@ -102,6 +102,7 @@ final class WP_Customize_Manager {
add_action( 'wp_ajax_customize_save', array( $this, 'save' ) );
add_action( 'customize_register', array( $this, 'register_controls' ) );
add_action( 'customize_register', array( $this, 'register_dynamic_settings' ), 11 ); // allow code to create settings first
add_action( 'customize_controls_init', array( $this, 'prepare_controls' ) );
add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_control_scripts' ) );
}
@@ -110,11 +111,23 @@ final class WP_Customize_Manager {
* Return true if it's an AJAX request.
*
* @since 3.4.0
* @since 4.2.0 Added $action param.
*
* @param string|null $action whether the supplied Ajax action is being run.
* @return bool
*/
public function doing_ajax() {
return isset( $_POST['customized'] ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX );
public function doing_ajax( $action = null ) {
$doing_ajax = ( defined( 'DOING_AJAX' ) && DOING_AJAX );
if ( ! $doing_ajax ) {
return false;
}
if ( ! $action ) {
return true;
} else {
// Note: we can't just use doing_action( "wp_ajax_{$action}" ) because we need to check before admin-ajax.php gets to that point
return isset( $_REQUEST['action'] ) && wp_unslash( $_REQUEST['action'] ) === $action;
}
}
/**
@@ -411,8 +424,8 @@ final class WP_Customize_Manager {
if ( isset( $_POST['customized'] ) ) {
$this->_post_values = json_decode( wp_unslash( $_POST['customized'] ), true );
}
if ( empty( $this->_post_values ) ) { // if not isset or of JSON error
$this->_post_values = false;
if ( empty( $this->_post_values ) ) { // if not isset or if JSON error
$this->_post_values = array();
}
}
if ( empty( $this->_post_values ) ) {
@@ -441,6 +454,19 @@ final class WP_Customize_Manager {
}
}
/**
* Override a setting's (unsanitized) value as found in any incoming $_POST['customized']
*
* @since 4.2.0
*
* @param string $setting_id The ID for the WP_Customize_Setting instance.
* @param mixed $value
*/
public function set_post_value( $setting_id, $value ) {
$this->unsanitized_post_values();
$this->_post_values[ $setting_id ] = $value;
}
/**
* Print JavaScript settings.
*
@@ -726,6 +752,65 @@ final class WP_Customize_Manager {
$this->settings[ $setting->id ] = $setting;
}
/**
* Register any dynamically-created settings, such as those from $_POST['customized'] that have no corresponding setting created.
*
* This is a mechanism to "wake up" settings that have been dynamically created
* on the frontend and have been sent to WordPress in $_POST['customized']. When WP
* loads, the dynamically-created settings then will get created and previewed
* even though they are not directly created statically with code.
*
* @since 4.2.0
*
* @param string[] $setting_ids The setting IDs to add.
* @return WP_Customize_Setting[] The settings added.
*/
public function add_dynamic_settings( $setting_ids ) {
$new_settings = array();
foreach ( $setting_ids as $setting_id ) {
// Skip settings already created
if ( $this->get_setting( $setting_id ) ) {
continue;
}
$setting_args = false;
$setting_class = 'WP_Customize_Setting';
/**
* Filter a dynamic setting's constructor args.
*
* For a dynamic setting to be registered, this filter must be employed
* to override the default false value with an array of args to pass to
* the WP_Customize_Setting constructor.
*
* @since 4.2.0
*
* @param false|array $setting_args The arguments to the WP_Customize_Setting constructor.
* @param string $setting_id ID for dynamic setting, usually coming from $_POST['customized'].
*/
$setting_args = apply_filters( 'customize_dynamic_setting_args', $setting_args, $setting_id );
if ( false === $setting_args ) {
continue;
}
/**
* Allow non-statically created settings to be constructed with custom WP_Customize_Setting subclass.
*
* @since 4.2.0
*
* @param string $setting_class WP_Customize_Setting or a subclass.
* @param string $setting_id ID for dynamic setting, usually coming from $_POST['customized'].
* @param string $setting_args WP_Customize_Setting or a subclass.
*/
$setting_class = apply_filters( 'customize_dynamic_setting_class', $setting_class, $setting_id, $setting_args );
$setting = new $setting_class( $this, $setting_id, $setting_args );
$this->add_setting( $setting );
$new_settings[] = $setting;
}
return $new_settings;
}
/**
* Retrieve a customize setting.
*
@@ -735,8 +820,9 @@ final class WP_Customize_Manager {
* @return WP_Customize_Setting
*/
public function get_setting( $id ) {
if ( isset( $this->settings[ $id ] ) )
if ( isset( $this->settings[ $id ] ) ) {
return $this->settings[ $id ];
}
}
/**
@@ -1274,6 +1360,15 @@ final class WP_Customize_Manager {
}
}
/**
* Add settings from the POST data that were not added with code, e.g. dynamically-created settings for Widgets
*
* @since 4.2.0
*/
public function register_dynamic_settings() {
$this->add_dynamic_settings( array_keys( $this->unsanitized_post_values() ) );
}
/**
* Callback for validating the header_textcolor value.
*