我将Wrox WordPress插件开发书用作开始使用新插件的主要参考资料,并且我了解所有设置都可以保存为1个数组,但是书中没有给出有关此示例以及我所从事的所有工作的示例从一个例子到另一个例子,在网络上查找似乎是如此不同。康斯坦丁(Konstantin)发表的文章的后半部分让我很接近,但我真的很想看到一个包含多个字段的更完整的示例。

#1 楼

简短的答案:您的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在那里不起作用。

还有一些边缘情况和不完整的零件,我在这里没有提到–您将在需要时找到它们。 :)

评论


哇谢谢。这非常有帮助。我读过的其他任何一篇文章都没有提到有关网络插件的任何内容,这是我将来会记住的重要注意事项。

–比约恩
13年5月21日在5:37

只是对此的附录。如果您尝试显示/存储复选框,则我已将回调代码更改为:''

–joesk
2014年4月10日在16:25



复习答案我对使用plugin:t5_sae_option_group包含一个冒号感到困惑。我已经详尽地查找过,但没有找到对此语法的解释。您能否在PHP文档中指出对此的解释?谢谢

–user50909
2014年4月27日14:41



@ user50909:对我来说,这些看起来像简单的字符串标识符。 PHP语法不应成为一个因素。

– s_ha_dum
2014年4月27日在15:04

@Dan尝试使用基名($ _SERVER ['REQUEST_URI'])。

– fuxia♦
2014年5月26日13:48