Using Headless Kit
A practical guide in two parts. Part 1 is for the developer who sets the site up and maintains it. Part 2 is for the people who write and edit in WordPress every day; you can hand it to your client as is.
The kit's README.md is the technical reference (how each piece works, every filter). This guide is the walkthrough.
How the pieces fit
WordPress (cms.example.com) Next.js (example.com)
editors write here visitors see this
Headless Kit plugin -- content -> pages from blocks
-- changed -> /api/revalidate
-- preview -> /api/preview
<- style ---- /api/theme
Headless Kit theme (optional: turns on Styles)- Editors never touch code. They write in Gutenberg; the site updates as soon as they publish.
- The developer owns the look. A shadcn preset in code sets the colors, fonts and component style; WordPress gets the same palette and an editor that looks like the site.
- Optionally, editors can change colors and fonts in WordPress too, and the site follows.
Part 1: For developers
1. What's in the box
| File | What it is |
|---|---|
headless-kit-<version>.zip | The whole kit: web/ (Next.js app), the plugin and theme sources, docs |
headless-kit-plugin-<version>.zip | The WordPress plugin, ready for Plugins → Add New → Upload |
headless-kit-theme-<version>.zip | The optional block theme, ready for Appearance → Themes → Add New → Upload |
You need Node.js 20.9+ and pnpm, and a WordPress 6.4+ site (6.5+ for the theme and Font Library) on PHP 8.0+.
2. Run it locally
Option A: a throwaway local WordPress (needs Docker). From the kit folder:
npx @wordpress/env startThat starts WordPress at http://localhost:8888 (login admin / password) with the plugin and theme mounted, plus ACF and the supported SEO plugins to try out.
Option B: your own WordPress (LocalWP, a staging site…). Upload the plugin zip and activate it.
Then, in WordPress:
- Settings → Permalinks: anything but "Plain".
- Settings → Headless Kit: set Frontend URL to
http://localhost:3000and copy the Shared secret. - Optional: tick Projects for a portfolio section.
And the Next.js app:
cd web
cp .env.example .env.local
# WORDPRESS_URL=http://localhost:8888 (no trailing slash)
# HEADLESS_KIT_SECRET=<the secret you copied>
pnpm install
pnpm devOpen http://localhost:3000. Back in Settings → Headless Kit, the Connection line should say the frontend accepted the secret. If it doesn't, see Troubleshooting.
3. Add some content
- Homepage: create a page called "Home", then Settings → Reading → Your homepage displays → A static page. Its blocks render at
/, followed by your latest projects and posts. - Blog: posts appear at
/blogand/blog/<slug>, with category and tag pages. - Menus: Appearance → Menus, assign one to Header menu (Next.js) and one to Footer menu (Next.js). (With the Headless Kit theme active, WordPress still offers Appearance → Menus because the plugin registers these locations.)
- Projects (if enabled): Projects → Add New.
Use plenty of block types on a test page (headings, lists, quotes, buttons, a group with a background, a table, a details block): it's the quickest way to see what the kit does with them.
4. Pick the look
Three looks ship with the kit:
pnpm style studio # minimal and neutral, Geist (default)
pnpm style editorial # warm stone and amber, Playfair Display headings
pnpm style bold # zinc and violet, Space Grotesk, large radiusOr design your own on ui.shadcn.com/create, copy the preset code and run pnpm style <code>. Name your favourites in web/presets.json.
A preset sets the colors (light and dark), fonts, radius and the shape of every component: buttons, cards, tables, accordions. Everything on the site, block content included, is built from those components, so the whole site changes with one command.
WordPress follows automatically. After you deploy a new preset, click Sync style now under Settings → Headless Kit (it also refreshes on its own every 12 hours). The editor then gets:
- the preset's colors as the color palette (Primary, Secondary, Muted, Accent, Card…),
- the preset's fonts,
- an editor canvas styled like the site: headings, buttons, cards, tables and so on look the way they will when published,
- Preview dark mode in the editor's ⋮ menu.
5. Let editors change colors and fonts (optional)
Upload and activate headless-kit-theme-<version>.zip. It's a nearly empty block theme: visitors never see it (Next.js renders the site), it only turns on Appearance → Editor → Styles.
Editors can then change palette colors (light and dark) and the body and heading fonts, including fonts from the Font Library. Saving updates the live site right away. Your preset stays the base: colors nobody touched keep following code, and Reset in Styles hands everything back to it. See Part 2, section 6 for the editor's side.
Leave the theme off if you'd rather the look stays in code only.
6. Deploy
The usual setup: WordPress on a subdomain (cms.example.com), Next.js on the main domain.
Vercel
- Import the repo, set the root directory to
web/. - Environment variables:
WORDPRESS_URL,HEADLESS_KIT_SECRET,NEXT_PUBLIC_SITE_URL(your public site URL). - Deploy, point your domain at it.
Your own server
web/ builds a standalone server (output: "standalone"):
cd web
pnpm build
cp -r public .next/standalone/ # Next.js doesn't copy it for you
cp -r .next/static .next/standalone/.next/
cd .next/standalone && HOSTNAME=127.0.0.1 PORT=3000 node server.jsPut a reverse proxy (Caddy, nginx) in front. Build on the same OS and CPU architecture as the server, since some dependencies (image optimization) ship native binaries.
Then, in WordPress:
- Settings → Headless Kit: set Frontend URL to the live site, check the Connection line.
- Tick Frontend redirect to send visitors of the old WordPress front end to the Next.js site. wp-admin, login and the REST API keep working.
- Click Sync style now.
7. Customize
Change how a block looks. Block components live in web/src/components/blocks/, and their classes in blocks/styles.ts. Change the classes there, not inline in the components: pnpm theme (run by dev, build and style) builds the editor stylesheet from that file, so the editor keeps matching the site. If you style a block that the editor doesn't map yet, add a line to blockMap() in web/scripts/editor-style.mjs.
Add a block. Write a component that takes { block, children } and register it in defaultComponents in block-renderer.tsx:
"acme/testimonial": Testimonial,Blocks without a component fall back to WordPress' own HTML, styled to match. In development, the console lists which blocks use the fallback.
Custom post types and taxonomies. Register them with public and show_in_rest (CPT UI, ACF or code). They appear at /<rewrite slug>/<post> with an index page, and their taxonomies get term pages. No route files needed; add a route folder (e.g. app/events/[slug]/page.tsx) only if you want a custom layout.
ACF fields. Turn on Show in REST API for a field group, then read fields in a server component:
import { acf, type AcfImage } from "@/lib/wordpress/acf"
const hero = acf<AcfImage | null>(post, "hero")SEO. With Rank Math, SEOPress or Yoast active, titles, descriptions, canonicals, noindex and social images flow into page metadata automatically.
Dark mode. On by default with a header toggle. For a light-only site, remove ThemeToggle from the header.
README.md lists every plugin filter for shaping data, paths and styles.
8. Update to a new version
Kit and plugin share one version number; update both together.
- Upload the new plugin zip (and theme zip, if you use it). WordPress replaces the old version.
- Bring in the new
web/: on a new git branch, copy the newweb/over yours, review the diff so your own changes stay, thenpnpm install && pnpm build. - Deploy, then click Sync style now.
CHANGELOG.md says what changed in each version.
9. Checklist before going live
pnpm typecheck,pnpm lintandpnpm buildpass- Connection line is green, with the live frontend URL
- Publishing a post shows the change on the live site within seconds
- Preview on a draft opens it on the live site
- Header and footer menus are assigned
- Sync style now done; a post in the editor looks like the site
- Frontend redirect on
- Permalinks not "Plain"
Part 2: For editors
You write in WordPress exactly as you're used to. The difference: visitors see a separate, faster website that's built from what you write. Everything you publish shows up there within seconds.
1. Write and publish
Create posts under Posts and pages under Pages, using the block editor as usual. When you click Publish or Update, the website updates right away; there's nothing else to do.
What the editor shows is close to the real site: same fonts, colors, heading sizes, buttons, cards and tables. It isn't pixel-perfect (WordPress adds its own spacing and selection outlines), so use Preview for the final check.
2. Preview drafts
Click Preview in the editor (top right). It opens the draft on the real website, as visitors would see it once published. A banner at the top shows you're in preview mode; click Exit preview to leave it.
- Save the draft first; the preview shows the last saved version. After saving again, refresh the preview tab.
- Preview links work for 10 minutes. Click Preview again for a fresh one.
3. Use the right blocks
Most blocks become a matching part of the site's design:
| In the editor | On the site |
|---|---|
| Heading | The site's heading style (H2 gets a line underneath) |
| Paragraph, List, Quote | Body text in the site's style |
| Buttons | The site's buttons. Outline style gives a secondary-looking button |
| Group with a background color | A card |
| Table | A clean table with a header row |
| Details | An expandable section (good for FAQs) |
| Code | A code box |
| Image, Gallery, Cover, Video embed | Responsive images and video |
Other blocks still show up; they just use WordPress' own styling.
Colors. The color picker offers the site's own colors (Primary, Secondary, Muted, Accent, Card…). Use those rather than custom colors: they adapt to dark mode and follow future design changes. A group colored Primary stays "the brand color" even if the brand color changes later.
Dark mode preview. Visitors can switch the site to dark mode. To see your content in dark mode while editing, open the ⋮ menu (top right) and choose Preview dark mode. Choose it again to switch back. It only changes your view, not the site.
4. The homepage, projects and menus
- Homepage: it's a normal page (often called "Home"). Edit it like any page; the latest projects and posts are added below it automatically.
- Projects (if your site has them): Projects → Add New. Fill in the Project details box (client, year, role, live URL), add a featured image, an excerpt (shown as the intro) and project tags. The Order field (in Page Attributes) sorts them.
- Menus: Appearance → Menus. The menus assigned to Header menu (Next.js) and Footer menu (Next.js) are the site's navigation. Changes show up as soon as you save.
5. SEO
If your site uses Yoast, Rank Math or SEOPress, fill in the SEO box under each post and page as usual. The title, description and social image are used on the website. Previews show the last saved SEO values.
6. Change colors and fonts
Only if your developer installed the Headless Kit theme. Go to Appearance → Editor → Styles:
- Colors → Palette: change any of the site's colors. Each color has a (dark) twin that sets it for dark mode.
- Typography: pick the font for Text (body) and Headings. Add new fonts with Manage fonts (WordPress' Font Library), from Google Fonts or your own files.
Click Save and the live site updates right away.
Good to know:
- Change colors you need and leave the rest; untouched colors keep following the site's design.
- Reset (⋮ menu in Styles) brings back the original design.
- Only colors and the two fonts carry over to the website. Other Styles settings (spacing, layout, per-block styles) only affect the editor.
7. If something looks off
| You see | Try |
|---|---|
| A change doesn't show on the site | Reload the page. Still old after a minute? Ask your developer: the connection may be down. |
| Preview says the link expired | Click Preview again. |
| The editor looks different from the site after a redesign | Ask your developer to click Sync style now (or wait up to 12 hours). |
| A color you picked looks wrong in dark mode | Use one of the site's colors instead of a custom one, or set its (dark) twin in Styles. |
Troubleshooting
For developers.
| Problem | Cause and fix |
|---|---|
| Connection line: "The frontend rejected the secret" | HEADLESS_KIT_SECRET in Next.js doesn't match Settings → Headless Kit. Copy it again and restart / redeploy. |
| Connection line: HTTP error or can't connect | WordPress can't reach the Frontend URL. With local Docker WordPress, localhost inside the container isn't your machine: use your machine's LAN IP (e.g. http://192.168.1.20:3000) and run pnpm dev -H 0.0.0.0. |
| Published changes don't show up | Same as above: revalidation is a request from WordPress to /api/revalidate. Pages also refresh on their own within the cache lifetime. |
pnpm build fails reaching WordPress | WORDPRESS_URL must be reachable at build time; pages are prerendered from real content. |
| Images don't load from a local WordPress | Next.js blocks private IPs for image optimization; the kit allows them only when WORDPRESS_URL is localhost or a private IP. Restart pnpm dev after changing it. |
| "Sync style now" says the editor stylesheet couldn't be loaded | The frontend isn't serving /editor-style.css. Self-hosted: copy public/ into .next/standalone/. |
[theme] Couldn't build the editor stylesheet during dev/build | The site still builds; the editor keeps the previous stylesheet. Usually a block style in styles.ts or a ui component that the script can't read; the message says which. |
| A page shows "not found" but the URL is right | Check the post is published, permalinks aren't "Plain", and for custom post types that show_in_rest is on. |
| Fonts chosen in Styles don't load on the site | They're served through /api/fonts/… from WordPress' fonts folder; check that WordPress is reachable from the Next.js server. |