Respuesta corta: los valores del atributo name
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 hace eso por ti, esto no es una característica de WordPress. :)
¿Cómo hacer que funcione con la configuración de la API?
Digamos que queremos esta página de opciones, y todos los valores deben almacenarse en una opción y validarse en una función.

Lapáginadeopciones
Necesitamoselganchoadmin_menu
ydosfunciones:unapararegistrarlapágina,unapararepresentarlasalida.
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
}
El formulario action
debe ser options.php
, o no se llamará la validación. Mire la fuente de PHP de wp-admin/options-permalink.php
- hay una captura oculta do_settings_sections('permalink');
- pero no puede funcionar porque la forma action
es incorrecta.
Ahora, de vuelta a nuestra página personalizada. Lo hacemos mejor que WordPress.
Registrar configuraciones, secciones y campos
Nos conectamos a 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, registrémonos como locos:
-
Recogemos los valores de las opciones de nuestra página y los analizamos contra algunos valores predeterminados. Bastante básico.
-
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.
-
Luego registramos dos secciones, 1 y 2.
-
Y agregamos tres secciones, dos para la primera sección, una para la segunda. Pasamos el nombre de la opción y el valor escaped 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 los controladores de devolución de llamada para las secciones y los campos se llamarán automáticamente cuando llamemos a do_settings_sections( 't5_sae_slug' );
en nuestra página. Ya lo hicimos, así que solo tenemos que ...
Imprimir los campos
Observe cómo se crean los atributos name
: la% parte pasada option_name
es 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 corchete, 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 tal código en producción. Pero hace lo que debe: devuelve una matriz validada de valores. WordPress serializará la matriz, la almacenará bajo el nombre de nuestra opción en la base de datos y la devolverá sin ser serializada, cuando llamamos a get_option()
.
Todo esto funciona, pero es innecesariamente complicado, obtenemos un marcado a partir de 1998 ( <tr valign="top">
) y muchos despidos.
Usa la API de configuración cuando tengas que hacerlo. Como alternativa, use 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, tienes que hacerlo cuando escribes un complemento de red, porque la API de configuración no funciona allí.
También hay algunos casos de borde y partes incompletas que no mencioné aquí, las encontrará cuando las necesite. :)