べんりワザ・WordPressのカスタムフィールド(ACF・SCF)

get_post_metaでカスタムフィールドを扱う

プラグインを使わずカスタムフィールドを扱う方法。get_post_metaの第3引数の意味、更新・削除の関数、ブロックエディタで入力欄を出す手順、ACFとの関係をまとめました。

カスタムフィールドはプラグインなしでも扱えます。読み出しはget_post_meta()の1行です。

<?php $price = get_post_meta(get_the_ID(), 'price', true); ?>
<?php if ($price !== '') : ?>
  <p class="price"<?php echo esc_html(number_format((int) $price)); ?></p>
<?php endif; ?>

第3引数のtrueが最初の関門です。ここを理解すれば、あとは応用だけです。

第3引数(single)の意味

投稿メタは同じキーに複数の値を持てる仕組みなので、返し方が2通りあります。

get_post_meta(get_the_ID(), 'price', true);   // '3300'(値そのもの)
get_post_meta(get_the_ID(), 'price', false);  // ['3300'](配列)
get_post_meta(get_the_ID(), 'price');         // 省略時もfalseと同じ=配列

ふつうは1つの値を使うのでtrueを付けます。trueを忘れるとArrayと表示される、というのが定番のつまずきです。

キーも省略すると、その投稿のメタ全部が配列で返ります。デバッグに便利です。

<?php var_dump(get_post_meta(get_the_ID())); ?>

入力欄を出す(標準のカスタムフィールド欄)

ブロックエディタでは、標準のカスタムフィールド欄が最初は隠れています。

  1. 編集画面の右上「」→「設定」を開く
  2. 「パネル」の中の「カスタムフィールド」をオンにする(画面が再読みこみされます)
  3. 編集画面の下に「カスタムフィールド」欄が出る
  4. 「新規追加」で名前price3300を入力して追加

カスタム投稿タイプでこの欄を使うには、register_post_type()supports'custom-fields'を含めます。

べんりワザカスタム投稿タイプの作り方(register_post_type)カスタム投稿タイプの作り方はこちら

保存・更新・削除

プログラムから値を書きこむときはこの3つです。

update_post_meta($post_id, 'price', 3300);   // 無ければ追加、あれば更新(基本これ)
add_post_meta($post_id, 'tag', 'sale');      // 同じキーに値を足す(複数値になる)
delete_post_meta($post_id, 'price');         // 削除

迷ったらupdate_post_meta()。「あれば更新、無ければ追加」なので、二重登録の事故が起きません。

数値として使うときの注意

投稿メタの値は、種類を区別せず文字列として保存されています。計算や比較に使うときは型を決めます。

<?php $price = (int) get_post_meta(get_the_ID(), 'price', true); ?>
<p>税込 <?php echo esc_html(number_format((int) round($price * 1.1))); ?>円</p>

一覧を価格で絞る・並べ替えるときも、同じ理由で型の指定が必要です。

べんりワザmeta_queryでカスタムフィールドで絞る・並べ替えるmeta_queryで絞りこむ・並べ替える書き方はこちら

「0」を表示したいときの落とし穴

<?php if (get_post_meta(get_the_ID(), 'stock', true)) : ?>   <!-- ❌ 0が「無い」扱いになる -->
<?php if (get_post_meta(get_the_ID(), 'stock', true) !== '') : ?>   <!-- ✅ -->

在庫0・価格0を表示したいサイトでは、空文字と比較する書き方にします。PHPでは0'0'も条件式では偽になるためです。

アンダースコアで始まるキー

_で始まるメタキー(_thumbnail_idなど)は保護されたメタとして扱われ、標準のカスタムフィールド欄には出てきません。

  • 画面から編集させたい値priceのように普通の名前
  • プログラム専用の内部値_my_internal_flagのようにアンダースコア始まり

WordPressやプラグインが使う内部データも、この形で保存されています。

ブロックエディタやREST APIで使うなら登録する

ブロックエディタのサイドバーやREST API経由でメタを読み書きしたい場合は、register_post_meta()で宣言しておきます。

add_action('init', function () {
  register_post_meta('shohin', 'price', [
    'type'          => 'number',
    'single'        => true,
    'show_in_rest'  => true,
    'auth_callback' => function () {
      return current_user_can('edit_posts');
    },
  ]);
});

show_in_restを立てることで、ブロックエディタ(JavaScript側)からも扱える値になります。

ACF(SCF)との関係

ACFも内部では同じ投稿メタとして保存しているので、get_post_meta()で読めます。ただし違いがあります。

get_post_meta()get_field()(ACF/SCF)
返るもの保存されている生の値型に応じて整形された値
画像フィールドIDの文字列設定に応じてID・URL・配列
くり返し・グループ行数や内部キーの生データ使いやすい配列

ACFを入れているならget_field()を使うのが確実です。get_post_meta()が活躍するのは、プラグインを入れない構成や、プラグインが停止しても壊れないテーマを作るときです。

べんりワザACFフィールド別・表示の書き方早見表ACFを使う場合のフィールド別の書き方はこちら

入力欄を自作する(add_meta_box)

標準の「名前と値」の欄は、運用する人には分かりづらいものです。専用の入力欄を作るならadd_meta_box()を使います。

add_action('add_meta_boxes', function () {
  add_meta_box('shohin_price', '価格', function ($post) {
    $value = get_post_meta($post->ID, 'price', true);
    wp_nonce_field('shohin_price_save', 'shohin_price_nonce');
    echo '<input type="number" name="price" value="' . esc_attr($value) . '">';
  }, 'shohin', 'side');
});

add_action('save_post_shohin', function ($post_id) {
  if (!isset($_POST['shohin_price_nonce'])
      || !wp_verify_nonce($_POST['shohin_price_nonce'], 'shohin_price_save')) {
    return;
  }
  if (!current_user_can('edit_post', $post_id)) {
    return;
  }
  update_post_meta($post_id, 'price', (int) ($_POST['price'] ?? 0));
});

保存処理ではnonceの確認と権限の確認が必須です。ここを省くと、外部から値を書きこめる穴になります。

べんりワザエスケープ関数の使い分け(esc_html・esc_attr・esc_url)エスケープとnonceの使い分けはこちら

まとめ

  1. 読み出しはget_post_meta($id, 'キー', true)trueが「1つの値として取る」指定
  2. 書きこみはupdate_post_meta()が基本(無ければ追加・あれば更新)
  3. 値は文字列で保存されるので、数値は(int)で型を決める0の表示は空文字と比較する
  4. ACFを入れているならget_field()が確実。標準機能はプラグイン非依存のテーマ向き

標準機能で扱えると分かると、「プラグインが無いから作れない」場面がなくなります。

よくある質問

get_post_metaの第3引数のtrueは何ですか?
値を1つだけ取り出す指定です。trueなら値そのもの(文字列)、falseまたは省略すると配列で返ります。ふつうは1つの値を使うのでtrueを付けます。
ブロックエディタでカスタムフィールドの欄が出ません
編集画面の右上「⋮」→「設定」→パネルの「カスタムフィールド」をオンにすると表示されます(画面が再読みこみされます)。カスタム投稿タイプではsupportsに'custom-fields'を含める必要もあります。
アンダースコアで始まるキーが編集画面に出ません
_で始まるメタキーは「保護されたメタ」として扱われ、標準のカスタムフィールド欄には表示されません。プログラムから読み書きする内部用の値に使われます。
ACFで入力した値もget_post_metaで取れますか?
取れます。ACF(SCF)も投稿メタとして保存しているためです。ただし画像フィールドの返り値変換などACF独自の整形はかからないので、通常はget_field()を使うほうが確実です。