PR

【WordPress】設定画面へラジオボタンやチェックボックスを追加で完成形へ

ワードプレスで Settings API を使って設定画面を作ります。

以下の記事で、ワードプレス管理画面へのメニュー追加から、セクションを作ってフィールド(URLの入力項目)を1つ作りましたが、ここではその続き。

【WordPress】設定画面の作り方|初心者にも分かりやすく解説!

複数行入力の textarea や、ラジオボタン、チェックボックスの設定項目を追加して完成させましょう。

セクションの追加にしてもフィールドの追加にしても、最初に作ったURLの入力をベースにコピペしてチョイチョイと修正すれば割と簡単(スライムレベル)。でもラジオボタン、特にチェックボックスの攻略が実はラスボス的に大変なのだ。

では冒険の旅にいざ進めていきましょう。

⇒「Settings APIの使い方まとめ」に戻る

全ての設定項目を入れて完成形へ

ここまで作成した手順を使って、
以下赤枠の残り全ての設定項目を追加します。

やることは以下。

  • 1)セクション1(ブログ情報)に項目追加
    • タイトル入力:1行の通常の文字列入力
      (input: type="text")
    • 説明入力:複数行の文字列入力
      (textarea)
  • 2)セクション2(管理者情報)を追加
  • 3)セクション2(管理者情報)に項目追加
    • 性別:ラジオボタン(男性、女性)
      (input: type="radio")
    • 興味:チェックボックス(旅行、IT、遊び、の3つの項目)
      (type="checkbox")
    • 自己紹介:複数行の文字列入力
      (textarea)

1)セクション1(ブログ情報)に項目追加

まずはセクション1(ブログ情報)
残り2つのフィールド(ブログタイトル、ブログ説明の入力)を追加。

このフィールド追加では以下2つが必要になりますね。

・各々のフィールドを追加
・各々の設定値と初期値を登録

タイトル入力の追加(input text)

タイトル入力は、最初に作ったURL入力と基本同じなのでコピペしてチョコチョコ修正。

まずフィールド(タイトル入力)の追加は以下。

PHP
//フィールド(ブログ情報):タイトル
add_settings_field(
	'field_id_title',                         // ① id:⑥でlabel_forを指定する場合、inputタグなどのid属性に同じ文字列を設定する
	'タイトル',                               // ② フィールドのタイトル(設定項目のラベル)
	'jin_test_setting_field_callback_title',  // ③ input要素などを表示するコールバック関数
	'jin-test-setting-slug',                  // ④ 設定画面のスラッグ
	'jin_test_setting_section_id1',           // ⑤ 表示するセクションのID
	[ 'label_for' => 'field_id_title' ]       // ⑥ 配列:省略可。'label_for'を指定して①のidを入れると、項目名をlabelタグで囲んでくれる
);
Jin Simple Code Block
  • 3~5行目:タイトル用にid変えたり文言変えたりして修正
  • 6,7行目:URL入力と同じページ、同じセクションなのでそのまま
  • 8行目:URL入力同様、とりあえず label_for を設定しておく

③のコールバック関数は以下。

PHP
// コールバック)ブログ情報:タイトル
function jin_test_setting_field_callback_title() {
	$value = get_option( 'item_title' );
	// inputタグのvalue属性として出力するので、esc_attr でエスケープします
	echo '<input name="item_title" id="field_id_title" type="text" maxlength="100" value="' . esc_attr( $value ) . '" />';
}
Jin Simple Code Block
  • 3行目:タイトル用に変数名やidを変える
  • 4行目:最大入力文字数は100ぐらいにしておいた
  • 4行目:表示の際は esc_attr() を使用
    画面に表示する際は、安全のために esc_attr を使って出力。
    (データベースへ保存する際は、後述する登録処理(register_setting)の中で sanitize_text_field を使ってしっかり掃除するように設定)

関数リファレンス:esc_attr(ワードプレス公式)

初期値や設定値の登録も、URL入力にほぼ同じでコピペしてチョコっと修正。

Auto
// 初期値設定
$item_title_init = ''; // ブログ情報:タイトル

// 設定値の登録
// ブログ情報:タイトル
register_setting(
	'jin-test-setting-field-group', // ① グループ名(settings_fieldsで設定されたもの)
	'item_title',                    // ② inputやtextareaなどのname要素と合わせる
	[
		'sanitize_callback' => 'sanitize_text_field', // ③ サニタイズ関数(より安全な関数へ変更)
		'default'           => $item_title_init       // ④ 初期値
	]
);
Jin Simple Code Block
  • 2行目: 初期値を設定。タイトル入力なので、空文字にしておく
  • 7行目: 同じ設定画面上なので変更なし
  • 8行目: タイトル入力用に変数名を修正
  • 11行目: サニタイズ(無害化)は上のフィールドの追加と同様、普通のテキスト入力なので、より安全で適切な sanitize_text_field を使っておく
  • 12行目: 2行目で定義した初期値を設定しておく

説明入力の追加(textarea)

ブログの説明入力は input要素ではなく、複数行入力できるように textarea要素にしますが、違いはそれだけ。

