Soumettre des formulaires sans recharger la page : implémentation AJAX dans WordPress
Publié: 2022-03-10Si vous avez déjà voulu envoyer un formulaire sans recharger la page, fournir une fonction de recherche anticipée qui invite l'utilisateur avec des suggestions au fur et à mesure qu'il tape, ou enregistrer automatiquement des documents, alors ce dont vous avez besoin est AJAX (également connu sous le nom de XHR ). Une demande en coulisse est envoyée au serveur et renvoie les données à votre formulaire. Chaque fois que vous voyez une animation de chargeur après avoir effectué une action sur la page, il s'agit probablement d'une requête AJAX soumise au serveur.
Dans cet article, je vais vous guider tout au long du processus de création et de gestion des appels AJAX. Vous apprendrez non seulement comment passer un appel AJAX, mais aussi comment le faire de la meilleure façon en utilisant les fonctionnalités que WordPress offre aux développeurs dès la sortie de la boîte. Nous allons créer un plugin simple qui permettra aux lecteurs d'envoyer un rapport à l'administrateur avec des informations sur tout bogue qu'ils pourraient repérer sur votre site Web.
À la fin de l'article, vous pouvez télécharger l'exemple de travail et examiner le code dans son intégralité.
Allons creuser !
AJAX
"Sans recharger la page" est la phrase clé ici. AJAX signifie Asynchronous JavaScript And XML car initialement, les données renvoyées par le serveur sont censées être en XML. Cependant, il est plus facile de les envoyer en JSON, ce que JavaScript préfère.
Nous allons utiliser AJAX pour envoyer un email. Vous ne pouvez pas le faire depuis le front-end, vous devez donc appeler le back-end. Habituellement, nous enverrons une requête POST au serveur, la traiterons et redirigerons l'utilisateur vers la page avec le formulaire. Dans cette itération, nous ne voulons pas recharger la page. Au lieu de cela, nous appelons directement le backend où nous allons capturer les données du formulaire avec JavaScript, puis envoyons une requête asynchrone au serveur pour gérer la réponse.
Il y a trois choses dont WordPress AJAX a besoin pour fonctionner - cinq d'entre elles pour bien fonctionner. Ceux-ci sont:
- Objet pour l'action AJAX
- Script JavaScript
- Action WordPress
- protection
- La gestion des erreurs
Examinons de plus près chacun d'eux.
Objet
Notre objet est la forme. C'est notre truc à gérer avec JavaScript. J'ai commencé par créer un fichier avec l'en-tête nécessaire au plugin WordPress et en mettant un objet vide à l'intérieur. Au final, je crée une nouvelle instance de la classe du 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();
Même si j'utilise un peu de POO ici, nous n'allons pas utiliser de pratiques avancées. Le code fonctionnerait aussi bien s'il était écrit de manière procédurale avec des fonctions séparées. Mais les objets dans les plugins WordPress ont un avantage : vous n'avez pas besoin de préfixer vos fonctions — seul le nom de la classe doit être unique.
Montrons notre formulaire aux utilisateurs. Nous allons nous connecter au filtre the_content
et intégrer le formulaire à la fin de chaque publication. Dans le constructeur de la classe, j'ai ajouté le filtre :
public function __construct() { add_filter( 'the_content', array( $this, 'report_button' ), 10, 1 ); }
Et créé une méthode de rappel avec le formulaire 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; }
Le formulaire contient tout le balisage nécessaire :
- Un bouton pour afficher le formulaire et envoyer le message ;
-
textarea
; - Conteneur pour la réponse (nous allons l'utiliser plus tard).
Le bouton a l'attribut data-post_id
qui stocke l'ID de publication actuel. Nous allons saisir ceci dans le JavaScript pour identifier l'article.
Nous n'avons besoin que d'un style de base, alors enregistrons notre propre feuille de style avec l'action wp_enqueue_scripts
et le rappel correspondant :
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' ); }
La feuille de style elle-même est très simple. Nous voulons ranger le design.
.report-a-bug-message { display: none; margin-top: 1em; } .report-a-bug-response { margin-top: 1em; }
Voici à quoi ressemble le bouton :
Scénario
Nous avons notre objet prêt à lui donner un peu de vie. Au lieu de le faire en JavaScript, nous allons utiliser jQuery que WordPress charge par défaut sur chaque page.
Dans la méthode des scripts existants, j'ajouterai le fichier JS à l'aide de la fonction 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' ) ) ); }
J'utilise également la fonction wp_localize_script
pour transmettre l'étiquette de bouton traduite à JS. Nous n'avons pas de fonctions gettext
en JavaScript, nous devons donc le faire ici. Cette fonction va créer l'objet settings accessible directement depuis notre script.
Dans notre script, nous allons écouter un clic sur un bouton. Une fois que cela se produit, nous afficherons la zone de texte et textarea
la classe du bouton pour écouter le deuxième clic qui envoie le formulaire.
( 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 );
Voici l'avancement actuel :
C'est le meilleur moment pour créer la requête AJAX !
Requêtes AJAX à WordPress
Pour envoyer une requête AJAX, vous n'avez vraiment besoin que d'un seul et unique paramètre : l'URL demandée. WordPress a le fichier spécial pour AJAX, nous n'avons donc pas à créer le nôtre. C'est /wp-admin/admin-ajax.php
.
Tant que nous sommes dans la zone wp-admin
, cette URL de fichier est disponible en JS dans la variable ajaxurl
. Sur le front-end, nous devons passer cette variable par nous-mêmes. Heureusement, nous avons déjà utilisé la fonction wp_localize_script
, nous pouvons donc simplement lui ajouter une autre clé :
wp_localize_script( 'report-a-bug', 'settings', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'send_label' => __( 'Send report', 'reportabug' ) ) );
Nous avons préparé toutes les variables, créons donc l'appel AJAX. Nous allons l'envoyer une fois que l'utilisateur aura cliqué une seconde fois sur le bouton.
$( '.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' ); } ); } );
Nous attendons un clic sur la classe que nous avons activée sur le bouton avant.
Comme vous pouvez le voir, je change le texte du bouton en "..." Pourquoi ? Parce que c'est une bonne pratique de montrer à l'utilisateur que quelque chose se passe. Les requêtes AJAX dépendent des performances du serveur et prendront un certain temps. Peut-être 30 ms, mais peut-être aussi 3 secondes. Si après avoir cliqué sur le bouton, il semble n'y avoir aucun effet, il est fort probable que le bouton sera cliqué une deuxième fois. Cela dupliquerait la demande car, comme vous le savez maintenant, celles-ci sont asynchrones.
Ensuite, je crée l'objet data
. Celui-ci contient toutes les variables qui seront envoyées au callback du serveur. Le fichier WordPress admin-ajax.php
nécessite la propriété action. Cela doit être unique, sauf si vous souhaitez que l'autre plugin gère vos demandes. Le reste des paramètres est facultatif. J'envoie l'ID de publication et le message de rapport de textarea
.
Nous appelons alors la méthode $.post
. Ensuite, vous l'avez deviné; il envoie la requête POST. C'est une méthode abrégée, mais vous pouvez également utiliser la méthode $.ajax
, qui a plus d'options. Comme premier paramètre, nous devons passer l'URL de notre fichier de gestionnaire, puis les paramètres, puis la fonction de rappel de succès. C'est l'endroit où nous traitons la réponse. Pour l'instant, nous envoyons simplement le message simple à la console du navigateur.
Nous sommes prêts à traiter la demande sur le back-end.
Action WordPress
Vous vous demandez peut-être comment nous connectons au admin-ajax.php . Avec de l'action, bien sûr ! WordPress a deux types d'actions :
wp_ajax_nopriv_{$action} wp_ajax_{$action}
Où est $action
, le nom de l'action passé dans les paramètres AJAX. C'est send_bug_report
dans notre cas.
La première de ces actions sera exécutée uniquement pour les utilisateurs non connectés. Le second uniquement pour les utilisateurs connectés. Donc, si vous voulez que la demande soit traitée pour les deux, vous devez définir les deux. C'est ce que j'ai fait dans le constructeur de la 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' ) ); }
Dans le rappel, je reçois juste le titre du message et j'envoie 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 partie la plus importante en termes de gestion d'AJAX dans WordPress est la dernière fonction - wp_send_json_success
qui imprime la sortie codée JSON et meurt. Tout ce dont nous avons besoin pour saisir la réponse avec le rappel de réussite AJAX. Il a aussi un frère jumeau, wp_send_json_error
, mais nous y reviendrons plus tard.
L'objet de ces fonctions a deux propriétés :
- Succès
Est un booléen et dépend si vous l'appelez fonction de succès ou d'erreur. - Les données
Si vous fournissez le paramètre pour la fonction.
C'est tout du côté back-end. Gérons la réponse en JS.
Nous allons supprimer le bouton et la zone de texte et afficher un message renvoyé par le serveur dans le conteneur que nous avons préparé auparavant :
$.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 ); });
Et c'est tout! Nous avons l'appel AJAX qui fonctionne ! Mais ne vous arrêtez pas là. Notre demande n'est pas sécurisée et certainement pas conviviale. Nous devons nous assurer que la demande n'est exécutée que lorsqu'elle doit l'être.
protection
Nonce
Le nonce est un "nombre utilisé une fois". C'est un hachage court créé à partir d'une chaîne d'entrée. Nous pouvons l'utiliser pour valider la demande - si elle a vraiment été faite par WordPress et que personne ne la simule.
Nous allons utiliser un autre attribut de données pour le bouton :
$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>';
Comme vous pouvez le voir, j'ajoute l'ID de publication à la chaîne d'entrée. Nous aurons cet ID disponible dans les propriétés de la requête AJAX, donc c'est juste plus sécurisé.
Maintenant, nous devons ajouter le nonce aux propriétés 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() };
Nous allons maintenant le valider dans le backend à l'aide de la fonction check_ajax_referer
, fournie par 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' ) ); }
Pour valider la requête, nous devons régénérer la chaîne d'entrée, j'utilise donc la clé post_id
envoyée depuis AJAX. Le deuxième paramètre est la clé dans le $_REQUEST array
. Le troisième contrôle le wp_die
automatisé si nonce ne correspond pas.
Je ne veux pas qu'il meure lui-même. Au lieu de cela, j'attrape le résultat de cette fonction et j'envoie une erreur JSON dans un bel objet.
Vous pouvez également remarquer l'utilisation de la fonction sanitize_text_field
dans le paramètre de message électronique. C'est juste pour s'assurer que l'utilisateur n'enverra pas de scripts ou HTML nuisibles.
Enfin, nous devons encapsuler le rappel de réussite AJAX dans JS dans l'instruction if pour vérifier si la requête a réussi :
$.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 ); } });
Protection des boutons
Vous savez que l'utilisateur peut cliquer sur le bouton une deuxième fois, avant qu'AJAX ne termine l'appel. Mais il y a une astuce simple qui bloquera le deuxième clic - désactiver le bouton. Donc après le clic, je vais le bloquer et le débloquer après avoir obtenu la réponse :
$('.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); }); });
La gestion des erreurs
Validation
Que se passe-t-il si l'utilisateur essaie d'envoyer un message vide ? Je ne veux pas être dérangé par de tels e-mails. Bloquons ces tentatives avec des techniques de validation.
Dans JS, je vais ajouter une simple validation, pour montrer à l'utilisateur que quelque chose s'est mal passé. Si le message est vide, l'utilisateur verra la bordure rouge autour de la zone de texte. Si un message y est présent, nous rétablissons la bordure neutre :
$('.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 });
Vérification des erreurs dans l'action WordPress
Nous pouvons également avoir un problème avec l'envoi de l'e-mail. Si nous ne vérifions pas le résultat de la fonction wp_mail
, l'utilisateur recevra un message de réussite même si aucun e-mail n'a été envoyé.
Traitons cela :
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(); } }
Comme vous le voyez, nous avons utilisé la fonction wp_send_json_error
deux fois, mais il n'est pas nécessaire d'afficher des messages uniques pour les utilisateurs. Au lieu de cela, en passant la description exacte de l'erreur, je vais ajouter une autre clé à notre objet de paramètres de script qui couvrira les deux erreurs :
// 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' ) ) );
Il ne reste plus qu'à afficher l'erreur à l'utilisateur :
$.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 ); } );
Exemple complet
Nous l'avons fait ! Notre requête AJAX a été effectuée ; il est bien sécurisé et convivial. Voici ce qu'un utilisateur verra en cas d'erreur :
Ci-dessous, vous pouvez télécharger le plugin complet et consulter les guides d'utilisation :
- Télécharger le plugin sur Github
- Télécharger le plugin sur Wordpress.org
- Accéder aux guides d'utilisation
J'espère que cela vous donne une bonne base pour vos propres solutions "sans rafraîchissement de page". Vous pouvez le faire pour tous les formulaires de votre site Web. C'est également un excellent moyen d'optimiser tout élément lourd du site Web qui n'a pas besoin d'être chargé immédiatement, comme une grande liste de produits dans une liste déroulante. Vous pouvez les charger via AJAX juste après avoir cliqué sur le menu déroulant - c'est aussi simple que cela.
Les possibilités sont presque illimitées. Faites-moi savoir dans les commentaires quelles sont vos idées!