WordPressとajax (1)
Image by Phil Riley from Pixabay
2021.10.11(更新日:2021.10.20)
非同期で条件に合わせて値を変化させるなんて場合は「Ajax」を使う。
Wordpressにはそれ様の関数なんかもあるので、やり方さえ分かれば問題ない・・・はずだったが
久々に使うとスッカリ脳内消失なので、サンプルを作りまとめてみる。
オレオレ式の説明なので正式な表現は多分してないのはご了承。
この記事は1年以上経過しています。内容的に古い場合があります。
サンプルの仕様
項目をチェックボックスにてフォーム内表示させ、選択するごとに記事の合計が表示されると言うもの。
submitする前にどれくらいの件数があるか確認出来るのでユーザービリティ向上には一役買える。
ただしサンプルなので簡潔にしたく、投稿とカテゴリーを使用して構成する。
これを応用し「複数のタクソノミーを持ちいて選択条件に一致した数を表示する」などが本来。
(なので「これならajax使う必要ないじゃん」とは言わないことを条件に読み進めて欲しい)
まずはテンプレート部分から。
<?php
/* テンプレート内にでも */
$lists = '';
$args = array(
'orderby' => 'menu_order',
'order' => 'ASC',
'hide_empty' => 0
);
$categories = get_categories( $args );
foreach( $categories as $value ){
if( $value->parent === 0 ){
$lists .= '<label>';
}
}
?>
<form method="get" id="searchform">
<div><?php echo $lists; ?></div>
<div>該当件数:<span id="search-result-count"></span>件</div>
<div><input type="submit" value="検索"></div>
</form>
get_categoriesで取得したオブジェクトのparent値が0のものだけ表示することにより、最上位のタームだけ表示。
チェックボックスの値にはタームの投稿数を入れる。
ajaxで取得した値はsearch-result-count内に件数を表示させる。
手っ取り早くjQueryを使う
調べた結果、JavaScriptで非同期に通信を行うには以下の方法がある。
- XMLHttpRequest・・・JavaScriptの組み込みオブジェクト
- jQuery.ajax・・・jQueryメソッド(ただしバージョンによって使えるものが変わる)
- axios・・・ajax通信専用のライブラリ(らしい。使ったことなし)
今回はWordpressにて使用するので実績のあるjQueryを使用する。解説サイトもいっぱいあるので、手始めには一番無難かなと思う。また何とかie11もカバーしてくれている様子なので、未だにie11・・・と言うお客様もフォロー出来る。(かもしれない)
アクションフックで下準備
JSで何らかの値を投げてPHPで取得し、PHPで処理した値をまたJSに返す。これがざっくりした流れ。
あと重要なのが言語を取り持つjson。この型式で言語の違いをカバーする。
今回Worepressを使うので、作法に従いアクションフックを用いて行う。
兎にも角にも最初にjQueryをテーマで読み込ませる。
/* functions.phpなど */
add_action('wp_enqueue_scripts', 'my_load_scripts');
function my_load_scripts() {
wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'jquery-migrate' );
}
上記はWordpressに梱包されているものをそのまま読み込んだ例。Wordpress ver5.8.1 で
- jQuery ver3.6
- jQuery Migrate ver3.3.2
と意外と最新のものだった。(2021.10) このバージョンなら流用してもいいかな。
nonceを加えてJSに渡す
なんてことなくDBのデータを取ってこれるajax。逆に言えば悪用されたらとっても怖い。
そこで「nonce」と言う一時的な値を生成、確認要素とし値を比較することで「処理するか中断」を判断させる。
/* functions.phpなど */
add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );
function my_enqueue_scripts() {
$handle = 'sample_handle'; // 1. JSファイルにhandle名を付ける
$action = 'sample-ajax-action'; // 2. Ajaxのアクション名
$object_name = 'sampleAjax'; // 3. JSで扱う変数名
// 4. ajaxの指示を書いたjsファイルの読み込み。外部ファイル
wp_enqueue_script( $handle, get_template_directory_uri().'/js/script-ajax.js', array( 'jquery' ) );
// 5. JS側へAjaxで使う各パラメータを渡す
wp_localize_script(
$handle,
$object_name,
array(
'url' => admin_url( 'admin-ajax.php' ),
'action' => $action,
'nonce' => wp_create_nonce( $action ),
)
);
wp_enqueue_script( $handle );
}
この部分整理しておかないと結構ゴチャゴチャしてくるけど
- スクリプトの識別名を決める。ユニークな値
- JSとPHPで共有するアクション名。ユニークな値
- wp_localize_scriptで生成された値を入れとく変数名。ユニークな値(アンダースコアまたはキャメルケースを使用)
- 読み込み場所やファイル名は適宜変更
- wp_localize_script を使いJSで使うパラメータを生成。array部分の値をscriptタグで表示
これでwp_localize_scriptによってJSで使う要素をscritpタグにて表示(head内)してくれるので、JSで拾える。
$objct_nameで指定した「sampleAjax」にurlやaction、nonceの値もあるのが確認出来ると思う。
/* 公開側のhead内に出されたもの */
<script id='sample_handle-js-extra'>
var sampleAjax = {"url":"http:\/\/xxx.com\/wordpress\/wp-admin\/admin-ajax.php","action":"sample-ajax-action","nonce":"f15adbcb77"};
</script>
JSファイルの制作
/* script-ajax.js */
(function($) {
$(function (){
$("#searchform").change(function() {
seachMatchCount();
});
function seachMatchCount(){
$.ajax({
type: 'POST',
url: sampleAjax.url, // A
dataType: 'json',
data: {
action : sampleAjax.action, // A
nonce: sampleAjax.nonce, // A
terms : term_id // B
}
}).done( function( data ) {
// 成功時。出力する部分(処理)
$('#search-result-count').html(data);
}).fail( function( XMLHttpRequest, textStatus, error ){
// 通信失敗時のコールバック処理
console.log( 'XMLHttpRequest : ' + XMLHttpRequest.status );
console.log( 'textStatus : ' + textStatus );
console.log( 'errorThrown : ' + error.message );
}).always(function (data) {
// 常に実行する処理
});
}
});
})(jQuery);
ajaxを発火させる処理
submitされてからでは意味ない。checkboxをチェックに対して反応して欲しいので「change」で対応。
(今回はチェックボックスしかないのでフォームのパーツが変更されたらとしている)
ajax処理
「seachMatchCount」の部分。ajaxの説明をしているサイトは多々あるけど「done / fail / always」の書き方が良いらしい。
(jQueryのバージョン等々にもよるかも。少なくとも3.Xはこれで書く)
「A」の部分は、前の章でアクションフック値を記述。(my_enqueue_scriptsの$object_name)
「B」はフォームによってPOSTされる値をキー付きで記述。(フォームの input checkbox のname値)
「done」部分は成功時。戻り値を書き込み処理。
失敗時にはコンソールにてエラー表示するようにした。alwaysは今回必要ないと思えるが、ajaxの記述型式を説明するために入れてある。
JSON
説明が結構面倒なのでパス。実際「やんわり」としか分かってないので以下参照。
アクションフックで処理コード
JSの方で「チェックボックスをチェックしたら件数を返せ」と記述した。
その際チェックボックスの値がajaxでPOSTにて送信される。これを受け取ってPHPで処理して返すと言うのがこれ。
POSTされた値は数字が入った単なる配列。で、それらの合計を返却。
/* functionsとかに */
add_action( 'wp_ajax_sample-ajax-action', 'get_match_count' );
add_action( 'wp_ajax_nopriv_sample-ajax-action', 'get_match_count' );
function get_match_count(){
$count = 0;
if( $_SERVER['REQUEST_METHOD'] === 'POST' && check_ajax_referer( 'sample-ajax-action', 'nonce' ) ) {
terms = filter_input( INPUT_POST, 'terms', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
if( isset( $terms ) ){
foreach( $terms as $value ) $count = $count + (int)$value;
}
}
header("Content-type: application/json; charset=UTF-8");
echo json_encode( $count );
wp_die();
}
なんだか色々書いてあるが、パターン化し使い回すのが吉。
/* PHP */
add_action( 'wp_ajax_(アクション名)', '処理関数名' );
add_action( 'wp_ajax_nopriv_(アクション名)', '処理関数名' );
function 処理関数名(){
if( $_SERVER['REQUEST_METHOD'] === 'POST' && check_ajax_referer( 'アクション名', 'nonce' ) ) {
// 処理を記述
}
header("Content-type: application/json; charset=UTF-8");
echo json_encode( JSに返す変数 );
wp_die();
}
まとめ
必須のnonceを入れるところで、アクション名とJSの変数名の位置づけを理解する。
今回のサンプルは「配列をPOSTし、単一の値を返却」するものなので、JSON部分を意識しないでも出来た。
次回は「配列でPOST、配列で返却」をやる予定。