PHP
//フィールド(ブログ情報):説明
add_settings_field(
	'field_id_description',                       // ① id:⑥でlabel_forを指定する場合、inputタグなどのid属性に同じ文字列を設定する
	'説明',                                       // ② フィールドのタイトル(設定項目のラベル)
	'jin_test_setting_field_callback_description', // ③ input要素などを表示するコールバック関数
	'jin-test-setting-slug',                      // ④ 設定画面のスラッグ
	'jin_test_setting_section_id1',               // ⑤ 表示するセクションのID
	[ 'label_for' => 'field_id_description' ]     // ⑥ 配列:省略可。'label_for'を指定して①のidを入れると、項目名をlabelタグで囲んでくれる
);
Jin Simple Code Block
  • 3~5行目: ブログの説明入力用にid変えたり文言変えたりして修正
  • 6,7行目: URL入力と同じページ、同じセクションなのでそのまま
  • 8行目: URL入力同様、とりあえず label_for を設定しておく
PHP
// コールバック)ブログ情報:説明
function jin_test_setting_field_callback_description() {
	$value = get_option( 'item_description' ); // 3行目:データ取得
	?>
	<textarea name="item_description" id="field_id_description" rows="2" cols="30" maxlength="200"><?php echo esc_textarea( $value ); ?></textarea>
	<p>どんなブログかの簡単な説明</p>
	<?php
}
Jin Simple Code Block
  • 3行目: ブログの説明入力用に値を取得して変数へ代入
  • 5行目: row(行数)はとりあえず2行、入力欄の幅(cols)も30文字程度でいいかな、と適当に決めておく。最大入力文字数は200ぐらいにしておいた
  • 5行目: サニタイズ(無害化)は、textarea(複数行の入力)なので esc_textarea() を使っておく
  • 6行目: 項目名が「説明」だけではちょっと分かりづらい、というのと、お試しまでにということで、以下みたいに入力ボックス下にガイド表示を <p></p> で入れてみた

関数リファレンス:esc_textarea(ワードプレス公式)

初期値や設定値の登録も、URL入力にほぼ同じでコピペして修正。

PHP
// 初期値設定
$item_description_init = ''; // ブログ情報:説明

// 設定値の登録
// ブログ情報:説明
register_setting(
	'jin-test-setting-field-group', // ① グループ名(settings_fieldsで設定されたもの)
	'item_description',              // ② inputやtextareaなどのname要素と合わせる
	[
		'sanitize_callback' => 'sanitize_textarea_field', // ③ サニタイズ関数
		'default'           => $item_description_init     // ④ 初期値
	]
);
Jin Simple Code Block
  • 2行目: 初期値を設定。ブログの説明入力なので、タイトル同様空文字にしておく
  • 7行目: 同じ設定画面上なので変更なし
  • 8行目: ブログの説明入力用に変数を修正
  • 11行目: サニタイズ(無害化)はテキストエリアなので、より安全で適切な sanitize_textarea_field を使っておく
  • 12行目: 2行目で定義した初期値を設定しておく

ここまでで、セクション1(ブログの情報)は完了!

ここまでのコード全体と実行結果

ここまでのコードをまとめると以下の通り。

PHP
<?php
// ------------------------------------
// 手順1)「メニュー情報」の関数名を指定(関数Bを指定)
// ------------------------------------
add_action( 'admin_menu', 'jin_test' );

// ------------------------------------
// 手順2)「メニュー情報」の関数の具体的内容(関数B)
// ------------------------------------
function jin_test() {
	add_options_page(
		'JIN Test Settings',     // ① ページタイトル
		'JINテスト用設定',        // ② メニュー名
		'manage_options',        // ③ メニューが表示されるユーザー権限
		'jin-test-setting-slug', // ④ メニューのスラッグ
		'jin_test_setting_func'  // ⑤ 「設定画面」表示の関数名(関数Aを指定)
	);
}

// ------------------------------------
// 手順3)「設定画面」表示関数の具体的内容(関数A)
// ------------------------------------
function jin_test_setting_func() {
	?>
	<div class="wrap">
		<h1>JINのテスト用設定画面なのだ</h1>
		<form method="post" action="options.php">
			<?php settings_fields( 'jin-test-setting-field-group' ); ?>
			<?php do_settings_sections( 'jin-test-setting-slug' ); ?>
			<?php submit_button(); ?>
		</form>
	</div>
	<?php
}

/* ------------------------------------
  セクションの追加
------------------------------------ */
// admin_initフックを使って呼び出す
function jin_test_setting_section_init() {
	// ブログ情報のセクション1
	add_settings_section(
		'jin_test_setting_section_id1',       // ① ID
		'ブログ情報',                         // ② セクションのタイトル
		'jin_test_setting_section_callback1', // ③ コールバック関数1
		'jin-test-setting-slug'               // ④ 設定ページSlug
	);
}
add_action( 'admin_init', 'jin_test_setting_section_init' );

// ③ コールバック関数
// ブログ情報用
function jin_test_setting_section_callback1() {
	echo '<p>ブログの情報を入力してね</p>';
}

