探究 WordPress `WP_Customize_Manager` 类的源码:如何通过 `add_setting()` 和 `add_control()` 创建主题定制器选项。

各位观众老爷们,今天咱们来聊聊 WordPress 主题定制器这玩意儿,特别是里面的 WP_Customize_Manager 类,以及它是怎么耍花招,让我们能用 add_setting()add_control() 变出各种主题选项的。准备好,咱们要开始扒源码了!

一、定制器:你的主题魔镜

首先,得明白主题定制器是干嘛的。你可以把它想象成一面魔镜,但不是让你问“谁是世界上最美丽的人”,而是让你实时调整主题的外观,比如颜色、字体、布局,然后立马看到效果。这种所见即所得的体验,简直不要太爽!

WordPress 提供了 WP_Customize_Manager 类,专门负责管理这个魔镜。它就像一个总指挥,协调各种设置(settings)、控制(controls)和面板(panels),让你轻松定制主题。

二、WP_Customize_Manager:幕后大 BOSS

WP_Customize_Manager 类是定制器的核心。它负责:

  • 启动定制器界面
  • 注册设置、控制和面板
  • 处理 AJAX 请求
  • 保存定制选项

要访问这个类,你得先判断它是否存在,通常在 customize_register 钩子中进行:

add_action( 'customize_register', 'my_theme_customize_register' );

function my_theme_customize_register( $wp_customize ) {
    // $wp_customize 就是 WP_Customize_Manager 的实例
    // 现在你可以用它来添加设置、控制和面板了
}

三、add_setting():定义主题选项

add_setting() 方法用来定义一个主题选项。它告诉 WordPress,我们需要存储一个值,并为这个值分配一个 ID。这个 ID 就像一个房间号,以后我们就可以通过它来找到这个房间里的东西(也就是选项的值)。

add_setting() 方法接受两个参数:

  1. $id:选项的 ID,必须是唯一的。
  2. $args:一个数组,包含选项的各种属性。
$wp_customize->add_setting(
    'my_theme_accent_color', // 选项 ID
    array(
        'default'           => '#007bff', // 默认值
        'type'              => 'theme_mod', // 存储类型,theme_mod 或 option
        'capability'        => 'edit_theme_options', // 权限
        'transport'         => 'refresh', // 刷新方式,refresh 或 postMessage
        'sanitize_callback' => 'sanitize_hex_color', // 清理回调函数
    )
);

咱们来分解一下 $args 数组里的几个关键属性:

属性 描述
default 选项的默认值。如果没有设置任何值,就使用这个默认值。
type 选项的存储类型。theme_mod 表示存储在主题的设置中,option 表示存储在 WordPress 的 wp_options 表中。通常情况下,主题选项使用 theme_mod
capability 允许修改这个选项的用户权限。edit_theme_options 表示只有具有编辑主题选项权限的用户才能修改。
transport 刷新方式。refresh 表示页面需要重新加载才能看到效果,postMessage 表示可以通过 JavaScript 实时更新页面,无需重新加载。postMessage 体验更好,但需要编写额外的 JavaScript 代码来处理。
sanitize_callback 清理回调函数。这个函数会在保存选项值之前被调用,用来清理用户输入,防止恶意代码注入。sanitize_hex_color 是一个 WordPress 内置的函数,用来清理十六进制颜色值。

四、add_control():创建控制面板

光有设置还不够,还得有个控制面板让用户来修改选项的值。add_control() 方法就是用来创建控制面板的。它会在定制器界面上显示一个表单元素,让用户输入或选择值。

add_control() 方法也接受两个参数:

  1. $id:控制的 ID,必须是唯一的。
  2. $args:一个数组,包含控制的各种属性。
$wp_customize->add_control(
    new WP_Customize_Color_Control( // 控制类型
        $wp_customize,
        'my_theme_accent_color', // 控制 ID,与 setting 的 ID 相同
        array(
            'label'    => __( 'Accent Color', 'my-theme' ), // 标签
            'section'  => 'colors', // 所属的 section
            'settings' => 'my_theme_accent_color', // 关联的 setting ID
        )
    )
);

