Réponse courte: vos name
valeurs d'attribut doivent utiliser le schéma option_name[array_key]
. Alors, quand vous utilisez…
<input name="option_name[key1]">
<input name="option_name[key2]">
… Vous obtenez un tableau comme valeur d'option dans votre fonction de validation:
array (
'key1' => 'some value',
'key2' => 'some other value'
)
PHP le fait pour vous, ce n'est pas une fonctionnalité de WordPress. :)
Comment faire fonctionner cela avec les paramètres de l'API?
Disons que nous voulons cette page d’options et que toutes les valeurs doivent être stockées dans une option et validées dans une fonction.
La page des options
Nous avons besoin du hook admin_menu
et de deux fonctions: une pour enregistrer la page, une pour afficher le résultat.
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
}
Le formulaire action
doit être options.php
, sinon la validation ne sera pas appelée. Regardez la source PHP de wp-admin/options-permalink.php
- il y a un piège caché do_settings_sections('permalink');
- mais cela ne peut pas fonctionner car la formeaction
est faux.
Revenons maintenant à notre page personnalisée. Nous le faisons mieux que WordPress.
Enregistrer les paramètres, les sections et les champs
Nous accrochons admin_init
quand nous en avons besoin et appelons une fonction d'enregistrement.
if ( ! empty ( $GLOBALS['pagenow'] )
and ( 'options-general.php' === $GLOBALS['pagenow']
or 'options.php' === $GLOBALS['pagenow']
)
)
{
add_action( 'admin_init', 't5_sae_register_settings' );
}
La partie importante ici est: $GLOBALS['pagenow']
doit être soit options-general.php
(pour la sortie) ouoptions.php
(pour la validation). N'appelez pas tout le code suivant sur chaque demande. La plupart des tutoriels et presque tous les plugins se trompent.
Ok, inscrivons-nous comme un fou:
Nous récupérons les valeurs d'option pour notre page et les analysons en fonction de certaines valeurs par défaut. Assez basique.
Nous enregistrons un groupe de paramètres avec le nom plugin:t5_sae_option_group
. J'aime les noms préfixés, ils sont plus faciles à trier et à comprendre de cette façon.
Ensuite, nous enregistrons deux sections, 1 et 2.
Et nous ajoutons trois sections, deux pour la première et une pour la seconde. Nous passons le nom de l'option et la valeur échappée aux fonctions de rappel pour chaque champ. Les gestionnaires de sortie ne doivent pas modifier les données, mais juste ajouter du 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
)
);
}
Tous les gestionnaires de rappel pour les sections et les champs seront appelés automatiquement lorsque nous appellerons do_settings_sections( 't5_sae_slug' );
dans notre page. Nous l'avons déjà fait, il nous faut juste…
Imprimer les champs
Notez comment les name
attributs sont construits: la option_name
première partie est passée , la clé de tableau suit entre crochets []
.
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, j'ai introduit une fonction t5_sae_debug_var()
. C'est ici:
function t5_sae_debug_var( $var, $before = '' )
{
$export = esc_html( var_export( $var, TRUE ) );
print "<pre>$before = $export</pre>";
}
Utile pour voir si nous avons obtenu ce que nous attendions.
Maintenant, ça marche plutôt bien, il suffit d’une chose:
Valider le tableau d'options
Comme nous avons utilisé la notation entre crochets, notre valeur est un tableau. Il suffit de parcourir chaque élément et de le valider.
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;
}
C'est plutôt moche; Je n'utiliserais pas un tel code en production. Mais il fait ce qu’il devrait: il retourne un tableau de valeurs validé. WordPress va sérialiser le tableau, le stocker sous notre nom d'option dans la base de données et le renvoyer non sérialisé, lorsque nous appelons get_option()
.
Tout cela fonctionne, mais ce n'est pas compliqué, nous obtenons un balisage à partir de 1998 ( <tr valign="top">
), ainsi que de nombreux redondances.
Utilisez les paramètres de l'API lorsque vous devez. admin_url( 'admin-post.php' )
Vous pouvez également utiliser une action de formulaire (regardez son source) et créer la page de paramètres complète avec votre propre code, probablement plus élégant.
En fait, vous devez le faire lorsque vous écrivez un plug-in de réseau, car l'API de paramètres ne fonctionne pas là-bas.
Il y a aussi des cas particuliers et des parties incomplètes que je n'ai pas mentionnées ici - vous les trouverez quand vous en aurez besoin. :)