WordPress有一套注册和修改配置的机制,很多插件设置都基于这套机制实现。以BAE-Helper为例,插件的配置都是通过wp-admin/options.php更新的,详见《[BAE-Helper]实现分析v0.1》。而具体WordPress是怎么更新配置的,则需要通过源码来了解。
插件要通过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'));
获取参数后的一段代码主要是权限控制和管理员帐号配置的更新,跳过。和插件配置相关的主要是后面白名单($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来添加(代码倒数第二行)。
插件配置的注册逻辑在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函数中,不再赘述。
白名单初始化完成后,正式进行配置的更新。
// 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; }
以上即是WordPress插件配置的更新流程分析,可以看出,WordPress实现了一套复杂的配置更新机制,使得插件可以很方便的进行配置更新,但整体而言,其学习门槛不算很高,只要了解其插件扩展机制,基本都可以弄明白。
P. S. 文章转自自己在BAE的Blog(http://home4j.duapp.com/index.php/2013/08/20/wordpress-source-code-study-plugin-option-updating.html),欢迎来踩踩。