设置
设置功能负责自定义化对象的实时预览、保存以及数据净化处理。每个设置都由一个控制对象来管理。在添加新设置时,有若干参数可供使用:
$wp_customize->add_setting( 'setting_id', array(
'type' => 'theme_mod', // 或 'option'
'capability' => 'edit_theme_options',
'theme_supports' => '', // 很少需要使用。
'default' => '',
'transport' => 'refresh', // 或 postMessage
'sanitize_callback' => '',
'sanitize_js_callback' => '', // 通常为 to_json。
) );重要提示:绝对不要使用类似 widget_*、sidebars_widgets[*]、nav_menu[*] 或 nav_menu_item[*] 这样的设置编号。这些编号格式分别保留给插件实例、侧边栏、导航菜单及导航菜单项使用。如果需要在设置编号中包含“widget”字样,应将其作为后缀而非前缀,例如 “homepage_widget”。设置主要分为两种类型:选项型与主题修改型。选项型设置会直接存储在 WordPress 数据库的 wp_options 表中,因此无论当前使用的是哪个主题,这些设置都会生效。主题应尽可能避免添加选项型的设置。而主题修改型设置则是特定于某个主题的。大多数主题选项都应属于主题修改型设置。例如,一个自定义 CSS 插件可以将自定义的 CSS 设置注册为主题修改型设置,这样每个主题就能拥有独特的 CSS 规则,且在切换主题后再切换回来时也不会丢失这些 CSS 规则。

