# permission_callback : ce que la REST API des templates autorise à modifier

> Exposer ou restreindre la modification de gabarits via une extension tierce impose de comprendre finement ce que vérifie réellement chaque point de terminaison REST.

- Auteur : WordPress Développement
- Publié le : 2022-03-07
- Mis à jour le : 2026-09-30
- Catégorie : Éditeur de site (FSE)
- URL : https://www.wpmoderne.fr/fse/permission-callback-rest-api-templates/

## L’essentiel

- Chaque point de terminaison définit son propre permission_callback
- edit_theme_options reste la vérification de base
- Un point de terminaison mal restreint expose plus que prévu

« 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.

> L'essentiel à retenir : Chaque point de terminaison définit son propre permission_callback ; edit_theme_options reste la vérification de base ; Un point de terminaison mal restreint expose plus que prévu

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_Error` est préférable à `false`.** Avec `false`, WordPress fabrique une erreur générique ; avec un `WP_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_true` pour 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_callback` dé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.
