自定义API是面向对象的,有四种主要的定制器对象类型:面板(Panels)、板块(Sections)、设置(Settings)和控件(Controls)。设置将UI元素(控件)与保存在数据库中的设置联系起来。板块是控件的UI容器,以改善其组织。面板是将多个板块组合在一起的容器。
每个定制器对象都由一个PHP类表示,所有的对象都由定制器管理(Customize Manager)对象(WP_Customize_Manager)管理。

要添加、删除或修改任何定制器对象,以及访问定制器管理,请使用customize_register钩子。
function themeslug_customize_register( $wp_customize ) {
// Do stuff with $wp_customize, the WP_Customize_Manager object.
}
add_action( 'customize_register', 'themeslug_customize_register' );
定制器管理为每个定制器对象类型提供 add_, get_, 和 remove_ 方法,每个方法都与一个id一起工作。get_ 方法允许直接修改添加控件时指定的参数。
add_action('customize_register','my_customize_register');
function my_customize_register( $wp_customize ) {
$wp_customize->add_panel();
$wp_customize->get_panel();
$wp_customize->remove_panel();
$wp_customize->add_section();
$wp_customize->get_section();
$wp_customize->remove_section();
$wp_customize->add_setting();
$wp_customize->get_setting();
$wp_customize->remove_setting();
$wp_customize->add_control();
$wp_customize->get_control();
$wp_customize->remove_control();
}
注意:主题一般不应该用 get 方法修改核心板块和面板,因为主题不应该修改核心的、与主题无关的功能。我们鼓励插件在必要时使用这些功能。主题不应该"重新组织"不是由主题添加的定制器板块。
设置
设置(Settings)处理实时预览、保存和净化你的定制器对象。每个设置都由一个控件对象管理,在添加一个新的设置时,有几个参数可用。
$wp_customize->add_setting( 'setting_id', array( 'type' => 'theme_mod', // or 'option' 'capability' => 'edit_theme_options', 'theme_supports' => '', // Rarely needed. 'default' => '', 'transport' => 'refresh', // or postMessage 'sanitize_callback' => '', 'sanitize_js_callback' => '', // Basically to_json. ) );
重要提示:不要使用类似 widget_*、sidebars_widgets[*]、nav_menu[*]或nav_menu_item[*]的设置 ID。这些设置ID模式分别保留给小工具实例、侧边栏、导航菜单和导航菜单项。如果你需要在你的设置ID中使用 "widget",把它作为后缀而不是前缀,例如 "homepage_widget"。
设置有两种主要类型:选项(option)和主题修改(theme_mod)。选项直接存储在WordPress数据库的wp_options表中,并应用于网站,而不考虑主题的启用。主题应该尽量少添加选项类型的设置。另一方面,主题修改是特定于某个主题的,大多数主题选项应该是theme_mod。例如,一个自定义的CSS插件可以将一个自定义的主题css设置注册为theme_mod,允许每个主题有一套独特的CSS规则,在切换主题时不会丢失CSS,然后再切换回来。
Theme_mod 和 option 的设置类型例子
通常最重要的是设置的默认值以及它的数据净化回调,这将确保没有不安全的数据被存储在数据库中。典型的主题用法:
$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', ) );
请注意,定制器可以使用选项类型处理存储为键值数组的设置的选项。这允许多个设置被存储在一个不是theme_mod的选项中。要检索和使用你的定制器选项值,请根据设置ID使用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()的第二个参数是默认值,它应该与你在添加设置时设置的默认值一致。
控件
控件(Controls)是创建用户界面的主要定制器对象。 具体来说,每个控件都必须与一个设置相关联,该设置将把用户输入的数据从控件中保存到数据库中(除了在实时预览中显示它并对其进行净化)。控件可以由定制器管理添加,并以最小的努力提供一套强大的UI选项:
$wp_customize->add_control( 'setting_id', array(
'type' => 'date',
'priority' => 10, // Within the section.
'section' => 'colors', // Required, core or custom.
'label' => __( 'Date' ),
'description' => __( 'This is a date control with a red border.' ),
'input_attrs' => array(
'class' => 'my-custom-class-for-js',
'style' => 'border: 1px solid #900',
'placeholder' => __( 'mm/dd/yyyy' ),
),
'active_callback' => 'is_front_page',
) );
在添加控件时,最重要的参数是它的类型(type),这决定了定制器将显示什么类型的UI。核心提供了几种内置的控件类型:
<input>任何允许类型的元素(见下文)checkboxtextarearadio(用choices参数传递一个数组,(键)选项值 => (值)标签)select(用choices参数传递一个数组,(键)选项值 => (值)标签)dropdown-pages(用allow_addition参数,允许用户从控件中添加新的页面)
对于html input元素支持任何input类型,只需在添加控件时将类型属性值传递给type参数。这样就可以支持text, hidden, number, range, url, tel, email, search, time, date, datetime, 和week等控件类型,但要等待浏览器支持。
控件在显示之前必须被添加到一个板块(板块必须包含要显示的控件)。这可以通过在添加控件时指定section参数来实现。下面是一个添加基本的textarea控件的例子。
$wp_customize->add_control( 'custom_theme_css', array( 'label' => __( 'Custom Theme CSS' ), 'type' => 'textarea', 'section' => 'custom_css', ) );
而这里是一个基本的range(滑块)控件的例子。请注意,大多数浏览器不会显示这个控件的数字值,因为range input类型是为精确值不重要的设置而设计的。如果数字值很重要,请考虑使用number类型。input_attrs参数将把一个数组:属性 => 值 映射到input元素上的属性,可以用于从占位符文本到自定义脚本中的数据--JavaScript引用的数据等目的。对于number和range控件,它允许我们设置最小、最大和阶梯值。
$wp_customize->add_control( 'setting_id', array(
'type' => 'range',
'section' => 'title_tagline',
'label' => __( 'Range' ),
'description' => __( 'This is the range control 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' => __( 'Accent Color', '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' => __( 'Featured Home Page Image', 'theme_textdomain' ), 'section' => 'media', 'mime_type' => 'image', ) ) );
$wp_customize->add_control( new WP_Customize_Media_Control( $wp_customize, 'audio_control', array( 'label' => _( 'Featured Home Page Recording', '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,它提供了一个在选择图片后裁剪的接口。这对于需要一个特定的长宽比的情况是很有用的。
板块
板块(Sections)是自定义控件的UI容器。虽然你可以在核心板块添加自定义控件,但如果你有超过几个选项,你可能想添加一个或多个自定义板块。使用WP_Customize_Manager对象的add_section方法来添加一个新的板块。
$wp_customize->add_section( 'custom_css', array( 'title' => __( 'Custom CSS' ), 'description' => __( 'Add custom CSS here' ), 'panel' => '', // Not typically needed. 'priority' => 160, 'capability' => 'edit_theme_options', 'theme_supports' => '', // Rarely needed. ) );
你只需要包含那些你想覆盖默认值的字段,例如,默认的优先级(排序)通常是可以接受的。如果你的选项一目了然,那么大多数板块不需要“描述”文本。如果你确实想改变自定义板块的位置,核心板块的优先级见下表:
| Title | ID | Priority (Order) |
| Site Title & Tagline | title_tagline | 20 |
| Colors | colors | 40 |
| Header Image | header_image | 60 |
| Background Image | background_image | 80 |
| Menus (Panel) | nav_menus | 100 |
| Widgets (Panel) | widgets | 110 |
| Static Front Page | static_front_page | 120 |
| default | 160 | |
| Additional CSS | custom_css | 200 |
在大多数情况下,只需指定一个或两个参数就可以添加板块。下面是一个添加与主题页脚有关的选项板块的例子:
// Add a footer/copyright information section. $wp_customize->add_section( 'footer' , array( 'title' => __( 'Footer', 'themename' ), 'priority' => 105, // Before Widgets. ) );
面板
定制器面板(Panels)API是在WordPress 4.0中引入的,它允许开发者在控件和板块之外创建一个额外的层次结构。面板不仅仅是简单地将控件分组,它被设计用来为定制器提供不同的上下文,比如自定义小工具、菜单,或者也许在未来,编辑文章。板块和面板对象之间有一个重要的技术区别。
在大多数情况下,主题不应该注册自己的面板。板块不需要嵌套在面板下,而且每个板块一般都应该包含多个控件。控件也应该被添加到核心提供的版块中,比如在颜色版块中添加颜色选项。还要确保你的选项尽可能地精简和有效,请看WordPress的哲学。面板被设计为整个功能的上下文,如Widgets、Menus或Posts,而不是作为通用版块的包装。如果你一定要使用面板,你会发现它的API和版块的API几乎是一样的。
$wp_customize->add_panel( 'menus', array( 'title' => __( 'Menus' ), 'description' => $description, // Include html tags such as <p>. 'priority' => 160, // Mixed with top-level-section hierarchy. ) ); $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';
/**
* Render the control's content.
*/
public function render_content() {
?>
<button class="button button-primary" id="create-new-menu-submit" tabindex="0"><?php _e( 'Create Menu' ); ?></button>
<?php
}
}
通过对基础控制类的子类化,你可以用自定义功能覆盖任何功能,或者根据你的需要使用核心功能。最常见的覆盖功能是render_content(),因为它允许你用HTML从头开始创建自定义UI。然而,自定义控件应该谨慎使用,因为它们可能会引入与周围的核心用户界面不一致的用户界面,并给用户带来混乱。定制器对象的添加方式与默认控件、板块和面板的添加方式类似。
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize, // WP_Customize_Manager
'accent_color', // Setting id
array( // Args, including any custom ones.
'label' => __( 'Accent Color' ),
'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标准
自定义控件、板块和面板应该尽可能地与核心的用户界面做法相匹配。这包括依靠wp-admin的标准,例如使用.button和.button-primary类。也有一些专门针对定制器的标准(从WordPress 4.7开始)。
- 白色背景颜色仅用于指示导航和可操作项目(如inputs)
- 一般的
#eee背景色提供了与白色元素的视觉对比 1px #ddd边框将导航元素与背景边距彼此分开- 在需要视觉分离的元素之间提供
15px的间距 4px边框用于导航元素一侧以显示悬停或焦点,颜色为#0073aa- 定制器文本使用颜色
#555d66,导航元素的悬停和焦点状态使用#0073aa
自定义设置类型
默认情况下,定制器支持将设置保存为选项或主题修改。但是这种行为可以很容易地被覆盖,以便在WordPress数据库的wp_options表之外手动保存和预览设置,或者应用其他自定义处理。要开始的话,在添加你的设置时指定一个选项或主题修改以外的类型(你可以使用几乎任何字符串)。
$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 is ordered array of item ids.
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 );
而这里是同一个插件如何实现对导航菜单项的预览(注意这个例子需要PHP5.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 );