WordPress函数:register_setting 注册设置选项
编辑文章简介
register_setting 是 WordPress Settings API 的核心函数,用于声明一个可被后台设置表单安全更新和管理的配置选项。它将你的插件选项与WordPress的配置系统集成,自动处理数据验证、权限检查和数据库存储。
语法
register_setting 函数定义于 wp-admin/includes/plugin.php 文件中,但在 wp-admin/options.php 中被主要使用。它在 admin_init 动作钩子中被调用,负责向全局 $new_whitelist_options 数组注册设置选项,这是处理表单提交时的核心安全机制之一。
函数签名(WordPress 4.7+ 版本):
register_setting(
string $option_group,
string $option_name,
array $args = array()
);
参数与返回值说明
| 参数名 | 类型 | 必选/可选 | 默认值 | 说明 |
|---|---|---|---|---|
$option_group |
字符串 | 必选 | 无 | 设置所属的组,必须与 settings_fields() 调用中的参数一致。 |
$option_name |
字符串 | 必选 | 无 | 在数据库 wp_options 表中存储的选项名称。 |
$args |
数组 | 可选 | array() |
配置选项的详细参数数组(见下方详述)。 |
$args 数组支持的键值:
| 键名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
type |
字符串 | 'string' |
选项的数据类型(string, boolean, integer, number, array, object)。 |
description |
字符串 | '' |
选项的简短描述,可通过 REST API 获取。 |
sanitize_callback |
可调用函数 | null |
用于清理和验证用户输入的回调函数。这是安全性的关键。 |
show_in_rest |
布尔值/数组 | false |
是否通过 WordPress REST API 公开此选项。 |
default |
混合 | 无 | 选项的默认值。 |
返回值:总是返回 null。此函数的主要作用是注册设置,而非返回值。
用法
基础用法
最常见的情况是为你的插件注册一个简单的文本选项,并在设置页面上提供表单字段。以下是一个完整示例,展示如何将 register_setting 与 add_settings_field 结合使用。
<?php
/**
* Plugin Name: 我的插件设置注册示例
*/
// 防止直接访问
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// 步骤1: 在 admin_menu 钩子中添加设置页面(可参考 add_options_page 教程)
add_action( 'admin_menu', 'my_plugin_add_menu' );
function my_plugin_add_menu() {
add_options_page(
'我的插件设置',
'我的插件',
'manage_options',
'my-plugin-settings',
'my_plugin_render_settings_page'
);
}
// 步骤2: 在 admin_init 钩子中注册设置、字段和章节
add_action( 'admin_init', 'my_plugin_register_settings' );
function my_plugin_register_settings() {
// 注册一个设置选项
register_setting(
'my_plugin_settings_group', // 选项组名,必须唯一
'my_plugin_api_key', // 选项名,即 wp_options 表中的 option_name
array(
'type' => 'string',
'description' => '用于连接第三方服务的API密钥',
// 最重要的部分:清理回调函数
'sanitize_callback' => 'my_plugin_sanitize_api_key',
'default' => '',
)
);
// 添加一个设置章节(可选,但推荐用于组织)
add_settings_section(
'my_plugin_main_section',
'主要设置',
'my_plugin_section_callback',
'my-plugin-settings' // 必须与 add_options_page 的 $menu_slug 一致
);
// 为上面的设置添加一个字段
add_settings_field(
'my_plugin_api_key_field',
'API 密钥',
'my_plugin_api_key_field_callback',
'my-plugin-settings', // 页面
'my_plugin_main_section' // 章节
);
}
// 清理回调函数:负责验证和清理输入
function my_plugin_sanitize_api_key( $input ) {
// 去除首尾空格
$cleaned = trim( $input );
// 示例验证:假设API密钥必须是32位十六进制字符串
if ( ! empty( $cleaned ) && ! preg_match( '/^[a-fA-F0-9]{32}$/', $cleaned ) ) {
// 如果验证失败,添加一个设置错误,并返回旧值
add_settings_error(
'my_plugin_api_key',
'invalid_api_key',
'API密钥必须是32位十六进制字符串。'
);
// 返回数据库中已存在的旧值,而不是无效的新值
return get_option( 'my_plugin_api_key' );
}
return $cleaned; // 返回清理后的值
}
// 设置章节的回调函数(可以输出一些描述)
function my_plugin_section_callback() {
echo '<p>请在此配置插件的主要设置。</p>';
}
// 设置字段的回调函数:输出表单HTML
function my_plugin_api_key_field_callback() {
$option_value = get_option( 'my_plugin_api_key', '' ); // 获取当前值
?>
<input type="text"
id="my_plugin_api_key"
name="my_plugin_api_key" <!-- 注意:name 属性必须等于选项名 -->
value="<?php echo esc_attr( $option_value ); ?>"
class="regular-text" />
<p class="description">请输入从服务提供商处获取的32位API密钥。</p>
<?php
}
// 步骤3: 渲染设置页面的回调函数
function my_plugin_render_settings_page() {
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<!-- 必须使用 options.php 作为表单处理器 -->
<form action="options.php" method="post">
<?php
// 输出必要的安全字段(nonce等),参数必须与 register_setting 的 $option_group 一致
settings_fields( 'my_plugin_settings_group' );
// 输出指定页面上的所有设置章节和字段
do_settings_sections( 'my-plugin-settings' );
// 输出提交按钮
submit_button( '保存设置' );
?>
</form>
</div>
<?php
}
?>
进阶用法
注册一个数组类型的选项,用于存储多个相关设置值,这比注册多个独立的选项更高效,也便于管理。
// 在 my_plugin_register_settings 函数中添加
register_setting(
'my_plugin_settings_group',
'my_plugin_social_links', // 这个选项将存储一个数组
array(
'type' => 'array', // 指定类型为数组
'sanitize_callback' => 'my_plugin_sanitize_social_links',
'default' => array(
'twitter' => '',
'facebook' => '',
'linkedin' => '',
),
)
);
// 对应的清理回调函数
function my_plugin_sanitize_social_links( $input ) {
$output = array();
// 确保输入是一个数组
if ( ! is_array( $input ) ) {
return get_option( 'my_plugin_social_links' ); // 返回旧值
}
// 清理每个社交链接字段
$allowed_keys = array( 'twitter', 'facebook', 'linkedin' );
foreach ( $allowed_keys as $key ) {
if ( isset( $input[ $key ] ) ) {
// 清理URL
$output[ $key ] = esc_url_raw( trim( $input[ $key ] ) );
} else {
$output[ $key ] = '';
}
}
return $output;
}
// 为数组选项添加多个字段
add_settings_field(
'my_plugin_twitter_field',
'Twitter URL',
'my_plugin_twitter_field_callback',
'my-plugin-settings',
'my_plugin_main_section'
);
function my_plugin_twitter_field_callback() {
$options = get_option( 'my_plugin_social_links' );
$value = isset( $options['twitter'] ) ? $options['twitter'] : '';
?>
<input type="url"
id="my_plugin_twitter"
name="my_plugin_social_links[twitter]" <!-- 注意:name 使用数组语法 -->
value="<?php echo esc_url( $value ); ?>"
class="regular-text" />
<?php
}
// ... 类似地为 facebook 和 linkedin 添加字段
易错点
$option_group与settings_fields()不匹配:这是最常见的错误。register_setting的第一个参数必须与settings_fields()函数调用时的参数完全相同,否则表单无法正确提交,安全验证会失败。- 缺少或无效的
sanitize_callback:这是严重的安全漏洞。没有清理回调,用户输入将直接存入数据库。回调函数必须返回清理后的值,或通过add_settings_error()报告错误并返回旧值。 - 在
sanitize_callback中直接使用$_POST:清理回调函数的参数是已提交的、待清理的值,不是$_POST数组。直接访问$_POST会绕过 WordPress 的安全检查,并可能导致逻辑错误。 - 选项名冲突:使用过于通用的选项名(如
api_key)可能与其他插件冲突。始终使用你的插件名称作为前缀(如myplugin_api_key)。 - 对数组选项处理不当:当选项类型是数组时,
sanitize_callback收到的$input可能不是数组(例如,如果所有字段都被清空)。你的清理函数必须能处理这种情况。 - 忘记设置
default:对于新安装,如果选项不存在且用户从未保存,get_option将返回false。设置合理的default值可以确保你的代码始终有预期的数据结构。
最佳实践
安全第一:设计健壮的清理回调
清理回调不仅要去除无效字符,更要进行业务逻辑验证。例如,一个存储邮箱列表的选项,其清理函数应该:
1. 将字符串按逗号分割为数组
2. 遍历每个邮箱,使用 sanitize_email() 清理
3. 移除无效的邮箱地址
4. 限制数组的最大长度(防止滥用)
5. 返回清理后的数组
function my_plugin_sanitize_email_list( $input ) {
if ( ! is_string( $input ) ) {
return array();
}
$emails = explode( ',', $input );
$cleaned_emails = array();
foreach ( $emails as $email ) {
$email = sanitize_email( trim( $email ) );
if ( is_email( $email ) && count( $cleaned_emails ) < 50 ) { // 限制最多50个
$cleaned_emails[] = $email;
}
}
return array_unique( $cleaned_emails ); // 去重
}
利用 show_in_rest 与现代架构集成
从 WordPress 4.7 开始,register_setting 支持 show_in_rest 参数,允许你的设置通过 WordPress REST API 暴露。这对于创建基于JavaScript的现代管理界面(如使用React的Gutenberg区块或自定义管理面板)至关重要。
register_setting(
'my_plugin_settings_group',
'my_plugin_preferences',
array(
'type' => 'object',
'description' => '用户界面偏好设置',
'sanitize_callback' => 'my_plugin_sanitize_preferences',
'default' => array(
'dark_mode' => false,
'items_per_page' => 20,
),
// 通过 REST API 公开此选项
'show_in_rest' => array(
'schema' => array(
'type' => 'object',
'properties' => array(
'dark_mode' => array(
'type' => 'boolean',
),
'items_per_page' => array(
'type' => 'integer',
'minimum' => 5,
'maximum' => 100,
),
),
),
),
)
);
这样,你可以通过 GET /wp-json/wp/v2/settings 读取和 POST /wp-json/wp/v2/settings 更新这些设置(需要适当权限)。
组织代码:面向对象的封装
对于拥有多个设置的复杂插件,使用类来封装所有设置相关逻辑可以提高代码的可维护性和可读性。
class My_Plugin_Settings {
private $option_group = 'my_plugin_settings_group';
public function __construct() {
add_action( 'admin_init', array( $this, 'register_all_settings' ) );
}
public function register_all_settings() {
$this->register_api_settings();
$this->register_ui_settings();
// ... 注册更多设置
}
private function register_api_settings() {
register_setting(
$this->option_group,
'my_plugin_api_key',
array(
'sanitize_callback' => array( $this, 'sanitize_api_key' ),
'default' => '',
)
);
// 注册对应的字段...
}
public function sanitize_api_key( $input ) {
// 清理逻辑
return trim( $input );
}
// ... 其他方法
}
new My_Plugin_Settings();