ページをリロードせずにフォームを送信する:WordPressでのAJAXの実装
公開: 2022-03-10ページをリロードせずにフォームを送信したい場合は、入力時にユーザーに提案を求める先読み検索機能を提供するか、ドキュメントを自動保存します。必要なのはAJAX ( XHRとも呼ばれます)です。 舞台裏のリクエストがサーバーに送信され、データがフォームに返されます。 ページ上で何らかのアクションを実行した後にローダーアニメーションが表示される場合は常に、サーバーに送信されているAJAXリクエストである可能性があります。
この記事では、AJAX呼び出しを作成および処理するプロセス全体をガイドします。 AJAX呼び出しを行う方法だけでなく、WordPressが開発者にすぐに提供する機能を使用してそれを最良の方法で行う方法も学習します。 読者があなたのウェブサイトで見つけたかもしれないバグについての情報を含むレポートを管理者に送ることを可能にする簡単なプラグインを構築します。
記事の最後で、実際の例をダウンロードして、コードを完全に調べることができます。
掘り下げましょう!
AJAX
「ページをリロードせずに」がここでの重要な文です。 AJAXはAsynchronousJavaScript And XMLの略です。これは、最初はサーバーから返されるデータがXMLであると想定されているためです。 ただし、JavaScriptが好むJSONで送信する方が簡単です。
AJAXを使用してメールを送信します。 フロントエンドからは実行できないため、バックエンドを呼び出す必要があります。 通常、POSTリクエストをサーバーに送信して処理し、ユーザーをフォームのあるページにリダイレクトします。 この反復では、ページをリロードしたくありません。 代わりに、JavaScriptを使用してフォームデータをキャプチャするバックエンドを直接呼び出し、非同期リクエストをサーバーに送信してレスポンスを処理します。
WordPress AJAXが機能するために必要なものは3つあり、そのうち5つはうまく機能します。 これらは:
- AJAXアクションのオブジェクト
- JavaScriptスクリプト
- WordPressアクション
- 保護
- エラー処理
それぞれを詳しく見ていきましょう。
物体
私たちの目的はフォームです。 これはJavaScriptで処理するものです。 WordPressプラグインに必要なヘッダーを含むファイルを作成し、その中に空のオブジェクトを配置することから始めました。 最後に、プラグインのクラスの新しいインスタンスを作成しています。
<?php /* Plugin Name: Report a bug Description: Allow your visitors to report a bug in your articles Author: Jakub Mikita Author URI: https://underdev.it Version: 1.0 License: GPL2 Text Domain: reportabug */ class Report_a_bug { } new Report_a_bug();
ここではいくつかのOOPを使用していますが、高度なプラクティスは使用しません。 このコードは、個別の関数を使用して手続き的に記述した場合にも同様に機能します。 ただし、WordPressプラグイン内のオブジェクトには、1つの利点があります。関数にプレフィックスを付ける必要はなく、クラス名のみが一意である必要があります。
フォームをユーザーに表示してみましょう。 the_content
フィルターに接続し、すべての投稿の最後にフォームを埋め込みます。 クラスのコンストラクターにフィルターを追加しました。
public function __construct() { add_filter( 'the_content', array( $this, 'report_button' ), 10, 1 ); }
そして、フォームHTMLでコールバックメソッドを作成しました。
public function report_button( $content ) { // display button only on posts if ( ! is_single() ) { return $content; } $content .= '<div class="report-a-bug"> <button class="show-form" data-post_>' . __( 'Report a bug', 'reportabug' ) . '</button> <textarea class="report-a-bug-message" placeholder="' . __( 'Describe what\'s wrong...', 'reportabug' ) . '"></textarea> <p class="report-a-bug-response"></p> </div>'; return $content; }
フォームには必要なすべてのマークアップがあります。
- フォームを表示してメッセージを送信するためのボタン。
-
textarea
; - 応答のコンテナ(これは後で使用します)。
Buttonには、現在の投稿IDを格納するdata-post_id
属性があります。 これをJavaScriptで取得して、記事を識別します。
基本的なスタイルだけが必要なので、独自のスタイルシートをwp_enqueue_scripts
アクションと対応するコールバックに登録しましょう。
public function __construct() { add_filter( 'the_content', array( $this, 'report_button' ), 10, 1 ); add_action( 'wp_enqueue_scripts', array( $this, 'scripts' ) ); } function scripts() { wp_enqueue_style( 'report-a-bug', plugin_dir_url( __FILE__ ) . 'css/style.css' ); }
スタイルシート自体は非常に単純です。 デザインを整理したい。
.report-a-bug-message { display: none; margin-top: 1em; } .report-a-bug-response { margin-top: 1em; }
ボタンの外観は次のとおりです。
脚本
オブジェクトに生命を吹き込む準備ができています。 プレーンなJavaScriptで行う代わりに、WordPressがすべてのページにデフォルトでロードするjQueryを使用します。
既存のscriptsメソッドでは、 wp_enqueue_script
関数を使用してJSファイルを追加します。
function scripts() { wp_enqueue_style( 'report-a-bug', plugin_dir_url( __FILE__ ) . 'css/style.css' ); wp_enqueue_script( 'report-a-bug', plugin_dir_url( __FILE__ ) . 'js/scripts.js', array( 'jquery' ), null, true ); // set variables for script wp_localize_script( 'report-a-bug', 'settings', array( 'send_label' => __( 'Send report', 'reportabug' ) ) ); }
また、 wp_localize_script
関数を使用して、翻訳されたボタンラベルをJSに渡します。 JavaScriptにはgettext
関数がないので、ここで実行する必要があります。 この関数は、スクリプトから直接アクセスできる設定オブジェクトを作成します。
スクリプトでは、ボタンのクリックをリッスンします。 それが発生したら、 textarea
を表示し、ボタンクラスを切り替えて、フォームを送信している2回目のクリックをリッスンします。
( function( $ ) { $( document ).ready( function() { $( '.report-a-bug' ).on( 'click', '.show-form', function( event ) { // change label and switch class $( this ).text( settings.send_label ).removeClass( 'show-form' ).addClass( 'send-report' ); // show textarea $( '.report-a-bug-message' ).slideDown( 'slow' ); }) }); })( jQuery );
現在の進捗状況は次のとおりです。
AJAXリクエストを作成するのに最適な時期です!
WordPressへのAJAXリクエスト
AJAXリクエストを送信するには、実際に必要なのは、リクエストされたURLという唯一のパラメータだけです。 WordPressにはAJAX用の特別なファイルがあるので、独自のファイルを作成する必要はありません。 /wp-admin/admin-ajax.php
です。
wp-admin
領域にいる限り、このファイルのURLはJSのajaxurl
変数で使用できます。 フロントエンドでは、この変数を自分で渡す必要があります。 幸い、すでにwp_localize_script
関数を使用しているので、別のキーを追加するだけです。
wp_localize_script( 'report-a-bug', 'settings', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'send_label' => __( 'Send report', 'reportabug' ) ) );
すべての変数を準備したので、AJAX呼び出しを作成しましょう。 ユーザーがボタンをもう一度クリックすると送信されます。
$( '.report-a-bug' ).on( 'click', '.send-report', function( event ) { var $button = $( this ); $button.width( $button.width() ).text('...'); // set ajax data var data = { 'action' : 'send_bug_report', 'post_id': $button.data( 'post_id' ), 'report' : $( '.report-a-bug-message' ).val() }; $.post( settings.ajaxurl, data, function( response ) { console.log( 'ok' ); } ); } );
以前にボタンをオンにしたクラスのクリックを聞いています。
ご覧のとおり、ボタンのテキストを「…」に変更しています。なぜですか。 何かが起こっていることをユーザーに示すのは良い習慣だからです。 AJAXリクエストはサーバーのパフォーマンスに依存し、時間がかかります。 たぶん30msですが、たぶん3秒です。 ボタンをクリックしても効果がないように思われる場合は、ボタンを2回クリックする可能性があります。 ご存知のように、これらは非同期であるため、これによりリクエストが複製されます。
次に、 data
オブジェクトを作成します。 これには、サーバーのコールバックに送信されるすべての変数が含まれます。 WordPressのadmin-ajax.php
ファイルにはactionプロパティが必要です。 他のプラグインにリクエストを処理させたくない場合を除いて、これは一意である必要があります。 残りのパラメーターはオプションです。 textarea
から投稿IDとレポートメッセージを送信しています。
次に、 $.post
メソッドを呼び出します。 次に、あなたはそれを推測しました。 POSTリクエストを送信しています。 これは省略形のメソッドですが、より多くのオプションがある$.ajax
メソッドを使用することもできます。 最初のパラメーターとして、ハンドラーファイルのURLを渡し、次にパラメーターを渡し、次に成功コールバック関数を渡す必要があります。 これは、私たちが応答を処理している場所です。 今のところ、ブラウザのコンソールに簡単なメッセージを送信しているだけです。
バックエンドでリクエストを処理する準備が整いました。
WordPressアクション
admin-ajax.phpにどのように接続するのか疑問に思われるかもしれません。 もちろん、アクション付き! WordPressには2つのアクションタイプがあります。
wp_ajax_nopriv_{$action} wp_ajax_{$action}
$action
がある場合、AJAXパラメーターで渡されるアクション名。 この場合はsend_bug_report
です。
これらのアクションの最初は、ログインしていないユーザーに対してのみ実行されます。 2つ目は、ログインしているユーザー専用です。 したがって、両方のリクエストを処理する場合は、両方を定義する必要があります。 これは、クラスのコンストラクターで行ったことです。
public function __construct() { add_filter( 'the_content', array( $this, 'report_button' ), 10, 1 ); add_action( 'wp_enqueue_scripts', array( $this, 'scripts' ) ); add_action( 'wp_ajax_nopriv_send_bug_report', array( $this, 'send_bug_report' ) ); add_action( 'wp_ajax_send_bug_report', array( $this, 'send_bug_report' ) ); }
コールバックでは、投稿のタイトルを取得し、メールを送信しています。
function send_bug_report() { $data = $_POST; $post_title = get_the_title( intval( $data['post_id'] ) ); wp_mail( '[email protected]', 'Bug report in post: ' . $post_title, $data['report'] ); wp_send_json_success( __( 'Thanks for reporting!', 'reportabug' ) ); }
WordPressでAJAXを処理する上で最も重要な部分は、最後の関数であるwp_send_json_success
であり、JSONでエンコードされた出力を出力して終了します。 AJAX成功コールバックで応答を取得するために必要なのはすべてです。 双子の兄弟wp_send_json_error
もありますが、その部分については後で説明します。
これらの関数のオブジェクトには、次の2つのプロパティがあります。
- 成功
ブール値であり、成功関数と呼ぶかエラー関数と呼ぶかによって異なります。 - データ
関数のパラメーターを指定した場合。
それはすべてバックエンド側からです。 JSで応答を処理してみましょう。
ボタンとtextareaを削除し、サーバーから返されたメッセージを前に準備したコンテナーに表示します。
$.post(settings.ajaxurl, data, function(response) { // remove button and textarea $button.remove(); $('.report-a-bug-message').remove(); // display success message $('.report-a-bug-response').html( response.data ); });
以上です! 動作するAJAX呼び出しがあります! しかし、そこで止まらないでください。 私たちの要求は安全ではなく、確かにユーザーフレンドリーではありません。 要求が必要な場合にのみ実行されるようにする必要があります。
保護
ノンス
ナンスは「一度使用した数」です。 これは、入力文字列から作成された短いハッシュです。 これを使用してリクエストを検証できます—実際にWordPressによって作成されたものであり、だれもそれを偽造していない場合。
ボタンに別のデータ属性を使用します。
$nonce = wp_create_nonce( 'report_a_bug_' . get_the_ID() ); $content .= '<div class="report-a-bug"> <button class="show-form" data-nonce="' . $nonce . '" data-post_>' . __( 'Report a bug', 'reportabug' ) . '</button> <textarea class="report-a-bug-message" placeholder="' . __( 'Describe what\'s wrong...', 'reportabug' ) . '"></textarea> <p class="report-a-bug-response"></p> </div>';
ご覧のとおり、入力文字列に投稿IDを追加しています。 このIDはAJAXリクエストプロパティで利用できるようになるため、より安全になります。
次に、ナンスをAJAXプロパティに追加する必要があります。
// set ajax data var data = { 'action' : 'send_bug_report', 'post_id': $button.data('post_id'), 'nonce' : $button.data('nonce'), 'report' : $('.report-a-bug-message').val() };
次に、WordPressが提供するcheck_ajax_referer
関数を使用してバックエンドで検証します。
function send_bug_report() { $data = $_POST; // check the nonce if ( check_ajax_referer( 'report_a_bug_' . $data['post_id'], 'nonce', false ) == false ) { wp_send_json_error(); } $post_title = get_the_title( intval( $data['post_id'] ) ); wp_mail( '[email protected]', 'Bug report in post: ' . $post_title, sanitize_text_field( $data['report'] ) ); wp_send_json_success( __( 'Thanks for reporting!', 'reportabug' ) ); }
リクエストを検証するには、入力文字列を再生成する必要があるため、AJAXから送信されたpost_id
キーを使用しています。 2番目のパラメーターは、 $_REQUEST array
のキーです。 3番目は、nonceが一致しない場合に、自動化されたwp_die
を制御します。
自分で死なせたくない。 代わりに、この関数の結果をキャッチして、素敵なオブジェクトでJSONエラーを送信しています。
また、電子メールメッセージパラメータでsanitize_text_field
関数が使用されていることに気付くかもしれません。 これは、ユーザーが有害なスクリプトやHTMLを送信しないようにするためだけのものです。
最後に、リクエストが成功したかどうかを確認するために、JSでAJAX成功コールバックをifステートメントでラップする必要があります。
$.post(settings.ajaxurl, data, function(response) { if ( response.success == true ) { // remove button and textarea $button.remove(); $('.report-a-bug-message').remove(); // display success message $('.report-a-bug-response').html( response.data ); } });
ボタン保護
AJAXが通話を終了する前に、ユーザーがボタンを2回クリックできることを知っています。 ただし、2回目のクリックをブロックする簡単なトリックが1つあります。それは、ボタンを無効にすることです。 それで、クリックした後、私はそれをブロックし、応答を得た後にそれをブロック解除するつもりです:
$('.report-a-bug').on('click', '.send-report', function(event) { var $button = $(this); $button.width( $button.width() ).text('...').prop('disabled', true); // set ajax data var data = {...}; $.post(settings.ajaxurl, data, function(response) { if ( response.success == true ) {...} // enable button $button.prop('disabled', false); }); });
エラー処理
検証
ユーザーが空のメッセージを送信しようとするとどうなりますか? そんなメールに煩わされたくない。 検証手法を使用して、これらの試行をブロックしましょう。
JSでは、何か問題が発生したことをユーザーに示すために、簡単な検証を追加します。 メッセージが空の場合、ユーザーにはテキストエリアの周りに赤い境界線が表示されます。 メッセージがそこに存在する場合、ニュートラルボーダーを復元しています。
$('.report-a-bug').on('click', '.send-report', function(event) { var $button = $(this); // check if message is not empty if ( $( '.report-a-bug-message' ).val().length === 0 ) { $( '.report-a-bug-message' ).css( 'border', '1px solid red' ); return false; } else { $( '.report-a-bug-message' ).css( 'border', '1px solid rgba(51, 51, 51, 0.1)' ); } // ... ajax });
WordPressアクションのエラーをチェックする
また、メールの送信に問題がある可能性があります。 wp_mail
関数の結果を確認しないと、電子メールが送信されていなくても、ユーザーは成功メッセージを受け取ります。
これを処理しましょう:
function send_bug_report() { $data = $_POST; // check the nonce if ( check_ajax_referer( 'report_a_bug_' . $data['post_id'], 'nonce', false ) == false ) { wp_send_json_error(); } $post_title = get_the_title( intval( $data['post_id'] ) ); $result = wp_mail( '[email protected]', 'Bug report in post: ' . $post_title, sanitize_text_field( $data['report'] ) ); if ( $result == false ) { wp_send_json_success( __( 'Thanks for reporting!', 'reportabug' ) ); } else { wp_send_json_error(); } }
ご覧のとおり、 wp_send_json_error
関数を2回使用しましたが、ユーザーに固有のメッセージを表示する必要はありません。 代わりに、正確なエラーの説明を渡して、両方のエラーをカバーする別のキーをスクリプト設定オブジェクトに追加します。
// set variables for script wp_localize_script( 'report-a-bug', 'settings', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'send_label' => __( 'Send report', 'reportabug' ), 'error' => __( 'Sorry, something went wrong. Please try again', 'reportabug' ) ) );
あとは、ユーザーにエラーを表示するだけです。
$.post( settings.ajaxurl, data, function( response ) { if ( response.success == true ) { // remove button and textarea $button.remove(); $( '.report-a-bug-message' ).remove(); // display success message $( '.report-a-bug-response' ).html( response.data ); } else { // display error message $( '.report-a-bug-response' ).html( settings.error ); } // enable button and revert label $button.text( settings.send_label ).prop( 'disabled', false ); } );
完全な例
やった! AJAXリクエストが行われました。 安全性が高く、ユーザーフレンドリーです。 これは、エラーが発生した場合にユーザーに表示される内容です。
以下で、完全なプラグインをダウンロードして、ユーザーガイドを確認できます。
- Githubでプラグインをダウンロードします
- Wordpress.orgでプラグインをダウンロードします
- ユーザーガイドに移動します
これにより、独自の「ページ更新なし」ソリューションの優れた基盤が提供されることを願っています。 あなたはあなたのウェブサイト上のすべてのフォームにこれを行うことができます。 また、ドロップダウン内の製品の大きなリストなど、すぐにロードする必要のないWebサイトの重い部分を最適化するための優れた方法でもあります。 ドロップダウンをクリックした直後にAJAXを介してそれらをロードできます—それはとても簡単です。
可能性はほぼ無限です。 コメントであなたのアイデアを教えてください!