2026年10月2日
2026年10月2日
WordPressのカスタムフィールドの作成と活用方法:標準機能・コード・ACFの使い分け
WordPress のカスタムフィールドは、投稿に本文以外の情報(サブタイトル、イベント日、価格など)を持たせる仕組みで、データは wp_postmeta テーブルにキーと値の組で保存されます。この記事では、標準機能での入力、コードでの登録・入力欄の作成・表示、並べ替えや絞り込みへの活用、ACF などのプラグインを使う場合の判断基準を順に説明します。
コードは子テーマの functions.php か、テーマを替えても残る mu-plugin(wp-content/mu-plugins/ 内の PHP ファイル)に置く前提です。作業前にバックアップを取り、ステージング環境で試してから本番に反映してください。
まず標準機能で試す
プラグインもコードも使わずに、カスタムフィールドを付けることができます。ブロックエディターでは、エディター右上のメニューから設定(環境設定)を開き、パネルの項目で「カスタムフィールド」を有効にすると、投稿の下部に入力欄が現れます。画面の表記と場所はバージョンで変わることがあります(2026年10月現在)。
入力欄では「名前」(メタキー)と「値」を入れて追加します。メタキーは後でコードから参照するので、subtitle や event_date のように半角英数字と下線で、意味の分かる名前にしておきます。
この方法は手軽ですが、入力する人がキー名を毎回選ぶ必要があり、入力の形式(日付の書き方など)も揃いません。編集者が複数いるサイトや、決まった項目を毎回入れる運用なら、次に説明する専用の入力欄を用意するほうが入力ミスを減らせます。
なお、パネルが出てこない場合は、テーマやカスタム投稿タイプが custom-fields をサポートしていない可能性があります。カスタム投稿タイプなら register_post_type() の supports に 'custom-fields' を加えます。
コードでメタキーを登録する
使うメタキーは register_post_meta() で登録しておくと、型・サニタイズ方法・編集できる権限を一か所で決められます。show_in_rest を有効にすると REST API やブロックエディターからも扱えるようになり、後述のブロックバインディングにも使えます。
<?php
// wp-content/mu-plugins/mysite-custom-fields.php
add_action( 'init', function () {
register_post_meta( 'post', 'subtitle', array(
'type' => 'string',
'single' => true,
'show_in_rest' => true,
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => function ( $allowed, $meta_key, $post_id ) {
return current_user_can( 'edit_post', $post_id );
},
) );
} );
single を true にすると、1つの投稿に1つの値を持つ項目として扱われます。auth_callback は、その投稿を編集できるユーザーだけに書き込みを許すためのものです。
メタキーを下線 _ で始めると「保護されたメタ」として扱われ、標準のカスタムフィールド欄には表示されません。専用の入力欄だけで編集させたい内部用の値に使われる慣習です。
専用の入力欄(メタボックス)を作る
決まった項目を入力させるために、投稿編集画面にメタボックスを追加します。保存処理では、nonce の検証・自動保存の除外・権限チェック・サニタイズを省かないことが要点です。
<?php
add_action( 'add_meta_boxes', function () {
add_meta_box( 'mysite_subtitle', 'サブタイトル', 'mysite_subtitle_box', 'post', 'side' );
} );
function mysite_subtitle_box( $post ) {
wp_nonce_field( 'mysite_subtitle_save', 'mysite_subtitle_nonce' );
$value = get_post_meta( $post->ID, 'subtitle', true );
echo '<label for="mysite_subtitle">サブタイトル</label>';
echo '<input type="text" id="mysite_subtitle" name="mysite_subtitle" class="widefat" value="' . esc_attr( $value ) . '">';
}
add_action( 'save_post_post', function ( $post_id ) {
if ( ! isset( $_POST['mysite_subtitle_nonce'] ) ) {
return;
}
$nonce = sanitize_text_field( wp_unslash( $_POST['mysite_subtitle_nonce'] ) );
if ( ! wp_verify_nonce( $nonce, 'mysite_subtitle_save' ) ) {
return;
}
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
if ( isset( $_POST['mysite_subtitle'] ) ) {
$subtitle = sanitize_text_field( wp_unslash( $_POST['mysite_subtitle'] ) );
update_post_meta( $post_id, 'subtitle', $subtitle );
}
} );
save_post_post は「投稿タイプ post の保存時」に動くフックです(save_post_{投稿タイプ} の形)。nonce の検証は、他のページから送られた偽のリクエストで値を書き換えられるのを防ぎます。wp_unslash() は WordPress が $_POST に付けるエスケープを外すためのもので、これを忘れると引用符の前にバックスラッシュが溜まっていきます。
保存されないときは、nonce のフィールド名と検証側の名前の食い違い、投稿タイプ名の誤り(save_post_page など)、isset の対象となる name 属性の綴りを順に確認します。
テーマで表示する
値の取得は get_post_meta() です。第3引数を true にすると単一の値が返り、値が無ければ空文字になります。出力するときは、文脈に合ったエスケープ関数を通します。
<?php
$subtitle = get_post_meta( get_the_ID(), 'subtitle', true );
if ( '' !== $subtitle ) {
echo '<p class="post-subtitle">' . esc_html( $subtitle ) . '</p>';
}
本文中の HTML として出すなら esc_html()、属性値なら esc_attr()、URL なら esc_url() を使います。入力時にサニタイズしていても、出力時のエスケープは別に行うのが WordPress の基本です。
ブロックテーマで PHP テンプレートを触りたくない場合は、ブロックバインディング API(WordPress 6.5 以降)で、段落や見出しブロックの内容を core/post-meta のメタ値に結び付ける方法もあります。対象のメタキーは show_in_rest を有効にして登録しておく必要があります。エディター上での編集の可否など、バージョンごとに機能が広がっている部分なので、使う前に手元のバージョンの挙動を確認してください。
並べ替えと絞り込みに使う
カスタムフィールドは、WP_Query の meta_query で絞り込みや並べ替えの条件に使えます。次は、event_date(2026-11-15 のような Y-m-d 形式で保存)が今日以降のイベントを日付順に10件取得する例です。
<?php
$events = new WP_Query( array(
'post_type' => 'event',
'posts_per_page' => 10,
'meta_key' => 'event_date',
'orderby' => 'meta_value',
'order' => 'ASC',
'meta_query' => array(
array(
'key' => 'event_date',
'value' => wp_date( 'Y-m-d' ),
'compare' => '>=',
'type' => 'DATE',
),
),
) );
if ( $events->have_posts() ) {
while ( $events->have_posts() ) {
$events->the_post();
printf( '<li>%s(%s)</li>', esc_html( get_the_title() ), esc_html( get_post_meta( get_the_ID(), 'event_date', true ) ) );
}
wp_reset_postdata();
}
日付を Y-m-d で揃えて保存しておくのは、文字列として並べても日付順になり、比較も正しく働くようにするためです。2026/1/5 のような書き方が混ざると並び順が崩れます。
注意したいのは性能です。wp_postmeta の meta_value 列にはそのままではインデックスが効きにくく、投稿数が多いサイトで meta_query を多用すると遅くなります。頻繁に絞り込む項目が多いなら、タクソノミーで表現できないかを先に検討してください。
ACF などのプラグインを使う判断
入力欄を何種類も作る場合や、画像・日付・選択肢など入力形式の多い項目を扱う場合は、Advanced Custom Fields(ACF)のようなフィールド管理プラグインを使うほうが効率的です。画面上でフィールドを定義でき、表示には get_field() を使います。
<?php
$price = get_field( 'price' );
if ( $price ) {
echo '<p class="price">' . esc_html( $price ) . '</p>';
}
ACF には無料版と有料の ACF PRO があり、繰り返しフィールド(リピーター)、フレキシブルコンテンツ、ギャラリー、オプションページなどは PRO の機能です。必要な機能がどちらに含まれるかは、導入前に公式の説明で確認してください。また、2024年以降、ACF は配布元をめぐる経緯があり、WordPress.org のプラグインディレクトリでは Secure Custom Fields という名前のフォークが配布されています。どの配布元のものを使うかを決め、更新の入手先を把握しておくと運用で迷いません。
プラグインを使う場合でも、保存先は同じ wp_postmeta です。プラグインを停止しても値は残りますが、get_field() のようなプラグイン固有の関数を使った表示は動かなくなるため、テーマ側で function_exists() を確認しておくと表示エラーを避けられます。
まとめ
- カスタムフィールドは投稿ごとの追加情報を
wp_postmetaにキーと値で保存する仕組み。標準の入力パネルで手軽に試せる。 - 本格的に使うなら
register_post_meta()でキーを登録し、メタボックスの保存処理では nonce・自動保存・権限・サニタイズを確認する。 - 表示は
get_post_meta()で取得し、esc_html()などでエスケープする。ブロックテーマではブロックバインディングも選択肢になる。 meta_queryは便利だが大規模サイトでは遅くなりやすい。日付はY-m-dで揃える。- 項目が多いなら ACF などを検討し、無料版と PRO の機能差、配布元を確認する。