/* ------------------------------------
  フィールドの追加
------------------------------------ */
// admin_initフックを使って呼び出す
function jin_test_settings_fields_init() {
	// フィールド(ブログ情報):URL
	add_settings_field(
		'field_id_url',                         // ① id:⑥でlabel_forを指定する場合、inputタグなどのid属性に同じ文字列を設定する
		'URL',                                  // ② フィールドのタイトル(設定項目のラベル)
		'jin_test_setting_field_callback_url',  // ③ input要素などを表示するコールバック関数
		'jin-test-setting-slug',                // ④ 設定画面のスラッグ
		'jin_test_setting_section_id1',         // ⑤ 表示するセクションのID
		[ 'label_for' => 'field_id_url' ]       // ⑥ 配列:省略可。'label_for'を指定して①のidを入れると、項目名をlabelタグで囲んでくれる
	);

	// フィールド(ブログ情報):タイトル
	add_settings_field(
		'field_id_title',                         // ① id:⑥でlabel_forを指定する場合、inputタグなどのid属性に同じ文字列を設定する
		'タイトル',                               // ② フィールドのタイトル(設定項目のラベル)
		'jin_test_setting_field_callback_title',  // ③ input要素などを表示するコールバック関数
		'jin-test-setting-slug',                  // ④ 設定画面のスラッグ
		'jin_test_setting_section_id1',           // ⑤ 表示するセクションのID
		[ 'label_for' => 'field_id_title' ]       // ⑥ 配列:省略可。'label_for'を指定して①のidを入れると、項目名をlabelタグで囲んでくれる
	);

	// フィールド(ブログ情報):説明
	add_settings_field(
		'field_id_description',                        // ① id:⑥でlabel_forを指定する場合、inputタグなどのid属性に同じ文字列を設定する
		'説明',                                        // ② フィールドのタイトル(設定項目のラベル)
		'jin_test_setting_field_callback_description', // ③ input要素などを表示するコールバック関数
		'jin-test-setting-slug',                       // ④ 設定画面のスラッグ
		'jin_test_setting_section_id1',                // ⑤ 表示するセクションのID
		[ 'label_for' => 'field_id_description' ]      // ⑥ 配列:省略可。'label_for'を指定して①のidを入れると、項目名をlabelタグで囲んでくれる
	);
}
add_action( 'admin_init', 'jin_test_settings_fields_init' );

// ------------------------------------
// フィールドのコールバック関数
// label_forを使う場合、input要素のidはadd_settings_fieldのidと同じにする
// ------------------------------------

// コールバック)ブログ情報:URL(1行テキスト入力:input(text))
function jin_test_setting_field_callback_url() {
	$value = get_option( 'item_url' );
	?>
	<input name="item_url" id="field_id_url" type="text" maxlength="200" value="<?php echo esc_url( $value ); ?>" />
	<?php
}

// コールバック)ブログ情報:タイトル(1行テキスト入力:input(text))
function jin_test_setting_field_callback_title() {
	$value = get_option( 'item_title' );
	?>
	<input name="item_title" id="field_id_title" type="text" maxlength="100" value="<?php echo esc_attr( $value ); ?>" />
	<?php
}

// コールバック)ブログ情報:説明(複数行テキスト入力:textarea)
function jin_test_setting_field_callback_description() {
	$value = get_option( 'item_description' );
	?>
	<textarea name="item_description" id="field_id_description" rows="2" cols="30" maxlength="200"><?php echo esc_textarea( $value ); ?></textarea>
	<p>どんなブログかの簡単な説明</p>
	<?php
}

/* ------------------------------------
  設定値と初期値を登録
------------------------------------ */
// admin_initフックを使って呼び出す
function jin_test_settings_values_init() {
	// 初期値設定
	$item_title_init       = ''; // ブログ情報:タイトル
	$item_description_init = ''; // ブログ情報:説明

	// URL:初期(まだ変数自体がない)または空の文字列では「http://」を表示する
	if ( esc_url( get_option( 'item_url' ) ) == false ) {
		update_option( 'item_url', 'http://' );
	}

	// 設定値の登録
	// ブログ情報:URL
	register_setting(
		'jin-test-setting-field-group', // ① グループ名(settings_fieldsで設定されたもの)
		'item_url',                      // ② inputやtextareaなどのname要素と合わせる
		'esc_url'                        // ③ サニタイズ関数
	);

	// ブログ情報:タイトル
	register_setting(
		'jin-test-setting-field-group', // ① グループ名(settings_fieldsで設定されたもの)
		'item_title',                    // ② inputやtextareaなどのname要素と合わせる
		[
			'sanitize_callback' => 'sanitize_text_field', // ③ サニタイズ関数
			'default'           => $item_title_init       // ④ 初期値
		]
	);

	// ブログ情報:説明
	register_setting(
		'jin-test-setting-field-group', // ① グループ名(settings_fieldsで設定されたもの)
		'item_description',              // ② inputやtextareaなどのname要素と合わせる
		[
			'sanitize_callback' => 'sanitize_textarea_field', // ③ サニタイズ関数
			'default'           => $item_description_init     // ④ 初期値
		]
	);
}
add_action( 'admin_init', 'jin_test_settings_values_init' );
Jin Simple Code Block

このコードを実際 functions.php(テーマのための関数)に貼り付けて動作されてみると...

「JINテスト用設定」で3つの入力項目が表示されました。
(「説明」のテキストエリア下にガイド文言も表示されてますね)

