スクリプトのエンキュー
このセクションでは、WordPressに不慣れな経験豊富なコーダーがつまずくAJAXの2つの主要な特異点について説明します。1つは、ページのヘッダーセクションにメタリンクを正しく表示させるためにスクリプトをエンキューする必要があることです。もう1つは、すべての AJAXリクエストはwp-admin/admin-ajax.php
を通じて送信する必要があることです。プラグインページに直接リクエストを送信しないでください。
エンキュー
関数wp_enqueue_script()
を使用して、WordPressにページのセクションにスクリプトへのメタリンクを挿入させます。ヘッダーテンプレートにそのようなリンクをハードコーディングしないでください。プラグイン開発者として、ヘッダーテンプレートに直接アクセスすることはできませんが、このルールは言及する価値があります。
エンキュー関数は、次の5つのパラメータを受け入れます:
- $handle はスクリプトの名前です。
- $src はスクリプトの場所を定義します。ポータビリティのために、
plugins_url()
を使用して適切なURLを構築します。プラグイン以外の何かのためにスクリプトをエンキューする場合は、適切なURLを作成するために関連する関数を使用してください - ハードコーディングしないでください。 - $deps は、新しいスクリプトが依存するスクリプト(例えばjQuery)を処理できる配列です。AJAXリクエストを送信するためにjQueryを使用しているので、少なくとも
'jquery'
を配列にリストする必要があります。 - $ver はバージョン番号をリストすることを可能にします。
- $args は、フッター印刷(
in_footer
キーを介して)およびスクリプト読み込み戦略(strategy
キーを介して)を定義する引数の配列で、defer
やasync
などがあります。これは、WordPressバージョン6.3以降の$in_footer
パラメータを置き換え/オーバーロードします。
wp_enqueue_script(
'ajax-script',
plugins_url( '/js/myjquery.js', __FILE__ ),
array( 'jquery' ),
'1.0.,0',
array(
'in_footer' => true,
)
);
スクリプトコードページが読み込まれているときに、プラグインコードから直接スクリプトをエンキューすることはできません。スクリプトは、いくつかのアクションフックのいずれかからエンキューする必要があります - どのフックを使用するかは、スクリプトがリンクされるページの種類によります。管理ページの場合はadmin_enqueue_scripts
を使用します。フロントエンドページの場合はwp_enqueue_scripts
を使用しますが、ログインページの場合はlogin_enqueue_scripts
を使用します。
``````bash
add_action( 'admin_enqueue_scripts', 'my_enqueue' );
function my_enqueue( $hook ) {
if ( 'myplugin_settings.php' !== $hook ) {
return;
}
wp_enqueue_script(
'ajax-script',
plugins_url( '/js/myjquery.js', __FILE__ ),
array( 'jquery' ),
'1.0.0',
array(
'in_footer' => true,
)
);
}
`
ここで名前付き関数を使用する理由は、jQueryで匿名関数を使用するのとは異なります。クロージャは最近PHPでサポートされるようになりました。jQueryはかなり前からそれをサポートしています。古いバージョンのPHPを使用している人もいるかもしれないので、最大の互換性のために常に名前付き関数を使用します。最近のPHPバージョンを持っていて、自分のインストールのためだけに開発している場合は、好きな場合はクロージャを使用してください。
登録とエンキュー
他のチュートリアルではwp_register_script()
を厳格に使用する例が見られるでしょう。これは問題ありませんが、その使用はオプションです。オプションではないのはwp_enqueue_script()
です。この関数は、スクリプトファイルがウェブページに正しくリンクされるために呼び出す必要があります。では、なぜスクリプトを登録するのですか?それは、必要に応じてコードのさまざまな部分でスクリプトを簡単に参照できる便利なタグまたはハンドルを作成するからです。スクリプトを読み込むだけで、コードの他の場所で参照しない場合は、登録する必要はありません。
遅延スクリプト読み込み
WordPressは、wp_register_script()
およびwp_enqueue_script()
関数を介してスクリプト読み込み戦略を指定するサポートを提供します。これは、WordPress 6.3で導入された新しい$args
配列パラメータ内のstrategy
キーを介して行われます。
サポートされている戦略は次のとおりです:
- defer
- $argsパラメータに
'strategy' => 'defer'
の配列キー値ペアを指定することで追加されます。 - 遅延実行のためにマークされたスクリプトは、DOMツリーが完全に読み込まれた後(ただし、
DOMContentLoaded
およびウィンドウの読み込みイベントの前)にのみ実行されます。遅延スクリプトは、DOMに印刷/追加された順序で実行され、非同期スクリプトとは異なります。
- $argsパラメータに
- async
$args
パラメータに'strategy' => 'async'
の配列キー値ペアを指定することで追加されます。- 非同期実行のためにマークされたスクリプトは、ブラウザによって読み込まれるとすぐに実行されます。非同期スクリプトは、実行順序が保証されていません。スクリプトB(スクリプトAの後にDOMに追加されても)がスクリプトAよりも先に実行される可能性があります。このようなスクリプトは、DOMが完全に構築される前または
DOMContentLoaded
イベントの後に実行される可能性があります。
以下は、プラグイン内で追加のスクリプトエンキューのための読み込み戦略を指定する例です:
wp_register_script(
'ajax-script-two',
plugins_url( '/js/myscript.js', __FILE__ ),
array( ajax-script ),
'1.0.,0',
array(
'strategy' => 'defer',
)
);
遅延スクリプト読み込み戦略を指定する際には、スクリプトの依存関係ツリー(その依存関係および/または依存先)を考慮して、「適格な戦略」を決定します。これにより、1つのスクリプトには有効だが、ツリー内の他のスクリプトには有害な戦略が適用されることを防ぎます。このような論理の結果、`````$args`````パラメータを介して渡す意図された読み込み戦略は、最終的な(選択された)戦略ではないかもしれませんが、意図された戦略に対して有害であったり、厳格であったりすることはありません。
<a name="nonce"></a>
### ノンス
jQuery AJAXリクエストが不正なリクエストではなく正当なリクエストとして検証されるように、ノンスを作成する必要があります。あなたのPHPスクリプトとjQueryスクリプトだけがこの値を知っています。リクエストが受信されると、ここで作成されたのと同じ値であることを確認できます。これが私たちの例のためのノンスを作成する方法です:
``````bash
$title_nonce = wp_create_nonce( 'title_example' );
`
パラメータtitle_example
は任意の文字列で構いません。ノンスが使用される目的に関連する文字列を推奨しますが、実際にはあなたに合ったものであれば何でも構いません。
ローカライズ
jQueryセクションを思い出すと、PHPによってjQueryで使用されるために作成されたデータは、my_ajax_obj
という名前のグローバルオブジェクトに渡されました。私たちの例では、このデータはノンスとadmin-ajax.php
への完全なURLでした。オブジェクトプロパティを割り当て、グローバルjQueryオブジェクトを作成するプロセスは、ローカライズと呼ばれます。これは、wp_localize_script()
を使用した私たちの例で使用されるローカライズコードです。
wp_localize_script(
'ajax-script',
'my_ajax_obj',
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => $title_nonce,
)
);
スクリプトハンドルajax-script
が使用されて、グローバルオブジェクトが正しいスクリプトに割り当てられることに注意してください。このオブジェクトは私たちのスクリプトに対してグローバルであり、すべてのスクリプトに対してグローバルではありません。ローカリゼーションは、スクリプトをエンキューするために使用されるのと同じフックからも呼び出すことができます。ノンスを作成することも同様ですが、その特定の関数はほぼどこでも呼び出すことができます。それらすべてを単一のフックコールバックにまとめると、次のようになります:
add_action( 'admin_enqueue_scripts', 'my_enqueue' );
/**
* Enqueue my scripts and assets.
*
* @param $hook
*/
function my_enqueue( $hook ) {
if ( 'myplugin_settings.php' !== $hook ) {
return;
}
wp_enqueue_script(
'ajax-script',
plugins_url( '/js/myjquery.js', __FILE__ ),
array( 'jquery' ),
'1.0.0',
true
);
wp_localize_script(
'ajax-script',
'my_ajax_obj',
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'title_example' ),
)
);
}
必要なページにのみこのノンスローカリゼーションを追加することを忘れないでください。使用すべきでない人にノンスを表示しないでください。そして、current_user_can()
を使用して、セキュリティを完了するために能力または役割を使用することを忘れないでください。
AJAXアクション
サーバー側のPHPコードのもう1つの主要な部分は、POSTされたデータを受信し、それに対して何かを行い、適切な応答をブラウザに返す実際のAJAXハンドラーです。これは、WordPressのaction hookの形式を取ります。どのフックタグを使用するかは、ユーザーがログインしているかどうか、およびjQueryスクリプトがaction:値として渡した値によって異なります。
$_GET , $_POST および $_COOKIE vs $_REQUEST
おそらく、$_GET
や$_POST
などのPHPスーパーグローバルを使用して、フォームやクッキーから値を取得したことがあるでしょう($_COOKIE
を使用)。$_REQUEST
を代わりに好むか、少なくともそれが使用されているのを見たことがあるかもしれません。それはクールです - リクエストメソッドに関係なく、POST
またはGET
、フォーム値を持っています。両方のメソッドを使用するページに最適です。その上、クッキー値も持っています。一つのストップショッピングです!そこに悲劇的な欠陥があります。名前の衝突が発生した場合、クッキー値はフォーム値を上書きします。したがって、悪意のあるアクターがブラウザで偽のクッキーを作成し、リクエストから期待されるフォーム値を上書きするのは非常に簡単です。$_REQUEST
は、ハッカーが任意のデータをフォーム値に注入するための簡単なルートです。特に安全にするために、特定の変数に固執し、すべてに適したものを避けてください。
私たちのAJAX交換はプラグインの設定ページのためのものであるため、ユーザーはログインしている必要があります。jQueryセクションを思い出すと、action:
値は"my_tag_count"
です。これは、私たちのアクションフックタグがwp_ajax_my_tag_count
になることを意味します。もし私たちのAJAX交換が現在ログインしていないユーザーによって利用される場合、アクションフックタグはwp_ajax_nopriv_my_tag_count
になります。アクションをフックするために使用される基本的なコードは次のようになります:
add_action( 'wp_ajax_my_tag_count', 'my_ajax_handler' );
/**
* Handles my AJAX request.
*/
function my_ajax_handler() {
// Handle the ajax request here
wp_die(); // All ajax handlers die when finished
}
あなたのAJAXハンドラーが最初に行うべきことは、jQueryによって送信されたノンスをcheck_ajax_referer()
で確認することです。これは、スクリプトがエンキューされたときにローカライズされたのと同じ値である必要があります。
check_ajax_referer( 'title_example' );
提供されたパラメータは、wp_create_nonce()
に以前に提供されたパラメータと同一でなければなりません。このノンスがチェックアウトしない場合、関数は単に終了します。これが真のノンスであれば、使用されたため、その値はもはや有効ではありません。新しいものを生成し、コールバックスクリプトに送信して次のリクエストで使用できるようにします。しかし、WordPressのノンスは24時間有効であるため、チェックするだけで何もする必要はありません。
データ
ノンスが解決されたので、ハンドラーは$_POST['title']
に含まれるjQueryスクリプトによって送信されたデータを処理できます。まず、予期しない引用符を削除するためにwp_unslash()を通して実行した後、新しい変数に値を割り当てます。
$title = wp_unslash( $_POST['title'] );
ユーザーの選択をユーザーメタに保存するには、update_user_meta()を使用します。
update_user_meta( get_current_user_id(), 'title_preference', sanitize_post_title( $title ) );
次に、選択されたタイトルタグの投稿数を取得するためのクエリを構築します。
$args = array(
'tag' => $title,
);
$the_query = new WP_Query( $args );
最後に、jQueryスクリプトに応答を返すことができます。データを送信する方法はいくつかあります。具体的な例に対処する前に、いくつかのオプションを見てみましょう。
XML
PHPのXMLサポートは期待外れです。幸いなことに、WordPressはWP_Ajax_Response
クラスを提供して、作業を容易にします。WP_Ajax_Responseクラスは、XML形式の応答を生成し、ヘッダーの正しいコンテンツタイプを設定し、応答XMLを出力し、終了します - 適切なXML応答を保証します。
JSON
この形式は軽量で使いやすく、WordPressはwp_send_json
関数を提供して、応答をjsonエンコードし、印刷し、終了します - 実質的にWP_Ajax_Responseを置き換えます。WordPressはwp_send_json_success
およびwp_send_json_error
関数も提供しており、これによりJSで適切なdone()またはfail()コールバックが発火します。
その他
送信者と受信者が調整されている限り、データを好きな方法で転送できます。カンマ区切りやタブ区切りのようなテキスト形式は、多くの可能性の1つです。少量のデータの場合、生のストリームを送信するだけで十分かもしれません。それが私たちの例で行うことです - 実際の置き換えHTMLを送信します、他には何もありません。
echo esc_html( $title ) . ' (' . $the_query->post_count . ') ';
実際のアプリケーションでは、アクションが何らかの理由で失敗する可能性を考慮する必要があります - たとえば、データベースサーバーがダウンしているかもしれません。応答はこの不測の事態を考慮する必要があり、応答を受信するjQueryスクリプトはそれに応じて行動する必要があります。たとえば、ユーザーに後で再試行するように指示するかもしれません。
終了
ハンドラーがすべてのタスクを完了したら、終了する必要があります。WP_Ajax_Responseまたはwp_send_json*関数を使用している場合、これは自動的に処理されます。そうでない場合は、単にWordPressのwp_die()
関数を使用してください。
AJAXハンドラーの概要
私たちの例の完全なAJAXハンドラーは次のようになります:
/**
* AJAX handler using JSON
*/
function my_ajax_handler__json() {
check_ajax_referer( 'title_example' );
$title = wp_unslash( $_POST['title'] );
update_user_meta( get_current_user_id(), 'title_preference', sanitize_post_title( $title ) );
$args = array(
'tag' => $title,
);
$the_query = new WP_Query( $args );
wp_send_json( esc_html( $title ) . ' (' . $the_query->post_count . ') ' );
}
/**
* AJAX handler not using JSON.
*/
function my_ajax_handler() {
check_ajax_referer( 'title_example' );
$title = wp_unslash( $_POST['title'] );
update_user_meta( get_current_user_id(), 'title_preference', sanitize_post_title( $title ) );
$args = array(
'tag' => $title,
);
$the_query = new WP_Query( $args );
echo esc_html( $title ) . ' (' . $the_query->post_count . ') ';
wp_die(); // All ajax handlers should die when finished
}