分析 WordPress `WP_Customize_Manager` 类的源码:它是如何通过 `$settings` 和 `$controls` 管理定制器选项的。

咳咳,各位观众老爷,大家好!今天咱们来聊聊 WordPress 定制器背后的男人—— WP_Customize_Manager 类。这哥们儿,掌管着整个定制器的生杀大权,你的主题选项是美是丑,全看他心情(当然,更准确地说,是看你代码写得好不好)。咱们今天就扒开他的裤衩,啊不,源码,看看他是怎么通过 $settings$controls 这两个左膀右臂来管理定制器选项的。

一、 WP_Customize_Manager:定制器的幕后大佬

首先,咱们得认识一下 WP_Customize_Manager 这个类。 简单来说,它就是 WordPress 定制器的核心管理器。 你在后台看到的定制器界面,以及你能修改的各种选项,都是通过这个类来组织和控制的。 当你在 functions.php 或者插件里使用 WP_Customize_Manager 的实例(通常是 $wp_customize 全局变量)来添加 section、setting、control 时,实际上就是在跟这位大佬打交道。

二、 $settings:选项的“户口本”

WP_Customize_Manager$settings 属性,是一个关联数组,存储了所有定制器选项的 WP_Customize_Setting 对象。 每个选项(比如主题颜色、logo 图片)都有一个对应的 WP_Customize_Setting 对象,它就像是这个选项的“户口本”,记录了选项的各种信息,比如:

  • id (string): 选项的唯一标识符,就像选项的身份证号。
  • default (mixed): 选项的默认值,就像选项的出生时的初始状态。
  • transport (string): 选项的传输方式,决定了选项值的更新方式(refresh 还是 postMessage)。
  • type (string): 选项的数据类型,默认是 theme_mod,表示主题选项。
  • capability (string): 拥有修改这个选项的权限。
  • sanitize_callback (callable): 用于清理和验证选项值的回调函数,确保数据的安全性。
  • validate_callback (callable): 用于验证选项值的回调函数。
  • dirty (bool): 标记选项是否被修改过。

$settings 数组的键就是选项的 id,值就是对应的 WP_Customize_Setting 对象。 我们可以用以下代码来获取某个选项的 WP_Customize_Setting 对象:

global $wp_customize;

$setting = $wp_customize->get_setting( 'blogname' );

if ( $setting ) {
    echo '选项 ID: ' . $setting->id . '<br>';
    echo '默认值: ' . $setting->default . '<br>';
    echo '传输方式: ' . $setting->transport . '<br>';
    echo '数据类型: ' . $setting->type . '<br>';
}

这段代码会尝试获取 blogname 选项的 WP_Customize_Setting 对象,如果找到了,就输出它的 iddefaulttransport 属性。

三、 $controls:选项的“展示台”

WP_Customize_Manager$controls 属性,也是一个关联数组,存储了所有定制器控件的 WP_Customize_Control 对象。 每个控件(比如文本框、颜色选择器、图片上传器)都负责在定制器界面上展示一个选项,并允许用户修改它的值。 控件和选项之间存在着紧密的联系:一个控件通常会关联到一个选项,用于控制该选项的值。

WP_Customize_Control 对象也有一堆属性,其中比较重要的有:

  • id (string): 控件的唯一标识符,就像控件的身份证号。
  • label (string): 控件的标签,显示在定制器界面上,告诉用户这个控件是干嘛的。
  • section (string): 控件所属的 section 的 ID,决定了控件在定制器界面上的位置。
  • settings (string|array): 控件关联的选项的 ID,或者是一个包含多个选项 ID 的数组。
  • priority (int): 控件的优先级,决定了控件在 section 中的显示顺序。
  • active_callback (callable): 一个回调函数,用于控制控件是否显示,可以根据其他选项的值来动态地显示或隐藏控件。

$controls 数组的键就是控件的 id,值就是对应的 WP_Customize_Control 对象。 我们可以用以下代码来获取某个控件的 WP_Customize_Control 对象:

global $wp_customize;

$control = $wp_customize->get_control( 'blogname' );

if ( $control ) {
    echo '控件 ID: ' . $control->id . '<br>';
    echo '标签: ' . $control->label . '<br>';
    echo '所属 section: ' . $control->section . '<br>';
    echo '关联的选项: ' . $control->settings . '<br>';
}

这段代码会尝试获取 blogname 控件的 WP_Customize_Control 对象,如果找到了,就输出它的 idlabelsectionsettings 属性。

四、 $settings$controls 的关系:相辅相成,缺一不可

$settings$controls 就像一对好基友,一个负责存储选项的数据,一个负责展示选项的界面。 没有 $settings$controls 就失去了控制的对象,就像没了灵魂的躯壳。 没有 $controls$settings 就无法被用户修改,就像藏在深闺的千金小姐。

它们之间的关系可以用下图简单表示:

+---------------------+    +---------------------+
| WP_Customize_Setting|----| WP_Customize_Control|
| (选项数据)           |    | (界面控件)          |
+---------------------+    +---------------------+
     | setting_id           |    | settings             |
     | (选项 ID)            |    | (关联的选项 ID)     |
     +---------------------+    +---------------------+

可以看到,WP_Customize_Control 对象通过 settings 属性关联到 WP_Customize_Setting 对象。 当用户在定制器界面上修改控件的值时,WP_Customize_Control 对象会将新的值传递给对应的 WP_Customize_Setting 对象,然后 WP_Customize_Setting 对象会负责清理、验证和保存这个值。

五、 如何使用 $settings$controls 添加定制器选项

现在,咱们来演示一下如何使用 $settings$controls 来添加一个定制器选项。 假设我们要添加一个选项,让用户可以修改网站的背景颜色。

