Endpoints custom
L'API native ne suffit pas ? Crée tes propres routes.
5.1Pourquoi des endpoints custom ?
L'API native expose les données brutes de WordPress. Mais côté front, tu as souvent besoin de :
- Regrouper des données : un seul appel qui retourne l'article + ses médias + l'auteur, au lieu de 3 requêtes.
- Formater les réponses : retourner seulement les champs nécessaires, dans le format que Next.js attend.
- Logique métier : vérifier un abonnement, traquer une progression, gérer un panier.
- Sécurité : protéger certaines données derrière une authentification.
5.2Ton premier endpoint
On va créer un namespace monsite/v1 avec un endpoint /projets qui retourne uniquement ce dont le front a besoin :
<?php
add_action('rest_api_init', function() {
register_rest_route('monsite/v1', '/projets', [
'methods' => 'GET',
'callback' => 'get_projets_for_front',
'permission_callback' => '__return_true', // Public
]);
});
function get_projets_for_front(WP_REST_Request $request) {
$posts = get_posts([
'post_type' => 'projet',
'post_status' => 'publish',
'posts_per_page' => 12,
'orderby' => 'date',
'order' => 'DESC',
]);
$data = array_map(function($post) {
$thumbnail_id = get_post_thumbnail_id($post->ID);
$image_url = $thumbnail_id
? wp_get_attachment_image_url($thumbnail_id, 'large')
: null;
return [
'id' => $post->ID,
'title' => $post->post_title,
'slug' => $post->post_name,
'excerpt' => get_the_excerpt($post),
'image' => $image_url,
'url_site' => get_field('url_site', $post->ID),
'client' => get_field('client', $post->ID),
'stack' => get_field('stack', $post->ID) ?: [],
];
}, $posts);
return rest_ensure_response($data);
}Résultat : /wp-json/monsite/v1/projets retourne un JSON propre, léger, directement utilisable par Next.js.
5.3Paramètres et validation
Tu peux ajouter des paramètres à tes routes et les valider automatiquement :
<?php
register_rest_route('monsite/v1', '/projets/(?P<slug>[a-z0-9-]+)', [
'methods' => 'GET',
'callback' => 'get_projet_by_slug',
'permission_callback' => '__return_true',
'args' => [
'slug' => [
'required' => true,
'type' => 'string',
'sanitize_callback' => 'sanitize_title',
'validate_callback' => function($value) {
return !empty($value) && strlen($value) < 200;
},
],
],
]);
function get_projet_by_slug(WP_REST_Request $request) {
$slug = $request->get_param('slug');
$posts = get_posts([
'post_type' => 'projet',
'post_status' => 'publish',
'name' => $slug,
'posts_per_page' => 1,
]);
if (empty($posts)) {
return new WP_Error(
'not_found',
'Projet non trouvé.',
['status' => 404]
);
}
$post = $posts[0];
return rest_ensure_response([
'id' => $post->ID,
'title' => $post->post_title,
'slug' => $post->post_name,
'content' => apply_filters('the_content', $post->post_content),
'image' => wp_get_attachment_image_url(
get_post_thumbnail_id($post->ID), 'full'
),
'url_site' => get_field('url_site', $post->ID),
'repo_github' => get_field('repo_github', $post->ID),
'client' => get_field('client', $post->ID),
'date_livraison' => get_field('date_livraison', $post->ID),
'stack' => get_field('stack', $post->ID) ?: [],
]);
}5.4Endpoints authentifiés
Certains endpoints ne doivent être accessibles qu'aux utilisateurs connectés. Utilise le permission_callback :
<?php
register_rest_route('monsite/v1', '/me', [
'methods' => 'GET',
'callback' => function(WP_REST_Request $request) {
$user = wp_get_current_user();
return rest_ensure_response([
'id' => $user->ID,
'email' => $user->user_email,
'display_name' => $user->display_name,
'role' => $user->roles[0] ?? 'subscriber',
'registered' => $user->user_registered,
]);
},
'permission_callback' => function() {
// Seuls les utilisateurs connectés peuvent accéder
return is_user_logged_in();
},
]);5.5Organiser ses endpoints
Quand tu as plusieurs endpoints, organise-les en fichiers séparés :
wp-content/plugins/mon-api/
├── mon-api.php # Plugin principal (loader)
├── endpoints/
│ ├── projets.php # /monsite/v1/projets
│ ├── auth.php # /monsite/v1/login, /me, /register
│ ├── contact.php # /monsite/v1/contact
│ └── dashboard.php # /monsite/v1/dashboard
└── helpers/
└── response.php # Fonctions utilitairesLe fichier principal charge tous les modules :
<?php
/**
* Plugin Name: Mon API Headless
* Description: Endpoints REST custom pour le front Next.js
*/
foreach (glob(plugin_dir_path(__FILE__) . 'endpoints/*.php') as $file) {
require_once $file;
}