Kurze Antwort: Ihre name
Attributwerte müssen das Schema verwenden option_name[array_key]
. Also, wenn Sie verwenden ...
<input name="option_name[key1]">
<input name="option_name[key2]">
… Erhalten Sie in Ihrer Validierungsfunktion ein Array als Optionswert:
array (
'key1' => 'some value',
'key2' => 'some other value'
)
PHP erledigt das für Sie, dies ist keine WordPress-Funktion. :)
Wie funktioniert das mit der Einstellungs-API?
Angenommen, wir möchten diese Optionsseite, und alle Werte sollten in einer Option gespeichert und in einer Funktion validiert werden.
Die Optionsseite
Wir brauchen den Hook admin_menu
und zwei Funktionen: eine zum Registrieren der Seite, eine zum Rendern der Ausgabe.
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
}
Das Formular action
muss sein options.php
, sonst wird die Validierung nicht aufgerufen. Schauen Sie sich die PHP-Quelle von an wp-admin/options-permalink.php
- es gibt eine versteckte Falle do_settings_sections('permalink');
- aber es kann nicht funktionieren, weil das Formular action
falsch ist.
Nun zurück zu unserer benutzerdefinierten Seite. Wir machen es besser als WordPress.
Registrieren Sie Einstellungen, Abschnitte und Felder
Wir melden admin_init
uns bei Bedarf an und rufen eine Registrierungsfunktion auf.
if ( ! empty ( $GLOBALS['pagenow'] )
and ( 'options-general.php' === $GLOBALS['pagenow']
or 'options.php' === $GLOBALS['pagenow']
)
)
{
add_action( 'admin_init', 't5_sae_register_settings' );
}
Der wichtige Teil hier ist: $GLOBALS['pagenow']
muss entweder options-general.php
(für die Ausgabe) oder options.php
(für die Validierung) sein. Rufen Sie nicht bei jeder Anforderung den gesamten folgenden Code auf. Die meisten Tutorials und fast alle Plugins verstehen das falsch.
Okay, lass uns registrieren wie verrückt:
Wir rufen die Optionswerte für unsere Seite ab und analysieren sie anhand einiger Standardwerte. Ziemlich einfach.
Wir registrieren eine Einstellungsgruppe mit dem Namen plugin:t5_sae_option_group
. Ich mag Präfixnamen, sie sind einfacher zu sortieren und auf diese Weise zu verstehen.
Dann registrieren wir zwei Abschnitte, 1 und 2.
Und wir fügen drei Abschnitte hinzu, zwei für den ersten Abschnitt und einen für den zweiten. Wir übergeben den Optionsnamen und den maskierten Wert an die Rückruffunktionen für jedes Feld. Ausgabehandler sollten keine Daten ändern, sondern nur HTML hinzufügen.
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
)
);
}
Alle diese Callback-Handler für die Abschnitte und Felder werden automatisch aufgerufen, wenn wir do_settings_sections( 't5_sae_slug' );
unsere Seite aufrufen. Das haben wir schon gemacht, also müssen wir nur ...
Drucken Sie die Felder aus
Beachten Sie, wie die name
Attribute aufgebaut sind: Der übergebene Teil option_name
ist der erste Teil, der Array-Schlüssel folgt in eckigen Klammern []
.
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, ich habe eine Funktion eingeführt t5_sae_debug_var()
. Hier ist es:
function t5_sae_debug_var( $var, $before = '' )
{
$export = esc_html( var_export( $var, TRUE ) );
print "<pre>$before = $export</pre>";
}
Nützlich, um zu sehen, ob wir das bekommen haben, was wir erwartet hatten.
Das funktioniert ganz gut, wir brauchen nur eins:
Überprüfen Sie das Optionsarray
Da wir die Klammernotation verwendet haben, ist unser Wert ein Array. Wir müssen nur durch jedes Element gehen und es validieren.
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;
}
Das ist ziemlich hässlich; Ich würde solchen Code nicht in der Produktion verwenden. Aber es tut, was es sollte: Es gibt ein validiertes Array von Werten zurück. WordPress serialisiert das Array, speichert es unter unserem Optionsnamen in der Datenbank und gibt es unserialisiert zurück, wenn wir anrufen get_option()
.
All dies funktioniert, aber es ist unnötig kompliziert, wir bekommen Markup von 1998 ( <tr valign="top">
) und viele Redundanzen.
Verwenden Sie die Einstellungs-API, wenn Sie müssen. Alternativ können Sie admin_url( 'admin-post.php' )
als Formularaktion (siehe Quelle) die vollständige Einstellungsseite mit Ihrem eigenen, wahrscheinlich eleganteren Code erstellen.
Tatsächlich müssen Sie dies tun, wenn Sie ein Netzwerk-Plugin schreiben, da die Einstellungs-API dort nicht funktioniert.
Es gibt auch einige Randfälle und unvollständige Teile, die ich hier nicht erwähnt habe - Sie werden sie finden, wenn Sie sie brauchen. :)