# Créer un endpoint REST sur mesure avec register_rest_route()

> Tutoriel pas à pas pour concevoir un endpoint REST WordPress personnalisé, sécurisé et validé, avec register_rest_route() dans un plugin.

- Auteur : Clément Hadrot
- Publié le : 2020-07-15
- Mis à jour le : 2020-07-15
- Catégorie : Headless &amp; API
- URL : https://wpmoderne.dev.wordpress-developpement.fr/headless/endpoint-rest-sur-mesure-register-rest-route/

## L’essentiel

- Un namespace personnalisé évite les collisions avec wp/v2
- permission_callback ne doit jamais être ignoré
- validate_callback et sanitize_callback sécurisent les arguments

L'API REST native de WordPress couvre les besoins standards : articles, pages, médias, taxonomies. Mais un projet headless réclame presque toujours des routes sur mesure, adaptées à une logique métier précise, comme récupérer les articles « à la une », calculer un résumé de statistiques, ou exposer une ressource qui n'a pas d'équivalent direct dans le cœur.

C'est exactement le rôle de la fonction `register_rest_route()`. Elle permet de déclarer une route entièrement personnalisée dans un plugin, avec son propre espace de noms, sa logique de traitement et ses règles de sécurité. Ce tutoriel construit, étape par étape, un endpoint qui retourne les articles mis en avant d'un site.

## Où et quand enregistrer la route

L'enregistrement doit se faire sur le hook `rest_api_init`, jamais avant, sous peine d'erreurs silencieuses. Voici le squelette de base, à placer dans un plugin dédié plutôt que dans functions.php d'un thème, pour que la fonctionnalité survive à un changement de thème :

```
add_action( 'rest_api_init', function () {
    register_rest_route( 'wpmoderne/v1', '/articles-a-la-une', array(
        'methods'             => WP_REST_Server::READABLE,
        'callback'            => 'wpmoderne_get_articles_a_la_une',
        'permission_callback' => '__return_true',
    ) );
} );
```

Le namespace `wpmoderne/v1` est un choix volontaire : préfixer avec le nom de votre projet ou plugin évite toute collision avec `wp/v2` ou avec les routes d'un autre plugin. Le suffixe `/v1` permet de faire évoluer la route plus tard sans casser les intégrations existantes : le jour où la structure change en profondeur, on publie simplement `/v2` en parallèle.

## Écrire le callback

Le callback reçoit un objet `WP_REST_Request` et doit renvoyer soit un `WP_REST_Response`, soit un `WP_Error` en cas de problème. Voici l'implémentation de notre endpoint :

```
function wpmoderne_get_articles_a_la_une( WP_REST_Request $request ) {
    $query = new WP_Query( array(
        'post_type'      => 'post',
        'posts_per_page' => 5,
        'meta_key'       => 'a_la_une',
        'meta_value'     => '1',
    ) );

    $articles = array();
    foreach ( $query->posts as $post ) {
        $articles[] = array(
            'id'    => $post->ID,
            'titre' => get_the_title( $post ),
            'lien'  => get_permalink( $post ),
        );
    }

    return new WP_REST_Response( $articles, 200 );
}
```

> L'essentiel à retenir : Un namespace personnalisé évite les collisions avec wp/v2 ; permission_callback ne doit jamais être ignoré ; validate_callback et sanitize_callback sécurisent les arguments

## Le permission_callback : la règle numéro un

C'est le point le plus souvent négligé, et le plus critique en matière de sécurité. Depuis WordPress 5.5, ne pas définir `permission_callback` déclenche même un message d'avertissement dans les logs, précisément pour forcer les développeurs à y réfléchir.

Trois cas de figure typiques :

- **Route publique en lecture** : `permission_callback` peut valoir `__return_true`, en toute connaissance de cause, uniquement si la donnée exposée est réellement publique
- **Route réservée aux utilisateurs connectés** : utiliser une fonction qui vérifie `is_user_logged_in()` ou une capacité précise avec `current_user_can()`
- **Route d'écriture** : toujours vérifier une capacité adaptée à l'action, jamais un simple `is_user_logged_in()` qui n'exclut pas les rôles trop permissifs

```
'permission_callback' => function () {
    return current_user_can( 'edit_posts' );
},
```

> Un `__return_true` posé « pour tester » a une fâcheuse tendance à survivre jusqu'en production. Sur nos projets, chaque route fait l'objet d'une revue explicite de son `permission_callback` avant la mise en ligne, sans exception.

## Valider et nettoyer les arguments

Pour une route qui accepte des paramètres, l'argument `args` permet de déclarer un schéma de validation et de nettoyage, exécuté automatiquement par WordPress avant que le callback ne soit appelé :

```
register_rest_route( 'wpmoderne/v1', '/articles-a-la-une', array(
    'methods'             => WP_REST_Server::READABLE,
    'callback'            => 'wpmoderne_get_articles_a_la_une',
    'permission_callback' => '__return_true',
    'args'                => array(
        'limite' => array(
            'default'           => 5,
            'sanitize_callback' => 'absint',
            'validate_callback' => function( $value ) {
                return is_numeric( $value ) && $value <= 20;
            },
        ),
    ),
) );
```

Cette séparation est importante : `validate_callback` rejette la requête si la valeur est incorrecte, tandis que `sanitize_callback` nettoie la valeur avant utilisation. Les deux se complètent et ne doivent pas être confondus.

### Gérer les erreurs proprement

Quand une requête ne peut pas aboutir, renvoyez un `WP_Error` plutôt qu'un tableau vide silencieux : le frontend saura distinguer une absence de résultat d'une véritable erreur.

```
if ( empty( $articles ) ) {
    return new WP_Error(
        'aucun_article',
        'Aucun article à la une pour le moment.',
        array( 'status' => 404 )
    );
}
```

## En résumé

`register_rest_route()` donne un contrôle total sur la logique métier exposée à un frontend headless, à condition de respecter trois règles simples : un namespace propre à votre projet, un `permission_callback` pensé pour chaque route et jamais laissé par défaut, et une validation systématique des arguments reçus. Ces bonnes pratiques, appliquées dès le premier endpoint, évitent la plupart des failles de sécurité qu'on retrouve encore sur des projets headless bâclés.
