API de configurações com exemplo de matrizes

32

Estou usando o livro de desenvolvimento de plugins Wrox para WordPress como referência principal para começar a usar um novo plug-in e entendo que todas as configurações podem ser salvas como 1 array, mas o livro não dá um exemplo disso e de tudo Eu estou achando na web parece tão diferente de um exemplo para outro. A segunda metade de um post de Konstantin me aproxima, mas eu realmente gostaria de ver mais exemplo completo com vários campos.

    
por Bjorn 20.05.2013 / 02:51
fonte

1 resposta

31

Resposta curta: seus valores de atributo name devem usar o esquema option_name[array_key] . Então, quando você usa…

<input name="option_name[key1]">
<input name="option_name[key2]">

… você obtém um array como valor da opção na sua função de validação:

array (
    'key1' => 'some value',
    'key2' => 'some other value'
)

PHP faz isso por você, este não é um recurso do WordPress. :)

Como fazer isso funcionar com a API de configurações?

Digamos que queremos essa página de opções, e todos os valores devem ser armazenados em uma opção e validados em uma função.

  

Apáginadeopções

Precisamosdoganchoadmin_menuededuasfunções:umapararegistrarapágina,umapararenderizarasaída.

add_action('admin_menu','t5_sae_add_options_page');functiont5_sae_add_options_page(){add_options_page('T5SettingsAPIExample',//$page_title,'T5SAE',//$menu_title,'manage_options',//$capability,'t5_sae_slug',//$menu_slug't5_sae_render_page'//Callback);}functiont5_sae_render_page(){?><divclass="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
}

O formulário action deve ser options.php ou a validação não será chamada. Olhe para a fonte PHP de wp-admin/options-permalink.php - existe uma armadilha oculta do_settings_sections('permalink'); - mas ela não funciona porque o formulário action está errado.

Agora, voltemos à nossa página personalizada. Nós o fazemos melhor que o WordPress.

Registrar configurações, seções e campos

Nós conectamos em admin_init quando precisamos e chamamos uma função de registro.

if ( ! empty ( $GLOBALS['pagenow'] )
    and ( 'options-general.php' === $GLOBALS['pagenow']
        or 'options.php' === $GLOBALS['pagenow']
    )
)
{
    add_action( 'admin_init', 't5_sae_register_settings' );
}

A parte importante aqui é: $GLOBALS['pagenow'] deve ser options-general.php (para a saída) ou options.php (para a validação). Não chame todo o código a seguir em cada solicitação. A maioria dos tutoriais e quase todos os plugins entendem isso errado.

Ok, vamos registrar como um louco:

  1. Buscamos os valores das opções para nossa página e os analisamos em relação a alguns padrões. Bastante básico.

  2. Registramos um grupo de configurações com o nome plugin:t5_sae_option_group . Eu gosto de nomes prefixados, eles são mais fáceis de classificar e entender dessa maneira.

  3. Em seguida, registramos duas seções, 1 e 2.

  4. E adicionamos três seções, duas para a primeira seção e uma para a segunda. Nós passamos o nome da opção e o valor escapou para as funções de retorno de chamada para cada campo. Os manipuladores de saída não devem alterar os dados, basta adicionar um pouco de 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
        )
    );
}

Todos os manipuladores de retorno de chamada para as seções e campos serão chamados automaticamente quando chamarmos do_settings_sections( 't5_sae_slug' ); em nossa página. Nós já fizemos isso, então precisamos apenas…

Imprimir os campos

Observe como os atributos name são criados: o% passado option_name é a primeira parte, a chave da matriz segue entre colchetes [] .

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']
    );
}

Oh, eu introduzi uma função t5_sae_debug_var() . Aqui está:

function t5_sae_debug_var( $var, $before = '' )
{
    $export = esc_html( var_export( $var, TRUE ) );
    print "<pre>$before = $export</pre>";
}

Útil para ver se conseguimos o que esperávamos.

Agora, isso funciona muito bem, precisamos de apenas uma coisa:

Validar a matriz de opções

Como usamos a notação de colchetes, nosso valor é uma matriz. Nós apenas temos que percorrer cada elemento e validá-lo.

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;
}

Isso é bastante feio; Eu não usaria esse código em produção. Mas faz o que deve: retorna uma matriz validada de valores. O WordPress irá serializar o array, armazená-lo em nosso nome de opção no banco de dados e retorná-lo não serializado, quando chamarmos get_option() .

Tudo isso funciona, mas é desnecessariamente complicado, recebemos a marcação de 1998 ( <tr valign="top"> ) e muitas redundâncias.

Use a API de configurações quando for necessário. Como alternativa, use admin_url( 'admin-post.php' ) como ação de formulário (observe sua origem) e crie a página de configurações completa com seu próprio código, provavelmente mais elegante.

Na verdade, você precisa fazer isso quando escreve um plug-in de rede, porque a API de configurações não funciona lá.

Existem também alguns casos de limites e partes incompletas que não mencionei aqui - você os encontrará quando precisar deles. :)

    
por fuxia 21.05.2013 / 01:17
fonte