分析 WordPress `get_theme_mod()` 和 `set_theme_mod()` 函数的源码:如何与主题定制器选项交互。

咳咳,各位同学,今天咱们来聊聊 WordPress 主题定制器的两大利器:get_theme_mod()set_theme_mod()。 别看名字挺长,其实它们的作用很简单,就像咱们家里控制灯泡亮度的开关一样,一个负责读取亮度(get_theme_mod()),一个负责调节亮度(set_theme_mod())。

咱们的目标是,扒光它们的源码,看看它们是如何跟主题定制器选项眉来眼去的。放心,不会让你头秃,我会尽量用大白话把事情讲清楚。

一、get_theme_mod():主题定制器数据的“读取器”

首先,咱们来看看 get_theme_mod() 的源码(WordPress 源码位于 wp-includes/theme.php):

/**
 * Retrieve a theme modification value.
 *
 * @since 3.4.0
 *
 * @param string $name Theme modification name.
 * @param mixed  $default Optional. Default value to return if the theme modification does not exist. Default false.
 * @return mixed Theme modification value, or $default if the modification does not exist.
 */
function get_theme_mod( $name, $default = false ) {
    return get_option( 'theme_mods_' . get_stylesheet(), $default )[ $name ] ?? $default;
}

是不是感觉有点短?没错,get_theme_mod() 本身只是一个“二传手”,它真正干活的是 get_option()。咱们来拆解一下:

  1. $name: 这是你要读取的主题定制器选项的名称,比如 'header_textcolor' (头部文字颜色)。
  2. $default: 如果这个选项没有设置值,就返回这个默认值。 默认值是 false
  3. get_stylesheet(): 这个函数会返回当前主题的样式表名称(通常就是主题的目录名)。 比如,你的主题目录是 'my-awesome-theme',那么 get_stylesheet() 就会返回 'my-awesome-theme'
  4. 'theme_mods_' . get_stylesheet(): 这部分代码拼接出一个选项名,这个选项名是 WordPress 用来存储主题定制器选项的。 比如,当前主题是 'my-awesome-theme',那么这个选项名就是 'theme_mods_my-awesome-theme'
  5. get_option( 'theme_mods_' . get_stylesheet(), $default ): 这个函数才是真正从数据库里读取选项值的。它会读取名为 'theme_mods_my-awesome-theme' 的选项,如果这个选项不存在,就返回 $default
  6. [ $name ] ?? $default: 这是PHP7.0+的语法,叫做 NULL 合并运算符。它的意思是:如果 get_option() 返回的数组中存在键名为 $name 的元素,就返回这个元素的值;否则,就返回 $default。简单来说,就是从刚才读取的数组里,取出 $name 对应的值,如果 $name 不存在,就返回 $default

总结:get_theme_mod() 的工作流程

  1. 拼接出存储主题定制器选项的选项名('theme_mods_' . 主题名)。
  2. 使用 get_option() 从数据库中读取这个选项的值(一个数组)。
  3. 从这个数组中取出 $name 对应的值,如果 $name 不存在,就返回 $default

举个栗子:

假设你有一个主题,主题名是 'my-awesome-theme',并且你在主题定制器中设置了 'header_textcolor' 的值为 '#FF0000'

那么,当你调用 get_theme_mod( 'header_textcolor', '#000000' ) 时,get_theme_mod() 会执行以下步骤:

  1. 拼接出选项名 'theme_mods_my-awesome-theme'
  2. 使用 get_option() 从数据库中读取 'theme_mods_my-awesome-theme' 选项的值,假设读取到的值是 array( 'header_textcolor' => '#FF0000', 'background_color' => '#FFFFFF' )
  3. 从这个数组中取出 'header_textcolor' 对应的值 '#FF0000' 并返回。

如果 'header_textcolor' 没有设置值,那么 get_theme_mod() 就会返回你传入的默认值 '#000000'

二、set_theme_mod():主题定制器数据的“写入器”

