渲染自定义控件

WordPress 4.1还增加了对完全用JavaScript渲染重度JavaScript和高量级控件的支持。这允许更多的动态行为,特别是与动态添加的控件有关。核心的颜色和媒体控件目前利用了这个API,所有的核心控件在将来都会使用它。基于PHP的控件API不会消失,但在未来,大多数控件可能会使用新的API,因为它为用户和开发者提供了更快的体验。WordPress 4.3引入了类似的用于JS模板的Sections和Panels的API,然而,从WordPress 4.7开始,在动态创建JS对象的便利性方面仍然存在一些差距,见#30741。

注册控件类型

为了引入同一类型的多个定制器控件有一个模板的概念,我们需要引入一种方法来向定制器管理注册一种类型的控件。以前,只有在使用WP_Customize_Manager::add_control()添加自定义控件时才会遇到自定义控件对象。但是,如果没有其他类型的实例被加载,检测添加的控件类型来渲染每个类型的模板将不允许动态地创建新的控件。WP_Customize_Manager::register_control_type()解决了这个问题。

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' );
}

所有注册的控件类型的模板都由WP_Customize_Manager::print_control_templates()打印到定制器。

 

发送PHP控件数据到JavaScript

虽然定制器控件数据一直被传递到控件的JS模型中,而且这一直能够被扩展,但在使用JS模板时,你更有可能需要将数据下发。任何你想在PHP中访问的render_content()都需要被导出到JavaScript中,以便在你的控件模板中访问。WP_Customize_Control默认导出以下控件类变量:

  • type
  • label
  • description
  • active (boolean state)

你可以通过在自定义控件子类中覆盖WP_Customize_Control::to_json()来为你的自定义控件添加额外的特定参数。在大多数情况下,你会想同时调用父类的to_json()方法,以确保所有的核心变量也被导出。下面是一个来自核心颜色控件的例子:

public function to_json() {
  parent::to_json();
  $this->json['statuses'] = $this->statuses;
  $this->json['defaultValue'] = $this->secodeing->default;
}

 

JS/Underscore 模板化

一旦你将自定义控件类注册为控件类型,并导出了任何自定义类的变量,你就可以创建渲染控件用户界面的模板。你将覆盖WP_Customize_Control::content_template()(默认为空)作为WP_Customize_Control::render_content()的替代。渲染内容仍然会被调用,所以一定要在你的子类中用一个空函数覆盖它。

Underscore风格的自定义控件模板与PHP非常相似。随着越来越多的WordPress核心变得由JavaScript驱动,这些模板正变得越来越普遍。核心部分的一些模板代码可以在媒体、修订、主题浏览中找到,甚至在Twenty Fifteen主题中,一个JS模板被用来保存配色方案数据,并在定制器中即时预览配色方案的变化。学习这些模板如何工作的最好方法是研究核心中的类似代码,因此,这里有一个简单的例子:

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_acoder_e( 'Hex Value' ); ?>" {{ defaultValue }} />
      </div>
    </label>
    <?php
  }
}

在上面的核心自定义颜色控件的模板中,你可以看到在结束的PHP标签之后,我们有一个JS模板。 符号被用在要评估的语句周围--在大多数情况下,这被用于条件反射。所有我们导出到JS的控件实例数据都存储在`data`对象中,我们可以使用双括号(转义)或三括号(未转义)符号{{ }}来打印一个变量。就像我之前说的,掌握编写这样的控件的最好方法是阅读现有的例子。WP_Customize_Upload_Control最近也进行了更新,以利用这个API,与媒体管理器的实现方式很好地整合,并从最小的代码量中挤出大量的功能。如果你想要一些真正好的实践,可以尝试转换一些其他的核心控件来使用这个API--当然也可以向核心控件提交补丁。

 

将碎片拼凑起来

下面是在自定义控件子类中利用新的API所需的内容摘要:

  1. 让你的render_content()函数为空(但它确实需要存在以覆盖默认函数)。
  2. 创建一个新的函数content_template(),并把render_content()的旧内容放在那里。
  3. 通过修改to_json()函数(见WP_Customize_Color_Control的例子),添加任何自定义类变量,这些变量是控件输出到浏览器中的JavaScript(JSON数据)所需要的。
  4. 将render_content()中的PHP转换为JS模板,使用<# JS语句 #>,并用{{变量}}来打印。PHP类变量在数据对象中可用,例如,标签可以用{{ data.label }}打印。
  5. 注册自定义控件的class/type。这个关键步骤告诉定制器打印这个控件的模板。这与打印所有添加的控件的模板不同,因为我们的想法是这个控件类型的许多实例可以从一个模板中呈现出来,而且任何注册的控件类型都可以在将来用于动态控件的创建。就像$wp_customize->register_control_type( 'WP_Customize_Color_Control'); 。

自定义API中仅有的PHP部分仍然被完全支持,而且使用起来完全没问题。但鉴于长期目标是使定制器更加灵活,如在定制器中切换主题而不需要页面加载,我们强烈建议在可行的情况下对所有定制器对象使用JS/Underscore模板。