Headless CMS: WordPress API v2 To Next.js

Grab The Ultimate Guide To Headless Wordpess and Next.js

Save time with your Jamstack Headless WordPress and Next.js integration. The guide I wish I had when first starting out Here

About a year ago I created a post about connecting a wordpress installation to React.js.

For some reason that post has brought 1000’s of eyeballs to my site in terms of traffic…I guess a lot of people are trying to do the same thing.

I’ve been meaning to convert my site over to Next.js and take advantage of GetStaticPaths/Props for months but life just gets in the way.

This week I finally took that off my ToDo list. I’ll try and keep this short and sweet.

Past Problems

I was fetching my wordpress posts everytime someone loaded my React SPA and saving that to a context provider, the site is small so not a big deal of api calls…..but

My wordpress installation has an SSL cert set up, but this thing expires every 2/3 months.

Every time that cert expired, my fetch attempt would fail and the posts wouldn’t show up.

Statically generating these posts and pages would save me a tonne of worry and time, so let’s get into how it’s done.

Setting up WordPress

I’ve already covered this but here’s what we need;

You may be able to skip the next three if you’re just fetching regular posts, but I’m working with custom post types, so i can add my own features to the API.

We’re going to dynamically fetch all of the posts that live in a specific route of your site and also grab more than the default which I think was 25 at some point in time.

URL: Non custom post type:
Here’s a list of all the default end points for WP API, you’ll probably need /posts or /pages.

URL: Custom post type
Update the url below to match your website and after the v2 you’ll need the custom post type name that you’ve chosen.

Then per page we want at least 100, which I think is the max without pagination

Setting up Next.js

For my site, I wanted, so I started with creating a ‘blog’ folder in my next.js Pages folder, then added a dynamic js file with the square brackets.

Pages -> blog -> [slug].js

The name in these brackets needs to match params object you’re returning in getStaticPaths which you’ll see below.

export async function getStaticProps({ params }) {
  const post = await fetch(
  ).then((response) => response.json());
  return {
    props: { post: post },
    revalidate: 1,
export async function getStaticPaths() {
  const results = await fetch(
  ).then((response) => response.json());
  const paths = => {
    return {
      params: { slug: post.slug },
  return { paths, fallback: "blocking" };

Paths function is going to fetch from my custom post type called react_blog and grab, at most, 100 posts from there.

Convert all of that into JSON and save it to results.

We’re then mapping over results and creating out params objects. These are then passed to Static Props where we do almost the exact same thing, but this time with a single url.

I fetch the content from that URL and send an object called props up to the component.

  • Props gets passed to this file’s component as an array with single object item, so i needed to get props[0]. This contains my entire wordpress post, title, slug, featured image etc.
  • Without GetStaticProps, GetStaticPaths does nothing, so include them both.
  • Fetch is polyfilled with next.js so you don’t need to import or install it.
  • You can view the results both of these functions in dev mode, but they are run when the site is being deployed and become really snappy on the live site.

Rendering HTML Content

I haven’t found a nice way to do this, other than using dangerouslySetInnerHTML which just sounds bad 🙂

const Blog = ({ post }) => {
  // post comes in as array with single object
  const content = post[0];
  return (
	  <div dangerouslySetInnerHTML={{ __html: content.content.rendered }}></div>
export default Blog;
Contact Me