通常而言,为设置指定默认值以及净化回调函数最为重要,这能够确保没有不安全的数据被存储在数据库中。主题的典型用法如下:
$wp_customize->add_setting( 'accent_color', array(
'default' => '#f72525',
'sanitize_callback' => 'sanitize_hex_color',
) );插件的典型用法如下:
$wp_customize->add_setting( 'myplugin_options[color]', array(
'type' => 'option',
'capability' => 'manage_options',
'default' => '#ff2525',
'sanitize_callback' => 'sanitize_hex_color',
) );需要注意的是,对于使用选项型设置的那些以键值对数组形式存储的选项,Customizer 也可以进行处理。这样一来,非主题修改型的单个选项中就可以存储多个设置。若要获取并使用这些自定义设置的值,可利用设置编号,通过 get_theme_mod() 和 get_option() 函数来实现:
function my_custom_css_output() {
echo '<style type="text/css" id="custom-theme-css">' .
get_theme_mod( 'custom_theme_css', '' ) . '</style>';
echo '<style type="text/css" id="custom-plugin-css">' .
get_option( 'custom_plugin_css', '' ) . '</style>';
}
add_action( 'wp_head', 'my_custom_css_output');请注意,get_theme_mod() 和 get_option() 函数的第二个参数是默认值,该值应与添加设置时设定的默认值保持一致。
控制元素
控制元素是用于构建用户界面的核心自定义化对象。具体而言,每个控制元素都必须与某个设置相关联,该设置会将用户通过控制元素输入的数据保存到数据库中(同时还会在实时预览中显示这些数据并对数据进行净化处理)。Customizer 管理器可以轻松地添加各种控制元素,从而为开发者提供丰富的界面选项:
$wp_customize->add_control( 'setting_id', array(
'type' => 'date',
'priority' => 10, // 在该部分内的优先级。
'section' => 'colors', // 必填,可以是核心内置的或自定义的。
'label' => __( '日期' ),
'description' => __( '这是一个带有红色边框的日期输入控件。' ),
'input_attrs' => array(
'class' => 'my-custom-class-for-js',
'style' => 'border: 1px solid #900',
'placeholder' => __( 'mm/dd/yyyy' ),
),
'active_callback' => 'is_front_page',
) );添加控制元素时最重要的参数是其类型——它决定了 Customizer 将呈现何种类型的用户界面。WordPress 核心提供了几种内置的控制元素类型:
- 任何允许的类型的
<input>元素(详见下文) checkboxtextarearadio(需将值与标签的键值对数组传递给choices参数)select(需将值与标签的键值对数组传递给choices参数)dropdown-pages(可使用allow_addition参数允许用户通过该控件添加新页面)
对于 html input 元素所支持的任何输入类型,只需在添加控制元素时将对应的类型属性值传递给 type 参数即可。这样一来,在浏览器支持的前提下,就可以使用 text、hidden、number、range、url、tel、email、search、time、date、datetime 以及 week 这些控制元素类型。
控制元素必须先添加到某个部分中才会被显示出来(而部分中必须包含控制元素才能被显示)。实现这一点的方法就是在添加控制元素时指定 section 参数。以下是一个添加基本文本区域控制元素的示例:
$wp_customize->add_control( 'custom_theme_css', array(
'label' => __( '自定义主题 CSS' ),
'type' => 'textarea',
'section' => 'custom_css',
) );下面是一个基本范围(滑块)控制元素的示例。需要注意的是,由于范围输入类型的设计初衷是用于那些精确数值并不重要的设置,因此大多数浏览器都不会显示该控制元素的数值。如果数值非常重要,建议使用 number 类型。input_attrs 参数可以将属性与值的键值对数组映射到输入元素上的相应属性,其用途十分广泛,从设置占位符文本到在自定义脚本中引用 data- 格式的数据均可使用。对于数字和范围控制元素,该参数还可用于设置最小值、最大值以及步长值。
$wp_customize->add_control( 'setting_id', array(
'type' => 'range',
'section' => 'title_tagline',
'label' => __( '范围值' ),
'description' => __( '这是该范围控制元素的描述。' ),
'input_attrs' => array(
'min' => 0,
'max' => 10,
'step' => 2,
),
) );核心内置控制元素
如果现有的基本控制类型无法满足您的需求,您可以轻松创建并添加自定义控制。本文后面会更详细地介绍自定义控制,其实它们本质上是基础 WP_Customize_Control 对象的子类,能够实现您所需的任何任意 HTML 标记与功能。核心功能中还包含了几种内置的自定义控制,让开发者能够轻松实现由 JavaScript 驱动的丰富功能。如下所示即可添加颜色选择器控制:
$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'color_control', array(
'label' => __( '强调色', 'theme_textdomain' ),
'section' => 'media',
) ) );WordPress 4.1 和 4.2 还通过媒体控制功能增加了对各类多媒体内容的支持。该媒体控制实现了 WordPress 原生的媒体管理器,允许用户从自己的媒体库中选择文件或上传新文件。在添加控制时指定 mime_type 参数,即可指示媒体库仅显示特定类型的文件,比如图片或音频:
$wp_customize->add_control( new WP_Customize_Media_Control( $wp_customize, 'image_control', array(
'label' => __( '首页特色图片', 'theme_textdomain' ),
'section' => 'media',
'mime_type' => 'image',
) ) );$wp_customize->add_control( new WP_Customize_Media_Control( $wp_customize, 'audio_control', array(
'label' => __( '首页特色音频', 'theme_textdomain' ),
'section' => 'media',
'mime_type' => 'audio',
) ) );需要注意的是,与 WP_Customize_Media_Control 相关联的设置会保存对应的附件 ID,而所有其他与媒体相关的控制(即 WP_Customize_Upload_Control 的子类)则会在设置中保存媒体文件的 URL。更多相关信息可在 Make WordPress Core 文档中找到。
此外,WordPress 4.3 还引入了 WP_Customize_Cropped_Image_Control,它提供了在选中图片后对其进行裁剪的接口,对于需要特定宽高比的场景非常有用。
板块
板块是自定义化控制器的 UI 容器。虽然您可以将自定义控制添加到核心板块中,但如果选项较多,您可能希望添加一个或多个自定义板块。可以使用 WP_Customize_Manager 对象的 add_section 方法来添加新板块:
$wp_customize->add_section( 'custom_css', array(
'title' => __( '自定义 CSS', 'themename' ),
'description' => __( '在此处添加自定义 CSS' ),
'panel' => '', // 通常不需要。
'priority' => 160,
'capability' => 'edit_theme_options',
'theme_supports' => '', // 很少需要。
) );您只需包含那些需要覆盖默认值的字段即可。例如,默认的优先级(显示顺序)通常已经足够,而且如果选项本身就很直观,大多数板块也不需要额外的描述性文字。如果您确实想更改自定义板块的位置,以下是核心板块的优先级顺序:
| 标题 | ID | 优先级(顺序) |
| 站点标题与标语 | title_tagline | 20 |
| 颜色 | colors | 40 |
| 页头图片 | header_image | 60 |
| 背景图片 | background_image | 80 |
| 菜单(面板) | nav_menus | 100 |
| 小部件(面板) | widgets | 110 |
| 静态首页 | static_front_page | 120 |
| 默认 | 160 | |
| 附加 CSS | custom_css | 200 |
在大多数情况下,只需指定一两个参数即可添加板块。以下是一个用于添加与主题页脚相关的选项板块的示例:
// 添加页脚/版权信息板块。
$wp_customize->add_section( 'footer' , array(
'title' => __( '页脚', 'themename' ),
'priority' => 105, // 位于小部件之前。
) );面板
自定义化面板 API 是在 WordPress 4.0 中引入的,它允许开发者在控制与板块之外再创建一层层次结构。面板不仅仅用于对控制板块进行分组,其设计目的是为自定义化界面提供不同的使用场景,比如自定义小部件、菜单,未来甚至可能用于编辑文章。板块对象与面板对象之间存在重要的技术区别。
在大多数情况下,主题不应注册自己的面板。板块无需嵌套在面板之下,而且每个板块通常应包含多个控制。控制也应添加到核心提供的板块中,比如在“颜色”板块中添加颜色选项。同时,请确保您的选项尽可能简洁高效;详情可参阅 WordPress 的设计理念。面板是为整个功能模块(如小部件、菜单或文章)设计的,而非用于包裹普通板块的容器。如果您确实必须使用面板,会发现其 API 与板块的 API 几乎完全相同:
$wp_customize->add_panel( 'menus', array(
'title' => __( '菜单', 'themename' ),
'description' => $description, // 可以包含 <p> 等 HTML 标签。
'priority' => 160, // 与顶级板块的层次结构混合。
) );
$wp_customize->add_section( $section_id , array(
'title' => $menu->name,
'panel' => 'menus',
) );面板必须至少包含一个板块,而该板块又必须至少包含一个控制,才能被显示出来。从上面的示例可以看出,向面板中添加板块的方式与向板块中添加控制的方式类似。不过,与控制不同,如果在注册板块时面板参数为空,该板块将会显示在主要的顶级自定义化界面中,因为大多数板块本就不应被包含在面板之中。
自定义控制、板块与面板
通过继承与各个自定义化对象相关的 PHP 对象,即可轻松创建自定义控制、板块和面板:WP_Customize_Control、WP_Customize_Section 以及 WP_Customize_Panel(其实 WP_Customize_Setting 也可以这样处理,但如下一节所述,通常使用自定义设置类型来实现自定义设置会更为合适)。以下是一个基本自定义控制的示例:
class WP_New_Menu_Customize_Control extends WP_Customize_Control {
public $type = 'new_menu';
/**
* 显示控制的内容。
*/
public function render_content() {
?>
<button class="button button-primary" id="create-new-menu-submit" tabindex="0"><?php _e( '创建菜单' ); ?></button>
<?php
}
}通过继承基础控制类,您可以根据需求用自定义功能覆盖原有功能,或者直接使用核心功能。最常需要覆盖的函数是 render_content(),因为它允许您使用 HTML 从头开始创建自定义 UI。不过,使用自定义控制时需谨慎,因为它们可能会引入与周围核心 UI 不一致的用户界面,从而给用户带来困惑。自定义自定义化对象的添加方式与默认控制、板块和面板的添加方式类似:
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize, // WP_Customize_Manager
'accent_color', // 设置 ID
array( // 参数,包括任何自定义参数。
'label' => __( '强调色' ),
'section' => 'colors',
)
)
);在添加控制时传递的参数会映射到控制类中的类变量,因此当您的自定义对象的某些部分在不同实例中有所不同时,就可以添加并使用自定义参数。
在创建自定义控件、板块或面板时,强烈建议参考核心代码,这样才能充分了解哪些功能可以被覆盖。核心代码中还包含了每种类型自定义对象的示例,可分别在 wp-includes/class-wp-customize-control.php、wp-includes/class-wp-customize-section.php 以及 wp-includes/class-wp-customize-panel.php 中找到。每种自定义器对象类型还配有 JavaScript API,可用于扩展自定义对象;更多详情请参阅自定义器 JavaScript API 部分。
自定义器 UI 标准
自定义的自定义器控件、板块和面板应尽可能遵循核心 UI 惯例。这包括采用 wp-admin 中的标准,例如使用 .button 和 .button-primary 类。此外,从 WordPress 4.7 开始,还有一些针对自定义器的特定标准:
- 仅使用白色背景色来标识导航项及可操作项目(如输入框)
- 通用的
#eee背景色可与白色元素形成视觉对比 - 使用
1px #ddd的边框将导航元素与背景边缘以及彼此分隔开 - 在需要视觉分隔的元素之间设置
15px的间距 - 导航元素的一侧会使用
4px的边框来显示悬停或聚焦状态,颜色为#0073aa - 自定义器文本的颜色为
color: #555d66,而导航元素的悬停和聚焦状态则使用#0073aa
自定义设置类型
默认情况下,自定义器支持将设置保存为选项或主题修改。但这一行为可以被轻松覆盖,从而实现将设置手动保存并预览到 WordPress 数据库的 wp_options 表之外,或应用其他自定义处理方式。要开始使用,可在添加设置时指定除 option 或 theme_mod 之外的类型(几乎可以使用任何字符串):
$wp_customize->add_setting( $nav_menu_setting_id, array(
'type' => 'nav_menu',
'default' => $item_ids,
) );当关联控件中的该设置值发生变化时,它将不再被保存或预览。此时,可以使用 customize_update_$setting->type 和 customize_preview_$setting->type 函数来实现自定义的保存与预览功能。以下是来自 Menu Customizer 项目的示例,用于保存菜单项的顺序属性(该设置的值是一个按顺序排列的菜单 ID 数组):
function menu_customizer_update_nav_menu( $value, $setting ) {
$menu_id = str_replace( 'nav_menu_', '', $setting->id );
// ...
$i = 0;
foreach( $value as $item_id ) { // $value 是按顺序排列的元素 ID 数组。
menu_customizer_update_menu_item_order( $menu_id, $item_id, $i );
$i++;
}
}
add_action( 'customize_update_nav_menu', 'menu_customizer_update_nav_menu', 10, 2 );以下是同一个插件实现导航菜单项预览的方式(请注意,此示例需要 PHP 5.3 或更高版本):
function menu_customizer_preview_nav_menu( $setting ) {
$menu_id = str_replace( 'nav_menu_', '', $setting->id );
add_filter( 'wp_get_nav_menu_items', function( $items, $menu, $args ) use ( $menu_id, $setting ) {
$preview_menu_id = $menu->term_id;
if ( $menu_id == $preview_menu_id ) {
$new_ids = $setting->post_value();
foreach ( $new_ids as $item_id ) {
$item = wp_setup_nav_menu_item( $item );
$item->menu_order = $i;
$new_items[] = $item;
$i++;
}
return $new_items;
} else {
return $items;
}
}, 10, 3 );
}
add_action( 'customize_preview_nav_menu', 'menu_customizer_preview_nav_menu', 10, 2 );