WordPress有一套注册和修改配置的机制,很多插件设置都基于这套机制实现。以BAE-Helper为例,插件的配置都是通过wp-admin/options.php更新的,详见《[BAE-Helper]实现分析v0.1》。而具体WordPress是怎么更新配置的,则需要通过源码来了解。
1. 配置更新表单
插件要通过wp-admin/options.php更新配置,需要构造相应的表单请求,WordPress为此提供了辅助函数settings_fields($option_group)。函数以插件对应的配置组为参数,用于给插件生成必要的请求参数,内容如下。
<input value="bae-helper-settings-group" name="option_page" type="hidden">
<input value="update" name="action" type="hidden">
<input value="40099a7e66" name="_wpnonce" id="_wpnonce" type="hidden">
<input value="/wp-admin/options-general.php?page=bae_helper_settings&settings-updated=true"
name="_wp_http_referer" type="hidden">
其中,“option_page”指明对应更新的是哪一个配置组;“action”表明请求是用于更新配置的;“_wpnonce”是WordPress中类似CSRF Token的东西;“_wp_http_referer”则是配置更新完成后返回的页面地址。
接到请求后,WordPress首先把“option_page”和“action”设置成了全局的变量,便于在后续逻辑中引用。
// wp-admin/options.php
/**
* wp_reset_vars可以把数组中的参数从$_GET和$_POST请求中设置到全局变量中
*/
wp_reset_vars(array('action', 'option_page'));
2. 配置白名单
获取参数后的一段代码主要是权限控制和管理员帐号配置的更新,跳过。和插件配置相关的主要是后面白名单($whitelist_options)初始化代码,白名单保存了配置组及具体的配置项列表,WordPress基于此进行配置更新控制,只有在白名单里的配置项才能被更新。
// wp-admin/options.php
$whitelist_options = array(
'general' => array( 'blogname', 'blogdescription', 'gmt_offset',
'date_format', 'time_format', 'start_of_week', 'timezone_string' )
...
, 'writing' => array( 'use_smilies', 'default_category',
'default_email_category', 'use_balanceTags', 'default_link_category',
'default_post_format' )
);
...
$whitelist_options = apply_filters( 'whitelist_options', $whitelist_options );
...
初始化时,WordPress已经把内置配置写到了白名单中,而插件的配置,则通过“whitelist_options” Filter来添加(代码倒数第二行)。
2.1. 插件配置注册流程
插件配置的注册逻辑在wp-admin/includes/plugin.php中。
// wp-admin/includes/plugin.php
function register_setting( $option_group, $option_name, $sanitize_callback = '' ) {
global $new_whitelist_options;
...
$new_whitelist_options[ $option_group ][] = $option_name;
...
}
插件注册配置时,先把新加入的配置项写到全局的
global $new_whitelist_options变量中,然后通过
“whitelist_options” Filter把插件配置写入白名单中。
// wp-admin/includes/plugin.php
function option_update_filter( $options ) {
global $new_whitelist_options;
if ( is_array( $new_whitelist_options ) )
$options = add_option_whitelist( $new_whitelist_options, $options );
return $options;
}
add_filter( 'whitelist_options', 'option_update_filter' );
具体的添加白名单逻辑则在add_option_whitelist函数中,不再赘述。
3. Update Action
白名单初始化完成后,正式进行配置的更新。
// wp-admin/options.php
/*
* 只有'update' == $action,才处理插件配置页传入的更新请求
*/
if ( 'update' == $action ) {
...
// 配置组不在白名单中,直接返回错误页
if ( !isset( $whitelist_options[ $option_page ] ) )
wp_die( __( '<strong>ERROR</strong>: options page not found.' ) );
if ( 'options' == $option_page ) {
...
} else {
// 取出配置组内的配置列表
$options = $whitelist_options[ $option_page ];
}
...
if ( $options ) {
// 遍历更新配置组下的配置项
foreach ( $options as $option ) {
...
$option = trim( $option );
$value = null;
if ( isset( $_POST[ $option ] ) ) {
$value = $_POST[ $option ];
if ( ! is_array( $value ) )
$value = trim( $value );
$value = wp_unslash( $value );
}
update_option( $option, $value );
}
}
/**
* 如果没有错误,则显示更新成功提示,否则显示错误信息
*/
if ( !count( get_settings_errors() ) )
add_settings_error('general', 'settings_updated', __('Settings saved.'), 'updated');
set_transient('settings_errors', get_settings_errors(), 30);
/**
* 配置更新后,跳回插件配置页面,通过表单的“_wp_http_referer”参数指定
*/
$goback = add_query_arg( 'settings-updated', 'true', wp_get_referer() );
wp_redirect( $goback );
exit;
}
4. 小结
以上即是WordPress插件配置的更新流程分析,可以看出,WordPress实现了一套复杂的配置更新机制,使得插件可以很方便的进行配置更新,但整体而言,其学习门槛不算很高,只要了解其插件扩展机制,基本都可以弄明白。
P. S. 文章转自自己在BAE的Blog(http://home4j.duapp.com/index.php/2013/08/20/wordpress-source-code-study-plugin-option-updating.html),欢迎来踩踩。