Les alternatives à admin-ajax.php

L’AJAX dans WordPress c’est pas du gâteau.

Contexte et rappels

Dans un fonctionnement web assez basique, on clique sur un bouton, la requête est envoyée côté serveur et le résultat est affiché en rechargeant la page.

En AJAX, les requêtes sont faites en arrière-plan et en asynchrone. Cela évite donc d’avoir à recharger la page par exemple pour des actions courantes comme afficher des résultats d’une WP_Query ou soumettre un formulaire.

Dans WordPress, les appels AJAX sont centralisés, un seul fichier est utilisé. Ce fichier est situé dans le répertoire d’admin : /wp-admin/admin-ajax.php.

Quel sont les problèmes ?

Ce fonctionnement présente un avantage majeur, à savoir centraliser, normaliser, faciliter l’implémentation pour les développeurs tout en donnant des règles.

Malheureusement, c’est relativement insuffisant à l’utilisation et je vais essayer de justifier mon point de vue.

Un des premiers problèmes est d’appeler un fichier « réservé » à l’admin (situé dans le dossier wp-admin) même pour faire des requêtes en front.

Un deuxième problème est de devoir charger tout un WordPress à chaque requête faite via admin-ajax.php, donc toute requête AJAX dans WordPress. Cela impacte évidemment de manière négative la performance globale de nos requêtes :

/** Load WordPress Bootstrap */
require_once( dirname( dirname( __FILE__ ) ) . '/wp-load.php' );

La sécurité ?

D’une part, j’invite à la prudence quand on se prononce là-dessus à propos de l’AJAX dans WordPress. Ce n’est pas toujours « la faute à WP », beaucoup beaucoup beaucoup de développeurs ne se servent pas des nonces dans leurs appels AJAX. C’est donc un élément de sécurité existant qui est zappé.

Source

D’autre part, tout dépend de l’implémentation. Il ne suffit pas d’utiliser les actions AJAX de WordPress, il faut aussi gérer la validité des nonces donc mais aussi l’échappement des requêtes en base si jamais on en fait, la vérification des capabilités, etc.

En somme, le fait que l’on appelle un fichier d’admin en front ne suffit pas pour dire que ce serait non sécurisé.

La perf !

Un argument indiscutable au moins celui-là. Dans chaque requête AJAX dans WordPress, on charge un WordPress au complet.

Par nature, ce fonctionnement ne peut pas faire la course en mode « fast and furious » avec le reste du monde, encore moins en 2018 (ce qui n’est pas son but en même temps).

Prenez l’extension wp job manager, créée et maintenue par Automattic, regardez à l’intérieur, aucun appel à admin-ajax.php #cqfd :

$ajax_url = WP_Job_Manager_Ajax::get_endpoint();

Comment faire autrement ?

Il existe plusieurs approches, j’ai pris les plus génériques :

Dupliquer admin-ajax.php en mode light ?

Elle est assez pratique quand on a pas le temps mais c’est reculer pour mieux sauter. Je copie le fichier admin-ajax.php, je mets la copie dans un répertoire de mon choix. A l’intérieur j’enlève tout ce qui me sert pas et je restreins l’usage à ce qui m’intéresse. Je créé une version « light » du fichier au final.

Là pour le coup on doit se poser la question de la sécurité car on laisse un fichier sur l’installation (un point d’entrée) en libre accès. En plus, on a dupliqué du code, donc à maintenir c’est pas top.

Enfin, on a toujours notre problème de charger WordPress… donc c’est une méthode qui va améliorer le rendu mais ça bricole un peu quand même dans le sens où on se contente de charger moins de choses uniquement.

Source

Une URL d’AJAX personnalisée

Une première solution est de faire comme Automattic en créant sa propre URL d’AJAX. Pour faire de l’AJAX, en général on ajoute un script js personnalisé, dans son extension ou son thème, et on lui passe le chemin vers le fichier de WordPress comme suit :