这里有点不一样,第一个参数不是一个简单的字符串,而是一个 WP_Customize_Color_Control 类的实例。这是因为 WordPress 提供了多种控制类型,比如文本框、下拉列表、单选按钮等等。每种控制类型都有自己的类。

咱们来看看 $args 数组里的几个关键属性:

属性 描述
label 控制的标签,也就是在控制面板上显示的文字。
section 控制所属的 section。section 是定制器界面的一个分组,用来组织相关的控制。WordPress 默认提供了一些 section,比如 colorsheader_imagebackground_image 等等。你也可以自定义 section。
settings 关联的 setting ID。这个属性告诉 WordPress,这个控制是用来修改哪个 setting 的值的。

五、控制类型:各式各样的表单元素

WordPress 提供了多种控制类型,满足不同的需求:

  • WP_Customize_Control:基类,所有控制类型都继承自它。
  • WP_Customize_Color_Control:颜色选择器。
  • WP_Customize_Image_Control:图片上传器。
  • WP_Customize_Upload_Control:文件上传器。
  • WP_Customize_Media_Control:媒体上传器 (支持图片、音频、视频)。
  • WP_Customize_Cropped_Image_Control:裁剪图片上传器。
  • WP_Customize_Background_Image_Control:背景图片上传器。
  • WP_Customize_Header_Image_Control:头部图片上传器。
  • WP_Customize_Dropdown_Pages_Control:页面下拉列表。

如果你觉得这些控制类型不够用,还可以自定义控制类型。这需要你创建一个继承自 WP_Customize_Control 的类,并重写 render_content() 方法来渲染控制的内容。

六、面板(Panels)和 Section:定制器的组织者

为了让定制器界面更清晰,我们可以使用面板(Panels)和 Section 来组织控制。

  • 面板(Panels): 面板是最高级别的分组,可以包含多个 Section。你可以把相关的 Section 放在同一个面板里。
  • Section: Section 是控制的分组,用来组织相关的控制。

使用 add_panel() 方法可以添加面板:

$wp_customize->add_panel(
    'my_theme_general_settings',
    array(
        'title'       => __( 'General Settings', 'my-theme' ),
        'description' => __( 'General settings for my theme', 'my-theme' ),
        'priority'    => 10,
    )
);

使用 add_section() 方法可以添加 Section:

$wp_customize->add_section(
    'my_theme_header_settings',
    array(
        'title'       => __( 'Header Settings', 'my-theme' ),
        'description' => __( 'Settings for the header', 'my-theme' ),
        'priority'    => 20,
        'panel'       => 'my_theme_general_settings', // 所属的 panel ID
    )
);

注意,Section 可以属于一个 Panel,也可以不属于任何 Panel。

七、get_theme_mod():取出主题选项的值

当我们定义了设置和控制,用户就可以在定制器界面上修改选项的值了。那么,我们如何在主题中使用这些值呢?

答案是使用 get_theme_mod() 函数。

$accent_color = get_theme_mod( 'my_theme_accent_color', '#007bff' ); // 获取选项的值,第二个参数是默认值

echo '<style>';
echo 'a { color: ' . esc_attr( $accent_color ) . '; }';
echo '</style>';

get_theme_mod() 函数接受两个参数:

  1. $name:选项的 ID,与 add_setting() 方法的第一个参数相同。
  2. $default:选项的默认值。如果选项没有设置任何值,就返回这个默认值。

八、postMessage:实时预览的魔法

前面提到过,transport 属性可以设置为 postMessage,实现实时预览的效果。但这需要我们编写额外的 JavaScript 代码来处理。

首先,在 add_setting() 方法中,将 transport 属性设置为 postMessage

