問題描述

我使用 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(用於驗證) 。請勿在每個請求上呼叫以下所有程式碼。大多數教程和幾乎所有的外掛都會出錯。

好的,讓我們註冊一下瘋狂:

  1. 我們獲取頁面的選項值,並根據某些預設值對其進行解析。相當基本

  2. 我們註冊一個名稱為 plugin:t5_sae_option_group 的設定組。我喜歡字首名稱,它們更容易排序和理解這種方式。

  3. 然後我們註冊兩個部分,1 和 2 。

  4. 我們新增三個部分,第二部分為第二部分,第二部分為第一部分。我們將選項名稱和轉義值傳遞給每個欄位的回撥函式。輸出處理程序不應該更改資料,只需新增一些 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 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。