« Chaque route doit définir son propre permission_callback, faute de quoi un avertissement s’affichera dans les journaux. » Cette exigence, présente dans la documentation officielle de la REST API sur developer.wordpress.org, prend tout son sens dès que l’on s’intéresse aux points de terminaison exposant les gabarits de l’éditeur de site.
Ce billet s’adresse à un développeur qui expose ou restreint la modification de gabarits via une extension tierce s’appuyant sur la REST API. Il ne traite pas de l’authentification par mot de passe d’application, un mécanisme distinct qui intervient en amont de la vérification de permission.
Ce que couvre wp/v2/templates
Le point de terminaison wp/v2/templates permet de lister, lire, créer et modifier les gabarits d’un site directement via des requêtes HTTP, sans passer par l’écran de l’éditeur de site. Chaque méthode HTTP associée à ce point de terminaison — GET, POST, PUT, DELETE — définit sa propre logique de vérification des permissions, indépendamment des autres.

Dans WordPress 5.9, le contrôleur qui sert ces routes passe par une vérification commune : avant de lister, lire, créer, modifier ou supprimer un gabarit, il contrôle que l’utilisateur courant dispose de la capacité edit_theme_options. À défaut, la réponse est une erreur rest_cannot_manage_templates, avec le code HTTP 401 pour un visiteur anonyme ou 403 pour un utilisateur connecté mais insuffisamment autorisé. C’est la vérification de base, celle qu’un administrateur possède et qu’un éditeur ne possède pas.
Vous pouvez le constater sans écrire une ligne de PHP, avec un mot de passe d’application (disponible depuis WordPress 5.6) :
# Utilisateur de rôle éditeur : refus attendu (403)
curl -i -u "redacteur:xxxx xxxx xxxx xxxx xxxx xxxx" \
"https://exemple.fr/wp-json/wp/v2/templates"
# Administrateur : liste des gabarits (200)
curl -s -u "admin:xxxx xxxx xxxx xxxx xxxx xxxx" \
"https://exemple.fr/wp-json/wp/v2/templates?_fields=slug,title,source"
Le paramètre _fields allège la réponse ; le champ source distingue un gabarit fourni par le thème d’un gabarit personnalisé enregistré en base. Cette distinction compte pour la sécurité : modifier un gabarit crée ou met à jour une entrée en base qui prend le pas sur le fichier du thème.
Ce qu’il faut retenir du permission_callback
- Un appel, une vérification. Chaque groupe de méthodes d’une route possède son propre
permission_callback: une route peut autoriser la lecture à un rôle et la suppression à un autre. - Retourner un
WP_Errorest préférable àfalse. Avecfalse, WordPress fabrique une erreur générique ; avec unWP_Error, vous maîtrisez le code, le statut HTTP et le message. - La fonction
rest_authorization_required_code()renvoie 401 pour un visiteur non connecté et 403 pour un utilisateur connecté : utilisez-la plutôt qu’un statut écrit en dur. - Ne jamais retourner
__return_truepour une route qui modifie quoi que ce soit. Ce raccourci n’est légitime que pour une lecture réellement publique.
Exposer une lecture en restant strict
Supposons qu’une extension d’agence doive afficher la liste des gabarits dans un tableau de bord interne, sans donner accès aux routes d’écriture. Plutôt que d’ouvrir wp/v2/templates à un rôle supplémentaire, on crée une route dédiée, en lecture seule, avec sa propre vérification :
add_action( 'rest_api_init', 'agence_route_gabarits' );
function agence_route_gabarits() {
register_rest_route( 'agence/v1', '/gabarits', array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'agence_lister_gabarits',
'permission_callback' => function () {
if ( current_user_can( 'edit_theme_options' ) ) {
return true;
}
return new WP_Error(
'agence_interdit',
'Vous ne pouvez pas consulter les gabarits.',
array( 'status' => rest_authorization_required_code() )
);
},
) );
}
function agence_lister_gabarits() {
$resultat = array();
foreach ( get_block_templates( array(), 'wp_template' ) as $gabarit ) {
$resultat[] = array(
'slug' => $gabarit->slug,
'titre' => $gabarit->title,
'source' => $gabarit->source,
);
}
return rest_ensure_response( $resultat );
}
La fonction get_block_templates() est disponible depuis WordPress 5.8. La route ne renvoie que trois champs, jamais le contenu des gabarits : on n’expose que ce dont le tableau de bord a besoin.
Durcir les routes existantes
À l’inverse, on peut vouloir resserrer ce que le cœur autorise, par exemple réserver la suppression d’un gabarit aux seuls gestionnaires du site. Le filtre rest_endpoints permet d’envelopper le permission_callback d’origine sans le réécrire :
add_filter( 'rest_endpoints', 'agence_durcir_suppression_gabarits' );
function agence_durcir_suppression_gabarits( $routes ) {
foreach ( $routes as $route => &$gestionnaires ) {
if ( 0 !== strpos( $route, '/wp/v2/templates' ) ) {
continue;
}
foreach ( $gestionnaires as &$gestionnaire ) {
if ( ! is_array( $gestionnaire )
|| empty( $gestionnaire['permission_callback'] )
|| empty( $gestionnaire['methods']['DELETE'] ) ) {
continue;
}
$origine = $gestionnaire['permission_callback'];
$gestionnaire['permission_callback'] = function ( $requete ) use ( $origine ) {
$resultat = call_user_func( $origine, $requete );
if ( true !== $resultat ) {
return $resultat;
}
if ( ! current_user_can( 'manage_options' ) ) {
return new WP_Error(
'agence_suppression_interdite',
'La suppression de gabarits est réservée aux gestionnaires.',
array( 'status' => rest_authorization_required_code() )
);
}
return true;
};
}
unset( $gestionnaire );
}
unset( $gestionnaires );
return $routes;
}
Le principe est de ne jamais affaiblir la vérification d’origine : on l’exécute d’abord, et on ne fait qu’ajouter une condition. Le code ne dépend pas de la forme exacte de la route, seulement de son préfixe, ce qui le rend moins fragile d’une version de WordPress à l’autre.
Une route sans vérification de permission est une porte sans serrure : qu’elle mène à un couloir ou à la salle des machines, elle reste ouverte.
Les pièges fréquents
- Confondre authentification et autorisation. Un mot de passe d’application prouve qui appelle ; seul le
permission_callbackdécide ce qu’il a le droit de faire. - Supposer que l’éditeur de site est la seule porte. Un gabarit modifiable depuis l’interface l’est aussi par HTTP : toute règle de restriction doit donc vivre côté serveur, pas dans l’interface.
- Élargir une capacité pour « dépanner ». Donner
edit_theme_optionsà un rôle éditorial pour qu’il modifie un pied de page lui ouvre aussi la modification de tous les gabarits et des menus. - Oublier les sites multisites. Sur un réseau, les capacités d’un administrateur de site et d’un super administrateur diffèrent : testez avec les deux profils.
Conclusion
La REST API des gabarits n’a rien de magique : chaque point de terminaison s’appuie sur un permission_callback qui se résume, en 5.9, à la capacité edit_theme_options. Pour une extension tierce, la bonne démarche consiste à vérifier ce que le cœur autorise réellement, à créer des routes dédiées et minimales quand un besoin précis existe, et à envelopper plutôt que remplacer les vérifications d’origine. Un point de terminaison mal restreint expose toujours plus que prévu : le tester avec le profil le moins privilégié est la recette la plus économique.