WordPress函数:add_settings_field 添加设置字段
编辑文章简介
add_settings_field 函数是 WordPress Settings API 的重要组成部分,用于在后台设置页面中定义一个具体的配置字段(如表单输入框、选择框等)。它负责将字段的HTML输出逻辑与底层的数据存储逻辑连接起来。
语法
add_settings_field 函数定义于 wp-admin/includes/template.php 文件中,它向全局 $wp_settings_fields 数组添加字段信息,这些信息随后由 do_settings_sections 和 do_settings_fields 函数读取并输出。
函数签名:
add_settings_field(
string $id,
string $title,
callable $callback,
string $page,
string $section = 'default',
array $args = array()
);
参数与返回值说明
| 参数名 | 类型 | 必选/可选 | 默认值 | 说明 |
|---|---|---|---|---|
$id |
字符串 | 必选 | 无 | 字段的唯一标识符(HTML id属性的一部分)。 |
$title |
字符串 | 必选 | 无 | 字段的标签文本,显示在字段左侧。 |
$callback |
可调用函数 | 必选 | 无 | 输出字段HTML内容的回调函数。 |
$page |
字符串 | 必选 | 无 | 字段所属的设置页面slug,必须与 add_options_page 的 $menu_slug 一致。 |
$section |
字符串 | 可选 | 'default' |
字段所属的设置章节id,必须与 add_settings_section 的 $id 一致。 |
$args |
数组 | 可选 | array() |
传递给回调函数的额外参数数组。 |
返回值:
– 总是返回 null。此函数的作用是注册字段信息。
用法
基础用法
与 register_setting 和 add_settings_section 配合使用,创建一个完整的文本输入字段。
以下是一个完整示例,展示如何创建包含两个字段的设置页面:
<?php
/**
* Plugin Name: 设置字段示例插件
*/
// 防止直接访问
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// 1. 添加设置页面
add_action( 'admin_menu', 'my_plugin_add_settings_page' );
function my_plugin_add_settings_page() {
add_options_page(
'我的插件设置',
'我的插件',
'manage_options',
'my-plugin-settings',
'my_plugin_render_settings_page'
);
}
// 2. 注册设置和字段
add_action( 'admin_init', 'my_plugin_register_settings' );
function my_plugin_register_settings() {
// 注册设置选项
register_setting(
'my_plugin_settings_group',
'my_plugin_settings', // 使用一个数组存储所有设置
array(
'type' => 'array',
'sanitize_callback' => 'my_plugin_sanitize_settings',
'default' => array(
'text_field' => '',
'select_field' => 'option1',
),
)
);
// 添加设置章节
add_settings_section(
'my_plugin_main_section',
'主要设置',
'my_plugin_main_section_callback',
'my-plugin-settings'
);
// 添加文本字段
add_settings_field(
'my_plugin_text_field', // 字段ID
'文本字段', // 字段标题
'my_plugin_text_field_callback', // 输出字段HTML的回调函数
'my-plugin-settings', // 页面slug
'my_plugin_main_section', // 章节ID
array( // 传递给回调函数的额外参数
'label_for' => 'my_plugin_text_field', // 让标签关联到字段
'description' => '这是一个示例文本字段',
)
);
// 添加选择字段
add_settings_field(
'my_plugin_select_field',
'选择字段',
'my_plugin_select_field_callback',
'my-plugin-settings',
'my_plugin_main_section',
array(
'label_for' => 'my_plugin_select_field',
'description' => '请选择一个选项',
)
);
}
// 3. 清理回调函数
function my_plugin_sanitize_settings( $input ) {
$output = array();
// 清理文本字段
if ( isset( $input['text_field'] ) ) {
$output['text_field'] = sanitize_text_field( $input['text_field'] );
}
// 验证选择字段
$valid_options = array( 'option1', 'option2', 'option3' );
if ( isset( $input['select_field'] ) && in_array( $input['select_field'], $valid_options, true ) ) {
$output['select_field'] = $input['select_field'];
} else {
$output['select_field'] = 'option1'; // 默认值
}
return $output;
}
// 4. 章节回调函数
function my_plugin_main_section_callback() {
echo '<p>这里可以放置章节的描述信息。</p>';
}
// 5. 文本字段回调函数
function my_plugin_text_field_callback( $args ) {
$options = get_option( 'my_plugin_settings' );
$value = isset( $options['text_field'] ) ? $options['text_field'] : '';
?>
<input type="text"
id="<?php echo esc_attr( $args['label_for'] ); ?>"
name="my_plugin_settings[text_field]"
value="<?php echo esc_attr( $value ); ?>"
class="regular-text" />
<?php if ( ! empty( $args['description'] ) ) : ?>
<p class="description"><?php echo esc_html( $args['description'] ); ?></p>
<?php endif; ?>
<?php
}
// 6. 选择字段回调函数
function my_plugin_select_field_callback( $args ) {
$options = get_option( 'my_plugin_settings' );
$current_value = isset( $options['select_field'] ) ? $options['select_field'] : 'option1';
?>
<select id="<?php echo esc_attr( $args['label_for'] ); ?>"
name="my_plugin_settings[select_field]">
<option value="option1" <?php selected( $current_value, 'option1' ); ?>>选项一</option>
<option value="option2" <?php selected( $current_value, 'option2' ); ?>>选项二</option>
<option value="option3" <?php selected( $current_value, 'option3' ); ?>>选项三</option>
</select>
<?php if ( ! empty( $args['description'] ) ) : ?>
<p class="description"><?php echo esc_html( $args['description'] ); ?></p>
<?php endif; ?>
<?php
}
// 7. 渲染设置页面
function my_plugin_render_settings_page() {
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<form action="options.php" method="post">
<?php
settings_fields( 'my_plugin_settings_group' );
do_settings_sections( 'my-plugin-settings' );
submit_button( '保存设置' );
?>
</form>
</div>
<?php
}
?>
进阶用法
创建可重复添加的动态字段组,比如允许用户添加多个自定义链接。
// 在注册设置时,使用数组存储多个链接
register_setting(
'my_plugin_settings_group',
'my_plugin_custom_links',
array(
'type' => 'array',
'sanitize_callback' => 'my_plugin_sanitize_custom_links',
'default' => array(),
)
);
// 动态字段组的回调函数
function my_plugin_links_field_callback() {
$links = get_option( 'my_plugin_custom_links', array() );
// 添加一个空项用于JavaScript克隆
$links[] = array( 'title' => '', 'url' => '' );
echo '<div id="custom-links-container">';
foreach ( $links as $index => $link ) {
$title = isset( $link['title'] ) ? $link['title'] : '';
$url = isset( $link['url'] ) ? $link['url'] : '';
?>
<div class="custom-link-row" data-index="<?php echo esc_attr( $index ); ?>">
<input type="text"
name="my_plugin_custom_links[<?php echo esc_attr( $index ); ?>][title]"
value="<?php echo esc_attr( $title ); ?>"
placeholder="链接标题"
class="regular-text" />
<input type="url"
name="my_plugin_custom_links[<?php echo esc_attr( $index ); ?>][url]"
value="<?php echo esc_url( $url ); ?>"
placeholder="https://example.com"
class="regular-text" />
<button type="button" class="button remove-link">移除</button>
</div>
<?php
}
echo '</div>';
echo '<button type="button" id="add-link" class="button">添加链接</button>';
// 简单的JavaScript用于动态添加/移除行
?>
<script>
jQuery(document).ready(function($) {
$('#add-link').on('click', function() {
var container = $('#custom-links-container');
var index = container.find('.custom-link-row').length;
var html = '<div class="custom-link-row" data-index="' + index + '">' +
'<input type="text" name="my_plugin_custom_links[' + index + '][title]" value="" placeholder="链接标题" class="regular-text" /> ' +
'<input type="url" name="my_plugin_custom_links[' + index + '][url]" value="" placeholder="https://example.com" class="regular-text" /> ' +
'<button type="button" class="button remove-link">移除</button>' +
'</div>';
container.append(html);
});
$(document).on('click', '.remove-link', function() {
if ($('.custom-link-row').length > 1) {
$(this).closest('.custom-link-row').remove();
}
});
});
</script>
<?php
}
// 对应的清理函数
function my_plugin_sanitize_custom_links( $input ) {
if ( ! is_array( $input ) ) {
return array();
}
$output = array();
foreach ( $input as $link ) {
if ( empty( $link['title'] ) && empty( $link['url'] ) ) {
continue; // 跳过空行
}
$title = sanitize_text_field( $link['title'] );
$url = esc_url_raw( $link['url'] );
if ( ! empty( $title ) || ! empty( $url ) ) {
$output[] = array(
'title' => $title,
'url' => $url,
);
}
}
return $output;
}
易错点
- 字段ID不唯一:在同一页面内,字段ID必须是唯一的,否则会导致HTML id属性冲突,可能影响JavaScript操作和CSS样式。
- 页面slug不匹配:
add_settings_field的$page参数必须与add_options_page的$menu_slug以及add_settings_section的$page参数完全一致,包括大小写。 - 章节ID不匹配:如果指定了
$section参数,必须与add_settings_section的$id完全一致,否则字段不会出现在预期的章节中。 - 回调函数未输出正确的name属性:字段的
name属性必须与register_setting的选项名匹配。对于简单选项,直接使用选项名;对于数组选项,使用option_name[key]格式。 - 忘记转义输出:在回调函数中输出任何动态数据时,必须使用适当的转义函数。标签文本使用
esc_html,输入框值使用esc_attr,URL使用esc_url。 - 在回调函数中直接访问
$_POST:字段回调函数只负责输出HTML,不应该处理表单提交。表单数据处理应由register_setting的sanitize_callback处理。 - 使用
selected()和checked()函数不正确:这些辅助函数需要三个参数(当前值、比较值、是否回显),但第三个参数通常省略(默认为true)。确保比较逻辑正确。
最佳实践
使用 $args 参数传递上下文信息
通过 $args 参数向回调函数传递额外的上下文信息,可以使回调函数更加灵活和可复用。
// 定义字段时传递自定义参数
add_settings_field(
'my_plugin_email_field',
'邮箱地址',
'my_plugin_generic_text_field_callback',
'my-plugin-settings',
'my_plugin_main_section',
array(
'label_for' => 'my_plugin_email_field',
'option_name' => 'my_plugin_settings',
'field_key' => 'email',
'type' => 'email', // 指定输入类型
'description' => '请输入有效的邮箱地址',
'class' => 'regular-text ltr', // 添加CSS类
'placeholder' => 'user@example.com',
)
);
// 通用的文本字段回调函数
function my_plugin_generic_text_field_callback( $args ) {
$options = get_option( $args['option_name'] );
$value = isset( $options[ $args['field_key'] ] ) ? $options[ $args['field_key'] ] : '';
$type = isset( $args['type'] ) ? $args['type'] : 'text';
$class = isset( $args['class'] ) ? $args['class'] : 'regular-text';
$placeholder = isset( $args['placeholder'] ) ? $args['placeholder'] : '';
?>
<input type="<?php echo esc_attr( $type ); ?>"
id="<?php echo esc_attr( $args['label_for'] ); ?>"
name="<?php echo esc_attr( $args['option_name'] . '[' . $args['field_key'] . ']' ); ?>"
value="<?php echo esc_attr( $value ); ?>"
class="<?php echo esc_attr( $class ); ?>"
placeholder="<?php echo esc_attr( $placeholder ); ?>"
<?php echo ( isset( $args['required'] ) && $args['required'] ) ? 'required' : ''; ?> />
<?php if ( ! empty( $args['description'] ) ) : ?>
<p class="description"><?php echo esc_html( $args['description'] ); ?></p>
<?php endif; ?>
<?php
}
字段回调函数的模块化设计
将不同类型的字段抽象为独立的函数或类方法,提高代码复用性。
class My_Plugin_Field_Renderer {
public static function render_text_field( $args ) {
$defaults = array(
'option_name' => '',
'field_key' => '',
'value' => '',
'type' => 'text',
'class' => 'regular-text',
'placeholder' => '',
'description' => '',
);
$args = wp_parse_args( $args, $defaults );
?>
<input type="<?php echo esc_attr( $args['type'] ); ?>"
id="<?php echo esc_attr( $args['field_key'] ); ?>"
name="<?php echo esc_attr( $args['option_name'] . '[' . $args['field_key'] . ']' ); ?>"
value="<?php echo esc_attr( $args['value'] ); ?>"
class="<?php echo esc_attr( $args['class'] ); ?>"
placeholder="<?php echo esc_attr( $args['placeholder'] ); ?>" />
<?php if ( $args['description'] ) : ?>
<p class="description"><?php echo esc_html( $args['description'] ); ?></p>
<?php endif; ?>
<?php
}
public static function render_select_field( $args ) {
$defaults = array(
'option_name' => '',
'field_key' => '',
'value' => '',
'options' => array(),
'class' => '',
'description' => '',
);
$args = wp_parse_args( $args, $defaults );
?>
<select id="<?php echo esc_attr( $args['field_key'] ); ?>"
name="<?php echo esc_attr( $args['option_name'] . '[' . $args['field_key'] . ']' ); ?>"
class="<?php echo esc_attr( $args['class'] ); ?>">
<?php foreach ( $args['options'] as $option_value => $option_label ) : ?>
<option value="<?php echo esc_attr( $option_value ); ?>"
<?php selected( $args['value'], $option_value ); ?>>
<?php echo esc_html( $option_label ); ?>
</option>
<?php endforeach; ?>
</select>
<?php if ( $args['description'] ) : ?>
<p class="description"><?php echo esc_html( $args['description'] ); ?></p>
<?php endif; ?>
<?php
}
}
// 在字段回调中使用
function my_plugin_special_field_callback() {
$options = get_option( 'my_plugin_settings' );
My_Plugin_Field_Renderer::render_text_field( array(
'option_name' => 'my_plugin_settings',
'field_key' => 'special_field',
'value' => isset( $options['special_field'] ) ? $options['special_field'] : '',
'type' => 'text',
'class' => 'regular-text',
'placeholder' => '请输入内容',
'description' => '这是一个特殊字段',
) );
}
与 WordPress 核心UI样式保持一致
使用WordPress核心的CSS类来确保字段样式与后台其他部分一致,提供一致的用户体验。
regular-text:普通宽度文本输入框large-text:宽文本输入框small-text:小文本输入框code:等宽字体,适合代码color-picker:颜色选择器字段date-picker:日期选择器字段
// 使用WordPress核心样式类
function my_plugin_field_with_classes_callback() {
$value = get_option( 'my_plugin_field', '' );
?>
<input type="text" class="regular-text code" value="<?php echo esc_attr( $value ); ?>" />
<p class="description">使用 <code>regular-text code</code> 类显示等宽字体</p>
<textarea class="large-text" rows="5"></textarea>
<p class="description">使用 <code>large-text</code> 类创建多行文本框</p>
<input type="text" class="small-text" value="100" />
<p class="description">使用 <code>small-text</code> 类创建小宽度输入框</p>
<?php
}
条件显示字段
根据其他字段的值动态显示或隐藏相关字段,提供更智能的用户界面。
// 在字段回调中添加JavaScript实现条件逻辑
function my_plugin_conditional_field_callback() {
$options = get_option( 'my_plugin_settings' );
$enable_feature = isset( $options['enable_feature'] ) ? $options['enable_feature'] : 'no';
$feature_option = isset( $options['feature_option'] ) ? $options['feature_option'] : '';
?>
<fieldset>
<label>
<input type="radio" name="my_plugin_settings[enable_feature]" value="yes"
<?php checked( $enable_feature, 'yes' ); ?> />
启用功能
</label><br>
<label>
<input type="radio" name="my_plugin_settings[enable_feature]" value="no"
<?php checked( $enable_feature, 'no' ); ?> />
禁用功能
</label>
</fieldset>
<div id="feature-options-wrapper" style="<?php echo ( 'yes' !== $enable_feature ) ? 'display:none;' : ''; ?>">
<input type="text"
name="my_plugin_settings[feature_option]"
value="<?php echo esc_attr( $feature_option ); ?>"
class="regular-text"
placeholder="功能选项" />
</div>
<script>
jQuery(document).ready(function($) {
$('input[name="my_plugin_settings[enable_feature]"]').on('change', function() {
if ($(this).val() === 'yes') {
$('#feature-options-wrapper').show();
} else {
$('#feature-options-wrapper').hide();
}
});
});
</script>
<?php
}