接下来,咱们来看看 set_theme_mod() 的源码(WordPress 源码位于 wp-includes/theme.php):

/**
 * Modify a theme modification value.
 *
 * @since 3.4.0
 *
 * @param string $name Theme modification name.
 * @param mixed  $value Theme modification value.
 * @return bool True if the value was successfully set. False on failure.
 */
function set_theme_mod( $name, $value ) {
    $mods = get_theme_mods();

    if ( null === $value ) {
        unset( $mods[ $name ] );
    } else {
        $mods[ $name ] = $value;
    }

    return update_option( 'theme_mods_' . get_stylesheet(), $mods );
}

这次代码稍微长一点,但逻辑也很清晰:

  1. $name: 这是你要设置的主题定制器选项的名称,比如 'header_textcolor'
  2. $value: 这是你要设置的主题定制器选项的值,比如 '#00FF00'
  3. get_theme_mods(): 这个函数会返回当前主题的所有主题定制器选项,它本质上就是调用了 get_option( 'theme_mods_' . get_stylesheet() ),和 get_theme_mod 差不多,只不过是返回整个数组。
  4. if ( null === $value ): 如果 $valuenull,那么就从 $mods 数组中移除 $name 对应的元素。 这相当于删除一个主题定制器选项。
  5. else { $mods[ $name ] = $value; }: 否则,就将 $value 赋值给 $mods 数组中 $name 对应的元素。 这相当于设置或更新一个主题定制器选项。
  6. update_option( 'theme_mods_' . get_stylesheet(), $mods ): 这个函数会将 $mods 数组保存到数据库中,选项名还是 'theme_mods_' . 主题名

总结:set_theme_mod() 的工作流程

  1. 获取当前主题的所有主题定制器选项(一个数组)。
  2. 如果 $valuenull,就从数组中移除 $name 对应的元素。
  3. 否则,就将 $value 赋值给数组中 $name 对应的元素。
  4. 将修改后的数组保存到数据库中。

举个栗子:

假设你有一个主题,主题名是 'my-awesome-theme',并且你想要将 'header_textcolor' 设置为 '#00FF00'

那么,当你调用 set_theme_mod( 'header_textcolor', '#00FF00' ) 时,set_theme_mod() 会执行以下步骤:

  1. 使用 get_theme_mods() 获取当前主题的所有主题定制器选项,假设获取到的值是 array( 'background_color' => '#FFFFFF' )
  2. '#00FF00' 赋值给 $mods 数组中 'header_textcolor' 对应的元素,得到 $mods = array( 'background_color' => '#FFFFFF', 'header_textcolor' => '#00FF00' )
  3. 使用 update_option()$mods 数组保存到数据库中,选项名是 'theme_mods_my-awesome-theme'

如果你调用 set_theme_mod( 'header_textcolor', null ),那么 set_theme_mod() 会执行以下步骤:

  1. 使用 get_theme_mods() 获取当前主题的所有主题定制器选项,假设获取到的值是 array( 'background_color' => '#FFFFFF', 'header_textcolor' => '#FF0000' )
  2. $mods 数组中移除 'header_textcolor' 对应的元素,得到 $mods = array( 'background_color' => '#FFFFFF' )
  3. 使用 update_option()$mods 数组保存到数据库中,选项名是 'theme_mods_my-awesome-theme'

三、get_theme_mods():获取所有主题定制选项

我们上面提到了get_theme_mods(),它的源码也简单看一下,位于wp-includes/theme.php

/**
 * Get all theme modification values.
 *
 * @since 3.4.0
 *
 * @return array Theme modification values.
 */
function get_theme_mods() {
    return get_option( 'theme_mods_' . get_stylesheet() );
}

实际上就是调用了get_option(),获取'theme_mods_' . get_stylesheet()对应的值,返回的是一个包含所有主题定制选项的数组。

四、remove_theme_mod():移除单个主题定制选项

虽然 WordPress 没有直接提供 remove_theme_mod() 函数,但我们可以使用 set_theme_mod() 将选项的值设置为 null 来达到相同的效果。