<?php
wp_enqueue_script( 'handle_script_custom',  '/url/to/js/script-ajax.js', ['jquery'], 'version', true );		
wp_localize_script( 'handle_script_custom', 'name_js_object_for_ajax', [ 'ajax_url' => admin_url( 'admin-ajax.php' ), 'ajax_nonce' => wp_create_nonce( 'do_some_ajax' ) ] );

Cela permet dans le fichier js script-ajax.js de faire quelque chose comme :

jQuery.post(
    name_js_object_for_ajax.ajax_url,
    {
        'action': 'mon_action_ajax',
        'nonce': name_js_object_for_ajax.ajax_nonce
    },
    function(response){
        console.log(response);
    }
);

Ici Automattic fait simplement à la place :

$ajax_url = WP_Job_Manager_Ajax::get_endpoint();
wp_localize_script( 'handle_script_custom', 'name_js_object_for_ajax', [ 'ajax_url' => $ajaxurl ] );

Utiliser la REST API

La méthode la plus indiquée à mon sens.

Principe général

Déja pas mal de littérature sur le sujet dont : 

Globalement, on va arrêter d’appeler admin-ajax.php dans le js ou tout autre fichier et à la place on va passer une URL de la REST API. Par exemple pour récupérer une liste de posts, au lieu de faire une WP_Query et d’envoyer les résultats via wp-ajax, on pourrait faire directement :

$.ajax( {
    url: '/wp-json/posts?filter[posts_per_page]=7',

La performance serait nécessairement meilleure.

Points d’attention

Attention à plusieurs choses :

  1. Si vous interrogez des urls REST sur votre site mais que vos types de contenus ou vos taxinomies ne sont pas déclarés comme il faut, vous n’allez jamais obtenir vos données. Au minimum, il faudra donc que le paramètre « show_in_rest » soit utilisé et passé à true dans la déclaration du type de contenu ou de la taxinomie
  2. Si vous avez activé un plugin comme disable REST API pour renforcer la sécurité, veillez à bien autoriser les routes (endpoints) qui vous intéressent, autrement cela ne marchera pas en mode non connecté
  3. attention aux requêtes REST en « mode manuel » sans passer un nonce, ce n’est pas autorisé, regardez cette source

D’autres gains ?

Outre la perf accrue, il est possible de créer ses propres routes dans la REST API. Vous pourrez y exposer vos données de la manière qui vous convient. S’ajoute enfin que cela semble bien meilleur d’un point de vue maintenance.

Conclusion

Dans ce billet j’ai souhaité évoquer certaines solutions alternatives à wp ajax. Son avantage de normaliser les choses ne tient plus vraiment AMHA en 2018 car on a besoin de plus de souplesse et de rapiditité.

Il existe sûrement d’autres approches mais ce qui m’intéresse est bien le temps de réaction sur nos appels en front, rien de plus. Même si c’est pour 30-40% d’amélioration au final c’est fort en termes de ressenti.

La REST API semble donc une alternative intéressante et « généralisable ».

3 thoughts on “Les alternatives à admin-ajax.php”

  1. Top !
    Par contre la REST-API reste tout de même plus compliqué à implémenter que le fichier admin-ajax.php
    Ca demande plus d’expérience au développeur. Ca implique aussi de structurer ses appels et ses retours.

    1. oui c’est exact et ça rentre dans la philosophie générale de WP d’être accessible au plus grand nombre mais je trouve l’impact trop fort côté utilisateur. Cela va demander nécessairement plus de compétences mais for the win ^^

  2. +1 pour l’utilisation de REST, c’est l’avenir en termes d’interface même s’il est vrai que c’est plus long à mettre en oeuvre.

    J’ai testé avec succès même si tout n’est pas idéal, notamment côté prise en charge des custom fields. Pour info j’ai utilisé ce plugin : https://fr.wordpress.org/plugins/acf-to-rest-api/

    Bref, comme toujours les techniques les plus performantes réclament plus de travail, mais ça vaut le coup 😉

Comments are closed.