Il fut un temps où créer une route REST personnalisée dans WordPress se résumait à appeler register_rest_route avec un callback et rien d’autre. Ça fonctionnait, mais silencieusement : la route restait accessible à n’importe quel visiteur, authentifié ou non, sans que rien ne le signale dans le code. Beaucoup de développeurs ne s’en apercevaient qu’en production, parfois après qu’une donnée sensible avait fuité.
Depuis WordPress 5.5, sorti en août 2020, omettre le paramètre permission_callback déclenche un avertissement _doing_it_wrong visible dès que WP_DEBUG est actif. Ce n’est pas encore un blocage strict, mais c’est un signal clair : ce paramètre n’est plus optionnel dans l’esprit du cœur de WordPress. Voyons pourquoi, et comment l’écrire correctement selon le contexte.
Ce que fait vraiment permission_callback
Il ne faut pas confondre authentification et autorisation. L’authentification répond à la question « qui êtes-vous ? », via un cookie de session, un mot de passe d’application ou un jeton. L’autorisation répond à la question « avez-vous le droit de faire ceci ? ». permission_callback gère exclusivement la seconde question, et WordPress refuse désormais de laisser cette question sans réponse explicite.
register_rest_route( 'monplugin/v1', '/commandes', array(
'methods' => 'GET',
'callback' => 'monplugin_get_commandes',
'permission_callback' => function () {
return current_user_can( 'manage_woocommerce' );
},
) );
Dans cet exemple, la route liste des commandes : elle n’a évidemment pas vocation à être publique. Le callback de permission vérifie une capacité précise plutôt qu’un simple is_user_logged_in(), ce qui évite qu’un abonné basique puisse consulter des données réservées à la gestion de boutique.
__return_true : un choix, pas un oubli
WordPress fournit la fonction utilitaire __return_true, pratique pour déclarer explicitement qu’une route est publique. Le problème n’est pas son existence, mais son usage par réflexe pour faire disparaître l’avertissement sans réfléchir à la question de fond.

__return_trueconvient à une route qui affiche un contenu déjà public, comme une liste d’articles publiés- Il ne convient jamais à une route qui lit des données utilisateur, des commandes, des messages ou des réglages
- Il ne convient jamais à une route qui écrit ou modifie des données, quelle que soit la méthode HTTP utilisée
La règle mentale la plus sûre consiste à se demander, pour chaque route : « si cette réponse JSON était affichée en clair sur la page d’accueil du site, est-ce un problème ? ». Si la réponse est oui, __return_true est une erreur.
Vérifier les capacités selon le contexte
Le callback de permission peut recevoir l’objet WP_REST_Request en paramètre, ce qui permet des vérifications fines, par exemple limiter l’accès à un enregistrement précis plutôt qu’à toute la collection.
'permission_callback' => function ( WP_REST_Request $request ) {
$commande_id = (int) $request['id'];
$commande = wc_get_order( $commande_id );
if ( ! $commande ) {
return false;
}
return get_current_user_id() === $commande->get_customer_id()
|| current_user_can( 'manage_woocommerce' );
},
Ici, un client peut consulter sa propre commande, un gestionnaire peut consulter n’importe quelle commande, et tous les autres cas renvoient false. C’est ce niveau de granularité que permet permission_callback par rapport à une simple vérification binaire connecté ou non connecté.
Les erreurs les plus fréquentes
La première erreur consiste à vérifier une capacité dans le callback principal plutôt que dans permission_callback. Le résultat fonctionne souvent, mais WordPress ne peut alors pas court-circuiter la requête avant l’exécution du corps de la fonction, et certains comportements liés au cache ou aux en-têtes de réponse deviennent incohérents.
La deuxième erreur consiste à copier-coller un callback de permission d’une route à l’autre sans l’adapter. Une capacité pertinente pour une route de lecture ne l’est pas forcément pour une route de suppression : edit_posts ne devrait jamais suffire à valider une route DELETE, par exemple, où delete_others_posts ou une vérification par propriétaire est plus appropriée.
Tester ses routes comme un attaquant le ferait
Le test le plus simple, et pourtant souvent oublié, consiste à appeler chaque route personnalisée en étant déconnecté, avec un compte abonné basique, puis avec le rôle attendu. C’est un test rapide avec curl ou un client REST, qui révèle en quelques minutes les routes trop permissives.
# Sans authentification
curl https://exemple.fr/wp-json/monplugin/v1/commandes
# Avec un compte abonné
curl https://exemple.fr/wp-json/monplugin/v1/commandes \
-u "abonne:motdepasseapplication"
En résumé
La stricte obligation de renseigner permission_callback depuis WordPress 5.5 n’est pas une contrainte administrative supplémentaire, c’est un garde-fou qui force à se poser la bonne question au moment où elle compte le plus : au moment d’écrire la route. Un permission_callback pensé pour chaque cas d’usage, plutôt qu’un __return_true automatique, reste le meilleur moyen d’éviter qu’une route pratique en développement ne devienne une fuite de données en production.