実際入力して「変更を保存」をすると、入力した項目も反映されてます。

では後は残り半分にチャレンジ!

2)セクション2(管理者情報)を追加

続いてセクション2(管理者情報)をサクサクっと作っていきましょう。

まずはセクション2自体の追加から。
これはセクション1のほぼコピペになりますね。

Auto
function jin_test_setting_section_init() {
	// ブログ情報のセクション1
	add_settings_section(
		'jin_test_setting_section_id1',
		'ブログ情報',
		'jin_test_setting_section_callback1',
		'jin-test-setting-slug'
	);

	// 管理者情報のセクション2(追加分)
	add_settings_section(
		'jin_test_setting_section_id2',
		'管理者情報',
		'jin_test_setting_section_callback2',
		'jin-test-setting-slug'
	);
}
Jin Simple Code Block
  • 6行目: セクションのIDを修正。このIDを、今後追加する管理者情報用の各フィールドに指定します
  • 7行目: セクションのタイトルを「管理者情報」へと変更
  • 8行目: コールバック関数の名前を「2」に変更して重複を避ける
  • 9行目: セクション1と同一の設定ページに表示するため、スラッグは変更なし
  • 14行目: セクションのタイトルのすぐ下に表示されるガイド文言(管理者の情報を入力してね)を記述

コールバック関数はセクション1と同様に、
ちょっとしたガイド文言(管理者の情報を入力してね)ぐらいを表示する、
としておきます。

PHP
// ③ コールバック関数
// 管理者情報用
function jin_test_setting_section_callback2() {
	echo '<p>管理者の情報を入力してね</p>';
}
Jin Simple Code Block
  • 4行目: ガイド文言表示(管理者の情報を入力してね)を入れておいた。セクションタイトルの直下に表示されます。

3)セクション2(管理者情報)に項目追加

セクション2ができたので、
そのセクションに追加する残り3つの項目(フィールド)を作っていきましょう。

性別選択の追加(ラジオボタン)

ここが少しだけ手ごわいラジオボタンの入力。
add_settings_field はこれまで同様コピペして修正すればOK。

PHP
//フィールド(管理者情報):性別
add_settings_field(
	'field_id_gender',                        // ① id:⑥でlabel_forを指定する場合、inputタグなどのid属性に同じ文字列を設定する
	'性別',                                   // ② フィールドのタイトル(設定項目のラベル)
	'jin_test_setting_field_callback_gender', // ③ input要素などを表示するコールバック関数
	'jin-test-setting-slug',                  // ④ 設定画面のスラッグ
	'jin_test_setting_section_id2'            // ⑤ 表示するセクションのID
);
Jin Simple Code Block
  • 3~5行目: 性別選択用にid変えたり文言変えたりして修正
  • 6行目: URL入力と同じページなのでそのまま
  • 7行目: セクション2のID(jin_test_setting_section_id2)に変更
  • 補足: 性別選択では複数のラジオボタンがあり、特定の1つに label_for を紐付けるのが難しいため、8行目の label_for 設定は削除しています。

コールバック関数は、ラジオボタンを表示するため少し工夫が必要なのだ。

PHP
//コールバック)管理者情報:性別(選択:ラジオボタン:input(radio))
function jin_test_setting_field_callback_gender() {
    $gender = get_option( 'item_gender' );
    ?>
    <label><input type="radio" name="item_gender" value="男性" <?php checked( $gender, '男性' ); ?>>男性</label>
	<label><input type="radio" name="item_gender" value="女性" <?php checked( $gender, '女性' ); ?>>女性</label>
	<label><input type="radio" name="item_gender" value="秘密" <?php checked( $gender, '秘密' ); ?>>秘密</label>    <?php
}
Jin Simple Code Block
  • 3行目: 現在の設定値(保存されている文字列)を取得します。
  • 5〜7行目: 各選択肢を <label> タグで出力します。
    ※)checked() 関数が $gender の中身と value を比較し、一致すれば checked="checked" を自動的に挿入します。

※)ラジオボタンについて:
より詳しくは以下で説明してますので参照してみてください。
【WordPress】フォーム内ラジオボタンにcheckedを入れる方法

初期値や設定値の登録は、URL入力にほぼ同じでコピペして修正。

Auto
// 初期値設定
$item_gender_init = '秘密'; // 管理者情報:性別

// 設定値の登録
// 管理者情報:性別
register_setting(
	'jin-test-setting-field-group', // ① グループ名(settings_fieldsで設定されたもの)
	'item_gender',                    // ② inputやtextareaなどのname要素と合わせる
	[
		'sanitize_callback' => 'sanitize_text_field', // ③ サニタイズ関数
		'default'           => $item_gender_init       // ④ 初期値
	]
);
Jin Simple Code Block
  • 2行目: 初期値を設定。性別は「男性」「女性」「秘密」の3択にしているため、初期値としてはとりあえず「秘密」にしておく。
  • 7行目: 同じ設定画面上なので変更なし。
  • 8行目: 性別選択用の変数名(item_gender)に修正。
  • 11行目: サニタイズ(無害化)は、性別選択用の変数は普通のテキストなので、より安全で適切な sanitize_text_field を使っておく。
  • 12行目: 2行目で定義した初期値を設定しておく。

