问题描述
我使用 Wrox WordPress 插件开发书作为开始使用新插件的主要参考,我理解所有设置可以保存为 1 数组,但是这本书没有给出一个这样的例子,我所有的东西在网络上的发现似乎与一个例子不同。 post by Konstantin 的下半部分让我很近,但我真的很想看到一个更多的例子,它有多个字段。
最佳解决方案
简短的答案:您的 name
属性值必须使用模式 option_name[array_key]
。所以,当你使用…
<input name="option_name[key1]">
<input name="option_name[key2]">
你在验证函数中得到一个数组作为选项值:
array (
'key1' => 'some value',
'key2' => 'some other value'
)
PHP 为你做,这不是 WordPress 的功能。 🙂
如何使用设置 API 进行工作?
假设我们想要这个选项页面,所有的值都应存储在一个选项中,并在一个函数中进行验证。
选项页面
我们需要钩子 admin_menu
和两个功能:一个用于注册页面,一个用于渲染输出。
add_action( 'admin_menu', 't5_sae_add_options_page' );
function t5_sae_add_options_page()
{
add_options_page(
'T5 Settings API Example', // $page_title,
'T5 SAE', // $menu_title,
'manage_options', // $capability,
't5_sae_slug', // $menu_slug
't5_sae_render_page' // Callback
);
}
function t5_sae_render_page()
{
?>
<div class="wrap">
<h2><?php print $GLOBALS['title']; ?></h2>
<form action="options.php" method="POST">
<?php
settings_fields( 'plugin:t5_sae_option_group' );
do_settings_sections( 't5_sae_slug' );
submit_button();
?>
</form>
</div>
<?php
}
action
的格式必须为 options.php
,否则不会调用验证。看看 wp-admin/options-permalink.php
的 PHP 源码 – 有一个隐藏的陷阱 do_settings_sections('permalink');
– 但它不能工作,因为 action
的形式是错误的。
现在,回到我们的自定义页面。我们使它比 WordPress 更好。
注册设置,部分和字段
当我们需要它并调用注册功能时,我们挂接到 admin_init
。
if ( ! empty ( $GLOBALS['pagenow'] )
and ( 'options-general.php' === $GLOBALS['pagenow']
or 'options.php' === $GLOBALS['pagenow']
)
)
{
add_action( 'admin_init', 't5_sae_register_settings' );
}
这里的重要部分是:$GLOBALS['pagenow']
必须是 options-general.php
(用于输出) 或 options.php
(用于验证) 。请勿在每个请求上调用以下所有代码。大多数教程和几乎所有的插件都会出错。
好的,让我们注册一下疯狂:
-
我们获取页面的选项值,并根据某些默认值对其进行解析。相当基本
-
我们注册一个名称为
plugin:t5_sae_option_group
的设置组。我喜欢前缀名称,它们更容易排序和理解这种方式。 -
然后我们注册两个部分,1 和 2 。
-
我们添加三个部分,第二部分为第二部分,第二部分为第一部分。我们将选项名称和转义值传递给每个字段的回调函数。输出处理程序不应该更改数据,只需添加一些 HTML 。
function t5_sae_register_settings()
{
$option_name = 'plugin:t5_sae_option_name';
// Fetch existing options.
$option_values = get_option( $option_name );
$default_values = array (
'number' => 500,
'color' => 'blue',
'long' => ''
);
// Parse option values into predefined keys, throw the rest away.
$data = shortcode_atts( $default_values, $option_values );
register_setting(
'plugin:t5_sae_option_group', // group, used for settings_fields()
$option_name, // option name, used as key in database
't5_sae_validate_option' // validation callback
);
/* No argument has any relation to the prvious register_setting(). */
add_settings_section(
'section_1', // ID
'Some text fields', // Title
't5_sae_render_section_1', // print output
't5_sae_slug' // menu slug, see t5_sae_add_options_page()
);
add_settings_field(
'section_1_field_1',
'A Number',
't5_sae_render_section_1_field_1',
't5_sae_slug', // menu slug, see t5_sae_add_options_page()
'section_1',
array (
'label_for' => 'label1', // makes the field name clickable,
'name' => 'number', // value for 'name' attribute
'value' => esc_attr( $data['number'] ),
'option_name' => $option_name
)
);
add_settings_field(
'section_1_field_2',
'Select',
't5_sae_render_section_1_field_2',
't5_sae_slug', // menu slug, see t5_sae_add_options_page()
'section_1',
array (
'label_for' => 'label2', // makes the field name clickable,
'name' => 'color', // value for 'name' attribute
'value' => esc_attr( $data['color'] ),
'options' => array (
'blue' => 'Blue',
'red' => 'Red',
'black' => 'Black'
),
'option_name' => $option_name
)
);
add_settings_section(
'section_2', // ID
'Textarea', // Title
't5_sae_render_section_2', // print output
't5_sae_slug' // menu slug, see t5_sae_add_options_page()
);
add_settings_field(
'section_2_field_1',
'Notes',
't5_sae_render_section_2_field_1',
't5_sae_slug', // menu slug, see t5_sae_add_options_page()
'section_2',
array (
'label_for' => 'label3', // makes the field name clickable,
'name' => 'long', // value for 'name' attribute
'value' => esc_textarea( $data['long'] ),
'option_name' => $option_name
)
);
}
当我们在页面中调用 do_settings_sections( 't5_sae_slug' );
时,这些部分和字段的所有回调处理程序将被自动调用。我们已经做到了,所以我们只需要…
打印字段
注意 name
属性是如何构建的:通过的 option_name
是第一部分,数组键位于方括号 []
中。
function t5_sae_render_section_1()
{
print '<p>Pick a number between 1 and 1000, and choose a color.</p>';
}
function t5_sae_render_section_1_field_1( $args )
{
/* Creates this markup:
/* <input name="plugin:t5_sae_option_name[number]"
*/
printf(
'<input name="%1$s[%2$s]" id="%3$s" value="%4$s" class="regular-text">',
$args['option_name'],
$args['name'],
$args['label_for'],
$args['value']
);
// t5_sae_debug_var( func_get_args(), __FUNCTION__ );
}
function t5_sae_render_section_1_field_2( $args )
{
printf(
'<select name="%1$s[%2$s]" id="%3$s">',
$args['option_name'],
$args['name'],
$args['label_for']
);
foreach ( $args['options'] as $val => $title )
printf(
'<option value="%1$s" %2$s>%3$s</option>',
$val,
selected( $val, $args['value'], FALSE ),
$title
);
print '</select>';
// t5_sae_debug_var( func_get_args(), __FUNCTION__ );
}
function t5_sae_render_section_2()
{
print '<p>Makes some notes.</p>';
}
function t5_sae_render_section_2_field_1( $args )
{
printf(
'<textarea name="%1$s[%2$s]" id="%3$s" rows="10" cols="30" class="code">%4$s</textarea>',
$args['option_name'],
$args['name'],
$args['label_for'],
$args['value']
);
}
哦,我介绍了一个功能 t5_sae_debug_var()
。这里是:
function t5_sae_debug_var( $var, $before = '' )
{
$export = esc_html( var_export( $var, TRUE ) );
print "<pre>$before = $export</pre>";
}
有用的,看看我们是否得到了我们的期望。
现在,这很好,我们只需要一件事情:
验证选项数组
因为我们使用括号符号,我们的值是一个数组。我们只需要遍历每个元素并验证它。
function t5_sae_validate_option( $values )
{
$default_values = array (
'number' => 500,
'color' => 'blue',
'long' => ''
);
if ( ! is_array( $values ) ) // some bogus data
return $default_values;
$out = array ();
foreach ( $default_values as $key => $value )
{
if ( empty ( $values[ $key ] ) )
{
$out[ $key ] = $value;
}
else
{
if ( 'number' === $key )
{
if ( 0 > $values[ $key ] )
add_settings_error(
'plugin:t5_sae_option_group',
'number-too-low',
'Number must be between 1 and 1000.'
);
elseif ( 1000 < $values[ $key ] )
add_settings_error(
'plugin:t5_sae_option_group',
'number-too-high',
'Number must be between 1 and 1000.'
);
else
$out[ $key ] = $values[ $key ];
}
elseif ( 'long' === $key )
{
$out[ $key ] = trim( $values[ $key ] );
}
else
{
$out[ $key ] = $values[ $key ];
}
}
}
return $out;
}
这很丑陋我不会在生产中使用这样的代码。但它应该做到这一点:它返回一个经过验证的值数组。当我们调用 get_option()
时,WordPress 将序列化数组,将其存储在数据库中的选项名称下,并将其返回非串行化。
所有这些都是有效的,但这是不必要的复杂的,我们从 1998 年 (<tr valign="top">
) 获得加价,并有很多冗余。
必须使用设置 API 。作为替代使用 admin_url( 'admin-post.php' )
作为表单动作 (查看其来源),并使用自己的,可能更优雅的代码创建完整的设置页面。
实际上,当你编写网络插件时,你必须这样做,因为设置 API 在这里不起作用。
还有一些边案例和不完整的部分,我没有在这里提到 – 你会发现他们,当你需要它们。 🙂
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。