Senden von Formularen ohne Neuladen der Seite: AJAX-Implementierung in WordPress
Veröffentlicht: 2022-03-10Wenn Sie schon immer ein Formular versenden wollten, ohne die Seite neu zu laden, eine Look-Ahead-Suchfunktion bereitstellen, die dem Benutzer während der Eingabe Vorschläge macht, oder Dokumente automatisch speichern, dann brauchen Sie AJAX (auch als XHR bekannt). Eine Hinter-den-Kulissen-Anfrage wird an den Server gesendet und gibt Daten an Ihr Formular zurück. Wenn Sie eine Loader-Animation sehen, nachdem Sie eine Aktion auf der Seite ausgeführt haben, handelt es sich wahrscheinlich um eine AJAX-Anforderung, die an den Server gesendet wird.
In diesem Artikel werde ich Sie durch den gesamten Prozess der Erstellung und Verarbeitung von AJAX-Aufrufen führen. Sie lernen nicht nur, wie Sie einen AJAX-Aufruf tätigen, sondern auch, wie Sie dies am besten mit Funktionen tun, die WordPress Entwicklern direkt aus der Box bietet. Wir werden ein einfaches Plugin erstellen, das es den Lesern ermöglicht, einen Bericht mit Informationen über alle Fehler, die sie auf Ihrer Website entdecken, an den Administrator zu senden.
Am Ende des Artikels können Sie das funktionierende Beispiel herunterladen und den Code vollständig untersuchen.
Lassen Sie uns graben!
AJAX
„Ohne Neuladen der Seite“ ist hier der Schlüsselsatz. AJAX steht für Asynchronous JavaScript And XML , da die vom Server zurückgegebenen Daten zunächst in XML vorliegen sollen. Es ist jedoch einfacher, sie in JSON zu senden, was JavaScript mehr gefällt.
Wir werden AJAX verwenden, um eine E-Mail zu senden. Sie können dies nicht vom Frontend aus tun, also müssen Sie das Backend aufrufen. Normalerweise senden wir eine POST-Anfrage an den Server, verarbeiten sie und leiten den Benutzer zurück auf die Seite mit dem Formular. In dieser Iteration möchten wir die Seite nicht neu laden. Stattdessen rufen wir das Backend direkt auf, wo wir die Formulardaten mit JavaScript erfassen, und senden dann eine asynchrone Anfrage an den Server, um die Antwort zu verarbeiten.
Es gibt drei Dinge, die WordPress AJAX zum Funktionieren braucht – fünf davon, um gut zu funktionieren. Diese sind:
- Objekt für die AJAX-Aktion
- JavaScript-Skript
- WordPress-Aktion
- Schutz
- Fehlerbehandlung
Lassen Sie uns einen genaueren Blick auf jeden von ihnen werfen.
Objekt
Unser Objekt ist die Form. Das ist unsere Sache, mit JavaScript umzugehen. Ich begann damit, eine Datei mit dem vom WordPress-Plugin benötigten Header zu erstellen und ein leeres Objekt darin einzufügen. Am Ende erstelle ich eine neue Instanz der Klasse des Plugins.
<?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();
Auch wenn ich hier etwas OOP verwende, werden wir keine fortgeschrittenen Praktiken verwenden. Der Code würde genauso gut funktionieren, wenn er prozedural mit separaten Funktionen geschrieben würde. Aber Objekte innerhalb von WordPress-Plugins haben einen Vorteil: Sie müssen Ihren Funktionen kein Präfix voranstellen – nur der Klassenname muss eindeutig sein.
Lassen Sie uns unser Formular den Benutzern anzeigen. Wir werden uns in den Filter the_content
und das Formular am Ende jedes Beitrags einbetten. Im Konstruktor der Klasse habe ich den Filter hinzugefügt:
public function __construct() { add_filter( 'the_content', array( $this, 'report_button' ), 10, 1 ); }
Und eine Callback-Methode mit Formular-HTML erstellt:
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; }
Das Formular enthält alle erforderlichen Markups:
- Eine Schaltfläche zum Anzeigen des Formulars und zum Senden der Nachricht;
-
textarea
; - Container für die Antwort (wir werden dies später verwenden).
Button hat das Attribut data-post_id
, das die aktuelle Beitrags-ID speichert. Wir werden dies im JavaScript erfassen, um den Artikel zu identifizieren.
Wir brauchen nur ein paar grundlegende Stile, also registrieren wir unser eigenes Stylesheet mit der Aktion wp_enqueue_scripts
und dem entsprechenden Callback:
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' ); }
Das Stylesheet selbst ist sehr einfach. Wir wollen das Design aufräumen.
.report-a-bug-message { display: none; margin-top: 1em; } .report-a-bug-response { margin-top: 1em; }
So sieht die Schaltfläche aus:
Skript
Wir haben unser Objekt bereit, ihm etwas Leben einzuhauchen. Anstatt es in reinem JavaScript zu tun, werden wir jQuery verwenden, das WordPress standardmäßig auf jeder Seite lädt.
In der vorhandenen Skriptmethode füge ich die JS-Datei mit der Funktion wp_enqueue_script
.
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' ) ) ); }
Ich verwende auch die Funktion wp_localize_script
, um die übersetzte Schaltflächenbeschriftung an JS zu übergeben. Wir haben keine gettext
Funktionen in JavaScript, also müssen wir es hier tun. Diese Funktion erstellt das Einstellungsobjekt , auf das direkt von unserem Skript aus zugegriffen werden kann.
In unserem Skript werden wir auf einen Button-Klick lauschen. Sobald das passiert, zeigen wir den textarea
und schalten die Schaltflächenklasse so um, dass sie auf den zweiten Klick wartet, der das Formular sendet.
( 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 );
Hier der aktuelle Fortschritt:
Es ist die beste Zeit, um die AJAX-Anfrage zu erstellen!
AJAX-Anfragen an WordPress
Um eine AJAX-Anfrage zu senden, benötigen Sie wirklich nur einen einzigen Parameter: die angeforderte URL. WordPress hat die spezielle Datei für AJAX, sodass wir keine eigene erstellen müssen. Es ist /wp-admin/admin-ajax.php
.
Solange wir uns im wp-admin
Bereich befinden, ist diese Datei-URL in JS in der ajaxurl
Variablen verfügbar. Am Frontend müssen wir diese Variable selbst übergeben. Glücklicherweise haben wir die Funktion wp_localize_script
bereits verwendet, sodass wir ihr einfach einen weiteren Schlüssel hinzufügen können:
wp_localize_script( 'report-a-bug', 'settings', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'send_label' => __( 'Send report', 'reportabug' ) ) );
Wir haben alle Variablen vorbereitet, also erstellen wir den AJAX-Aufruf. Wir werden es senden, sobald der Benutzer ein zweites Mal auf die Schaltfläche klickt.
$( '.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' ); } ); } );
Wir hören auf einen Klick auf die Klasse, die wir zuvor eingeschaltet haben.
Wie Sie sehen können, ändere ich den Text der Schaltfläche in „…“ Warum? Weil es gute Praxis ist, dem Benutzer zu zeigen, dass etwas passiert. AJAX-Anfragen sind abhängig von der Serverleistung und dauern einige Zeit. Vielleicht 30 ms, aber vielleicht auch 3 Sekunden. Wenn nach dem Klicken auf die Schaltfläche keine Wirkung zu zeigen scheint, wird die Schaltfläche höchstwahrscheinlich ein zweites Mal angeklickt. Dies würde die Anfrage duplizieren, da diese, wie Sie jetzt wissen, asynchron sind.
Als nächstes erstelle ich das data
. Diese enthält alle Variablen, die an den Server-Callback gesendet werden. Die WordPress-Datei admin-ajax.php
erfordert die Aktionseigenschaft. Dies muss eindeutig sein, es sei denn, Sie möchten, dass das andere Plugin Ihre Anforderungen verarbeitet. Die restlichen Parameter sind optional. Ich sende die Post-ID und die Berichtsnachricht von textarea
.
Wir rufen dann die Methode $.post
. Als nächstes haben Sie es erraten; es sendet die POST-Anfrage. Es ist eine Kurzschriftmethode, aber Sie können auch die $.ajax
Methode verwenden, die mehr Optionen bietet. Als ersten Parameter müssen wir unsere Handler-Datei-URL übergeben, dann die Parameter und dann die Success-Callback-Funktion. Dies ist der Ort, an dem wir die Antwort bearbeiten. Im Moment senden wir nur die einfache Nachricht an die Konsole des Browsers.
Wir sind bereit, die Anfrage im Backend zu bearbeiten.
WordPress-Aktion
Sie fragen sich vielleicht, wie wir uns in die admin-ajax.php einklinken . Natürlich mit Action! WordPress hat zwei Aktionstypen:
wp_ajax_nopriv_{$action} wp_ajax_{$action}
Wo $action
ist, ist der Aktionsname, der in AJAX-Parametern übergeben wird. In unserem Fall ist es send_bug_report
.
Die erste dieser Aktionen wird nur für nicht angemeldete Benutzer ausgeführt. Die zweite nur für eingeloggte Benutzer. Wenn Sie also möchten, dass die Anfrage für beide behandelt wird, müssen Sie beide definieren. Folgendes habe ich im Konstruktor der Klasse getan:
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' ) ); }
Im Rückruf erhalte ich nur den Beitragstitel und sende die E-Mail:
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' ) ); }
Der wichtigste Teil in Bezug auf die Handhabung von AJAX in WordPress ist die letzte Funktion – wp_send_json_success
, die die JSON-codierte Ausgabe druckt und stirbt. Alles, was wir brauchen, um die Antwort mit AJAX Success Callback zu erhalten. Es hat auch einen Zwillingsbruder, wp_send_json_error
, aber dazu kommen wir später.
Das Objekt dieser Funktionen hat zwei Eigenschaften:
- Erfolg
Ist ein boolescher Wert und hängt davon ab, ob Sie es Erfolgs- oder Fehlerfunktion nennen. - Daten
Wenn Sie den Parameter für die Funktion bereitstellen.
Das ist alles von der Back-End-Seite. Lassen Sie uns die Antwort in JS verarbeiten.
Wir werden die Schaltfläche und das Textfeld entfernen und eine vom Server zurückgegebene Nachricht in dem zuvor vorbereiteten Container anzeigen:
$.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 ); });
Und das ist es! Wir haben den funktionierenden AJAX-Aufruf! Aber hören Sie hier nicht auf. Unsere Anfrage ist nicht sicher und schon gar nicht benutzerfreundlich. Wir müssen sicherstellen, dass die Anforderung nur dann ausgeführt wird, wenn dies erforderlich ist.
Schutz
Nonce
Die Nonce ist eine „einmal verwendete Zahl“. Es ist ein kurzer Hash, der aus einer Eingabezeichenfolge erstellt wird. Wir können damit die Anfrage validieren – wenn sie wirklich von WordPress stammt und niemand sie vortäuscht.
Wir werden ein anderes Datenattribut für die Schaltfläche verwenden:
$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>';
Wie Sie sehen können, füge ich die Beitrags-ID der Eingabezeichenfolge hinzu. Wir haben diese ID in den AJAX-Anforderungseigenschaften verfügbar, also ist sie einfach sicherer.
Jetzt müssen wir die Nonce zu den AJAX-Eigenschaften hinzufügen:
// 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() };
Jetzt validieren wir es im Backend mit der Funktion check_ajax_referer
, die WordPress bereitstellt:
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' ) ); }
Um die Anfrage zu validieren, müssen wir die Eingabezeichenfolge neu generieren, also verwende ich den von AJAX gesendeten post_id
Schlüssel. Der zweite Parameter ist der Schlüssel im $_REQUEST array
. Dritte steuert das automatisierte wp_die
, wenn Nonce nicht übereinstimmt.
Ich will nicht, dass es selbst stirbt. Stattdessen fange ich das Ergebnis dieser Funktion ab und sende einen JSON-Fehler in einem netten Objekt.
Möglicherweise bemerken Sie auch die Verwendung der Funktion sanitize_text_field
im E-Mail-Nachrichtenparameter. Dies soll nur sicherstellen, dass der Benutzer keine schädlichen Skripte oder HTML sendet.
Zuletzt müssen wir den AJAX-Erfolgs-Callback in JS in die if-Anweisung einschließen, um zu überprüfen, ob die Anfrage erfolgreich war:
$.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 ); } });
Tastenschutz
Sie wissen, dass der Benutzer ein zweites Mal auf die Schaltfläche klicken kann, bevor AJAX den Anruf beendet. Aber es gibt einen einfachen Trick, der den zweiten Klick blockiert – das Deaktivieren der Schaltfläche. Nach dem Klick werde ich es also blockieren und entsperren, nachdem ich die Antwort erhalten habe:
$('.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); }); });
Fehlerbehandlung
Validierung
Was ist, wenn der Benutzer versucht, eine leere Nachricht zu senden? Ich möchte nicht mit solchen E-Mails belästigt werden. Blockieren wir diese Versuche mit Validierungstechniken.
In JS werde ich eine einfache Validierung hinzufügen, um dem Benutzer zu zeigen, dass etwas schief gelaufen ist. Wenn die Nachricht leer ist, sieht der Benutzer den roten Rahmen um das Textfeld. Wenn dort eine Nachricht vorhanden ist, stellen wir die neutrale Grenze wieder her:
$('.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 });
Auf Fehler in der WordPress-Aktion prüfen
Möglicherweise haben wir auch ein Problem beim Senden der E-Mail. Wenn wir das Ergebnis der Funktion wp_mail
nicht überprüfen, erhält der Benutzer eine Erfolgsmeldung, obwohl keine E-Mail gesendet wurde.
Lassen Sie uns damit umgehen:
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(); } }
Wie Sie sehen, haben wir die Funktion wp_send_json_error
zweimal verwendet, aber es besteht keine Notwendigkeit, eindeutige Nachrichten für Benutzer anzuzeigen. Stattdessen werde ich, indem ich die genaue Fehlerbeschreibung übergebe, einen weiteren Schlüssel zu unserem Skripteinstellungsobjekt hinzufügen, der beide Fehler abdeckt:
// 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' ) ) );
Dem Benutzer muss nur noch der Fehler angezeigt werden:
$.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 ); } );
Vollständiges Beispiel
Wir haben es geschafft! Unsere AJAX-Anfrage wurde gestellt; es ist gut gesichert und benutzerfreundlich. Dies ist, was ein Benutzer im Falle von Fehlern sehen wird:
Unten können Sie das vollständige Plugin herunterladen und die Benutzerhandbücher überprüfen:
- Laden Sie das Plugin auf Github herunter
- Laden Sie das Plugin auf Wordpress.org herunter
- Gehen Sie zu den Benutzerhandbüchern
Ich hoffe, dies gibt Ihnen eine gute Grundlage für Ihre eigenen „Ohne-Seiten-Aktualisierung“-Lösungen. Sie können dies für alle Formulare auf Ihrer Website tun. Es ist auch eine großartige Möglichkeit, umfangreiche Teile der Website zu optimieren, die nicht sofort geladen werden müssen, z. B. eine große Liste von Produkten in einem Dropdown-Menü. Sie können sie einfach per AJAX laden, nachdem Sie auf das Dropdown-Menü geklickt haben – so einfach ist das.
Die Möglichkeiten sind nahezu grenzenlos. Lasst mich in den Kommentaren wissen, was eure Ideen sind!