趣味チェックの追加(チェックボックス)

趣味の設定では「旅行」「IT」「遊び」と複数のチェックボックスがあり、
この複数チェックボックスは今回のサンプル作成では一番の難関。

add_settings_field はこれまで同様で、コピペして修正すればOKなんですが、複数のチェックボックスがある場合のデータのやり取りは慣れないと悩む。

(チェックボックスは初めてだとかなり敷居が高いように感じるはず(私がそうなのだ笑))

まずチェックボックスのフィールドの追加は以下。

PHP
// フィールド(管理者情報):興味
add_settings_field(
	'field_id_interest',                        // ① id
	'興味',                                     // ② フィールドのタイトル
	'jin_test_setting_field_callback_interest', // ③ コールバック関数
	'jin-test-setting-slug',                   // ④ 設定ページのスラッグ
	'jin_test_setting_section_id2'             // ⑤ 表示するセクションのID
);
Jin Simple Code Block
  • 3~5行目: 趣味(興味)のフィールド用にIDや文言を変更して修正。
  • 6行目: これまで同様、設定画面全体のスラッグ(jin-test-setting-slug)を指定。
  • 7行目: 管理者情報用のセクションに表示するため、セクション2のID(jin_test_setting_section_id2)を設定。

フィールドの追加自体は特に問題ない。
実際チェックボックスを表示するコールバック関数が最初戸惑います。

PHP
// コールバック)管理者情報:興味(複数選択:チェックボックス)
function jin_test_setting_field_callback_interest() {
    $interest = get_option( 'item_interest', [] );
    if ( ! is_array( $interest ) ) {
        $interest = []; // 3~6行目:配列でない場合は空の配列にする
    }
    ?>
    <label><input type="checkbox" name="item_interest[]" value="旅行" <?php checked( in_array( '旅行', $interest ) ); ?>>旅行</label>
    <label><input type="checkbox" name="item_interest[]" value="IT" <?php checked( in_array( 'IT', $interest ) ); ?>>IT</label>
    <label><input type="checkbox" name="item_interest[]" value="遊び" <?php checked( in_array( '遊び', $interest ) ); ?>>遊び</label>
    <?php
}
Jin Simple Code Block
  • 3行目:データの取得
    • get_option で保存されているデータを取得。
    • 第2引数に [](空の配列)を指定することで、初期状態でも配列として扱えるようにする。
  • 4〜6行目:配列の保証(エラー防止)
    • 万が一、保存されているデータが配列でなかった場合に備え、強制的に空の配列 [] を代入。これを行わないと、これを行わないとエラーの原因になるため。
  • 8〜10行目:チェックボックスの表示
    • name属性を item_interest[] とする:末尾に [] をつけることで、複数の選択肢を『配列』としてまとめてサーバーに送信できる。
    • in_array() でチェック判定:取得した配列の中に、その項目の値(『旅行』など)が含まれているかを調べ、含まれていれば checked 属性を自動で付与する

最後に、趣味チェック(チェックボックス)のデータを正しく保存するための登録処理と、専用のサニタイズ関数を用意します。

PHP
// 初期値設定
$item_interest_init = []; // 管理者情報:興味(空の配列を初期値としておく)

// 設定値の登録
register_setting(
	'jin-test-setting-field-group', // ① グループ名
	'item_interest',                 // ② 項目名
	[
		'sanitize_callback' => 'sanitize_item_interest', // ★ここで自作サニタイズ関数を指定!
		'default'           => $item_interest_init       // ④ 初期値
	]
);

/**
 * サニタイズ(チェックボックスの配列用)
 * 保存される直前に実行される
 */
function sanitize_item_interest( $args ) {
	// 値がない(何もチェックされていない)場合は空の配列を返す
	if ( empty( $args ) ) {
		return [];
	}
	// 配列の各要素に sanitize_text_field を適用して安全にする
	return array_map( 'sanitize_text_field', (array) $args );
}
Jin Simple Code Block
  • 2行目:初期値の設定
    複数選択されるチェックボックスなので、データがない初期状態でもプログラムが「これは配列」と認識できるように、空の配列 [] を定義しておく。
  • 5〜12行目:設定値の登録(register_setting)
    ここで、保存する名前(item_interest)とサニタイズ処理を紐付けする。
  • 9行目:サニタイズ関数の指定
    配列データを安全に掃除するために、自作した専用関数 sanitize_item_interest を呼び出すように指定。 これにより、保存ボタンを押した瞬間に「強制配列化&洗浄」の処理が走る。
  • 18〜25行目:サニタイズ(専用関数)
    チェックボックス特有の「何もチェックしないとデータが送られない」という性質をカバーするための関数。
  • 20〜22行目:チェックなしの場合の処理
    もし何もチェックされずに保存された(empty( $args ))場合は、すぐに空の配列 [] を返す。 これにより、次に画面を開いた時に「データがないよ」というエラーが出るのを防ぐ。
  • 24行目:一括サニタイズと配列保証
    (array) $args とすることで、中身を強制的に「配列」として扱う。その上で array_map 関数を使い、配列内のすべての項目(旅行、ITなど)を一気に sanitize_text_field で掃除してから保存。

in_array について詳しく

