L’architecture headless

En mode headless, WordPress sert uniquement de CMS (gestion de contenu) via son API REST. Le front-end est développé séparément avec un framework JavaScript moderne comme Next.js, Astro ou Nuxt.

Lueur Externe développe des architectures headless WordPress pour les projets nécessitant des performances maximales.

Avantages du headless

AspectWordPress classiqueWordPress headless
PerformanceMoyenneExcellente (SSG/ISR)
SécuritéSurface d’attaque largeAPI seule exposée
Flexibilité frontLimitée au thèmeTotale (React, Vue…)
SEOBonExcellent (SSG)
ÉditionGutenberg completGutenberg + preview
ComplexitéFaibleMoyenne

Configurer l’API REST

Endpoints natifs

# Récupérer les articles
GET /wp-json/wp/v2/posts?per_page=10&_embed

# Récupérer un article par slug
GET /wp-json/wp/v2/posts?slug=mon-article&_embed

# Récupérer les pages
GET /wp-json/wp/v2/pages?per_page=100

# Récupérer les catégories
GET /wp-json/wp/v2/categories

Endpoints personnalisés

// Enregistrer un endpoint custom
add_action('rest_api_init', function () {
    register_rest_route('lueur/v1', '/featured-posts', [
        'methods'  => 'GET',
        'callback' => function () {
            $posts = get_posts([
                'meta_key'   => 'is_featured',
                'meta_value' => '1',
                'numberposts' => 6,
            ]);
            return array_map(function ($post) {
                return [
                    'id'      => $post->ID,
                    'title'   => $post->post_title,
                    'slug'    => $post->post_slug,
                    'excerpt' => get_the_excerpt($post),
                    'image'   => get_the_post_thumbnail_url($post, 'large'),
                ];
            }, $posts);
        },
        'permission_callback' => '__return_true',
    ]);
});

Intégration Next.js

Client API

// lib/wordpress.ts
const API_URL = process.env.WORDPRESS_API_URL!;

export async function getPosts(page = 1, perPage = 10) {
  const res = await fetch(
    `${API_URL}/wp-json/wp/v2/posts?page=${page}&per_page=${perPage}&_embed`,
    { next: { revalidate: 3600 } }
  );
  const posts = await res.json();
  const total = parseInt(res.headers.get('X-WP-Total') || '0');
  return { posts, total };
}

export async function getPostBySlug(slug: string) {
  const res = await fetch(
    `${API_URL}/wp-json/wp/v2/posts?slug=${slug}&_embed`,
    { next: { revalidate: 3600 } }
  );
  const posts = await res.json();
  return posts[0] || null;
}

Page article

// app/blog/[slug]/page.tsx
import { getPostBySlug, getPosts } from '@/lib/wordpress';

export async function generateStaticParams() {
  const { posts } = await getPosts(1, 100);
  return posts.map((post: any) => ({ slug: post.slug }));
}

export default async function BlogPost({ params }: { params: { slug: string } }) {
  const post = await getPostBySlug(params.slug);
  if (!post) return <div>Article non trouvé</div>;

  return (
    <article>
      <h1 dangerouslySetInnerHTML={{ __html: post.title.rendered }} />
      <div dangerouslySetInnerHTML={{ __html: post.content.rendered }} />
    </article>
  );
}

Preview et ISR

// app/api/preview/route.ts
import { draftMode } from 'next/headers';
import { redirect } from 'next/navigation';

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const secret = searchParams.get('secret');
  const slug = searchParams.get('slug');

  if (secret !== process.env.PREVIEW_SECRET) {
    return new Response('Invalid token', { status: 401 });
  }

  draftMode().enable();
  redirect(`/blog/${slug}`);
}

Conclusion

Le WordPress headless combine la puissance éditoriale de WordPress avec les performances d’un front-end moderne. Lueur Externe conçoit des architectures headless sur mesure pour ses clients.