$wp_customize->add_setting(
    'my_theme_accent_color',
    array(
        'default'           => '#007bff',
        'type'              => 'theme_mod',
        'capability'        => 'edit_theme_options',
        'transport'         => 'postMessage', // 设置为 postMessage
        'sanitize_callback' => 'sanitize_hex_color',
    )
);

然后,在 JavaScript 文件中,监听 customize-preview-init 事件,并使用 wp.customize() API 来获取选项的值,并更新页面:

( function( $ ) {
    wp.customize( 'my_theme_accent_color', function( value ) {
        value.bind( function( newval ) {
            $( 'a' ).css( 'color', newval );
        } );
    } );
} )( jQuery );

这段代码的意思是:

  1. 监听 my_theme_accent_color 选项的变化。
  2. 当选项的值发生变化时,执行回调函数。
  3. 在回调函数中,获取新的值 newval
  4. 使用 jQuery 将 a 标签的颜色设置为新的值。

九、完整代码示例

add_action( 'customize_register', 'my_theme_customize_register' );

function my_theme_customize_register( $wp_customize ) {

    // 1. 添加面板
    $wp_customize->add_panel(
        'my_theme_general_settings',
        array(
            'title'       => __( 'General Settings', 'my-theme' ),
            'description' => __( 'General settings for my theme', 'my-theme' ),
            'priority'    => 10,
        )
    );

    // 2. 添加 Section
    $wp_customize->add_section(
        'my_theme_header_settings',
        array(
            'title'       => __( 'Header Settings', 'my-theme' ),
            'description' => __( 'Settings for the header', 'my-theme' ),
            'priority'    => 20,
            'panel'       => 'my_theme_general_settings', // 所属的 panel ID
        )
    );

    // 3. 添加 Setting
    $wp_customize->add_setting(
        'my_theme_accent_color',
        array(
            'default'           => '#007bff',
            'type'              => 'theme_mod',
            'capability'        => 'edit_theme_options',
            'transport'         => 'postMessage',
            'sanitize_callback' => 'sanitize_hex_color',
        )
    );

    // 4. 添加 Control
    $wp_customize->add_control(
        new WP_Customize_Color_Control(
            $wp_customize,
            'my_theme_accent_color',
            array(
                'label'    => __( 'Accent Color', 'my-theme' ),
                'section'  => 'my_theme_header_settings', // 所属的 section
                'settings' => 'my_theme_accent_color', // 关联的 setting ID
            )
        )
    );
}

// 5. 获取选项的值并应用
add_action( 'wp_head', 'my_theme_accent_color_css' );

function my_theme_accent_color_css() {
    $accent_color = get_theme_mod( 'my_theme_accent_color', '#007bff' );

    echo '<style>';
    echo 'a { color: ' . esc_attr( $accent_color ) . '; }';
    echo '</style>';
}

// 6. JavaScript 代码 (enqueue 到主题)
add_action( 'customize_preview_init', 'my_theme_customize_preview_js' );

function my_theme_customize_preview_js() {
    wp_enqueue_script(
        'my-theme-customize-preview',
        get_template_directory_uri() . '/js/customize-preview.js',
        array( 'customize-preview', 'jquery' ),
        '',
        true
    );
}

/js/customize-preview.js 文件内容:

( function( $ ) {
    wp.customize( 'my_theme_accent_color', function( value ) {
        value.bind( function( newval ) {
            $( 'a' ).css( 'color', newval );
        } );
    } );
} )( jQuery );

十、总结

今天咱们一起扒了 WordPress WP_Customize_Manager 类的源码,了解了如何通过 add_setting()add_control() 创建主题定制器选项。简单来说,就是:

  1. add_setting() 定义选项,告诉 WordPress 我们要存储一个值。
  2. add_control() 创建控制面板,让用户修改选项的值。
  3. get_theme_mod() 获取选项的值,并在主题中使用。
  4. 如果想要实时预览的效果,可以使用 postMessage 和 JavaScript。

希望这次的讲解能让你对 WordPress 主题定制器有更深入的了解。下次再见!

发表回复

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