Trimiterea formularelor fără a reîncărca pagina: Implementarea AJAX în WordPress
Publicat: 2022-03-10Dacă ați dorit vreodată să trimiteți un formular fără a reîncărca pagina, oferiți o funcție de căutare anticipată care solicită utilizatorului sugestii pe măsură ce scrie sau salvarea automată a documentelor, atunci ceea ce aveți nevoie este AJAX (cunoscut și ca XHR ). O solicitare din culise este trimisă la server și returnează datele în formularul dvs. Ori de câte ori vedeți o animație de încărcare după ce ați făcut o acțiune pe pagină, probabil că este o solicitare AJAX trimisă la server.
În acest articol, vă voi ghida prin întregul proces de creare și gestionare a apelurilor AJAX. Veți învăța nu numai cum să efectuați un apel AJAX, ci și cum să o faceți în cel mai bun mod, folosind funcțiile pe care WordPress le oferă dezvoltatorilor imediat de la început. Vom construi un plugin simplu care va permite cititorilor să trimită un raport administratorului cu informații despre orice eroare pe care l-ar putea observa pe site-ul dvs.
La sfârșitul articolului, puteți descărca exemplul de lucru și puteți examina codul în întregime.
Să pătrundem!
AJAX
„Fără a reîncărca pagina” este propoziția cheie aici. AJAX înseamnă Asynchronous JavaScript And XML , deoarece inițial, datele returnate de la server ar trebui să fie în XML. Cu toate acestea, este mai ușor să le trimiteți în JSON, care îi place mai mult JavaScript.
Vom folosi AJAX pentru a trimite un e-mail. Nu o puteți face din front-end, așa că trebuie să apelați back-end-ul. De obicei, trimitem o solicitare POST către server, o gestionăm și redirecționăm utilizatorul înapoi la pagina cu formularul. În această iterație, nu dorim să reîncărcăm pagina. În schimb, apelăm direct backend-ul de unde vom captura datele formularului cu JavaScript, apoi vom trimite o solicitare asincronă serverului pentru a gestiona răspunsul.
Există trei lucruri de care WordPress AJAX trebuie să funcționeze - cinci dintre ele pentru a funcționa bine . Acestea sunt:
- Obiect pentru acțiunea AJAX
- Script JavaScript
- Acțiune WordPress
- Protecţie
- Eroare de manipulare
Să aruncăm o privire mai atentă la fiecare dintre ele.
Obiect
Obiectul nostru este forma. Acesta este lucrul nostru de tratat cu JavaScript. Am început cu crearea unui fișier cu antetul necesar pluginului WordPress și cu introducerea unui obiect gol înăuntru. În cele din urmă, creez o nouă instanță a clasei pluginului.
<?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();
Chiar dacă folosesc ceva OOP aici, nu vom folosi nicio practică avansată. Codul ar funcționa la fel de bine atunci când este scris procedural cu funcții separate. Dar obiectele din pluginurile WordPress au un avantaj: nu trebuie să prefixezi funcțiile tale - doar numele clasei trebuie să fie unic.
Să afișăm formularul nostru pentru utilizatori. Ne vom conecta la filtrul the_content
și vom încorpora formularul de la sfârșitul fiecărei postări. În constructorul clasei am adăugat filtrul:
public function __construct() { add_filter( 'the_content', array( $this, 'report_button' ), 10, 1 ); }
Și a creat o metodă de apel invers cu formularul 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; }
Formularul are toate markupurile necesare:
- Un buton pentru a afișa formularul și a trimite mesajul;
-
textarea
; - Container pentru răspuns (vom folosi acest lucru mai târziu).
Butonul are atributul data-post_id
care stochează ID-ul postării curente. Vom prelua acest lucru în JavaScript pentru a identifica articolul.
Avem nevoie doar de un stil de bază, așa că haideți să ne înregistrăm propria foaie de stil cu acțiunea wp_enqueue_scripts
și callback-ul corespunzător:
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' ); }
Foaia de stil în sine este foarte simplă. Vrem să punem în ordine designul.
.report-a-bug-message { display: none; margin-top: 1em; } .report-a-bug-response { margin-top: 1em; }
Iată cum arată butonul:
Scenariul
Avem obiectul nostru pregătit pentru a pune ceva viață în el. În loc să o facem în JavaScript simplu, vom folosi jQuery pe care WordPress îl încarcă implicit pe fiecare pagină.
În metoda scripturilor existente, voi adăuga fișierul JS folosind funcția 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' ) ) ); }
De asemenea, folosesc funcția wp_localize_script
pentru a transmite eticheta butonului tradus către JS. Nu avem nicio funcție gettext
în JavaScript, așa că trebuie să o facem aici. Această funcție va crea obiectul de setări care poate fi accesat direct din scriptul nostru.
În scriptul nostru, vom asculta un clic pe buton. Odată ce se întâmplă acest lucru, vom afișa zona de textarea
și vom schimba clasa de butoane pentru a asculta al doilea clic care trimite formularul.
( 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 );
Iată progresul actual:
Este cel mai bun moment pentru a crea cererea AJAX!
Solicitări AJAX către WordPress
Pentru a trimite o solicitare AJAX, aveți nevoie într-adevăr de un singur parametru: adresa URL solicitată. WordPress are fișierul special pentru AJAX, așa că nu trebuie să ne creăm al nostru. Este /wp-admin/admin-ajax.php
.
Atâta timp cât ne aflăm în zona wp-admin
, această adresă URL a fișierului este disponibilă în JS în variabila ajaxurl
. Pe front-end, trebuie să trecem singuri această variabilă. Din fericire, am folosit deja funcția wp_localize_script
, așa că putem adăuga o altă cheie:
wp_localize_script( 'report-a-bug', 'settings', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'send_label' => __( 'Send report', 'reportabug' ) ) );
Am pregătit toate variabilele, așa că haideți să creăm apelul AJAX. Îl vom trimite odată ce utilizatorul face clic pe butonul a doua oară.
$( '.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' ); } ); } );
Ascultăm un clic pe clasa pe care am activat butonul înainte.
După cum puteți vedea, schimb textul butonului în „…” De ce? Pentru că este o practică bună să arăți utilizatorului că se întâmplă ceva. Solicitările AJAX depind de performanța serverului și vor dura ceva timp. Poate 30 ms, dar poate și 3 secunde. Dacă după apăsarea butonului pare să nu existe niciun efect, cel mai probabil butonul va fi apăsat a doua oară. Acest lucru ar duplica cererea, deoarece, după cum știți acum, acestea sunt asincrone.
În continuare, creez obiectul de data
. Acesta conține toate variabilele care vor fi trimise către serverul de apel invers. Fișierul WordPress admin-ajax.php
necesită proprietatea de acțiune. Acest lucru trebuie să fie unic, cu excepția cazului în care doriți ca celălalt plugin să vă gestioneze solicitările. Restul parametrilor este opțional. Trimit ID-ul postării și mesajul de raportare din textarea
.
Apoi apelăm metoda $.post
. Apoi, ați ghicit; trimite cererea POST. Este o metodă scurtă, dar puteți folosi și metoda $.ajax
, care are mai multe opțiuni. Ca prim parametru trebuie să transmitem URL-ul fișierului nostru de gestionare, apoi parametrii și apoi funcția de apel invers de succes. Acesta este locul în care ne ocupăm de răspuns. Deocamdată, trimitem doar mesajul simplu către consola browserului.
Suntem gata să gestionăm cererea pe back-end.
Acțiune WordPress
Poate vă întrebați cum ne conectam la admin-ajax.php . Cu acțiune, desigur! WordPress are două tipuri de acțiuni:
wp_ajax_nopriv_{$action} wp_ajax_{$action}
Acolo unde este $action
, numele acțiunii a fost transmis în parametrii AJAX. Este send_bug_report
în cazul nostru.
Prima dintre aceste acțiuni va fi executată numai pentru utilizatorii care nu sunt autentificați. Al doilea doar pentru utilizatorii autentificati. Deci, dacă doriți ca cererea să fie tratată pentru ambele, trebuie să le definiți pe ambele. Iată ce am făcut în constructorul clasei:
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' ) ); }
În apelul înapoi, primesc doar titlul postării și trimit e-mailul:
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' ) ); }
Cea mai importantă parte în ceea ce privește gestionarea AJAX în WordPress este ultima funcție - wp_send_json_success
care tipărește rezultatul codificat JSON și moare. Tot ce avem nevoie pentru a obține răspunsul cu apel invers AJAX. Are și un frate geamăn, wp_send_json_error
, dar vom ajunge la acea parte mai târziu.
Obiectul din aceste funcții are două proprietăți:
- succes
Este un boolean și depinde dacă o numiți funcție de succes sau de eroare. - date
Dacă furnizați parametrul funcției.
Asta e tot din partea back-end. Să ne ocupăm de răspunsul în JS.
Vom elimina butonul și zona de text și vom afișa un mesaj returnat de la server în containerul pe care l-am pregătit înainte:
$.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 ); });
Si asta e! Avem apelul AJAX de lucru! Dar nu te opri aici. Solicitarea noastră nu este sigură și cu siguranță nu este ușor de utilizat. Trebuie să ne asigurăm că cererea este executată numai atunci când trebuie.
Protecţie
Nonce
Nonce este un „număr folosit o dată”. Este un hash scurt creat dintr-un șir de intrare. O putem folosi pentru a valida cererea - dacă într-adevăr a fost făcută de WordPress și nimeni nu o falsifică.
Vom folosi un alt atribut de date pentru buton:
$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>';
După cum puteți vedea, adaug ID-ul postării la șirul de intrare. Vom avea acest ID disponibil în proprietățile solicitării AJAX, deci este mai sigur.
Acum trebuie să adăugăm nonce la proprietățile 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() };
Acum îl vom valida în backend folosind funcția check_ajax_referer
, pe care WordPress o oferă:
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' ) ); }
Pentru a valida cererea, trebuie să regenerăm șirul de intrare, așa că folosesc cheia post_id
trimisă de la AJAX. Al doilea parametru este cheia din $_REQUEST array
. Third controlează wp_die
automat dacă nonce nu se potrivește.
Nu vreau să moară singur. În schimb, prind rezultatul acestei funcții și trimit o eroare JSON într-un obiect frumos.
Este posibil să observați, de asemenea, utilizarea funcției sanitize_text_field
în parametrul mesajului de e-mail. Acest lucru este doar pentru a vă asigura că utilizatorul nu va trimite niciun script dăunător sau HTML.
În cele din urmă, trebuie să încapsulăm apelul de succes AJAX în JS în declarația if pentru a verifica dacă cererea a avut succes:
$.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 ); } });
Protecție butoane
Știți că utilizatorul poate face clic pe butonul a doua oară, înainte ca AJAX să termine apelul. Dar există un truc simplu care va bloca al doilea clic - dezactivarea butonului. Deci, după clic, îl voi bloca și îl voi debloca după ce primesc răspunsul:
$('.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); }); });
Eroare de manipulare
Validare
Ce se întâmplă dacă utilizatorul încearcă să trimită un mesaj gol? Nu vreau să fiu deranjat cu astfel de e-mailuri. Să blocăm aceste încercări cu tehnici de validare.
În JS voi adăuga o validare simplă, pentru a arăta utilizatorului că ceva a mers prost. Dacă mesajul este gol, utilizatorul va vedea chenarul roșu în jurul zonei de text. Dacă există un mesaj acolo, restaurăm granița neutră:
$('.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 });
Verificarea erorilor în acțiunea WordPress
Este posibil să avem și o problemă cu trimiterea e-mailului. Dacă nu verificăm rezultatul funcției wp_mail
, utilizatorul va primi un mesaj de succes chiar dacă nu a fost trimis niciun e-mail.
Să ne ocupăm de asta:
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(); } }
După cum vedeți, am folosit funcția wp_send_json_error
de două ori, dar nu este nevoie să afișam mesaje unice pentru utilizatori. În schimb, trecând descrierea exactă a erorii, voi adăuga o altă cheie la obiectul nostru de setări de script care va acoperi ambele erori:
// 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' ) ) );
Tot ce rămâne de făcut este să afișeze eroarea utilizatorului:
$.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 ); } );
Exemplu complet
Am făcut-o! Solicitarea noastră AJAX a fost făcută; este bine securizat și ușor de utilizat. Iată ce va vedea un utilizator în cazul oricăror erori:
Mai jos puteți descărca pluginul complet și puteți verifica ghidurile de utilizare:
- Descărcați pluginul pe Github
- Descărcați pluginul de pe Wordpress.org
- Accesați ghidurile utilizatorului
Sper că acest lucru vă oferă o bază bună pentru propriile soluții „fără reîmprospătare a paginii”. Puteți face acest lucru pentru toate formularele de pe site-ul dvs. Este, de asemenea, o modalitate excelentă de a optimiza orice parte grea a site-ului web care nu trebuie să fie încărcată imediat, cum ar fi o listă mare de produse într-un drop-down. Le puteți încărca prin AJAX imediat după ce faceți clic pe meniul drop-down - este atât de simplu.
Posibilitățile sunt aproape nelimitate. Spune-mi în comentarii care sunt ideile tale!