Jawaban singkat: name
nilai atribut Anda harus menggunakan skema option_name[array_key]
. Jadi, ketika Anda menggunakan ...
<input name="option_name[key1]">
<input name="option_name[key2]">
... Anda mendapatkan array sebagai nilai opsi dalam fungsi validasi Anda:
array (
'key1' => 'some value',
'key2' => 'some other value'
)
PHP melakukan itu untuk Anda, ini bukan fitur WordPress. :)
Bagaimana cara membuatnya bekerja dengan pengaturan API?
Katakanlah, kami menginginkan halaman opsi ini, dan semua nilai harus disimpan dalam satu opsi dan divalidasi dalam satu fungsi.
Halaman opsi
Kami membutuhkan hook admin_menu
dan dua fungsi: satu untuk mendaftarkan halaman, satu untuk membuat output.
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
}
Formulir action
harus options.php
, atau validasi tidak akan dipanggil. Lihatlah sumber PHP wp-admin/options-permalink.php
- ada jebakan tersembunyi do_settings_sections('permalink');
- tetapi tidak dapat bekerja karena formulirnya action
salah.
Sekarang, kembali ke halaman khusus kami. Kami membuatnya lebih baik dari WordPress.
Mendaftar pengaturan, bagian dan bidang
Kami menghubungkan ke admin_init
saat kami membutuhkannya dan memanggil fungsi pendaftaran.
if ( ! empty ( $GLOBALS['pagenow'] )
and ( 'options-general.php' === $GLOBALS['pagenow']
or 'options.php' === $GLOBALS['pagenow']
)
)
{
add_action( 'admin_init', 't5_sae_register_settings' );
}
Bagian penting di sini adalah: $GLOBALS['pagenow']
harus berupa options-general.php
(untuk output) atau options.php
(untuk validasi). Jangan panggil semua kode berikut pada setiap permintaan. Sebagian besar tutorial dan hampir semua plugin salah.
Oke, mari daftar seperti orang gila:
Kami mengambil nilai opsi untuk halaman kami dan menguraikannya terhadap beberapa default. Cukup mendasar.
Kami mendaftarkan grup pengaturan dengan nama plugin:t5_sae_option_group
. Saya suka nama yang diawali, mereka lebih mudah disortir dan dipahami dengan cara ini.
Kemudian kami mendaftarkan dua bagian, 1 dan 2.
Dan kami menambahkan tiga bagian, dua untuk bagian pertama, satu untuk yang kedua. Kami meneruskan nama opsi dan nilai lolos ke fungsi panggilan balik untuk setiap bidang. Penangan keluaran tidak boleh mengubah data, cukup tambahkan beberapa 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
)
);
}
Semua penangan panggilan balik untuk bagian dan bidang akan dipanggil secara otomatis ketika kami memanggil do_settings_sections( 't5_sae_slug' );
halaman kami. Kami sudah melakukannya, jadi kami hanya perlu ...
Cetak bidangnya
Perhatikan bagaimana name
atribut dibangun: yang dilewati option_name
adalah bagian pertama, kunci array mengikuti tanda kurung siku []
.
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, saya memperkenalkan fungsi t5_sae_debug_var()
. Ini dia:
function t5_sae_debug_var( $var, $before = '' )
{
$export = esc_html( var_export( $var, TRUE ) );
print "<pre>$before = $export</pre>";
}
Berguna untuk melihat apakah kita mendapatkan apa yang kita harapkan.
Sekarang, ini bekerja dengan sangat baik, kita hanya perlu satu hal:
Validasikan array opsi
Karena kami menggunakan notasi braket, nilai kami adalah array. Kami hanya harus berjalan melalui setiap elemen dan memvalidasinya.
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;
}
Ini agak jelek; Saya tidak akan menggunakan kode seperti itu dalam produksi. Tapi ia melakukan apa yang seharusnya: mengembalikan array nilai yang divalidasi. WordPress akan membuat serial array, menyimpannya di bawah nama opsi kami di database dan mengembalikannya tidak teridentifikasi, ketika kita menelepon get_option()
.
Semua ini berfungsi, tetapi tidak perlu rumit, kami mendapatkan markup dari 1998 ( <tr valign="top">
), dan banyak redudansi.
Gunakan API pengaturan saat Anda harus. Sebagai alternatif gunakan admin_url( 'admin-post.php' )
sebagai tindakan formulir (lihat sumbernya) dan buat halaman pengaturan lengkap dengan kode Anda sendiri, mungkin kode yang lebih elegan.
Sebenarnya, Anda harus melakukannya ketika Anda menulis sebuah plugin jaringan, karena pengaturan API tidak berfungsi di sana.
Ada juga beberapa case tepi dan bagian tidak lengkap yang tidak saya sebutkan di sini - Anda akan menemukannya ketika Anda membutuhkannya. :)