iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Headless WordPress

Headless WordPress uses WP only as a content backend, with a separate front end (Next.js, Astro, Nuxt) consuming the REST or GraphQL API. The wins: modern dev experience, faster front end, better security (admin and front end on separate hosts). The trade-offs: previewing, block-aware rendering, and forms all need extra work.

REST/GraphQL API, Next.js front end, preview + caching

EXAMPLE
# 1) Enable a clean public API
#   - REST is built in:  https://example.com/wp-json/wp/v2/posts
#   - GraphQL via WPGraphQL plugin: https://example.com/graphql
#   Both expose posts, pages, custom post types, ACF / Meta Box fields.

# 2) Lock down what is exposed
#   - In WP, set user accounts to NOT be returned to anonymous (some plugins fix this)
#   - Disable XML-RPC and the comments endpoint if unused
#   - Cache the API at the edge — Cloudflare / Fastly / nginx fastcgi cache

# 3) Next.js front end — static + ISR
# app/posts/[slug]/page.tsx
import { notFound } from 'next/navigation';

export const revalidate = 300;          // ISR every 5 minutes

export async function generateStaticParams() {
  const res = await fetch(\`${process.env.WP_BASE}/wp-json/wp/v2/posts?per_page=100&_fields=slug\`,
                          { next: { revalidate: 600 } });
  const posts: { slug: string }[] = await res.json();
  return posts.map(({ slug }) => ({ slug }));
}

export default async function Post({ params }: { params: { slug: string } }) {
  const res = await fetch(
    \`${process.env.WP_BASE}/wp-json/wp/v2/posts?slug=${params.slug}&_embed\`,
    { next: { revalidate: 300 } });
  const [post] = await res.json();
  if (!post) notFound();
  return (
    <article>
      <h1 dangerouslySetInnerHTML={{ __html: post.title.rendered }} />
      <div dangerouslySetInnerHTML={{ __html: post.content.rendered }} />
    </article>
  );
}

# 4) Preview from inside wp-admin
# Add a 'Preview' button via a small plugin that sends the editor to:
# https://nextjs.example.com/api/preview?secret=${PREVIEW_SECRET}&slug=${post.slug}
# pages/api/preview.ts on Next.js:
# export default async function handler(req, res) {
#   if (req.query.secret !== process.env.PREVIEW_SECRET) return res.status(401).end();
#   res.setPreviewData({});
#   res.redirect('/posts/' + req.query.slug);
# }

# 5) Cache invalidation on publish — webhook from WP to the front end
# In a small plugin or via the 'WP Webhooks' plugin:
# add_action('save_post', function ($post_id) {
#   wp_remote_post('https://nextjs.example.com/api/revalidate', [
#     'body' => json_encode([
#       'secret' => 'WEBHOOK_SECRET',
#       'slug'   => get_post_field('post_name', $post_id),
#     ]),
#     'headers' => ['content-type' => 'application/json'],
#   ]);
# });

# /pages/api/revalidate.ts
# export default async function (req, res) {
#   if (req.body.secret !== process.env.REVALIDATE_SECRET) return res.status(401).end();
#   await res.revalidate('/posts/' + req.body.slug);
#   return res.json({ revalidated: true });
# }

# 6) Forms — Gravity Forms / Contact Form 7 still POST to wp-admin/admin-ajax.php
#   Headless implication: your front end POSTS to that endpoint, or to a tiny
#   server-side proxy that you write.

# 7) Block-aware rendering
#   The REST API returns post_content as HTML — fast path: dangerouslySetInnerHTML.
#   Block-aware: switch to WPGraphQL + WPGraphQL Content Blocks, then render
#   each block as a typed React component.

# 8) Architecture cheat sheet
#   - WP at admin.example.com (private), nginx + cache + WAF in front
#   - Front end at example.com on a CDN (Cloudflare/Vercel/Netlify)
#   - Webhooks from WP -> revalidate on the front
#   - One single source of truth for auth (do you actually need WP logins?)
#   - Treat WP as a stateful service with backups, not a CMS-and-server combo

# 9) When headless is the WRONG call
#   - Site that lives off shortcodes and page builders (Elementor / Divi)
#   - Tiny team without a JS front-end skill set
#   - Site whose value is the WP plugin ecosystem (WooCommerce hard to headless)
#   In those cases, classic WP + caching is usually faster to build and maintain.

Why it matters

Headless WP is the right move when the editorial team genuinely owns the content and the front end is a separate product. It is the wrong move when the value of WP IS the integrated theme + plugin experience — you spend the year rebuilding what WP gave you for free. Be honest about which one you are signing up for.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Use WP as a content API (REST or WPGraphQL); render with Next.js / Astro / Gatsby.
Try it Yourself »

Discussion

Loading…