Render WordPress pages block by block in Next.js

Fetch prepared WordPress page JSON with a blocks field, map every block to a frontend component, and keep WordPress as the editing interface.

Render WordPress blocks in Next.js with Smooth CDN

The problem

Headless WordPress often starts with rendered HTML. That works quickly, but it makes frontend control harder when the page is built from Gutenberg blocks.

Without block-level JSON, a Next.js app has less control over layout, components, media handling, and the way page sections are cached.

Rendered HTML treated as one blob

Harder component mapping in Next.js

Less control over media per section

Repeated reads from WordPress REST

Cache rules applied to entire pages only

Solution

Smooth API Accelerator can prepare WordPress REST responses as CDN-served JSON. When your response includes a blocks array, the frontend can render each block with a matching React component instead of treating the whole page as raw HTML.

1

Prepare page JSON with blocks

Expose a WordPress page payload that keeps normal page fields and adds block data. The exact shape can follow your theme or plugin, but the frontend should receive a stable block name, attributes, optional HTML, and nested blocks when needed.

Example page JSON
{
  "id": 42,
  "slug": "about",
  "title": "About us",
  "blocks": [
    {
      "name": "core/heading",
      "attrs": {"level": 1},
      "innerHTML": "About us"
    },
    {
      "name": "core/paragraph",
      "attrs": {},
      "innerHTML": "We build fast publishing workflows."
    },
    {
      "name": "core/image",
      "attrs": {"url": "https://cdn.smoothcdn.com/site/pages/about/team.jpg"}
    }
  ]
}

2

Fetch the prepared page in Next.js

The Next.js route can read from the Smooth CDN JSON URL instead of hitting WordPress on every request. Revalidation stays close to the frontend and WordPress remains the place where editors manage content.

Example Next.js page
import {BlockRenderer} from "@/app/components/BlockRenderer";

async function getPage(slug: string) {
  const response = await fetch(
    `https://cdn.smoothcdn.com/user/my-nextjs-cms/wp-json/pages/${slug}.json`,
    {next: {revalidate: 300}}
  );

  if (!response.ok) {
    return null;
  }

  return response.json();
}

export default async function Page({params}: {params: Promise<{slug: string}>}) {
  const {slug} = await params;
  const page = await getPage(slug);

  if (!page) {
    return null;
  }

  return (
    <main>
      {page.blocks.map((block: any, index: number) => (
        <BlockRenderer key={index} block={block}/>
      ))}
    </main>
  );
}

3

Render every block with a component

Keep a small map between WordPress block names and React components. Unknown blocks can fall back to sanitized HTML or be skipped depending on your content policy.

Example block renderer
const blocks: Record<string, (props: any) => React.ReactNode> = {
  "core/heading": ({block}) => {
    const Tag = `h${block.attrs?.level || 2}` as keyof JSX.IntrinsicElements;
    return <Tag>{block.innerHTML}</Tag>;
  },
  "core/paragraph": ({block}) => <p>{block.innerHTML}</p>,
  "core/image": ({block}) => (
    <img src={block.attrs.url} alt={block.attrs.alt || ""} loading="lazy"/>
  ),
};

export function BlockRenderer({block}: {block: any}) {
  const Component = blocks[block.name];

  if (!Component) {
    return null;
  }

  return <Component block={block}/>;
}

What You get

A headless WordPress flow where editors keep using blocks and developers keep control over React rendering, caching, and asset delivery.

WordPress remains the source of content

Next.js renders block-aware components

Prepared JSON can be served from Smooth CDN

Better control over media and page sections

Keep editing in WordPress. Render with Next.js.

Move repeated WordPress API reads to prepared JSON and render blocks with frontend components.