各位朋友,早上好!今天咱们来聊聊 WordPress 里面一对老朋友:get_option()
和 update_option()
。 这俩哥们儿,一个负责取,一个负责存,专门伺候 WordPress 的选项(options)。听起来简单,但里面的门道可不少,尤其是处理单值和多值选项的时候,那叫一个精彩。
咱们今天就扒开它们的源码,看看这俩家伙到底是怎么玩转单值和多值的。保证让大家听得明白,看得清楚,还能乐呵乐呵。
一、Option 是个什么玩意儿?
在 WordPress 的世界里,Option 就是一个键值对。你可以把它想象成一个简单的字典,里面装着各种各样的配置信息。 比如,网站的标题、描述、主题设置、插件配置等等,都可以用 Option 来存储。
WordPress 提供了一张表,叫做 wp_options
,专门用来存放这些 Option。 这张表里最关键的几个字段是:
option_id
: 唯一 ID,自增长。option_name
: Option 的名字,也就是键。option_value
: Option 的值,可以是字符串、数字、数组、对象,甚至是序列化后的数据。autoload
: 是否自动加载。 如果设置为yes
,WordPress 会在初始化的时候自动加载这个 Option,提高网站性能。
二、get_option()
:取经之路
咱们先来看看 get_option()
这个函数。 它的作用就是根据 Option 的名字,从数据库里把对应的值取出来。
function get_option( $option, $default = false ) {
global $wpdb;
/**
* Fires before retrieving an option.
*
* @since 2.9.0
*
* @param string $option Name of option to retrieve.
*/
do_action( 'pre_option_' . $option, $option );
// Filter the cached option value.
$cache_value = wp_cache_get( $option, 'options' );
if ( false !== $cache_value ) {
/**
* Filters the value of an existing option before it is retrieved.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.9.0
*
* @param mixed $value Value of option.
* @param string $option Name of the option.
*/
$value = apply_filters( 'option_' . $option, $cache_value, $option );
return $value;
}
// If the option exists as a site option for the current network, bypass the global option.
if ( is_multisite() ) {
$site_value = get_site_option( $option, false );
if ( false !== $site_value ) {
return $site_value;
}
}
$suppress = $wpdb->suppress_errors();
$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
$wpdb->suppress_errors( $suppress );
// Has to unserialize regardless if it is already an array.
// Sometimes options are serialized twice, so we have to check for that.
if ( is_object( $row ) ) {
$value = maybe_unserialize( $row->option_value );
} else {
$value = $default;
}
wp_cache_add( $option, $value, 'options' );
/**
* Filters the value of an option.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 1.5.0
*
* @param mixed $value Value of option.
* @param string $option Name of the option.
*/
return apply_filters( 'option_' . $option, $value, $option );
}
咱们来分解一下:
-
缓存优先:
get_option()
首先会去缓存里找,如果找到了,直接返回。 缓存是提高性能的好帮手,能避免频繁访问数据库。WordPress 用的是wp_cache_*
系列函数来操作缓存。 -
多站点判断: 如果是多站点环境,
get_option()
还会尝试从站点选项里取值。 多站点允许每个站点有自己的选项设置。 -
数据库查询: 如果缓存里没有,也不是站点选项,那就只能去数据库里查了。
get_row()
函数会执行 SQL 查询,从wp_options
表里找到option_name
对应的option_value
。 -
反序列化: 最关键的一步来了!
maybe_unserialize()
函数。 这个函数会判断option_value
是否是序列化后的数据,如果是,就把它反序列化成 PHP 的数组或者对象。 这就是get_option()
能够处理多值选项的关键所在! -
默认值: 如果数据库里没有找到对应的 Option,
get_option()
会返回你指定的默认值 ($default
)。 -
过滤器:
apply_filters( 'option_' . $option, $value, $option )
允许开发者通过过滤器来修改 Option 的值。 这是一个强大的扩展机制,可以让你在不修改 WordPress 核心代码的情况下,定制 Option 的行为。
三、update_option()
:存储之道
接下来,咱们看看 update_option()
函数,它是负责更新 Option 的。
function update_option( $option, $value, $autoload = null ) {
global $wpdb;
if ( is_protected_option( $option ) ) {
/**
* Fires when a protected option is attempted to be updated.
*
* @since 4.7.0
*
* @param string $option Name of the protected option.
* @param mixed $value Attempted new value for the protected option.
*/
do_action( 'update_option_' . $option, $option, $value );
return false;
}
/**
* Filters a specific option before its value is updated.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.6.0
*
* @param mixed $value The new, unserialized option value.
* @param mixed $old_value The old option value. It will be the same as
* $value if the option does not exist.
*/
$value = apply_filters( 'pre_update_option_' . $option, $value, get_option( $option ) );
// If the new and old values are the same, no need to update.
$old_value = get_option( $option );
if ( $value === $old_value ) {
return false;
}
/**
* Fires immediately before an option value is updated.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.9.0
*
* @param string $option Name of the option to update.
* @param mixed $old_value The old option value.
* @param mixed $value The new option value.
*/
do_action( 'update_option_' . $option, $option, $old_value, $value );
$autoload = ( null === $autoload ) ? 'yes' : $autoload;
$autoload = ( 'yes' === $autoload ) ? 'yes' : 'no';
if ( false === get_option( $option ) ) {
$suppress = $wpdb->suppress_errors();
$wpdb->query( $wpdb->prepare( "INSERT INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE `option_name` = VALUES(`option_name`), `option_value` = VALUES(`option_value`), `autoload` = VALUES(`autoload`)", $option, maybe_serialize( $value ), $autoload ) );
$wpdb->suppress_errors( $suppress );
wp_cache_add( $option, $value, 'options' );
} else {
$suppress = $wpdb->suppress_errors();
$wpdb->query( $wpdb->prepare( "UPDATE `$wpdb->options` SET `option_value` = %s, `autoload` = %s WHERE `option_name` = %s", maybe_serialize( $value ), $autoload, $option ) );
$wpdb->suppress_errors( $suppress );
wp_cache_replace( $option, $value, 'options' );
}
/**
* Fires immediately after an option value is updated.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.9.0
*
* @param string $option Name of the option to update.
* @param mixed $old_value The old option value.
* @param mixed $value The new option value.
*/
do_action( 'updated_option', $option, $old_value, $value );
do_action( 'updated_option_' . $option, $option, $old_value, $value );
return true;
}
咱们也来分解一下:
-
保护选项:
is_protected_option()
函数会检查要更新的 Option 是否是受保护的。 有些 Option 是 WordPress 核心使用的,不应该被随意修改。 -
过滤器:
apply_filters( 'pre_update_option_' . $option, $value, get_option( $option ) )
允许开发者在 Option 更新之前修改它的值。 -
值比较:
update_option()
会先比较新值和旧值,如果一样,就直接返回,避免不必要的数据库操作。 -
序列化: 关键的一步!
maybe_serialize()
函数。 这个函数会判断$value
是否是数组或者对象,如果是,就把它序列化成字符串。 这就是update_option()
能够存储多值选项的关键所在! -
数据库操作:
update_option()
会根据 Option 是否存在,执行 INSERT 或者 UPDATE 语句,把序列化后的值存入数据库。 -
缓存更新:
wp_cache_replace()
函数会更新缓存,保持数据的一致性。 -
Action 钩子:
do_action()
函数会触发一系列的 Action 钩子,允许开发者在 Option 更新之后执行一些自定义操作。
四、单值与多值:Option 的两种姿势
现在,咱们来聊聊单值和多值 Option 的区别。
-
单值 Option: Option 的值是一个简单的字符串、数字或者布尔值。 例如,网站的标题、描述、每页显示的文章数等等。
-
多值 Option: Option 的值是一个数组或者对象。 例如,主题的设置、插件的配置、用户的角色等等。
get_option()
和 update_option()
都能处理这两种类型的 Option。 关键在于 maybe_unserialize()
和 maybe_serialize()
这两个函数。
-
maybe_unserialize()
: 在get_option()
中,它负责把从数据库里取出来的序列化字符串反序列化成 PHP 的数组或者对象,让你能够方便地访问多值 Option。 -
maybe_serialize()
: 在update_option()
中,它负责把 PHP 的数组或者对象序列化成字符串,然后存入数据库。
五、代码示例:Option 的实战演练
咱们来写几个例子,演示一下如何使用 get_option()
和 update_option()
来处理单值和多值 Option。
1. 单值 Option:存储网站的每页文章数
// 获取每页文章数,如果不存在,默认值为 10
$posts_per_page = get_option( 'my_theme_posts_per_page', 10 );
// 输出每页文章数
echo '每页显示文章数:' . $posts_per_page;
// 更新每页文章数为 20
update_option( 'my_theme_posts_per_page', 20 );
2. 多值 Option:存储主题的颜色设置
// 获取颜色设置,如果不存在,使用默认值
$color_settings = get_option( 'my_theme_color_settings', array(
'background_color' => '#ffffff',
'text_color' => '#000000',
'link_color' => '#0000ff',
) );
// 输出颜色设置
echo '背景颜色:' . $color_settings['background_color'] . '<br>';
echo '文本颜色:' . $color_settings['text_color'] . '<br>';
echo '链接颜色:' . $color_settings['link_color'] . '<br>';
// 更新颜色设置
$color_settings['background_color'] = '#f0f0f0';
update_option( 'my_theme_color_settings', $color_settings );
六、Option 的注意事项
在使用 Option 的时候,有一些需要注意的地方:
-
Option Name 的唯一性: Option Name 必须是唯一的,否则会发生冲突。 建议使用前缀,例如
my_theme_
或者my_plugin_
,避免与其他主题或者插件的 Option Name 冲突。 -
Autoload 的合理使用:
autoload
设置为yes
可以提高网站性能,但是过多的自动加载会导致 WordPress 初始化变慢。 只有那些经常使用的 Option 才应该设置为自动加载。 -
Option 值的类型: 尽量保持 Option 值的类型一致。 例如,如果一个 Option 存储的是数字,就不要把它改成字符串。
-
数据安全: 对用户输入的数据进行验证和过滤,防止 SQL 注入攻击。
-
性能优化: 尽量使用缓存,避免频繁访问数据库。
七、总结:Option 的奥秘
今天咱们一起探索了 WordPress get_option()
和 update_option()
函数的源码,了解了它们是如何处理单值和多值 Option 的。 简单来说,maybe_unserialize()
和 maybe_serialize()
这两个函数是关键,它们负责在数据库存储和 PHP 变量之间进行转换。
希望今天的讲解能够帮助大家更好地理解 WordPress 的 Option 机制,写出更高效、更安全的代码。
八、彩蛋:几个常用的 Option
最后,给大家分享几个常用的 Option:
Option Name | 描述 |
---|---|
siteurl |
网站的 URL。 |
home |
网站的首页 URL。 |
blogname |
网站的标题。 |
blogdescription |
网站的描述。 |
admin_email |
管理员的邮箱。 |
users_can_register |
是否允许用户注册。 |
default_role |
默认的用户角色。 |
timezone_string |
时区。 |
date_format |
日期格式。 |
time_format |
时间格式。 |
好了,今天的讲座就到这里。 感谢大家的聆听! 如果有什么问题,欢迎随时提问。
祝大家编程愉快!