Chapitre 16 sur 20
Créer et utiliser des endpoints AJAX
L’AJAX est un ensemble de technologies permettant d’effectuer des requêtes réseau et d’actualiser la page sans un rechargement complet. Utilisé à bon escient, cette technique permet de grandement améliorer l’expérience utilisateur en s’approchant de l’expérience offertes par des applications natives.
WordPress est utilisé la plupart du temps dans un paradigme client-server web classique : le navigateur envoie une requête au serveur, celui-ci génère le résultat via les templates et retourne au navigateur le code HTML correspondant à la requête.
Cependant, WordPress possède également une API REST complète et permet d’enregistrer des fonctions pour répondre aux requêtes AJAX. Ces deux méthodes permettent :
- d’utiliser WordPress comme un CMS headless (un backend) et de gérer le front de manière totalement séparée (application native, mobile…) ;
- d’effectuer des actions sans provoquer un rechargement de page (ajout au panier, autosave dans l’admin).
Sur le site d’Alphapole, l’AJAX est utilisé afin de permettre l’ajout d’un article au panier sans recharger la page. Nous allons ici aborder la manière dont on ajoute des fonctions AJAX.
L’usage de l’API REST est un tout autre sujet, il existe un handbook dédié à l’API REST. Par ailleurs, si vous souhaitez exploiter cette API en JavaScript, je vous conseille d’utiliser node-wpapi.
L’AJAX en back
Déclarer une fonction handler en back n’est en somme pas très complexe. Si l’on travaille dans le thème, on déclarera nos fonctions dans le functions.php
. Par exemple, voici la fonction permettant de gérer l’ajout d’un produit au panier sur le site d’Alphapole.
function add_to_cart() {
if (empty($_POST['product_id']) || empty($_POST['qt'])) return;
WC()->cart->add_to_cart($_POST['productId'], $_POST['qt'], $_POST['variation_id']);
wp_die();
}
add_action('wp_ajax_nopriv_add_to_cart', 'add_to_cart');
add_action('wp_ajax_add_to_cart', 'add_to_cart');
On voit que l’on déclare une fonction, dans laquelle on récupère des données en POST
. On appelle ici une fonction de WooCommerce puis on termine l’exécution avec wp_die();
.
Enfin on associe cette fonction à deux hooks : wp_ajax_nopriv_add_to_cart
et wp_ajax_add_to_cart
. Les préfixes wp_ajax_
et wp_ajax_nopriv_
permettent respectivement d’enregistrer la fonction pour les utilisateurs connectés et les utilisateurs non connectés.
Si vous n’enregistrez la fonction que pour wp_ajax_nopriv_
, le endpoint AJAX sera inexistant pour les utilisateurs non connectés, et vice-versa.
Ici, le suffixe add_to_cart
est ce qui va faire le lien entre le front et le back. En effet, le JavaScript envoie ce suffixe lors de l’appel AJAX, c’est ce qui permet à WordPress de savoir quelle fonction appeler.
Afin de revenir sur wp_die()
, celui-ci permet de s’assurer que WordPress ne renvoie pas d’autre valeur que celle que renvoie la fonction. Si du HTML ou du texte brut venait à être ajouté à la fin de votre réponse, votre JavaScript serait très certainement mis en erreur.
L’AJAX en front
Du côté de votre front, il n’y a rien d’extraordinaire. Vous n’avez qu’une seule contrainte : envoyer les données avec l’encodage “multipart/form-data”. Mis à part cela, vous êtes comme à la maison.
Vous allez donc utiliser une des deux API disponibles dans les navigateurs, à savoir :
XMLHttpRequest
,fetch
.
XMLHttpRequest
est la méthode historique et présentait l’avantage d’offrir une plus grande compatibilité. On peut aujourd’hui considérer que fetch
est adapté à tous les usages si l’on n’a pas à supporter de très vieux navigateurs (comme Internet Explorer).
Pour ma part, dans la mesure où on ne communique pas en JSON, j’ai une préférence pour le XMLHttpRequest
car cette API dispose de l’interface FormData
pour gérer le passage de valeurs en POST
ou GET
.
Ainsi, voici la fonction helper que j’utilise pour l’AJAX dans mes projets WordPress.
/**
* Send XMLHttpRequest and call either error or success callback
* @param { String } method
* @param { String } url
* @param { Object } body
* @param { Function } errCallback
* @param { Function } successCallback
*/
function ajax(method, url, body, errCallback, successCallback) {
const xhr = new XMLHttpRequest();
const form = body ? new FormData() : null;
xhr.onload = () => {
if (xhr.status !== 200) {
errCallback(xhr.status);
return;
}
successCallback(xhr.response);
};
xhr.onerror = errCallback;
xhr.open(method, url);
if (body) {
Object.keys(body).forEach(key => form.append(key, body[key]));
xhr.send(form);
}
else xhr.send();
}
Les fonction handlers de WordPress sont toujours en POST dans la mesure où elles doivent forcément contenir la clef action
dans le corp de la requête.
Gérer les notifications WooCommerce
Par défaut, rien ou presque ne fonctionne en AJAX sur le front. Or WooCommerce possède un système de notifications :
- produit ajouté au panier,
- problème lié au stock,
- problème avec l’adresse de livraison,
- etc.
Lorsque des actions sont gérées en AJAX, les notifications restent dans une file et s’afficheront au prochain chargement de page. Pour éviter ce comportement non désirable, il faudra vérifier, récupérer et vider les notifications présentes dans cette file.
Pour cela, vous utiliserez les fonctions wc_has_notice
, wc_notice_count
, wc_get_notices
et wc_clear_notices
.
Par ailleurs, pour désactiver la notifications d’ajout au panier (vous le gérer directement en AJAX), vous pouvez utiliser le filtre suivant.
add_filter('wc_add_to_cart_message_html', '__return_false');
Il est possible d’utiliser cette fonction AJAX pour d’autres choses que les seuls endpoints AJAX que vous avez déclaré. C’est pourquoi je préfère conserver la possibilité de la méthode HTTP à utiliser.
Le endpoint est toujours /wp-admin/admin-ajax.php
. Voici donc comment je gère l’ajout d’un article au panier côté JS.
function addToCart(productId, qt, variationId, callback) {
ajax('POST', '/wp/wp-admin/admin-ajax.php', {
action: 'add_to_cart',
product_id: productId,
variation_id: variationId
qt,
}, errHandler, callback);
}
Ici, ma fonction errHandler
est une fonction générique qui affiche un message d’erreur tandis que la fonction callback
est directement passée en paramètre à addToCart
. Je peux par exemple dans cette fonction synchroniser d’autres éléments (le nombre d’articles dans le panier, le total…) ou invoquer d’autres requêtes (par exemple récupérer le HTML du mini panier).
Vous n’avez pas de contrainte sur le format des données renvoyées. Par exemple, il suffit d’utiliser echo
avec json_encode
en PHP afin de passer un tableau ou un objet en JSON. Il suffira de les décoder côté JS pour accéder aux données et actualiser l’interface.
Cependant, il est parfois plus avantageux de récupérer directement du HTML et de remplacer telle quelle une partie de la page. Il suffit dès lors d’utiliser innerHTML
sur le parent de l’élément pour le mettre à jour d’un seul coup.
J’utilise par exemple la première technique sur la page panier pour récupérer les différentes mises à jour lors de l’actualisation des éléments du panier mais je préfère la seconde pour mettre à jour le mini panier.
Commentaires
Rejoignez la discussion !