WordPress の投稿編集画面に、タイトルや本文とは別の「独自の入力欄」を追加したいことがあります。サブタイトルや外部リンク、商品の価格などを入力させたいときに使うのが add_meta_box() です。この記事では、メタボックス(独自の入力欄)を追加し、入力値を安全に保存して表示するまでの流れを解説します。
目次
メタボックスとは
メタボックスとは、投稿編集画面に表示される「枠」のことです。標準では「公開」「カテゴリー」「アイキャッチ画像」などがメタボックスとして並んでいます。add_meta_box() を使うと、ここに自分専用の入力欄を追加できます。
入力された値は「カスタムフィールド(投稿メタ)」として保存され、テンプレートから get_post_meta() で取り出して表示できます。この記事では例として、投稿に「サブタイトル」を入力できる欄を作ってみます。
add_meta_box() でメタボックスを登録する
メタボックスの登録は、add_meta_boxes アクションフックの中で add_meta_box() を呼び出して行います。引数で「どの投稿タイプに」「どこに」表示するかを指定します。
function mytheme_add_meta_box() {
add_meta_box(
'mytheme_subtitle', // メタボックスのID(ユニークに)
'サブタイトル', // 画面に表示されるタイトル
'mytheme_subtitle_callback', // 中身を出力するコールバック関数
'post', // 表示する投稿タイプ
'side', // 表示位置(normal / side / advanced)
'default' // 優先度(high / default / low)
);
}
add_action( 'add_meta_boxes', 'mytheme_add_meta_box' );
第4引数の投稿タイプを 'page' にすれば固定ページに、'product' にすればカスタム投稿タイプに表示できます。第5引数の表示位置は、本文の下なら 'normal'、サイドバーなら 'side' を指定します。
入力欄をコールバック関数で出力する
第3引数で指定したコールバック関数の中に、実際の入力欄(HTML)を書きます。ここでは保存済みの値を get_post_meta() で取得して初期値に入れ、あわせて改ざん防止用の wp_nonce_field() を出力しています。
function mytheme_subtitle_callback( $post ) {
// 保存済みの値を取得
$value = get_post_meta( $post->ID, '_mytheme_subtitle', true );
// 改ざん防止のnonceを出力
wp_nonce_field( 'mytheme_save_subtitle', 'mytheme_subtitle_nonce' );
// 入力欄を出力(値はesc_attr()でエスケープ)
echo '<input type="text" name="mytheme_subtitle" value="'
. esc_attr( $value )
. '" style="width:100%;">';
}
入力欄の name 属性(ここでは mytheme_subtitle)は、次の保存処理で値を受け取るときのキーになります。保存するメタのキー名を _mytheme_subtitle のように先頭にアンダースコアを付けると、カスタムフィールド一覧に表示されない「非公開メタ」になります。
入力値を save_post で保存する
投稿が保存されたときに走る save_post フックで、入力された値を update_post_meta() で保存します。このとき、セキュリティのために次の3つを必ずチェックします。
- nonce の検証:正規のフォームから送信されたか確認する
- 自動保存の除外:自動保存のタイミングでは保存しない
- 権限のチェック:その投稿を編集できるユーザーか確認する
function mytheme_save_subtitle( $post_id ) {
// 1. nonceを検証
if ( ! isset( $_POST['mytheme_subtitle_nonce'] )
|| ! wp_verify_nonce( $_POST['mytheme_subtitle_nonce'], 'mytheme_save_subtitle' ) ) {
return;
}
// 2. 自動保存のときは保存しない
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// 3. 編集権限のチェック
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
// 値をサニタイズして保存
if ( isset( $_POST['mytheme_subtitle'] ) ) {
update_post_meta(
$post_id,
'_mytheme_subtitle',
sanitize_text_field( $_POST['mytheme_subtitle'] )
);
}
}
add_action( 'save_post', 'mytheme_save_subtitle' );
ユーザーが入力した値は、そのまま保存せず必ずサニタイズします。1行のテキストなら sanitize_text_field()、URL なら esc_url_raw() のように、内容に合った関数を使いましょう。
保存した値をテンプレートで表示する
保存した値は、テンプレート(single.php など)で get_post_meta() を使って取り出します。出力するときは esc_html() でエスケープします。
$subtitle = get_post_meta( get_the_ID(), '_mytheme_subtitle', true );
if ( $subtitle ) {
echo '<p class="entry-subtitle">' . esc_html( $subtitle ) . '</p>';
}
第3引数に true を渡すと、配列ではなく単一の値が返ります。値が空のときは表示しないよう、if でチェックしておくと安全です。
値が保存されない・表示されないときは
メタボックスを作ったのに「値が保存されない」「保存したはずの値が消える」といったときは、保存処理まわりに原因があることが多いです。次の点を確認してみてください。
nonce のチェックが抜けている
セキュリティ(CSRF 対策)のため、入力欄を出力する側の wp_nonce_field() と、保存側の wp_verify_nonce() はセットで必要です。どちらかが抜けていると、検証に失敗して保存処理が return され、値が保存されません。両方が対応するキーで書かれているか確認しましょう。
自動保存で値が空になる
WordPress は編集中に自動保存を行います。このとき DOING_AUTOSAVE をチェックしていないと、入力欄が送られないタイミングの保存処理で、空の値に上書きされてしまうことがあります。保存関数の冒頭で自動保存を除外する処理を入れているか確認してください。
サニタイズ・エスケープを忘れている
保存時はサニタイズ(sanitize_text_field() など)、表示時はエスケープ(esc_html() や esc_attr())が必要です。どちらも安全性のために欠かせません。値が正しく扱われていないときは、入力内容に合った関数を使えているか見直しましょう。
登録が add_meta_boxes フックの外にある
そもそもメタボックス自体が表示されないときは、add_meta_box() の呼び出しが add_meta_boxes フックの中にあるかを確認します。フックの外で呼んでも、適切なタイミングで登録されず表示されません。
まとめ
投稿編集画面に独自の入力欄を追加するには、add_meta_box() でメタボックスを登録し、コールバックで入力欄を出力、save_post で値を保存する、という流れになります。
- 登録は
add_meta_boxesフック内でadd_meta_box()を呼ぶ - コールバックで入力欄と
wp_nonce_field()を出力する - 保存は
save_postで、nonce・自動保存・権限を確認してからupdate_post_meta() - 表示は
get_post_meta()で取り出しesc_html()でエスケープ
この基本形を覚えておけば、テキスト以外にもチェックボックスやセレクトボックスなど、さまざまな入力欄を投稿編集画面に追加できます。