Invio di moduli senza ricaricare la pagina: implementazione AJAX in WordPress

Pubblicato: 2022-03-10
Riassunto veloce ↬ Esistono molte soluzioni "senza aggiornamento della pagina", ma eccone una che puoi creare con AJAX. In questo tutorial puoi imparare a costruire un semplice plugin che permetterà ai lettori di inviare un report senza ricaricare la pagina.

Se hai mai desiderato inviare un modulo senza ricaricare la pagina, fornire una funzione di ricerca anticipata che richiede all'utente suggerimenti durante la digitazione o salvare automaticamente i documenti, allora ciò di cui hai bisogno è AJAX (noto anche come XHR ). Una richiesta dietro le quinte viene inviata al server e restituisce i dati al tuo modulo. Ogni volta che vedi un'animazione del caricatore dopo aver eseguito un'azione sulla pagina, è probabilmente una richiesta AJAX inviata al server.

In questo articolo, ti guiderò attraverso l'intero processo di creazione e gestione delle chiamate AJAX. Imparerai non solo come effettuare una chiamata AJAX, ma anche come farlo nel modo migliore utilizzando le funzionalità che WordPress offre agli sviluppatori immediatamente. Creeremo un semplice plug-in che consentirà ai lettori di inviare una segnalazione all'amministratore con informazioni su qualsiasi bug che potrebbero individuare sul tuo sito web.

Processo per l'invio della segnalazione di bug
Un utente incontra un bug e fa clic sul pulsante "Segnala un bug". Di conseguenza, viene presentato il modulo per un messaggio. Cliccando una seconda volta sul pulsante l'utente verrà inviato all'amministratore.

Alla fine dell'articolo, puoi scaricare l'esempio funzionante ed esaminare il codice per intero.

Scendiamo!

Altro dopo il salto! Continua a leggere sotto ↓

AJAX

“Senza ricaricare la pagina” è la frase chiave qui. AJAX sta per JavaScript asincrono e XML perché inizialmente i dati restituiti dal server dovrebbero essere in XML. Tuttavia, è più facile inviarli in JSON, che a JavaScript piace di più.

Useremo AJAX per inviare un'e-mail. Non puoi farlo dal front-end, quindi devi chiamare il back-end. Di solito, inviamo una richiesta POST al server, la gestiamo e reindirizziamo l'utente alla pagina con il modulo. In questa iterazione, non vogliamo ricaricare la pagina. Invece, chiamiamo direttamente il back-end dove cattureremo i dati del modulo con JavaScript, quindi invieremo una richiesta asincrona al server per gestire la risposta.

Ci sono tre cose di cui WordPress AJAX ha bisogno per funzionare: cinque per funzionare bene . Questi sono:

  • Oggetto per l'azione AJAX
  • Script JavaScript
  • Azione WordPress
  • Protezione
  • Gestione degli errori

Diamo un'occhiata più da vicino a ciascuno di essi.

Oggetto

Il nostro oggetto è la forma. Questa è la nostra cosa da gestire con JavaScript. Ho iniziato creando un file con l'intestazione necessaria al plugin di WordPress e inserendo un oggetto vuoto all'interno. Alla fine, sto creando una nuova istanza della classe del plugin.

 <?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();

Anche se sto usando alcune OOP qui, non utilizzeremo pratiche avanzate. Il codice funzionerebbe altrettanto bene se scritto proceduralmente con funzioni separate. Ma gli oggetti all'interno dei plugin di WordPress hanno un vantaggio: non devi anteporre le tue funzioni, solo il nome della classe deve essere univoco.

Mostriamo il nostro modulo agli utenti. Ci collegheremo al filtro the_content e incorporeremo il modulo alla fine di ogni post. Nel costruttore della classe ho aggiunto il filtro:

 public function __construct() { add_filter( 'the_content', array( $this, 'report_button' ), 10, 1 ); }

E creato un metodo di callback con modulo 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; }

Il modulo ha tutto il markup necessario:

  • Un pulsante per visualizzare il modulo e inviare il messaggio;
  • textarea ;
  • Contenitore per la risposta (lo useremo più avanti).

Il pulsante ha l'attributo data-post_id che memorizza l'ID del post corrente. Lo prenderemo in JavaScript per identificare l'articolo.

Abbiamo solo bisogno di uno stile di base, quindi registriamo il nostro foglio di stile con l'azione wp_enqueue_scripts e il callback corrispondente:

 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' ); }

Il foglio di stile stesso è molto semplice. Vogliamo riordinare il design.

 .report-a-bug-message { display: none; margin-top: 1em; } .report-a-bug-response { margin-top: 1em; }

Ecco come appare il pulsante:

