In this tutorial, we'll setup a WordPress graphql API with Advanced Custom Fields, and connect it to a Next.js frontend.
The final code can be found here - https://github.com/albertkimdev/nextjs-wpgraphql-acf
Prerequisites:
- Intermediate WordPress knowledge.
- Intermediate Next.js & React.js knowledge.
Technologies involved:
WordPress - the backend content management system where we get our data. Its use is similar to an API. We make requests from Next.js to get data from WordPress so we can build a dynamic frontend from content that is created and updated in WordPress.
Next.js - the frontend framework to build our website that the end user sees. We'll build React components from data we fetch from the WordPress backend. We'll use Next.js methods to fetch the data and then generate static pages to take advantage of those benefits while also enjoying a modern developer experience.
WPGraphQL - a WordPress plugin that creates a GraphQL API on top of WordPress so you can query data from it like any other GraphQL API.
Advanced Custom Fields - a WordPress plugin that allows you to build data structures for custom content.
WPGraphQL for Advanced Custom Fields - a WordPress plugin that exposes Advanced Custom Fields to the WPGraphQL API.
Apollo Client - a state management library for React that allows you to make graphql requests. We'll use this to make requests to the WPGraphQL API.
The steps involved:
- Setup your WordPress backend by installing WPGraphql, Advanced Custom Fields, and Advanced Custom Fields for WPGraphql.
- Create a custom field group using ACF.
- Query WordPress data using the GraphiQL IDE.
- Setup your Next.js frontend.
- Add Apollo Client to your frontend and query data from WPGraphQL.
- Generate static pages with getStaticProps.
- Build the frontend using WordPress data.
Setup WordPress by installing the plugins.
I won't cover how to setup WordPress, there are plenty of tutorials for that.
I'm starting with a fresh version 5.9 WordPress install. I'm using MAMP and my local computer for this but any environment will work.

We want to install the three required plugins: WPGraphql, ACF, and WPGraphql for ACF.
Search for and install those plugins.


For WPGraphql for ACF, you have to go to their Github page and download the zip file and manually upload the plugin.


Once the plugins are installed and activated, you should see some changes in your admin dashboard.

If you see the GraphiQL IDE button, Custom Fields sidebar section, and GraphQL sidebar section, you've successfully installed all the plugins!
Create custom fields using ACF.
Click the Custom Fields menu and press Add New


This page is where you create a new field group.
This may look like a lot, but you can leave most of the options as defaults.
A field group is a custom "Advanced Custom Type" and it's basically a data structure using field types that work with WordPress. Some examples of fields are:

For more on field types, check out their docs.
You're basically creating a JSON data structure where the data can be edited in a WordPress dashboard.
An example GraphQL query for a custom ACF looks like:

And the response in your web app would look like this:

This is an example of the data you'll receive in your Next.js app.
The custom ACF is called homepagehero
and it has 3 fields.
image
which is a type Image
.
subtitle
which is a type Text
.
title
which is a type Text
.
If you were to create a JavaScript object representation, it could look like:
const homepagehero = {
title: "Mira Nakashima",
image: {
sourceUrl: "http://localhost:8888/wordpress2/wp-content/uploads/2022/03/home.promo_.01.jpg"
},
subtitle: "Nakashima furniture is meant to be..."
}
Except you're doing it the WordPress and ACF way so anyone can go to the WordPress admin page and edit the values.
Like images, text, dates, videos etc... rather than strings, floats, and timestamps.
For developers, this is still good because we can CRUD the data using JSON, and it's also good for non-developers because they can update the values via the WordPress interface.
You may also notice that the object is under a page object.
This is because ACFs are attached to WordPress properties, like a page or a post.
So you don't query for an ACF, you create an ACF, attach it to a WordPress post or page, and then query for that page and its attached ACF to get the data.
Now let's create a simple ACF.

Here, we're creating a Field Group called "Home page hero."
This ACF will contain data about the home page hero, so the title, subtitle, and hero image.

The image above shows how to create an ACF. You just enter the form data where it's relevant.
You only need a few options: label
, name
, type
, and show in GraphQL
.
For the image, select these options:

Once you're done, your Field Group should look like:

Also notice in Location
, the rule is changed to expose this Field Group data specifically to Page -> Home
that I created earlier.
The last thing to do is scroll to the bottom and press Show in GraphQL
.

This allows you to query the ACF data using WPGraphQL with the help of the plugin installed earlier.
Now publish the Field Group and go to the Home Page to enter your ACF data.

The ACF form is in the bottom of the page. The fields we created, title
, subtitle
, and image
are editable within the Home page
edit screen.
The admin can set the Field Group and Fields and attach it to a specific or type of Page/Post/User/other WordPress property, so anyone can easily update the data.
Enter some data and update the page, then you're done this section.
Query WordPress data using GraphiQL.
Go to the GraphiQL interface, it should look like this:

