API налаштувань із прикладом масивів


32

Я використовую книгу розробки плагінів Wrox WordPress як основну орієнтир для початку роботи з новим плагіном, і я розумію, що всі параметри можна зберегти як 1 масив, але книга не дає приклад цього і всього іншого, що я пошук в Інтернеті здається настільки різним від одного прикладу до іншого. Друга половина повідомлення від Костянтина наближається до мене, але мені дуже хотілося б побачити більш повний приклад з кількома полями.

Відповіді:


32

Коротка відповідь: ваші 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, інакше перевірка не буде викликана. Подивіться на джерело PHP wp-admin/options-permalink.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;
}

Це досить негарно; Я б не використовував такий код у виробництві. Але він робить те, що повинен: повертає валідований масив значень. WordPress буде серіалізувати масив, зберігати його під нашим варіантом імені в базі даних і повертати його несеріалізованим, коли ми зателефонуємо get_option().


Все це працює, але це зайве складне, ми отримуємо розмітку з 1998 року ( <tr valign="top">) та багато надмірностей.

Використовуйте API налаштувань, коли потрібно. В якості альтернативи використовуйте admin_url( 'admin-post.php' )форму дії (подивіться на його джерело) та створіть сторінку із повними налаштуваннями з власним, можливо, більш елегантним кодом.

Насправді це потрібно зробити, коли ви пишете мережевий плагін, оскільки API налаштувань там не працює.

Також є деякі крайові корпуси та неповні частини, про які я тут не згадувався - ви знайдете їх, коли вам знадобляться. :)


Нічого, дякую. Це дуже корисно. Жодна з інших прочитаних вами публікацій нічого не згадувала про мережеві плагіни, що є важливою зауваженням, яку я пам’ятаю на майбутнє.
Бьорн

Просто додаток до цього. Якщо ви намагаєтеся відобразити / зберегти прапорці, я змінив код зворотного дзвінка на такий: '<type type = "checkbox" id = "% 3 $ s" name = "% 1 $ s [% 2 $ s] value =" % 4 $ s "'. Перевірено (' on ', $ args [' value '], false).' /> '
joesk

Перегляд відповіді я здивований використанням плагіна: t5_sae_option_group, який включає одну двокрапку. Я вичерпно подивився і не знайшов пояснення цього синтаксису. Чи можете ви вказати на пояснення цього в документації PHP? Дякую

@ user50909: мені це схоже на прості ідентифікатори рядків. Синтаксис PHP не повинен бути фактором.
s_ha_dum

1
@ Спробуйте basename( $_SERVER['REQUEST_URI'] ).
фуксія
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.