【WordPress】カテゴリーごとにカスタムフィールドの選択肢を動的に変える方法

【WordPress】カテゴリーごとにカスタムフィールドの選択肢を動的に変える方法 WordPress

WordPressで投稿画面にカスタムフィールドを追加する際、カテゴリーごとに選択肢を動的に切り替えたいというニーズは多くあります。特にAdvanced Custom Fields(ACF)を使用しているケースでは、投稿タイプに紐づく柔軟なUIを求める場面が増えています。

この記事では、選択されたカテゴリーに応じてカスタムフィールドの選択肢を動的に変更する方法を、ACFとJavaScript(Ajax)を活用して実装する方法を紹介します。

スポンサーリンク

カスタムフィールドの選択肢がカテゴリーに依存するケースとは

たとえば「製品レビュー」という投稿タイプで、「カテゴリ:パソコン」では「CPU」「メモリ」「GPU」といった項目が必要になる一方、「カテゴリ:スマホ」では「画面サイズ」「バッテリー容量」「カメラ性能」といった項目が必要になるとします。

このように投稿のカテゴリーに応じて異なる選択肢や項目を表示したい場合、標準のACFだけでは実現が難しいため、動的な制御が必要になります。

基本的な仕組みの流れ

  1. 投稿編集画面でカテゴリーが変更されるのを検知
  2. 選択されたカテゴリーIDをAjaxで送信
  3. PHPでカテゴリーに対応した選択肢を生成して返す
  4. JavaScriptで該当するセレクトボックスの中身を差し替える

この4ステップで動的な切り替えを実現します。

