← ClaudeAtlas

ghost-headless-bloglisted

Implement a headless Ghost CMS blog (/blog) in a Next.js App Router site — Content API client, ISR + webhook revalidation, tag/author/paged archives, author bio + social rendering, SEO metadata + JSON-LD, sitemap, Ghost koenig-card styling, blur-up images. Use when adding a Ghost-powered blog to a Next.js project, or debugging an existing headless Ghost integration (empty blog, stale pages, broken images/cards).
kasuncfdo/ghost-headless-blog-skill · ★ 5 · Web & Frontend · score 75
Install: claude install-skill kasuncfdo/ghost-headless-blog-skill
# Headless Ghost blog in Next.js (App Router) Battle-tested patterns from a live production site (Next.js 16 / React 19 / Tailwind v4, Ghost Content API v6.0). Everything below was learned the hard way — follow the decisions, not just the code. ## Architecture at a glance - **No `@tryghost/content-api` dependency.** Call the Content API REST endpoints directly (`{GHOST_URL}/ghost/api/content/posts/?key=...`) with an `Accept-Version: v6.0` header. The SDK adds weight and hides errors. - **All Ghost fetching is server-side** (server components, route handlers, `generateStaticParams`, sitemap). Content API keys only expose public data, but keep them server-only anyway: env vars `GHOST_URL` / `GHOST_CONTENT_API_KEY` with **no `NEXT_PUBLIC_` prefix**. - **ISR everywhere + instant webhook purge.** Every blog route exports `export const revalidate = 3600` and `export const dynamicParams = true`; a Ghost Admin webhook hits `/api/revalidate?secret=...` on post publish/update/unpublish/delete for instant purges. Hourly ISR is only the safety net. - **Ghost post HTML is rendered verbatim** via `dangerouslySetInnerHTML` inside `<article className="gh-content">`, styled by a dedicated `ghost-content.css`, with a small HTML post-processing pass (blur-up images, LCP fix) and tiny client components re-adding Ghost's interactive card JS (toggle cards). ## Routes to build | Route | Purpose | |---|---| | `/blog` | Index: hero + feed. Only the Ghost-fetching part is an