Configuración API con ejemplos de matrices

32

Estoy usando el libro de desarrollo del complemento Wrox WordPress como referencia principal para comenzar con un nuevo complemento y entiendo que todas las configuraciones se pueden guardar como 1 matriz, pero el libro no da un ejemplo de esto y todo lo que estoy haciendo. encontrar en la web parece muy diferente de un ejemplo a otro. La segunda mitad de una publicación de Konstantin me acerca, pero realmente me gustaría ver un ejemplo más completo con múltiples campos.

Bjorn
fuente

Respuestas:

32

Respuesta corta: los namevalores de sus atributos deben usar el esquema option_name[array_key]. Entonces, cuando usas ...

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

... obtienes una matriz como valor de opción en tu función de validación:

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

PHP lo hace por usted, esta no es una característica de WordPress. :)

¿Cómo hacer que eso funcione con la API de configuración?

Digamos que queremos esta página de opciones, y todos los valores deben almacenarse en una opción y validarse en una función.

ingrese la descripción de la imagen aquí

La página de opciones

Necesitamos el gancho admin_menuy dos funciones: una para registrar la página, otra para representar la salida.

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
}

El formulario actiondebe ser options.phpo no se llamará a la validación. Mire la fuente PHP de wp-admin/options-permalink.php- hay una trampa oculta do_settings_sections('permalink');- pero no puede funcionar porque el formulario actiones incorrecto.

Ahora, de vuelta a nuestra página personalizada. Lo hacemos mejor que WordPress.

Registrar configuraciones, secciones y campos

Nos conectamos admin_init cuando lo necesitamos y llamamos a una función 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' );
}

La parte importante aquí es: $GLOBALS['pagenow']debe ser options-general.php(para la salida) o options.php(para la validación). No llame a todos los siguientes códigos en cada solicitud. La mayoría de los tutoriales y casi todos los complementos se equivocan.

Bien, registremos como locos:

  1. Buscamos los valores de opción para nuestra página y los analizamos en función de algunos valores predeterminados. Bastante básico

  2. Registramos un grupo de configuraciones con el nombre plugin:t5_sae_option_group. Me gustan los nombres prefijados, son más fáciles de ordenar y entender de esta manera.

  3. Luego registramos dos secciones, 1 y 2.

  4. Y agregamos tres secciones, dos para la primera sección, una para la segunda. Pasamos el nombre de la opción y el valor escapado a las funciones de devolución de llamada para cada campo. Los controladores de salida no deben cambiar los datos, solo agregue algo 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 esos controladores de devolución de llamada para las secciones y campos se llamarán automáticamente cuando llamemos do_settings_sections( 't5_sae_slug' );a nuestra página. Ya lo hicimos, así que solo necesitamos ...

Imprimir los campos

Tenga en cuenta cómo namese crean los atributos: lo aprobado option_namees la primera parte, la clave de la matriz sigue entre corchetes [].

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, introduje una función t5_sae_debug_var(). Aquí está:

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

Útil para ver si obtuvimos lo que esperábamos.

Ahora, esto funciona bastante bien, solo necesitamos una cosa:

Validar la matriz de opciones

Debido a que usamos la notación de corchetes, nuestro valor es una matriz. Solo tenemos que recorrer cada elemento y validarlo.

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

Esto es bastante feo; No usaría ese código en producción. Pero hace lo que debería: devuelve una matriz validada de valores. WordPress serializará la matriz, la almacenará con el nombre de nuestra opción en la base de datos y la devolverá sin serializar, cuando llamemos get_option().


Todo esto funciona, pero es innecesariamente complicado, obtenemos marcado desde 1998 ( <tr valign="top">) y muchas redundancias.

Use la API de configuración cuando sea necesario. Como uso alternativo admin_url( 'admin-post.php' )como acción de formulario (mire su fuente) y cree la página de configuración completa con su propio código, probablemente más elegante.

En realidad, debes hacerlo cuando escribes un complemento de red, porque la API de configuración no funciona allí.

También hay algunos casos extremos y partes incompletas que no mencioné aquí: los encontrará cuando los necesite. :)

fuxia
fuente
Wow gracias. Esto es muy útil. Ninguna de las otras publicaciones que leí mencionó nada sobre los complementos de red, lo cual es una nota importante que tendré en cuenta para el futuro.
Bjorn
Solo una adición a esto. Si está intentando mostrar / almacenar casillas de verificación, he modificado el código de devolución de llamada para que sea: '<input type = "checkbox" id = "% 3 $ s" name = "% 1 $ s [% 2 $ s] value =" % 4 $ s "'. Verificado (' on ', $ args [' value '], false).' /> '
joesk
Al revisar la respuesta, estoy desconcertado por el uso del complemento: t5_sae_option_group, que incluye dos puntos. He buscado exhaustivamente y no he encontrado una explicación de esta sintaxis. ¿Podría señalar una explicación de esto en la documentación de PHP, por favor? Gracias
@ user50909: me parecen identificadores de cadena simples. La sintaxis de PHP no debería ser un factor.
s_ha_dum
1
@Dan Try basename( $_SERVER['REQUEST_URI'] ).
fuxia