クラシックエディタ専用の実装
本記事のコードは、投稿編集画面のカテゴリーチェックリスト(#categorychecklist)を対象としています。これはクラシックエディタ(メタボックス)のマークアップであり、Gutenberg(ブロックエディタ)のカテゴリーパネルはReactで実装された別物のため、このIDは存在しません。対象の投稿タイプがGutenbergを使用している場合は、動作しない点に注意してください。

JavaScriptの読み込み(admin_enqueue_scripts)

Ajax通信にはCSRF対策としてnonceが必須です。functions.phpでスクリプトを読み込み、nonceとAjax URLをwp_localize_script()でJavaScript側に渡します。

functions.php:スクリプトの読み込みとnonceの受け渡し
add_action('admin_enqueue_scripts', 'enqueue_dynamic_acf_script');
function enqueue_dynamic_acf_script($hook) {
  if ($hook !== 'post.php' && $hook !== 'post-new.php') return;

  wp_enqueue_script(
    'dynamic-acf-choices',
    get_stylesheet_directory_uri() . '/js/dynamic-acf-choices.js',
    array('jquery'),
    null,
    true
  );
  wp_localize_script('dynamic-acf-choices', 'dynamic_acf_ajax', array(
    'ajax_url' => admin_url('admin-ajax.php'),
    'nonce'    => wp_create_nonce('dynamic_acf_nonce'),
  ));
}
get_template_directory_uri() は親テーマのURLを返す
get_template_directory_uri()親テーマのディレクトリURLを返す関数です。子テーマ環境でJSファイルを子テーマ側に置くと、URLが親テーマを指してしまい404になります。子テーマのURLを正しく取得するにはget_stylesheet_directory_uri()を使ってください。

JavaScriptによるカテゴリー変更の検知とAjax送信

dynamic-acf-choices.js(上記でenqueueしたファイル)に、カテゴリー変更を検知してAjax通信を行う処理を記述します。

dynamic-acf-choices.js
jQuery(document).ready(function ($) {
  $('#categorychecklist input[type="checkbox"]').on('change', function () {
    const checked = $('#categorychecklist input[type="checkbox"]:checked');
    if (checked.length > 0) {
      const categoryId = checked.first().val(); // 最初にチェックされたカテゴリID

      $.ajax({
        url: dynamic_acf_ajax.ajax_url,
        type: 'POST',
        data: {
          action: 'get_dynamic_acf_options',
          category_id: categoryId,
          nonce: dynamic_acf_ajax.nonce,
        },
        success: function (response) {
          if (!response.success) return;
          // 選択肢を動的に置き換える
          const selectField = $('select[name="acf[field_123456789abc]"]'); // ACFフィールドのname属性を正確に指定
          selectField.empty();
          $.each(response.data, function (index, value) {
            selectField.append($('<option>', {
              value: value,
              text: value,
            }));
          });
        },
      });
    }
  });
});

Ajaxを受け取るPHP側の処理

次に、Ajaxリクエストを受けてカテゴリーに対応する選択肢を返す処理をfunctions.phpに記述します。nonceの検証(check_ajax_referer)と権限チェック(current_user_can)を必ず行いましょう。

functions.php:Ajaxハンドラー
add_action('wp_ajax_get_dynamic_acf_options', 'get_dynamic_acf_options');
function get_dynamic_acf_options() {
  check_ajax_referer('dynamic_acf_nonce', 'nonce');

  if (!current_user_can('edit_posts')) {
    wp_send_json_error(null, 403);
  }

  $category_id = isset($_POST['category_id']) ? intval($_POST['category_id']) : 0;
  $options = [];

  // カテゴリIDに応じた選択肢を定義(動的にDBから取得してもOK)
  if ($category_id === 5) {
    $options = ['CPU', 'メモリ', 'GPU'];
  } elseif ($category_id === 7) {
    $options = ['画面サイズ', 'バッテリー容量', 'カメラ性能'];
  }

  wp_send_json_success($options);
}

ACFのセレクトフィールドをあらかじめ作成しておく

管理画面でACFのフィールドグループにセレクトボックスを作成し、選択肢を仮でもいいので登録しておきます。JavaScriptで中身を上書きするため、初期値は後で上書かれて問題ありません。

注意点と拡張のヒント

  • カテゴリーが複数選択される場合は、どのIDを優先するか設計方針を決める必要があります。
  • カテゴリーではなく、カスタムタクソノミーや他のフィールドによって選択肢を制御する応用も可能です。
  • サーバー側の選択肢をDBから動的に取得するようにすれば、さらに柔軟な運用ができます。

よくある質問(FAQ)

Q記事のカテゴリー選択に応じてカスタムフィールドの選択肢を変えるには?
AJavaScriptでカテゴリー選択のchangeイベントを監視し、nonce付きのAjaxでカテゴリーに応じたオプション一覧を取得してセレクトボックスを更新します。PHPのAjaxハンドラーでcheck_ajax_referer()による検証を行った上でカテゴリー別オプションを返します。
QGutenbergエディターでも同様の動的フィールド制御は可能ですか?
AGutenbergのカテゴリーパネルは#categorychecklistを使わないReact実装のため、本記事のコードはそのままでは動作しません。PluginSidebarをReactで実装し、wp.dataのselect/subscribeでカテゴリー変更を監視してフィールドを更新する必要があり、クラシックエディターより実装は複雑になります。
QACFでフィールドグループをカテゴリーごとに切り替えるには?
AACFのフィールドグループの表示条件(Location Rules)でPost Categoryを設定します。カテゴリーごとに別々のフィールドグループを作り、それぞれに表示条件を設定します。
QカテゴリーとカスタムフィールドのマッピングをDBに保存・管理するには?
Aoptions APIのupdate_option()でカテゴリーIDをキーとしたオプション配列を保存します。管理画面にカスタム設定ページを作成して管理者がマッピングを編集できるようにすると運用が楽になります。

まとめ

WordPressの投稿画面で、カテゴリーに応じてACFの選択肢を動的に切り替えることで、より直感的で柔軟な管理UIが実現できます。本記事のようにJavaScript(Ajax)+PHP+ACFを組み合わせることで、用途に応じた高度なカスタマイズが可能になります。nonceによる検証と権限チェックを忘れずに実装し、安全なAjax通信を心がけましょう。

開発効率を高めたい、入力ミスを減らしたいという管理画面の改善に、ぜひ取り入れてみてください。