WordPressでは新規投稿や投稿を更新する際に、管理画面へログインし各編集用ページから更新ボタンをクリックするなどで同期的に行われますが、Ajaxを使って管理画面外からも非同期で投稿を更新したりすることができます。今回はAjaxで投稿済みのカスタムフィールドの値を更新する例を用いて、Ajax処理の実装をまとめていきたいと思います。ちなみに過去記事
「WordPressでサブループを使った非同期での無限ローディング機能を作成してみる」でもAjaxを使った処理の例を紹介しています。この時は投稿済みのデータを非同期で取得して表示させるだけでしたが、今回は実際にデータベースに登録されている情報を更新するので、また違ったアプローチとなります。
今回ですが、カスタムフィールドの値を更新する例となりますので、下記のカスタムフィールドが作成されている前提となります。
カスタムフィールドキー:'cf_example'
入力タイプ:テキストボックス
使用プラグイン:Advanced Custom Fields Plugin for WordPress
まず最初にカスタムフィールドの入力要素のUIをHTML上に作成しておきます。ここでは、カスタムフィールドの値を表示させる部分と更新用のテキストボックス、更新ボタンを用意していきます。Ajaxではカスタムフィールドの値を更新するために、テキストボックスの入力値、更新対象の投稿IDの情報を扱うので、カスタムデータ属性などを使ってあらかじめ取得しておきます。
<?php if(!empty(get_field('cf_example'))): ?>
<p><?php echo esc_html(get_field('cf_example')); ?></p>
<?php endif; ?>
<input type="text" class="js-form-input">
<button type="button" class="js-form-submit" data-post-id="<?php echo get_the_ID(); ?>">入力項目で更新</button>
今回の実装にあたり、処理に関しては下記のようにバックエンド側で実装するものと、フロントエンド側で実装するものと大きく2つに分けることができます。
●バックエンド側の処理
- スクリプトのローカライズ化
- アクションフックで処理を登録
●フロントエンド側の処理
- イベントハンドラでAjax処理の実行
そこで以下に順を追って実装例をまとめてみたいと思います。
(バックエンド側)スクリプトのローカライズ化
まずはバックエンド側の処理でスクリプトのローカライズ化を行います。これはWordPressで用意されているAjax用エンドポイントのURLやセキュリティトークンなどをフロント側で変数として扱えるようにするためです。その前にまずはフロントエンド側の処理を含むスクリプトファイルを読み込んでいきます。これは通常のスクリプトを読み込む方法と同じですね。
// フロントエンド側のAjax処理が含まれるスクリプトの読み込み
function register_script() {
if(!is_admin()) {
wp_enqueue_script('ajax-post-js', get_template_directory_uri().'/assets/js/ajax-post.js', array(), null, 'all');
}
}
add_action('wp_enqueue_scripts', 'register_script');
ただ、1点大事なポイントとして、wp_enqueue_script()メソッドで外部のスクリプトを読み込む際にハンドル名を指定しますが、このハンドル名がローカライズされる際に必要となります。ここを紐づけることでローカライズされた変数がここで読み込んだスクリプトで使えるようになるためです。
続いてローカライズの処理を行なっていきます。下記のように「wp_localize_script()」メソッドを使い、第一引数には先述のハンドル名を、第二引数には変数名を、第三引数には変数で使用するデータを入れていきます。データについてはAjax用のエンドポイントURLとnonceと呼ばれるWordPressで扱われるセキュリティトークンを格納します。それぞれ「admin_url()」「wp_create_nonce()」メソッドで生成することができます。
// Ajaxで使用するAPIのURLとセキュリティ対策のnonceを発行し、フロント側に変数として出力
function create_localize_script() {
$data = array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('ajax_nonce_action')
);
wp_localize_script('ajax-post-js', 'ajax_object', $data);
}
add_action('wp_enqueue_scripts', 'create_localize_script');
上記で扱われるメソッドについては下記にまとめておりますので、合わせてご参考ください。wp_create_nonce()で引数に指定している値は、nonceのトークンチェックの際に使用しますので重要です。
admin_url($path) |
管理画面領域のURLを出力するメソッドで、引数にパスを指定することができる。Ajax用のAPIエンドポイントの場合には「admin-ajax.php」を指定する。 |
wp_create_nonce($action_name) |
nonceを発行するためのメソッドで、セキュリティのためのトークンの役割を果たす。引数にはアクション名を指定する。 |
wp_localize_script($script_handle, $data_name, $data) |
変数をローカライズするメソッドで、第一引数でハンドル名で指定したスクリプトでローカライズされた変数が使用できる。変数名や変数に代入するデータを指定する。 |
上記処理の結果、AjaxでPOST先となるURLとnonceのトークン値をローカライズされました。ページ側へHTMLの中にスクリプトとして出力されて、フロント側でデータを参照できるようになり、ローカライズ対象のスクリプトの後に読み込まれるようにスクリプトが出力されます。wp_footer()によってHTML上に下記のように出力されているのが確認できます。
......
<script type='text/javascript' id='ajax-post-js-js-extra'>
/* <![CDATA[ */
var ajax_object = {"ajax_url":"https:\/\/example.com\/wp-admin\/admin-ajax.php","nonce":"abcde12345"};
/* ]]> */
</script>
<script type='text/javascript' src='https://example.com/wp-content/themes/sample-theme/assets/js/ajax-post.js' id='ajax-post-js-js'></script>
......
(バックエンド側)アクションフックで処理を登録
引き続きバックエンド側の処理を行なっていきます。次はフロントエンド側からAjaxによってPOSTされてきた値を受け取り、その値を使ってカスタムフィールドを更新する処理を作成していきます。それぞれfunctions.phpに追加し、「wp_ajax_」と「wp_ajax_nopriv_」のアクションフックで実行されるように用意しておきます。これはログイン用のユーザーと非ログイン用のユーザーとアクションフックが異なるため両方用意しておく必要があるからですね。
// ログインユーザー用
function ajax_update_meta_value() {
check_ajax_referer('ajax_nonce_action', 'nonce', ture);
update_post_meta($_POST['post_id'], 'cf_example', $_POST['value']);
wp_die();
}
add_action( 'wp_ajax_ajax_update_meta_value_action', 'ajax_update_meta_value' );
// 未ログインユーザー用
function ajax_update_meta_value_nopriv() {
check_ajax_referer('ajax_nonce_action', 'nonce', ture);
update_post_meta($_POST['post_id'], 'cf_example', $_POST['value']);
wp_die();
}
add_action( 'wp_ajax_nopriv_ajax_update_meta_value_action', 'ajax_update_meta_value_nopriv' );
上記ではフロントエンド側からAjaxで対象の投稿IDやカスタムフィールドに登録する値がPOST送信されてきたものを受け取り、update_post_meta()メソッドで更新するという流れになります。この際に「check_ajax_referer()」を使ってトークンチェックの処理を入れておくと安全です。また、アクションフックには「wp_ajax_」「wp_ajax_nopriv_」の後にそれぞれ、Ajax側で送られてきた「action」キーの値がそのままアクションフック名として使用されるので指定します。
check_ajax_referer($nonce_action, $query_arg, $die) |
nonceを検証するためのメソッドで、引数にはnonce生成時に設定したアクション名を指定する他、nonceの値を持つキーの指定や、無効時の終了処理などが指定できる。 |
wp_ajax_{$ajax_action} |
ログインユーザーを対象にAjaxに対してサーバー側の処理をするアクションフック。「wp_ajax_」をプレフィックスとして、Ajaxで送られてきたactionの値を指定する。 |
wp_ajax_nopriv_{$ajax_action} |
未ログインユーザーを対象にAjaxに対してサーバー側の処理をするアクションフック。「wp_ajax_nopriv_」をプレフィックスとして、同じようにactionの値を指定する。 |
これでバックエンド側の処理が揃いましたので、あとはフロントエンド側のAjax処理を作成していきます。
(フロントエンド側)イベントハンドラでAjax処理の実行
フロントエンド側の処理では、HTML上に出力されたWordPressのデータやフォーム入力値をクリックなどのイベントハンドラでAjaxを使ってバックエンド側にPOST送信していきます。先ほど「wp_enqueue_scripts」のフックで登録したスクリプトファイルに処理を書いていきます。
【assets/js/ajax-post.js】
const input = document.querySelector('.js-form-input');
const button = document.querySelector('.js-form-submit');
button.addEventListener('click', (event) => {
const params = new URLSearchParams([
[ 'action', 'ajax_update_meta_value_action' ],
[ 'nonce', ajax_object.nonce ],
[ 'post_id', Number(button.getAttribute('data-post-id')) ],
[ 'value', input.value ],
]);
fetch(ajax_object.ajax_url, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
body: params
}).then(() => {
location.reload();
}).catch((error) => {
console.log(error);
});
});
今回はHTML側に用意したテキストボックスと送信ボタンを使って、フォーム入力値がAPIのエンドポイントに送信される仕組みを作成します。上記ではVanillaJSでfetch()メソッドを使った方法ですが、jQueryの「ajax()」メソッドなんかもよく使われています。Ajaxで送信するデータですが、JSON文字列で送信する場合に400エラーが発生することもあるので、サーチパラメーター形式の文字列を採用しています。その際に、「headers」オプションでContent-Typeの指定だけ忘れずに行なっておきます。
その他、最初に設定したローカライズされた変数から、Ajax用のエンドポイントのURLやセキュリティトークンであるnonceの値などをこの処理の中で使っていきます。また、actionのキーの値ではアクションフック名となる文字列も指定しておくことも忘れないようにします。AjaxによるPOST送信後はバックエンド側にデータが更新されているものの、リロードしないと画面上は同期されないためリロードの処理を入れています。
これで、フロントエンドからイベントハンドラによってAjax処理が実行され、アクションフックを経由してWordPressに投稿されている情報を更新することができました。
今回はAjaxとアクションフックを使って非同期でWordPressの投稿データを更新する方法についてまとめてみました。この方法を使うことでいいねボタンやお気に入りの登録機能など、フロント側の処理を使ってWordPressの情報を更新することができます。一見するとややこしそうですがWordPressにはAjax処理に関するお作法のように用意されているので、ぜひ覚えておきたいですね。
参考にさせていただいたサイト
WordPress AJAX
WordPress Server Side PHP and Enqueuing
categories