Use Cases

Comment construire un CMS de blog avec Claude Code

Apprenez a construire un CMS de blog avec Claude Code. Inclut des exemples de code pratiques et un guide etape par etape.

Construire un CMS de blog avec Claude Code

Posseder son propre CMS de blog vous donne un controle total sur la liberte de design, le controle SEO et l’optimisation des performances. Avec Claude Code, vous pouvez construire en peu de temps un CMS complet avec gestion d’articles, apercu et flux de publication.

Conception des prompts

> Cree un CMS de blog avec Next.js App Router.
> Construis a la fois un panneau d'administration pour creer, editer et publier des articles en markdown,
> et un frontend genere en SSG.
> Implemente egalement le filtrage par categories et tags.

Definition du modele de donnees des articles

// src/types/post.ts
export interface Post {
  id: string;
  title: string;
  slug: string;
  content: string;        // Markdown
  excerpt: string;
  coverImage?: string;
  category: string;
  tags: string[];
  status: 'draft' | 'published' | 'archived';
  publishedAt?: Date;
  createdAt: Date;
  updatedAt: Date;
  authorId: string;
}

export interface PostCreateInput {
  title: string;
  content: string;
  category: string;
  tags: string[];
  status?: 'draft' | 'published';
}

Implementation de l’API de gestion des articles

// src/app/api/posts/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { generateSlug } from '@/lib/utils';

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const category = searchParams.get('category');
  const tag = searchParams.get('tag');
  const status = searchParams.get('status') || 'published';

  const posts = await prisma.post.findMany({
    where: {
      status,
      ...(category && { category }),
      ...(tag && { tags: { has: tag } }),
    },
    orderBy: { publishedAt: 'desc' },
    select: {
      id: true,
      title: true,
      slug: true,
      excerpt: true,
      category: true,
      tags: true,
      publishedAt: true,
      coverImage: true,
    },
  });

  return NextResponse.json(posts);
}

export async function POST(request: NextRequest) {
  const body = await request.json();
  const slug = generateSlug(body.title);

  const post = await prisma.post.create({
    data: {
      ...body,
      slug,
      excerpt: body.content.substring(0, 160),
      publishedAt: body.status === 'published' ? new Date() : null,
    },
  });

  return NextResponse.json(post, { status: 201 });
}

Composant editeur Markdown

// src/components/admin/MarkdownEditor.tsx
'use client';
import { useState } from 'react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';

interface Props {
  initialContent?: string;
  onSave: (content: string) => void;
}

export function MarkdownEditor({ initialContent = '', onSave }: Props) {
  const [content, setContent] = useState(initialContent);
  const [isPreview, setIsPreview] = useState(false);

  return (
    <div className="border rounded-lg">
      <div className="flex border-b">
        <button
          onClick={() => setIsPreview(false)}
          className={`px-4 py-2 ${!isPreview ? 'bg-blue-50 font-bold' : ''}`}
        >
          Editer
        </button>
        <button
          onClick={() => setIsPreview(true)}
          className={`px-4 py-2 ${isPreview ? 'bg-blue-50 font-bold' : ''}`}
        >
          Apercu
        </button>
      </div>
      {isPreview ? (
        <div className="prose p-4 max-w-none">
          <ReactMarkdown remarkPlugins={[remarkGfm]}>{content}</ReactMarkdown>
        </div>
      ) : (
        <textarea
          value={content}
          onChange={(e) => setContent(e.target.value)}
          className="w-full h-96 p-4 font-mono text-sm resize-none"
          placeholder="Ecrivez votre article en markdown..."
        />
      )}
      <div className="flex justify-end p-3 border-t">
        <button
          onClick={() => onSave(content)}
          className="bg-blue-600 text-white px-6 py-2 rounded"
        >
          Enregistrer
        </button>
      </div>
    </div>
  );
}

Generation automatique des metadonnees SEO

Si vous le demandez a Claude Code, il peut aussi implementer la generation automatique d’images OGP et la configuration des meta tags a partir du contenu de l’article.

// src/lib/seo.ts
export function generatePostMeta(post: Post) {
  return {
    title: `${post.title} | MyBlog`,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      type: 'article',
      publishedTime: post.publishedAt?.toISOString(),
      tags: post.tags,
      images: post.coverImage ? [{ url: post.coverImage }] : [],
    },
  };
}

Articles connexes

Pour la partie frontend de la construction du CMS, le guide de comparaison SSR/SSG est utile. Pour les strategies SEO, consultez egalement l’optimisation SEO.

Pour le choix de bibliotheques de traitement markdown, l’ecosysteme unified.js est complet et constitue une bonne reference.

#Claude Code #CMS #blog #Next.js #TypeScript