例如:

set_theme_mod( 'header_textcolor', null );

这行代码会从数据库中删除 'header_textcolor' 这个主题定制器选项。

五、主题定制器选项是如何与主题定制器界面交互的?

好,现在咱们来聊聊主题定制器选项是如何与主题定制器界面交互的。这部分涉及到更多主题定制器的 API,咱们先简单了解一下。

1. WP_Customize_Manager

WordPress 主题定制器是由 WP_Customize_Manager 类来管理的。这个类负责注册主题定制器面板、区块、设置和控件。

2. add_setting() 方法

add_setting() 方法用于注册一个主题定制器设置。设置定义了选项的类型、验证规则和传输方式。

global $wp_customize;

$wp_customize->add_setting( 'header_textcolor', array(
    'default'           => '#000000',
    'sanitize_callback' => 'sanitize_hex_color',
    'transport'         => 'postMessage', // 或 'refresh'
) );
  • 'header_textcolor':设置的名称,这个名称会和get_theme_mod()set_theme_mod()的第一个参数对应。
  • 'default':默认值。
  • 'sanitize_callback':用于对用户输入进行验证和清理的回调函数。
  • 'transport':传输方式。'postMessage' 表示使用 JavaScript 实时预览,'refresh' 表示刷新整个页面。

3. add_control() 方法

add_control() 方法用于注册一个主题定制器控件。控件是用户与设置交互的界面元素,比如文本框、颜色选择器、单选按钮等。

$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'header_textcolor', array(
    'label'   => __( 'Header Text Color', 'my-awesome-theme' ),
    'section' => 'title_tagline', // 所属的区块
    'settings' => 'header_textcolor', // 关联的设置
) ) );
  • 'header_textcolor':控件的 ID。
  • 'label':控件的标签。
  • 'section':控件所属的区块。
  • 'settings':与控件关联的设置。

4. 交互流程

当用户在主题定制器界面中修改一个选项时,会发生以下流程:

  1. 用户在控件中输入新的值。
  2. JavaScript 代码将新的值发送到服务器。
  3. 服务器端的 PHP 代码调用 set_theme_mod() 函数,将新的值保存到数据库中。
  4. 如果设置的 transport'postMessage',那么 JavaScript 代码会使用 postMessage API 将新的值发送到预览窗口,实现实时预览。
  5. 如果设置的 transport'refresh',那么整个预览窗口会刷新,显示新的值。

当主题加载时,会发生以下流程:

  1. 主题调用 get_theme_mod() 函数,从数据库中读取选项的值。
  2. 主题使用读取到的值来渲染页面。

六、实战演练:自定义一个主题定制器选项

为了更好地理解 get_theme_mod()set_theme_mod() 的用法,咱们来创建一个自定义的主题定制器选项。

1. 注册设置和控件

在你的主题的 functions.php 文件中,添加以下代码:

<?php

function my_awesome_theme_customize_register( $wp_customize ) {

    // 1. 注册一个设置
    $wp_customize->add_setting( 'my_custom_text', array(
        'default'           => 'Hello, World!',
        'sanitize_callback' => 'sanitize_text_field',
        'transport'         => 'refresh',
    ) );

    // 2. 注册一个控件
    $wp_customize->add_control( 'my_custom_text', array(
        'label'    => __( 'Custom Text', 'my-awesome-theme' ),
        'section'  => 'title_tagline', // 放在 "站点身份" 区块
        'type'     => 'text', // 文本输入框
        'settings' => 'my_custom_text',
    ) );

}
add_action( 'customize_register', 'my_awesome_theme_customize_register' );

这段代码会在主题定制器中添加一个名为 "Custom Text" 的文本输入框,并将它的值保存到 'my_custom_text' 这个主题定制器选项中。

2. 在主题中使用 get_theme_mod()

在你的主题的某个模板文件中(比如 header.php),添加以下代码:

