WordPress 4.1 引入了完全使用 JavaScript 渲染控件的新 API,支持动态行为和大量控件,如核心的 Color 和 Media 控件。未来大多数控件将采用此 API,以提升用户体验和开发效率,但基于 PHP 的 API 仍被支持。
add_action( 'customize_register', 'prefix_customize_register' );
function prefix_customize_register( $wp_customize ) {
// Define a custom control class, WP_Customize_Custom_Control.
// Register the class so that its JS template is available in the Customizer.
$wp_customize->register_control_type( 'WP_Customize_Custom_Control' );
}public function to_json() {
parent::to_json();
$this->json['statuses'] = $this->statuses;
$this->json['defaultValue'] = $this->setting->default;
}public function content_template() {
?>
<# var defaultValue = '';
if ( data.defaultValue ) {
if ( '#' !== data.defaultValue.substring( 0, 1 ) ) {
defaultValue = '#' + data.defaultValue;
} else {
defaultValue = data.defaultValue;
}
defaultValue = ' data-default-color=' + defaultValue; // Quotes added automatically.
} #>
<label>
<# if ( data.label ) { #>
<span class="customize-control-title">{{{ data.label }}}</span>
<# } #>
<# if ( data.description ) { #>
<span class="description customize-control-description">{{{ data.description }}}</span>
<# } #>
<div class="customize-control-content">
<input class="color-picker-hex" type="text" maxlength="7" placeholder="<?php esc_attr_e( 'Hex Value' ); ?>" {{ defaultValue }} />
</div>
</label>
<?php
}WordPress 4.1 also added support for rendering JavaScript-heavy and/or high-quantity controls entirely with JavaScript. This allows for more dynamic behavior, especially related to dynamically-added controls. The core Color and Media controls currently leverage this API, and all core Controls will eventually use it in the future. The PHP-based control API is not going away, but in the future most controls will likely use the new API since it provides a faster experience for users and developers. Similar APIs for JS-templated Sections and Panels were introduced WordPress 4.3; however, there remain some gaps in the ease of dynamically-creating objects in JS as of WordPress 4.7, see #30741.
In order to introduce a concept of having one template for multiple Customizer controls of the same type, we needed to introduce a way to register a type of control with the Customize Manager. Previously, custom control objects were only encountered when custom controls were added using <a href="https://developer.wordpress.org/reference/classes/wp_customize_manager/add_control/">WP_Customize_Manager::add_control()</a>. But detecting added control types to render one template per type wouldn’t allow new controls to be created dynamically if no other instances of that type were loaded. <a href="https://developer.wordpress.org/reference/classes/wp_customize_manager/register_control_type/">WP_Customize_Manager::register_control_type()</a> solves this:
add_action( 'customize_register', 'prefix_customize_register' );
function prefix_customize_register( $wp_customize ) {
// Define a custom control class, WP_Customize_Custom_Control.
// Register the class so that its JS template is available in the Customizer.
$wp_customize->register_control_type( 'WP_Customize_Custom_Control' );
}
All registered control types have their templates printed to the customizer by WP_Customize_Manager::print_control_templates().
While Customizer control data has always been passed to the control JS models, and this has always been able to be extended, you’re much more likely to need to send data down when working with JS templates. Anything that you would want access to in render_content() in PHP will need to be exported to JavaScript to be accessible in your control template. WP_Customize_Control exports the following control class variables by default:
typelabeldescriptionactive (boolean state)You can add additional parameters specific to your custom control by overriding <a href="https://developer.wordpress.org/reference/classes/wp_customize_control/to_json/">WP_Customize_Control::to_json()</a> in your custom control subclass. In most cases, you’ll want to call the parent class’ to_json() method also, to ensure that all core variables are exported as well. Here’s an example from the core color control:
public function to_json() {
parent::to_json();
$this->json['statuses'] = $this->statuses;
$this->json['defaultValue'] = $this->setting->default;
}
Once you’ve registered your custom control class as a control type and exported any custom class variables, you can create the template that will render the control UI. You’ll override <a href="https://developer.wordpress.org/reference/classes/wp_customize_control/content_template/">WP_Customize_Control::content_template()</a> (empty by default) as a replacement for <a href="https://developer.wordpress.org/reference/classes/wp_customize_control/render_content/">WP_Customize_Control::render_content()</a>. Render content is still called, so be sure to override it with an empty function in your subclass as well.
Underscore-style custom control templates are very similar to PHP. As more and more of WordPress core becomes JavaScript-driven, these templates are becoming increasingly more common. Some sample template code in core can be found in media, revisions, the theme browser, and even in the Twenty Fifteen theme, where a JS template is used to both save the color scheme data and instantly preview color scheme changes in the Customizer. The best way to learn how these templates work is to study similar code in core and, accordingly, here is a brief example:
class WP_Customize_Color_Control extends WP_Customize_Control {
public $type = 'color';
// ...
/**
* Render a JS template for the content of the color picker control.
*/
public function content_template() {
?>
<# var defaultValue = '';
if ( data.defaultValue ) {
if ( '#' !== data.defaultValue.substring( 0, 1 ) ) {
defaultValue = '#' + data.defaultValue;
} else {
defaultValue = data.defaultValue;
}
defaultValue = ' data-default-color=' + defaultValue; // Quotes added automatically.
} #>
<label>
<# if ( data.label ) { #>
<span class="customize-control-title">{{{ data.label }}}</span>
<# } #>
<# if ( data.description ) { #>
<span class="description customize-control-description">{{{ data.description }}}</span>
<# } #>
<div class="customize-control-content">
<input class="color-picker-hex" type="text" maxlength="7" placeholder="<?php esc_attr_e( 'Hex Value' ); ?>" {{ defaultValue }} />
</div>
</label>
<?php
}
}
In the above template for the core custom color control, you can see that after the closing PHP tag, we have a JS template. notation is used around statements to be evaluated – in most cases, this is used for conditionals. All of the control instance data that we exported to JS is stored in the `data` object, and we can print a variable using double (escaped) or triple (unescaped) brace notation {{ }}. As I said before, the best way to get the hang of writing controls like this is to read through existing examples. WP_Customize_Upload_Control was recently updated to leverage this API as well, integrating nicely with the way the media manager is implemented, and squeezing a ton of functionality out of a minimal amount of code. If you want some really good practice, try converting some of the other core controls to use this API – and submit patches to core too, of course!
Here’s a summary of what’s needed to leverage the new API in a custom customizer control subclass:
The PHP-only parts of the Customize API are still fully supported and perfectly fine to use. But given long term goals for making the customizer more flexible for doing things like switching themes in the customizer without a pageload, it is strongly encouraged to use JS/Underscore templates for all custom customizer objects where feasible.