Segnala un pulsante bug
Pulsante "Segnala un bug".

copione

Abbiamo il nostro oggetto pronto per metterci un po' di vita. Invece di farlo in semplice JavaScript, useremo jQuery che WordPress carica per impostazione predefinita su ogni pagina.

Nel metodo degli script esistenti, aggiungerò il file JS usando la funzione 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' ) ) ); }

Sto anche usando la funzione wp_localize_script per passare l'etichetta del pulsante tradotta a JS. Non abbiamo alcuna funzione gettext in JavaScript, quindi dobbiamo farlo qui. Questa funzione creerà l'oggetto delle impostazioni a cui è possibile accedere direttamente dal nostro script.

Nel nostro script, ascolteremo il clic di un pulsante. Una volta che ciò accade, mostreremo l'area di testo e textarea la classe del pulsante per ascoltare il secondo clic che sta inviando il modulo.

 ( 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 );

Ecco lo stato di avanzamento attuale:

Area di testo a discesa al clic
textarea a tendina al clic

È il momento migliore per creare la richiesta AJAX!

Richieste AJAX a WordPress

Per inviare una richiesta AJAX, hai davvero bisogno di un solo parametro: l'URL richiesto. WordPress ha il file speciale per AJAX, quindi non dobbiamo crearne uno nostro. È /wp-admin/admin-ajax.php .

Finché siamo nell'area wp-admin , questo URL del file è disponibile in JS nella variabile ajaxurl . Sul front-end, dobbiamo passare questa variabile da soli. Fortunatamente abbiamo già utilizzato la funzione wp_localize_script , quindi possiamo semplicemente aggiungere un'altra chiave ad essa:

 wp_localize_script( 'report-a-bug', 'settings', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'send_label' => __( 'Send report', 'reportabug' ) ) );

Abbiamo preparato tutte le variabili, quindi creiamo la chiamata AJAX. Lo invieremo una volta che l'utente farà clic sul pulsante una seconda volta.

 $( '.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' ); } ); } );

Stiamo ascoltando un clic sulla classe che abbiamo acceso prima il pulsante.

Come puoi vedere, sto cambiando il testo del pulsante in "..." Perché? Perché è buona norma mostrare all'utente che sta succedendo qualcosa. Le richieste AJAX dipendono dalle prestazioni del server e richiederanno del tempo. Forse 30 ms, ma forse anche 3 secondi. Se dopo aver cliccato sul pulsante sembra non esserci alcun effetto, molto probabilmente il pulsante verrà cliccato una seconda volta. Ciò duplicherà la richiesta perché, come ora sai, sono asincroni.

Successivamente, sto creando l'oggetto data . Questo contiene tutte le variabili che verranno inviate al callback del server. Il file admin-ajax.php WordPress richiede la proprietà dell'azione. Questo deve essere unico a meno che tu non voglia che l'altro plugin gestisca le tue richieste. Il resto dei parametri è facoltativo. Sto inviando l'ID del post e il messaggio di segnalazione da textarea .

Quindi chiamiamo il metodo $.post . Successivamente, hai indovinato; sta inviando la richiesta POST. È un metodo abbreviato, ma puoi usare anche il metodo $.ajax , che ha più opzioni. Come primo parametro dobbiamo passare l'URL del nostro file gestore, quindi i parametri e quindi la funzione di callback di successo. Questo è il luogo in cui stiamo gestendo la risposta. Per ora, stiamo solo inviando il semplice messaggio alla console del browser.

Invio di richiesta AJAX al back-end
Invio di richiesta AJAX al back-end

Siamo pronti a gestire la richiesta sul back-end.

Azione WordPress

Ti starai chiedendo come ci colleghiamo a admin-ajax.php . Con l'azione, ovviamente! WordPress ha due tipi di azione:

 wp_ajax_nopriv_{$action} wp_ajax_{$action}

Dove si trova $action , il nome dell'azione passato nei parametri AJAX. Nel nostro caso è send_bug_report .

La prima di queste azioni verrà eseguita solo per gli utenti non loggati. Il secondo solo per utenti loggati. Quindi, se vuoi che la richiesta venga gestita per entrambi, devi definire entrambi. Questo è quello che ho fatto nel costruttore della classe:

 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' ) ); }

Nella richiamata, ricevo solo il titolo del post e invio l'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' ) ); }

La parte più importante in termini di gestione di AJAX in WordPress è l'ultima funzione: wp_send_json_success che stampa l'output codificato JSON e muore. Tutto ciò di cui abbiamo bisogno per ottenere la risposta con il callback di successo di AJAX. Ha anche un fratello gemello, wp_send_json_error , ma arriveremo a quella parte più tardi.

