WordPress の カスタムフィールドのプラグインである ACF (Advanced Custom Fields) には、多数のフックや JavaScript API が用意されています。
やること
今回は、JavaScript API とフックの組み合わせで select2 フィールドをカスタマイズしてみます。具体的には、投稿のプルダウンをラジオボタンで選択したカテゴリーのみに絞って表示させる、ということをやってみます。
準備
ACF でカテゴリーのラジオボタンと投稿のプルダウンを用意します。表示する条件は固定ページにしておきます。
このときの各フィールドのキー (field_667d1f74494c8
や field_667d1d6343e57
) を控えておきます。
また、初期データとして、投稿とカテゴリーをいくつか用意しておきます。
投稿のプルダウンをクリックすると、全ての投稿が選択肢として表示されます。
コーディング
select2 フィールドのプルダウンはクリックの都度、Ajax 通信で表示する選択肢を取得しています。この Ajax のリクエストに介入する JavaScript のフックに select2_ajax_data
というのが用意されています。
getAjaxData: function (params) {
// vars
var ajaxData = {
action: this.get('ajaxAction'),
s: params.term || '',
paged: params.page || 1
};
// field helper
var field = this.get('field');
if (field) {
ajaxData.field_key = field.get('key');
if (field.get('nonce')) {
ajaxData.nonce = field.get('nonce');
}
}
// callback
var callback = this.get('ajaxData');
if (callback) {
ajaxData = callback.apply(this, [ajaxData, params]);
}
// filter
ajaxData = acf.applyFilters('select2_ajax_data', ajaxData, this.data, this.$el, field || false, this);
// return
return acf.prepareForAjax(ajaxData);
},
このフックを使ってラジオボタンで選択されたカテゴリーの情報を POST に追加するようにします。適当な JS ファイルに以下の記述をします。
// 素の JS
acf.add_filter('select2_ajax_data', function (data, args, $input, field, instance) {
if ('field_667d1d6343e57' !== data.field_key) {
// 投稿のプルダウンでなければ何もしない
return data;
}
// カテゴリーのラジオボタンで選択された value を取得する
const selectedCat = document.querySelector('input[name="acf[field_667d1f74494c8]"]:checked');
if (selectedCat) {
data.cat = selectedCat.value;
}
return data;
});
// jQuery
jQuery(document).ready(function ($) {
acf.add_filter('select2_ajax_data', function (data, args, $input, field, instance) {
if ('field_667d1d6343e57' !== data.field_key) {
return data;
}
const $selectedCat = $('input[name="acf[field_667d1f74494c8]"]:checked');
if ($selectedCat) {
data.cat = $selectedCat.val();
}
return data;
});
});
フィールド作成時に控えておいたキーはユニークになっているので、セレクタとして使用しています。
次に、PHP 側のフックを使って、作成した JS ファイルの enqueue を行います。注意点として、ACF の JavaScript API を利用するには、ハンドル名 acf-input
があらかじめ読み込まれている必要があるので、引数に追加するのを忘れないようにします。
add_action('admin_enqueue_scripts', function ($hook_suffix) {
if ('post.php' === $hook_suffix || 'post-new.php' === $hook_suffix) {
wp_register_script('acf-js-api-usage', plugin_dir_url(__FILE__) . '/acf-js-api-usage.js', ['acf-input']);
wp_enqueue_script('acf-js-api-usage');
}
});
PHP 側では POST したカテゴリー情報をハンドリングする処理も必要です。ACF で、acf/fields/post_object/query/key={$key}
というフックが用意されているので、これを利用します。
add_filter('acf/fields/post_object/query/key=field_667d1d6343e57', function($args, $field, $post_id) {
$args['cat'] = $_POST['cat'];
return $args;
}, 10, 3);
このフィルターフックで返却する $args
は最終的に WP_Query の引数になります。今回はカテゴリーで絞り込むので、POST した値を $args['cat']
に代入します。
画面を確認してみると、ラジオボタンで選択したカテゴリーの投稿のみが表示されていることがわかります。
まとめと感想
今回、ACF のコードを数年ぶりに読みました。私にとって、WordPress のプラグインの中では読みやすい部類だと感じました。ドキュメントもしっかりメンテされている (と思っている) ので、迷子になることもなかったです。
ACF の JavaScript API とフックは、設定画面では出来ないようなフィールドの複雑なカスタマイズやフィールドの表示条件を動的に変更することが出来るので、わりと便利な機能だと思っています。ただ、認知度が低い気がします。日本語の記事もほとんど見当たらなかったですし。だいぶニッチな機能なので仕方ないと言えばそうなのですが。。