in_array( '文字列' , $配列) という形で、配列中に value で指定されている文字列(ここでは 旅行 IT 遊び)が含まれるかチェック。

in_array() は、指定の文字列が配列中に含まれていれば true を返すので、checked関数で true と比較して両方とも true であれば「半角スペース + checked="checked"」をサクッと入れる。
(つまりチェックボックスにチェックが付いた状態で表示される)

関数リファレンス:in_array(PHPマニュアル)
関数リファレンス:checked(英語)

※)チェックボックスについて:
高速化など含めてより詳しくは以下にまとめてます。
さらに詳細を知りたいぞ!という場合には参照してみてください。
【WordPress】複数チェックボックスの値取得と設定反映!checkedはどうやって入れる?

また、ここでのサニタイズ関数について。
(21行目~28行目の関数)

PHP
function sanitize_item_interest( $args ) {
	// 値がない(何もチェックされていない)場合は空の配列を返す
	if ( empty( $args ) ) {
		return [];
	}
	// 配列の各要素に sanitize_text_field を適用して安全にする
	return array_map( 'sanitize_text_field', (array) $args );
}
Jin Simple Code Block
  • 3行目(コードの23行目):チェックなしの場合の処理
    • チェックボックスは、何もチェックせずに保存するとデータ自体が送信されない。
    • そのため、empty() を使ってデータが空(未チェック)なら、すぐに「空の配列 []」を返すようにしています。こうすることで、後の処理でエラーが出るのを防いでいる。
  • 7行目(コードの27行目):一括サニタイズと配列保証
    • ここでは2つのことを同時に行っています。 まず、(array) $args と書くことで、中身がどんな状態でも強制的に「配列」として扱うように保証している。
    • その配列に対して array_map 関数を使い、すべての項目に一括で sanitize_text_field を適用して、安全な状態に掃除(サニタイズ)してから保存している。

array_map について詳しく

array_map関数はかなり便利で、
array_map( '関数', $配列 ) という形で、配列の中の要素1つ1つに対して指定の関数を実行してくれるのだ。

関数リファレンス:array_map(PHPマニュアル)

つまり、array_map('esc_attr', $args) とすると、配列 args の中の1つ1つの要素(つまりすべての要素)に対して サニタイズ関数の esc_attr を実行して、実行した結果の配列を返してくれる。

こうすることで、配列全体をサニタイズしているんですが、他にもっとうまいやり方があるのかもしれません。

初期値や設定値の登録は、他とほぼ同じ流れなのでコピペでOK。
ただし、チェックボックスは『複数の値』を扱うので、初期値を空の配列([])にすることと、サニタイズに関数に『専用の自作関数』を指定するのを忘れないようにします。

Auto
// 初期値設定
$item_interest_init = []; // 管理者情報:興味(空の配列を初期値としておく)

// 設定値の登録
register_setting(
	'jin-test-setting-field-group', // ① グループ名
	'item_interest',                 // ② 項目名
	[
		'sanitize_callback' => 'sanitize_item_interest', // ★ここで自作サニタイズ関数を指定!
		'default'           => $item_interest_init       // ④ 初期値
	]
);
Jin Simple Code Block
  • 2行目: 初期値を設定。複数選択されるチェックボックスなので、空の配列([])として定義しておく。
  • 6行目: これまでと同じ設定グループ名(jin-test-setting-field-group)を指定。
  • 7行目: 興味・趣味のデータとして保存する名前(item_interest)に修正。
  • 9行目: サニタイズ(無害化)には、先ほど作った専用の関数名(sanitize_item_interest)を指定。 (これにより、保存ボタンを押した瞬間にあの「強制配列化&洗浄」の処理が走るようになる)
  • 10行目: 2行目で定義した初期値を設定しておく。

自己紹介入力の追加(textarea)

最後の自己紹介入力は、ブログの説明入力と同じテキストエリア。
ブログの説明入力のほぼコピペでできますね。

PHP
// フィールド(管理者情報):自己紹介
add_settings_field(
	'field_id_selfintro',
	'自己紹介',
	'jin_test_setting_field_callback_selfintro',
	'jin-test-setting-slug',
	'jin_test_setting_section_id2',
	[ 'label_for' => 'field_id_selfintro' ]
);
Jin Simple Code Block
  • 3~5行目: 自己紹介の入力用にID(field_id_selfintro)やタイトル、関数名を修正。
  • 6行目: これまでと同様、設定画面のスラッグを指定。
  • 7行目: 管理者情報用の「セクション2」のID(jin_test_setting_section_id2)に変更。
  • 8行目: テキストエリア(textarea)は単一の入力欄なので、クリックでフォーカスが当たるよう label_for を設定。

③のコールバック関数は以下。

Auto
// コールバック)管理者情報:自己紹介
function jin_test_setting_field_callback_selfintro() {
	$selfintro = get_option( 'item_selfintro' );
	?>
	<textarea name="item_selfintro" id="field_id_selfintro" rows="2" cols="30" maxlength="200"><?php echo esc_textarea( $selfintro ); ?></textarea>
	<p>ブログの管理者はどんな人か簡単な自己紹介</p>
	<?php
}
Jin Simple Code Block
  • 3行目: データベースから自己紹介のデータ(item_selfintro)を取得。
  • 5行目: 1行テキストではなく「複数行」のため textarea タグを使用。行数(rows)や幅(cols)を調整している。
  • 5行目: セキュリティ対策として、テキストエリア専用のエスケープ関数 esc_textarea() を通して出力。
  • 6行目: 入力欄の下に、ユーザー向けのガイド文言(補足説明)を表示。