L'oggetto di queste funzioni ha due proprietà:

  • successo
    È un booleano e dipende se lo chiami funzione di successo o di errore.
  • dati
    Se si fornisce il parametro per la funzione.

Questo è tutto dal lato posteriore. Gestiamo la risposta in JS.

Rimuoveremo il pulsante e l'area di testo e visualizzeremo un messaggio restituito dal server nel contenitore che abbiamo preparato prima:

 $.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 ); });

E questo è tutto! Abbiamo la chiamata AJAX funzionante! Ma non fermarti qui. La nostra richiesta non è sicura e certamente non user-friendly. Dobbiamo assicurarci che la richiesta venga eseguita solo quando è necessario.

Protezione

Nonce

Il nonce è un "numero usato una volta". È un breve hash creato da una stringa di input. Possiamo usarlo per convalidare la richiesta, se è stata davvero fatta da WordPress e nessuno la falsifica.

Useremo un altro attributo di dati per il pulsante:

 $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>';

Come puoi vedere, sto aggiungendo l'ID del post alla stringa di input. Avremo questo ID disponibile nelle proprietà della richiesta AJAX, quindi è solo più sicuro.

Ora dobbiamo aggiungere il nonce alle proprietà 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() };

Ora lo convalideremo nel backend utilizzando la funzione check_ajax_referer , fornita da WordPress:

 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' ) ); }

Per convalidare la richiesta dobbiamo rigenerare la stringa di input, quindi sto usando la chiave post_id inviata da AJAX. Il secondo parametro è la chiave $_REQUEST array . Terzo controlla il wp_die automatizzato se nonce non corrisponde.

Non voglio che muoia da solo. Invece, sto catturando il risultato di questa funzione e inviando un errore JSON in un bell'oggetto.

Potresti anche notare l'utilizzo della funzione sanitize_text_field nel parametro del messaggio di posta elettronica. Questo è solo per assicurarsi che l'utente non invii script o HTML dannosi.

Infine, è necessario racchiudere il callback di successo AJAX in JS nell'istruzione if per verificare se la richiesta ha avuto esito positivo:

 $.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 ); } });

Protezione dei pulsanti

Sai che l'utente può fare clic sul pulsante una seconda volta, prima che AJAX termini la chiamata. Ma c'è un semplice trucco che bloccherà il secondo clic: disabilitare il pulsante. Quindi, dopo il clic, lo bloccherò e lo sbloccherò dopo aver ricevuto la risposta:

 $('.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); }); });

Gestione degli errori

Convalida

Cosa succede se l'utente tenta di inviare un messaggio vuoto? Non voglio essere disturbato da tali e-mail. Blocchiamo questi tentativi con tecniche di validazione.

In JS aggiungerò una semplice convalida, per mostrare all'utente che qualcosa è andato storto. Se il messaggio è vuoto, l'utente vedrà il bordo rosso attorno all'area di testo. Se è presente un messaggio, stiamo ripristinando il confine neutro:

 $('.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 });

Verifica della presenza di errori nell'azione di WordPress

Potremmo anche avere un problema con l'invio dell'e-mail. Se non controlliamo il risultato della funzione wp_mail , l'utente riceverà un messaggio di successo anche se non è stata inviata alcuna e-mail.

Gestiamo questo:

 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(); } }

Come puoi vedere, abbiamo utilizzato due volte la funzione wp_send_json_error , ma non è necessario visualizzare messaggi univoci per gli utenti. Invece, passando la descrizione esatta dell'errore, aggiungerò un'altra chiave al nostro oggetto delle impostazioni dello script che coprirà entrambi gli errori:

 // 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' ) ) );

Tutto ciò che resta da fare è visualizzare l'errore all'utente:

 $.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 ); } );

Esempio completo

L'abbiamo fatto! La nostra richiesta AJAX è stata fatta; è ben protetto e facile da usare. Questo è ciò che un utente vedrà in caso di errori:

Esempio finito, richiesta AJAX con convalida
Esempio finito, richiesta AJAX con convalida

Di seguito puoi scaricare il plugin completo e consultare le guide per l'utente:

  • Scarica il plugin su Github
  • Scarica il plugin su Wordpress.org
  • Vai alle guide per l'utente

Spero che questo ti dia una buona base per le tue soluzioni "senza aggiornamento della pagina". Puoi farlo su tutti i moduli sul tuo sito web. È anche un ottimo modo per ottimizzare qualsiasi parte pesante del sito Web che non deve essere caricata subito, come un grande elenco di prodotti in un menu a discesa. Puoi caricarli tramite AJAX subito dopo aver fatto clic sul menu a discesa: è così semplice.

Le possibilità sono quasi illimitate. Fatemi sapere nei commenti quali sono le vostre idee!