首先,我们需要在 functions.php 或者插件里添加以下代码:

add_action( 'customize_register', 'my_theme_customize_register' );

function my_theme_customize_register( $wp_customize ) {

    // 1. 添加一个 section
    $wp_customize->add_section( 'my_theme_background_section', array(
        'title'      => __( '背景设置', 'my-theme' ),
        'priority'   => 30,
    ) );

    // 2. 添加一个 setting
    $wp_customize->add_setting( 'my_theme_background_color', array(
        'default'    => '#ffffff',
        'sanitize_callback' => 'sanitize_hex_color', // 使用 WordPress 内置的清理函数
        'transport'  => 'postMessage', // 使用 postMessage 方式实时预览
    ) );

    // 3. 添加一个 control
    $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'my_theme_background_color', array(
        'label'      => __( '背景颜色', 'my-theme' ),
        'section'    => 'my_theme_background_section',
        'settings'   => 'my_theme_background_color',
    ) ) );

    // 4. 添加 JavaScript 代码,实现实时预览
    ?>
    <script type="text/javascript">
    ( function( $ ) {
        wp.customize( 'my_theme_background_color', function( value ) {
            value.bind( function( newval ) {
                $( 'body' ).css( 'background-color', newval );
            } );
        } );
    } )( jQuery );
    </script>
    <?php
}

这段代码做了以下几件事:

  1. 添加一个 section: 使用 $wp_customize->add_section() 方法添加一个名为 my_theme_background_section 的 section,用于组织背景相关的选项。
  2. 添加一个 setting: 使用 $wp_customize->add_setting() 方法添加一个名为 my_theme_background_color 的 setting,用于存储背景颜色值。 这里指定了默认值为 #ffffff,并使用了 sanitize_hex_color 函数来清理用户输入的值,确保它是一个有效的十六进制颜色值。 transport 设置为 postMessage,表示使用 JavaScript 通过 postMessage API 来实时预览背景颜色。
  3. 添加一个 control: 使用 $wp_customize->add_control() 方法添加一个名为 my_theme_background_color 的 control,用于在定制器界面上展示颜色选择器。 这里使用了 WP_Customize_Color_Control 类,它是 WordPress 内置的颜色选择器控件。 section 设置为 my_theme_background_section,表示将这个控件放在背景设置 section 中。 settings 设置为 my_theme_background_color,表示这个控件控制的是 my_theme_background_color 选项。
  4. 添加 JavaScript 代码: 添加了一段 JavaScript 代码,用于实现实时预览。 这段代码使用 wp.customize() API 监听 my_theme_background_color 选项的变化,当选项值发生变化时,就将 body 元素的背景颜色设置为新的值。

完成以上步骤后,你就可以在定制器界面上看到一个新的 section,里面有一个颜色选择器,可以用来修改网站的背景颜色。 而且,当你修改颜色时,网站的背景颜色会实时更新,让你立刻看到效果。

六、 一些高级技巧和注意事项

  • 使用 active_callback 动态显示/隐藏控件: 你可以使用 active_callback 属性来动态地显示或隐藏控件。 active_callback 是一个回调函数,它接受一个 WP_Customize_Control 对象作为参数,并返回一个布尔值。 如果返回 true,则显示控件,否则隐藏控件。 例如,你可以根据某个选项的值来决定是否显示另一个选项的控件。
$wp_customize->add_control( 'my_theme_show_header', array(
    'label'    => __( '显示头部', 'my-theme' ),
    'section'  => 'my_theme_header_section',
    'settings' => 'my_theme_show_header',
    'type'     => 'checkbox',
) );

$wp_customize->add_control( 'my_theme_header_text', array(
    'label'    => __( '头部文字', 'my-theme' ),
    'section'  => 'my_theme_header_section',
    'settings' => 'my_theme_header_text',
    'active_callback' => function( $control ) use ( $wp_customize ) {
        return $wp_customize->get_setting( 'my_theme_show_header' )->value();
    },
) );

这段代码中,my_theme_header_text 控件的 active_callback 函数会检查 my_theme_show_header 选项的值。 如果 my_theme_show_header 选项的值为 true(即显示头部),则显示 my_theme_header_text 控件,否则隐藏 my_theme_header_text 控件。

  • 使用 WP_Customize_Settingsanitize_callbackvalidate_callback 确保数据的安全性: sanitize_callback 用于清理和转换用户输入的值,validate_callback 用于验证用户输入的值。 你应该始终使用这两个回调函数来确保数据的安全性,防止恶意代码注入。

  • 合理使用 transport 属性: transport 属性决定了选项值的更新方式。 refresh 表示刷新整个页面来更新选项值,postMessage 表示使用 JavaScript 通过 postMessage API 来实时预览。 一般来说,对于简单的选项(比如颜色、文本),可以使用 postMessage 来实现实时预览,对于复杂的选项(比如布局、样式),可以使用 refresh 来刷新整个页面。

  • 避免过度使用定制器: 虽然定制器很强大,但也不要过度使用它。 对于一些复杂的选项,最好还是使用主题选项页面来实现,而不是把所有的选项都放在定制器里。

七、 总结

今天咱们聊了 WP_Customize_Manager 类的 $settings$controls 属性,以及如何使用它们来添加定制器选项。 $settings 负责存储选项的数据,$controls 负责展示选项的界面。 它们之间的关系是相辅相成,缺一不可。 通过合理使用这两个属性,你可以轻松地为你的主题添加各种各样的定制器选项,让用户可以自由地定制他们的网站。

希望今天的讲座对大家有所帮助。 如果大家还有什么问题,欢迎提问。 咱们下期再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注