I won't get into GraphQL right now, there are many resources out there to learn about GraphQL.
The left side shows all the data fields you can search for. These fields are exposed automatically thanks to the WPGraphQL plugin. All you need to do is click the fields you want and the interface will create the query for us.
Since we want the home page with the ACF data, we can click page
and check the fields we want.

But first we need the id of the Home page because we only want the Home page data.
But to get the id, we need to search for all pages and query the id and title to see what we're working with.

Now I know the id for Home page and can build the query I need.

Now we have the query we need for our index page thanks to this interface. We can just copy and paste this query into the Next.js app.
Now it's time to start the Next.js app.
Setup your Next.js frontend.
The web app won't be fancy, just a simple Next.js statically generated website.
Instead of going over how to start a Next.js app, I'll be cloning a starter repo I created.
It sets you up with a Next.js app with Styled Components.
If you have a basic Next.js app working, then you're ready to move on.
Add Apollo Client to your frontend.
Your Next.js app should have a folder structure like below:
pages
_app.js
_document.js
index.js
Add the two packages you need to make graphql requests.
yarn add @apollo/client graphql
Create a folder called data
and a file called client.js
or something else.
Now my folder structure looks like:
data
client.js
pages
_app.js
_document.js
index.js
In client.js
I'm creating a simple Apollo client instance that sends its requests to my local WPGraphQL endpoint.
Here's what it looks like:
import { ApolloClient, InMemoryCache } from "@apollo/client";
export const client = new ApolloClient({
// My WordPress GraphQL endpoint.
uri: "http://localhost:8888/wordpress2/graphql",
// Apollo Cacheing
cache: new InMemoryCache(),
});
I have a WordPress server on my localhost and the graphql
endpoint was created by the WPGraphQL plugin, I didn't have to do anything.
Now I can use this client object in my Next app to make graphql requests to WordPress.
Generate static pages with getStaticProps.
getStaticProps is the method that turns your React app into a pre-built, statically generated website.
You use it in your page level components. If I add it to index.js
it would look like this:
const Index = (props) => {
return (
<Wrapper>
<p>Hello world</p>
</Wrapper>
);
};
export async function getStaticProps(context) {
return {
props: {}, // will be passed to the page component as props
}
}
By adding that method to our component file, it tells the Next.js build process the following information:
- We want to generate static pages for this component.
- We'll get data and return it as props to the component.
- Next.js will create static pages with the prefetched data passed as props.
For detailed information, check out the docs here.
All you need to know is - this method is where we pass WordPress data to the component before the HTML is built.
This is good for SEO and performance. The pages are built with the relevant data that is shown to the search engine crawlers and not something like Loading...
.
For performance, since you're sending the HTML files pre built from the server, the client doesn't have to make a network request and then load the data, it just shows all the data on the initial load.
Now we have everything we need to fetch data in our Next.js app from the WordPress API:
- An Apollo Client instance.
- A WordPress GraphQL API.
- GraphQL Query.
- getStaticProps method.
Here's what it looks like to query our WordPress API using client
:
export async function getStaticProps() {
try {
const { data, errors } = await client.query({
query: gql`
query MyQuery {
page(id: "cG9zdDo4") {
homepagehero {
title
subtitle
image {
sourceUrl
}
}
}
}
`,
});
return {
props: {
page: data.page,
},
};
} catch (err) {
console.log(err);
return {
props: {},
};
}
}
In this code I'm:
- Getting the
data
anderror
from our graphql query. - Creating the query by importing
client
and calling thequery
method on it. - Adding a query parameter which is the graphql query generated from the GraphiQL IDE in the WordPress admin, wrapped in a
gql
template for processing. - Returning the data as props or returning an empty object if there's an error.
To log the props in my component, the code is:
const Index = (props) => {
console.log(props);
return (
<Wrapper>
<p>Hello world</p>
</Wrapper>
);
};
And the output is:

Build the frontend using WordPress data.
The ACF I created was for a hero component with a title
, subtitle
, and image
.
To use the data in the component, I have this code:
const Index = (props) => {
const {
page: { homepagehero },
} = props;
return (
<Wrapper>
<p>{homepagehero.title}</p>
<p>{homepagehero.subtitle}</p>
<img src={homepagehero.image.sourceUrl} alt="" />
</Wrapper>
);
};
And my index.js
looks like:

I added some simple styling to the Wrapper
:
const Wrapper = styled.div`
padding: 2rem;
max-width: 800px;
margin: 0 auto;
text-align: center;
p {
margin: 1rem 0;
font-size: 2rem;
font-weight: bold;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
}
img {
max-height: 500px;
width: auto;
}
`;
And boom. Now you have a statically generated Next.js app with data from a WordPress GraphQL API with a custom Advanced Custom Field!