Headless WordPress with NextJs and wp-env

Dec 07, 2023
 — by 
Kris Kratz
 in 

After doing this, I found that it’s simply adds too much overhead to creating a site, so I recommend using the WordPress Full Site Editor instead.

But if you’re dead set on getting this running, keep reading to find out how to set it up in a few minutes.

I discussed the basics about how to get wp-env set up in a previous post. Now that we have WordPress set up and managing our content, it’s time to connect it to the most advanced front end for fast development of our awesome website.

NextJs is built using ReactJs. In fact, over the past several years WordPress has integrated more ReactJs into the its core practically each release. NextJs is a fantastic system to create rich interactive front end websites. It allows you to leverage the thousands of ready to use ReactJs libraries. But more than that it is extremely fast. Browsing a website built in NextJs feels like using an app more than a traditional WordPress website.

You’ll need to install Node and NPM to run this NextJs website. I recommend using NVM because it greatly simplifies managing Node installations. It allows you to switch between versions very quickly. This was very important when I was creating this install because I ran into a tricky bug. It turns out that NextJs plays better with LTS (Long Term Support) versions of node. I had Node version 19.17 installed, and I couldn’t get the darn application to launch. I kept getting a TypeScript error with “URL.canParse(“… and it’s a bug with non-lts versions of Node. Bottom line, work with the LTS versions. I used NVM to upgrade to Node version 20.10.0.

Once that’s going you can just follow a few simple steps, hahaha who am I kidding!? These steps are simple now that I figured it out, but heck it’s not easy doing the figuring.

1. Install WordPress

You already know from my previous post I LOVE wp-env, but for some reason developing a NextJs headless application is much faster with a live site.

Wp-env is the easiest way to get a WordPress development site up fast, but you’ll notice that it is laggy when interacting with NextJs in this scenario. If you still want to do it. Just follow my instructions in my other article for this step.

Please note, that I like to use my hosts file to create a local domain for my test sites.

Change the .wp-env.json file to look like this:

{
    "plugins": [ 
        "https://downloads.wordpress.org/plugin/wp-graphql.zip"
    ],
    "port": 8888,
    "testsPort": 8889,
    "config": {
        "WP_TESTS_DOMAIN": "example.local",
        "WP_SITEURL": "http://example.local",
        "WP_HOME": "http://example.local"
    }
}

2. Permalinks Matter

To make it work with NextJs headless, you need to change the permalink structure. You can do it from the WordPress Admin -> Settings -> Permalink Structure, or just run this command in your terminal app. Seems like there is a bug that doesn’t allow this to run correctly, so you’ll have to manually do it through admin.

$ wp-env run cli "wp rewrite structure /%postname%/"

Publish a few articles with featured images, excerpts, and authors, so it populates the new site for you.

3. Download and install NextJs and the example headless site

$ npx create-next-app --example cms-wordpress cms-wordpress-app
$ cd cms-wordpress-app
$ npm install
$ cp .env.local.template .env.local

Edit the first line of your new .env.local file so that it looks like this:

WORDPRESS_API_URL=http://example.local:8888/graphql

That’s how you tell NextJs to request information from WordPress.

If you try to run it now, NextJs is going to complain that the image’s “remotePatterns” are not set for the domain. To fix this problem, you need to edit next.config.js.

Just change the following

remotePatterns: [
    {
        protocol: protocol.slice(0, -1),
        hostname,
        port,
        pathname: `${pathname}/**`,
    },
],

To this:

remotePatterns: [
    {
        protocol: protocol.slice(0, -1),
        hostname: "2.gravatar.com",
        port: "",
        pathname: `/avatar/**`,
    },
    {
        protocol: protocol.slice(0, -1),
        hostname: "localhost",
        port: "8888",
        pathname: `/wp-content/**`,
    }
],

4. Ready for Launch!

Now that everything is set, you’re ready to launch the new app.

$ npm run dev

Just point your browser to https://example.local:3000, and you should have everything up and running!