各位同学,晚上好! 今天咱们来聊聊 WordPress 多站点模式下的一个关键函数:get_site_option()
。 相信不少同学都用过 get_option()
,它用来获取某个站点的选项。 那么 get_site_option()
呢? 顾名思义,它用来获取 整个网络 的选项。 听起来是不是很厉害的样子? 别怕,咱们一点点解剖它,让它在你面前变得像个透明人。
一、 啥是网络选项? 为什么要用它?
首先,我们要搞清楚啥是“网络选项”。 在 WordPress 多站点模式下,你可以把它想象成一个“总开关”。 某些设置,你希望整个网络的所有站点都遵循同一个规则, 比如:
- 网络管理员邮箱: 发送系统通知的邮箱。
- 注册设置: 是否允许新用户/站点注册。
- 上传文件类型限制: 允许上传的文件类型。
这些选项,如果每个站点都单独设置,管理起来会非常麻烦。 所以,WordPress 提供了“网络选项”,让你可以集中管理这些全局设置。
二、get_site_option()
函数:源码剖析
好,现在咱们进入正题,看看 get_site_option()
的源码(基于 WordPress 最新版本,可能会有细微差异):
function get_site_option( $option, $default = false ) {
global $wpdb, $wp_site_cache;
if ( ! is_multisite() ) {
return get_option( $option, $default );
}
$switched = false;
if ( ! isset( $wp_site_cache ) ) {
$wp_site_cache = new WP_Object_Cache();
}
$cache_key = $option;
$cache = $wp_site_cache->get( $cache_key, 'site-options' );
if ( false !== $cache ) {
/**
* Filters the value of a specific site option.
*
* The dynamic portion of the hook name, `$option`, refers to the site option name.
*
* @since 2.9.0
*
* @param mixed $value Value of the site option.
*/
return apply_filters( "site_option_{$option}", $cache );
}
// Load all options if not cached.
if ( ! isset( $wp_site_cache->cache['site-options']['alloptions'] ) ) {
$suppress = $wpdb->suppress_errors();
$alloptions = $wpdb->get_results( "SELECT option_name, option_value FROM {$wpdb->sitemeta} WHERE site_id = '{$wpdb->siteid}'" , OBJECT_K );
$wpdb->suppress_errors( $suppress );
$options = array();
foreach ( (array) $alloptions as $o ) {
$options[ $o->option_name ] = maybe_unserialize( $o->option_value );
}
$wp_site_cache->add( 'alloptions', $options, 'site-options' );
} else {
$options = $wp_site_cache->cache['site-options']['alloptions'];
}
if ( isset( $options[ $option ] ) ) {
/** This filter is documented in wp-includes/option.php */
$value = apply_filters( "site_option_{$option}", $options[ $option ] );
$wp_site_cache->add( $cache_key, $value, 'site-options' );
return $value;
}
/**
* Filters the default value of a specific site option.
*
* The dynamic portion of the hook name, `$option`, refers to the site option name.
*
* @since 2.9.0
*
* @param mixed $default Default value of the site option.
*/
return apply_filters( "default_site_option_{$option}", $default );
}
看起来有点长,别慌,咱们一段一段地分析:
2.1 前置条件:多站点检查
if ( ! is_multisite() ) {
return get_option( $option, $default );
}
这段代码很关键。 它首先检查当前 WordPress 是否运行在多站点模式下。 如果不是(! is_multisite()
),那么直接调用 get_option()
函数,也就是获取 当前站点 的选项值。 这意味着,在单站点模式下,get_site_option()
和 get_option()
的行为是完全一样的。
2.2 缓存机制:WP_Object_Cache
global $wpdb, $wp_site_cache;
if ( ! isset( $wp_site_cache ) ) {
$wp_site_cache = new WP_Object_Cache();
}
$cache_key = $option;
$cache = $wp_site_cache->get( $cache_key, 'site-options' );
if ( false !== $cache ) {
/**
* Filters the value of a specific site option.
*
* The dynamic portion of the hook name, `$option`, refers to the site option name.
*
* @since 2.9.0
*
* @param mixed $value Value of the site option.
*/
return apply_filters( "site_option_{$option}", $cache );
}
这部分代码负责缓存。 WordPress 使用 WP_Object_Cache
类来缓存网络选项,以提高性能。
global $wpdb, $wp_site_cache;
: 引入全局变量,$wpdb
用于数据库操作,$wp_site_cache
是缓存对象。if ( ! isset( $wp_site_cache ) ) { $wp_site_cache = new WP_Object_Cache(); }
:如果$wp_site_cache
未设置,则创建一个新的WP_Object_Cache
实例。$cache_key = $option;
:使用选项名作为缓存键。$cache = $wp_site_cache->get( $cache_key, 'site-options' );
:尝试从缓存中获取选项值,缓存组为 ‘site-options’。if ( false !== $cache ) { ... }
:如果缓存命中(即$cache
不是false
),则应用site_option_{$option}
过滤器并返回缓存值。 这个过滤器允许你修改缓存中的选项值。
2.3 从数据库加载选项:wp_sitemeta
表
// Load all options if not cached.
if ( ! isset( $wp_site_cache->cache['site-options']['alloptions'] ) ) {
$suppress = $wpdb->suppress_errors();
$alloptions = $wpdb->get_results( "SELECT option_name, option_value FROM {$wpdb->sitemeta} WHERE site_id = '{$wpdb->siteid}'" , OBJECT_K );
$wpdb->suppress_errors( $suppress );
$options = array();
foreach ( (array) $alloptions as $o ) {
$options[ $o->option_name ] = maybe_unserialize( $o->option_value );
}
$wp_site_cache->add( 'alloptions', $options, 'site-options' );
} else {
$options = $wp_site_cache->cache['site-options']['alloptions'];
}
如果缓存没有命中,或者缓存中没有加载所有选项,那么就需要从数据库中加载了。
if ( ! isset( $wp_site_cache->cache['site-options']['alloptions'] ) ) { ... }
:检查是否已经缓存了所有网络选项。$suppress = $wpdb->suppress_errors(); ... $wpdb->suppress_errors( $suppress );
: 临时禁止数据库错误报告,提高性能。$alloptions = $wpdb->get_results( "SELECT option_name, option_value FROM {$wpdb->sitemeta} WHERE site_id = '{$wpdb->siteid}'" , OBJECT_K );
:从wp_sitemeta
表中查询site_id
等于当前站点 ID 的所有选项。 注意:这里查询的是wp_sitemeta
表,而不是wp_options
表。wp_sitemeta
表存储网络选项,而wp_options
表存储单个站点的选项。$wpdb->siteid
包含当前站点的 ID。OBJECT_K
参数使结果集以option_name
作为键。foreach ( (array) $alloptions as $o ) { $options[ $o->option_name ] = maybe_unserialize( $o->option_value ); }
:将数据库查询结果转换为 PHP 数组,并使用maybe_unserialize()
函数反序列化选项值。$wp_site_cache->add( 'alloptions', $options, 'site-options' );
: 将所有选项缓存到WP_Object_Cache
中,键为 ‘alloptions’,缓存组为 ‘site-options’。else { $options = $wp_site_cache->cache['site-options']['alloptions']; }
:如果已经缓存了所有选项,则直接从缓存中获取。
2.4 返回选项值
if ( isset( $options[ $option ] ) ) {
/** This filter is documented in wp-includes/option.php */
$value = apply_filters( "site_option_{$option}", $options[ $option ] );
$wp_site_cache->add( $cache_key, $value, 'site-options' );
return $value;
}
if ( isset( $options[ $option ] ) ) { ... }
:检查选项是否存在于已加载的选项数组中。$value = apply_filters( "site_option_{$option}", $options[ $option ] );
:如果选项存在,则应用site_option_{$option}
过滤器,允许修改选项值。$wp_site_cache->add( $cache_key, $value, 'site-options' );
:将单个选项缓存到WP_Object_Cache
中,键为选项名,缓存组为 ‘site-options’。return $value;
:返回选项值。
2.5 返回默认值
/**
* Filters the default value of a specific site option.
*
* The dynamic portion of the hook name, `$option`, refers to the site option name.
*
* @since 2.9.0
*
* @param mixed $default Default value of the site option.
*/
return apply_filters( "default_site_option_{$option}", $default );
如果选项不存在,则应用 default_site_option_{$option}
过滤器,允许修改默认值,并返回默认值。
三、 重点总结:get_site_option()
的工作流程
为了方便大家理解,我们用一张表格来总结 get_site_option()
的工作流程:
步骤 | 描述 |
---|---|
1 | 检查是否是多站点模式。 如果不是,调用 get_option() 并返回结果。 |
2 | 尝试从缓存中获取选项值。 如果缓存命中,应用 site_option_{$option} 过滤器并返回缓存值。 |
3 | 如果缓存未命中,从 wp_sitemeta 表中加载所有网络选项,并缓存到 WP_Object_Cache 中。 |
4 | 检查选项是否存在于已加载的选项数组中。 如果存在,应用 site_option_{$option} 过滤器,缓存选项值并返回。 |
5 | 如果选项不存在,应用 default_site_option_{$option} 过滤器,并返回默认值。 |
四、 实际应用:代码示例
说了这么多理论,不如来点实际的。 咱们看几个使用 get_site_option()
的例子:
4.1 获取网络管理员邮箱:
$admin_email = get_site_option( 'admin_email' );
echo '网络管理员邮箱:' . esc_html( $admin_email );
4.2 检查是否允许新用户注册:
$registration = get_site_option( 'registration' );
if ( $registration == 'all' ) {
echo '允许新用户和站点注册';
} elseif ( $registration == 'user' ) {
echo '只允许新用户注册';
} else {
echo '不允许注册';
}
4.3 使用过滤器修改网络选项值:
function my_custom_admin_email( $email ) {
return '[email protected]';
}
add_filter( 'site_option_admin_email', 'my_custom_admin_email' );
$admin_email = get_site_option( 'admin_email' );
echo '网络管理员邮箱:' . esc_html( $admin_email ); // 输出:[email protected]
这个例子中,我们使用 site_option_admin_email
过滤器,将网络管理员邮箱修改为 [email protected]
。
4.4 使用默认值过滤器
function my_default_new_setting( $default ) {
return 'default_value';
}
add_filter( 'default_site_option_new_setting', 'my_default_new_setting' );
$new_setting = get_site_option( 'new_setting', 'fallback_value' );
echo 'New Setting: ' . esc_html( $new_setting ); // 输出:default_value
如果 new_setting
网络选项不存在,将返回 default_value
,而不是 fallback_value
。
五、 注意事项
- 性能: 尽量避免频繁调用
get_site_option()
,特别是获取同一个选项时。 可以将选项值缓存到你自己的变量中。 - 安全性: 不要直接输出
get_site_option()
获取的值,特别是用户输入相关的值。 使用esc_html()
等函数进行转义,防止 XSS 攻击。 - 上下文: 确保在多站点模式下调用
get_site_option()
。 在单站点模式下,它和get_option()
的行为是一样的。 - 数据表: 网络选项存储在
wp_sitemeta
表中,而不是wp_options
表中。
六、update_site_option()
和 delete_site_option()
和 get_site_option()
对应的,还有 update_site_option()
和 delete_site_option()
函数, 分别用于更新和删除网络选项。 它们的用法和 update_option()
和 delete_option()
类似,这里就不再赘述了。 记住,操作网络选项要谨慎,因为它们会影响整个网络的所有站点。
七、 总结
今天咱们深入剖析了 WordPress 多站点模式下的 get_site_option()
函数。 从源码分析到实际应用,希望你能对它有一个更清晰的认识。 记住,理解源码是成为 WordPress 高手的必经之路。 多阅读源码,多实践,你也能成为 WordPress 大神!
好了,今天的讲座就到这里。 感谢大家的聆听! 下次有机会,咱们再聊聊 WordPress 的其他有趣话题。 祝大家学习愉快!