以上ですべての項目が完了!(したはず ^-^;))

全体のコードと動作

ここまで作ったコード全体は以下。

PHP
// ------------------------------------
// 手順1)「メニュー情報」の登録
// ------------------------------------
add_action( 'admin_menu', 'jin_test' );

function jin_test() {
	add_options_page(
		'JIN Test Settings',     // ① ページタイトル
		'JINテスト用設定',        // ② メニュー名
		'manage_options',        // ③ ユーザー権限
		'jin-test-setting-slug', // ④ メニューのスラッグ
		'jin_test_setting_func'  // ⑤ 表示用関数名
	);
}

// ------------------------------------
// 手順2)「設定画面」のHTML表示
// ------------------------------------
function jin_test_setting_func() {
	?>
	<div class="wrap">
		<h1>JINのテスト用設定画面なのだ</h1>
		<form method="post" action="options.php">
			<?php
			settings_fields( 'jin-test-setting-field-group' );
			do_settings_sections( 'jin-test-setting-slug' );
			submit_button();
			?>
		</form>
	</div>
	<?php
}

/* ------------------------------------
  セクションの追加
------------------------------------ */
add_action( 'admin_init', 'jin_test_setting_section_init' );

function jin_test_setting_section_init() {
	// ブログ情報のセクション1
	add_settings_section( 'jin_test_setting_section_id1', 'ブログ情報', 'jin_test_setting_section_callback1', 'jin-test-setting-slug' );

	// 管理者情報のセクション2
	add_settings_section( 'jin_test_setting_section_id2', '管理者情報', 'jin_test_setting_section_callback2', 'jin-test-setting-slug' );
}

function jin_test_setting_section_callback1() {
	echo '<p>ブログの情報を入力してね</p>';
}

function jin_test_setting_section_callback2() {
	echo '<p>管理者の情報を入力してね</p>';
}

/* ------------------------------------
  フィールド(入力項目)の追加
------------------------------------ */
add_action( 'admin_init', 'jin_test_settings_fields_init' );

function jin_test_settings_fields_init() {
	// URL(セクション1)
	add_settings_field(
		'field_id_url',                        // ① ID
		'URL',                                 // ② タイトル
		'jin_test_setting_field_callback_url', // ③ コールバック関数
		'jin-test-setting-slug',               // ④ 設定画面のスラッグ
		'jin_test_setting_section_id1',        // ⑤ セクションID
		[ 'label_for' => 'field_id_url' ]      // ⑥ 配列(labelタグ用)
	);

	// タイトル(セクション1)
	add_settings_field(
		'field_id_title',
		'タイトル',
		'jin_test_setting_field_callback_title',
		'jin-test-setting-slug',
		'jin_test_setting_section_id1',
		[ 'label_for' => 'field_id_title' ]
	);

	// 説明(セクション1)
	add_settings_field(
		'field_id_description',
		'説明',
		'jin_test_setting_field_callback_description',
		'jin-test-setting-slug',
		'jin_test_setting_section_id1',
		[ 'label_for' => 'field_id_description' ]
	);

	// 性別(セクション2)
	add_settings_field(
		'field_id_gender',
		'性別',
		'jin_test_setting_field_callback_gender',
		'jin-test-setting-slug',
		'jin_test_setting_section_id2'
	);

	// 興味(セクション2)
	add_settings_field(
		'field_id_interest',
		'興味',
		'jin_test_setting_field_callback_interest',
		'jin-test-setting-slug',
		'jin_test_setting_section_id2'
	);

	// 自己紹介(セクション2)
	add_settings_field(
		'field_id_selfintro',
		'自己紹介',
		'jin_test_setting_field_callback_selfintro',
		'jin-test-setting-slug',
		'jin_test_setting_section_id2',
		[ 'label_for' => 'field_id_selfintro' ]
	);
}

/* ------------------------------------
  各フィールドの表示(コールバック関数)
------------------------------------ */

// URL
function jin_test_setting_field_callback_url() {
	$value = get_option( 'item_url' );
	echo '<input name="item_url" id="field_id_url" type="text" maxlength="200" value="' . esc_url( $value ) . '" />';
}

// タイトル
function jin_test_setting_field_callback_title() {
	$value = get_option( 'item_title' );
	echo '<input name="item_title" id="field_id_title" type="text" maxlength="100" value="' . esc_attr( $value ) . '" />';
}

// 説明
function jin_test_setting_field_callback_description() {
	$value = get_option( 'item_description' );
	?>
	<textarea name="item_description" id="field_id_description" rows="2" cols="30" maxlength="200"><?php echo esc_textarea( $value ); ?></textarea>
	<p>どんなブログかの簡単な説明</p>
	<?php
}