<?php
$custom_text = get_theme_mod( 'my_custom_text', 'Default Text' );
echo esc_html( $custom_text );
?>

这段代码会从数据库中读取 'my_custom_text' 选项的值,并将其显示在页面上。 如果没有设置值,则显示 "Default Text"。

3. 测试

现在,你可以打开主题定制器,找到 "站点身份" 区块,修改 "Custom Text" 文本框中的值,然后保存。 刷新页面,你应该能看到页面上显示了你修改后的文本。

七、代码示例

下面是一个更完整的示例,展示了如何在主题定制器中添加一个颜色选择器,并将选择的颜色应用到页面的背景色上。

1. 注册设置和控件

<?php

function my_awesome_theme_customize_register( $wp_customize ) {

    // 1. 添加一个区块 (Section)
    $wp_customize->add_section( 'my_custom_section', array(
        'title'    => __( 'Custom Background', 'my-awesome-theme' ),
        'priority' => 200, // 显示优先级
    ) );

    // 2. 注册一个颜色设置
    $wp_customize->add_setting( 'my_background_color', array(
        'default'           => '#FFFFFF',
        'sanitize_callback' => 'sanitize_hex_color',
        'transport'         => 'postMessage',
    ) );

    // 3. 注册一个颜色控件
    $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'my_background_color', array(
        'label'    => __( 'Background Color', 'my-awesome-theme' ),
        'section'  => 'my_custom_section', // 放在我们自定义的区块里
        'settings' => 'my_background_color',
    ) ) );

    // 4. 添加 JavaScript 实时预览
    wp_enqueue_script( 'my-awesome-theme-customizer', get_template_directory_uri() . '/js/customizer.js', array( 'customize-preview' ), false, true );

}
add_action( 'customize_register', 'my_awesome_theme_customize_register' );

2. 在 customizer.js 中添加 JavaScript 代码

在你的主题的 js 目录下创建一个名为 customizer.js 的文件,并添加以下代码:

( function( $ ) {

    wp.customize( 'my_background_color', function( value ) {
        value.bind( function( newval ) {
            $( 'body' ).css( 'background-color', newval );
        } );
    } );

} )( jQuery );

这段代码会监听 'my_background_color' 设置的变化,并将新的颜色值应用到 body 元素的背景色上。

3. 在主题中使用 get_theme_mod()

在你的主题的 header.php 文件中,添加以下代码:

<style type="text/css">
    body {
        background-color: <?php echo get_theme_mod( 'my_background_color', '#FFFFFF' ); ?>;
    }
</style>

这段代码会将 'my_background_color' 选项的值作为 body 元素的背景色。

表格总结:get_theme_mod() vs set_theme_mod()

函数 作用 参数 返回值
get_theme_mod() 读取主题定制器选项的值 $name (string): 选项名称。
$default (mixed, optional): 默认值,如果选项不存在则返回。默认为 false
选项的值 (mixed)。如果选项不存在,则返回 $default
set_theme_mod() 设置/更新主题定制器选项的值,或删除选项 (设置为 null) $name (string): 选项名称。
$value (mixed): 要设置的值。如果设置为 null,则删除该选项。
true (bool): 如果成功设置/更新/删除选项。
false (bool): 如果设置/更新/删除选项失败。

八、注意事项

  • 数据验证: 一定要对用户输入的数据进行验证和清理,以防止安全漏洞。 可以使用 WordPress 提供的 sanitize_text_field(), sanitize_hex_color(), absint() 等函数。
  • 传输方式: 选择合适的传输方式。 如果需要实时预览,可以使用 'postMessage'。 如果不需要实时预览,可以使用 'refresh'
  • 性能: 不要在主题中过度使用主题定制器选项,这可能会影响性能。 尽量将常用的选项缓存在内存中。

好了,今天的讲座就到这里。 希望大家通过今天的学习,能够更好地理解和使用 get_theme_mod()set_theme_mod() 函数,打造出更加个性化的 WordPress 主题。 下课!

发表回复

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