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 a Node.js server. 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:

  1. Setup your WordPress backend by installing WPGraphql, Advanced Custom Fields, and Advanced Custom Fields for WPGraphql.
  2. Create a custom field group using ACF.
  3. Query WordPress data using the GraphiQL IDE.
  4. Setup your Next.js frontend.
  5. Add Apollo Client to your frontend and query data from WPGraphQL.
  6. Generate static pages with getStaticProps.
  7. Build the frontend using WordPress data.

Setup WordPress by installing the plugins.

We won't cover how to setup WordPress, there are plenty of tutorials for that.

I'm starting with a fresh version 5.8 WordPress install. I'm using Xampp and my local computer for this but any environment will work.

Fresh WordPress install.

We want to install our 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, 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 may look like a lot, but you can leave most of the options as defaults.

This page is where you create a new field group.

A field group is a custom "Advanced Custom Type" and it's basically creating 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.

If you query an ACF field via an API call, the response will look like this:

This is an example of the data you'll receive in your Next.js app.

There are two Field Groups called firstQuoteSelection and headerQuoteAndImages.

firstQuoteSelection has three key value pairs: author -> text, image -> image, and quote -> text.

headerQuoteAndImages has: image1 -> image, image2 -> image, image3 -> image, and quote -> text.

In the GraphQL query, I'm only querying for altText and srcSet for the images but there are more fields you can get.

If you were to create a JavaScript object in this way, it could look like:

const firstQuoteSelection = {
  author: "Mira Nakashima",
  image: {
    altText: "",   
    srcSet: "..."
  },
  quote: "Mira Nakashima is a ..."
}

Except you're doing it the WordPress and ACF way so anyone can go in the WordPress admin page and edit the values for fields that are relevant to websites.

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.

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

Also notice in Location, the rule is changed to expose this Field Group data specifically to Page -> Home page 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 Hero image are editable within the Home page edit screen.

The admin can set the Field Group and Fields, 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 we first need the id of the Home page because we only want the Home page data.

But to get the id, we need to just 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.

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 similar folder structure to below:

pages
  _app.js
  _document.js
  index.js

Add the two packages you need to make graphql requests.

npm install @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/tutorial/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:

  1. We want to generate static pages for this component.
  2. We'll get data and return it as props to the component.
  3. 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.

Now we have everything we need to fetch data in our Next.js app from the WordPress API:

  1. An Apollo Client instance.
  2. A WordPress GraphQL API.
  3. GraphQL Query.
  4. 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: "cG9zdDo2") {
            homePageHero {
              title
              subtitle
              heroImage {
                altText
                srcSet
              }
            }
          }
        }
      `,
    });
    return {
      props: {
        page: data.page,
      },
    };
  } catch (err) {
    console.log(err);
    return {
      props: {},
    };
  }
}

In this code I'm:

  1. Getting the data and error from our graphql query.
  2. Creating the query by importing client and calling the query method on it.
  3. 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.
  4. 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:

The ACF form inputs in my WordPress admin dashboard:

And if I View page source I'll see the content is available:

If this website was client side rendered, you wouldn't see that data in the page source.

The data being available is important for performance and SEO reasons. Mostly SEO.

Build the frontend using WordPress data.

The ACF I created was for a header with a title, subtitle, and heroImage.

To use the data in the component, I have this code:

const Index = (props) => {
  const {
    page: { homePageHero },
  } = props;

  let srcMap = {};

  homePageHero.heroImage.srcSet.split(",").forEach((src) => {
    let srcSplit = src.split(" ");
    if (srcSplit.length === 3) {
      srcMap[srcSplit[2]] = srcSplit[1];
    } else {
      srcMap[srcSplit[1]] = srcSplit[0];
    }
  });

  return (
    <Wrapper>
      <p>{homePageHero.title}</p>
      <p>{homePageHero.subtitle}</p>
      <img src={srcMap[`768w`]} alt="" />
    </Wrapper>
  );
};

The srcMap is some code to turn the srcSet string into an easily usable object.

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;
  }
`;

And boom. Now you have a statically generated Next.js app with data from a WordPress GraphQL API with a custom Advanced Custom Field!