// 性別(ラジオボタン)※name属性のミスを修正済
function jin_test_setting_field_callback_gender() {
	$gender = get_option( 'item_gender' );
	?>
	<label><input type="radio" name="item_gender" value="男性" <?php checked( $gender, '男性' ); ?>>男性</label>
	<label><input type="radio" name="item_gender" value="女性" <?php checked( $gender, '女性' ); ?>>女性</label>
	<label><input type="radio" name="item_gender" value="秘密" <?php checked( $gender, '秘密' ); ?>>秘密</label>
	<?php
}

// 興味(チェックボックス:改善版)
function jin_test_setting_field_callback_interest() {
	$interest = get_option( 'item_interest', [] );
	if ( ! is_array( $interest ) ) {
		$interest = [];
	}
	?>
	<label><input type="checkbox" name="item_interest[]" value="旅行" <?php checked( in_array( '旅行', $interest ) ); ?>>旅行</label>
	<label><input type="checkbox" name="item_interest[]" value="IT" <?php checked( in_array( 'IT', $interest ) ); ?>>IT</label>
	<label><input type="checkbox" name="item_interest[]" value="遊び" <?php checked( in_array( '遊び', $interest ) ); ?>>遊び</label>
	<?php
}

// 自己紹介
function jin_test_setting_field_callback_selfintro() {
	$selfintro = get_option( 'item_selfintro' );
	?>
	<textarea name="item_selfintro" id="field_id_selfintro" rows="2" cols="30" maxlength="200"><?php echo esc_textarea( $selfintro ); ?></textarea>
	<p>ブログの管理者はどんな人か簡単な自己紹介</p>
	<?php
}

/* ------------------------------------
  サニタイズ(専用関数)
------------------------------------ */
function sanitize_item_interest( $args ) {
	if ( empty( $args ) ) {
		return [];
	}
	return array_map( 'sanitize_text_field', (array) $args );
}

/* ------------------------------------
  設定値と初期値の登録
------------------------------------ */
add_action( 'admin_init', 'jin_test_settings_values_init' );

function jin_test_settings_values_init() {
	// 初期値
	$item_title_init       = '';
	$item_description_init = '';
	$item_gender_init      = '秘密';
	$item_interest_init    = [];
	$item_selfintro_init   = '';

	// URL項目の初期設定
	if ( false === get_option( 'item_url' ) ) {
		update_option( 'item_url', 'http://' );
	}

	// 設定値の登録(サニタイズを強化)

	// URL
	register_setting(
		'jin-test-setting-field-group', // ① グループ名
		'item_url',                     // ② 項目名
		'esc_url_raw'                   // ③ サニタイズ関数
	);

	// タイトル
	register_setting(
		'jin-test-setting-field-group',
		'item_title',
		[
			'sanitize_callback' => 'sanitize_text_field', // サニタイズ
			'default'           => $item_title_init,      // 初期値
		]
	);

	// 説明
	register_setting(
		'jin-test-setting-field-group',
		'item_description',
		[
			'sanitize_callback' => 'sanitize_textarea_field',
			'default'           => $item_description_init,
		]
	);

	// 性別
	register_setting(
		'jin-test-setting-field-group',
		'item_gender',
		[
			'sanitize_callback' => 'sanitize_text_field',
			'default'           => $item_gender_init,
		]
	);

	// 興味(チェックボックス用)
	register_setting(
		'jin-test-setting-field-group',
		'item_interest',
		[
			'sanitize_callback' => 'sanitize_item_interest', // 自作サニタイズ関数
			'default'           => $item_interest_init,
		]
	);

	// 自己紹介
	register_setting(
		'jin-test-setting-field-group',
		'item_selfintro',
		[
			'sanitize_callback' => 'sanitize_textarea_field',
			'default'           => $item_selfintro_init,
		]
	);
}
Jin Simple Code Block

このコードをfunctions.php(テーマのための関数)に貼り付け、作った設定画面にアクセスしてみると以下のようになりますね。

※注意点:
すでに functions.php に何か記述がある場合は、一番下の行にコードを貼り付けてください。その際、先頭の「 <?php 」は不要(エラーの原因)になるので、コピーする範囲から外すか、貼り付け後に削除してください。

いいじゃないですか。
ちゃんとできているようですね!

実際URLやタイトルなど入力したり、性別や興味を選んだりして「変更を保存」クリックで値も保存されているようです。

これにて今回のサンプル設定はまずは完了!

後はCSSでちょっとデザインを整えたり
(入力ボックスの横幅をそろえたり、チェックボックスでは項目間の間をあけたりなど)
自作プラグインの場合には変数を1つにまとめる(配列にする)のが作法といった話もあるようなのでそうしてみたいですね。

まずはここまで、お疲れさまでした!

変数を配列でひとまとめにしてみたり、デザインカスタマイズにチャレンジする場合には、以下から続きを進めてみてくださいね。

⇒「Settings APIの使い方まとめ」に戻る

早期退職して海外で奮闘する JIN のメールマガジン

時間や場所に縛られず稼いだJINが教える

~ 最短で月収10万円稼げるようになる方法 ~

お名前/ニックネーム

隣のあの人にも、思わず教えたくなる秘密

配信停止は、いつでもできます

迷惑メールは一切配信されませんので、ご安心くださいね

自らの手で未来を変える力を手に入れる!

コメント