Custom Content in Headless WordPress Using Advanced Custom Fields and WPGraphQL

Grace Erixon Avatar

·

Creating custom content types is a prevalent part of many modern, content-rich headless WordPress sites. By defining custom content types, developers can structure their data in a way that best suits their specific requirements, ensuring consistency and efficiency in content management. On a headless WordPress site, this can be done easily using Advanced Custom Fields to design the content structure and WPGraphQL to query data.

Introducing Advanced Custom Fields (ACF)

While WordPress provides built-in support for standard content types such as posts and pages, Advanced Custom Fields (ACF) allows users to define custom content types and fields for WordPress websites. This plugin enables developers to visually create custom fields for posts, pages, custom post types, and taxonomy terms. These custom fields can store a wide range of data types, including text, images, files, and more, making it a popular tool for tailoring WordPress content to specific needs.

Begin by defining custom post types and fields using the ACF interface within the WordPress admin dashboard. You can create any type of custom post type and add a few fields to it. Then, add some example data in the WordPress admin.

Setting Up GraphQL in WordPress

To expose WordPress data via GraphQL, we’ll utilize the WPGraphQL plugin. WPGraphQL provides a schema and endpoints to query WordPress data using GraphQL syntax.

WPGraphQL serves as the bridge between WordPress and modern frontend frameworks by exposing WordPress data via a GraphQL API. With WPGraphQL, developers can query WordPress content with precision, retrieving only the data they need for a particular request.

We will need to install two plugins to access ACF data using GraphQL queries: the WPGraphQL plugin and the WPGraphQL for ACF plugin.

Accessing ACF Data with GraphQL Queries

Settings to Make Data Accessible

Notably, you will need to do two things to proceed with accessing ACF data. First, check the Enable Public Introspection box in GraphQL’s settings. Then, on each created Post Type’s page in ACF, click the slider for Advanced Configuration. Select the furthest right tab titled GraphQL and enable the Show in GraphQL slider.

GraphQL Queries

Let’s dive into using GraphQL queries to retrieve ACF data from WordPress.

For example, here is a query that fetches a list of products along with their ACF fields:

{
  products {
    edges {
      node {
        id
        title
        acfFields {
          productName
          productDescription
          productImage {
            sourceUrl
            altText
          }
        }
      }
    }
  }
}

Let’s break down what each part of the query is doing:

  1. products: This is the root field of the query, indicating that we want to retrieve data related to products.
  2. edges: This is a connection type used in WPGraphQL to represent a list of items with pagination information. It’s commonly used when querying data from a list or collection.
  3. node: Within each edge, there is a node representing a single product item. This is where the actual data for each product resides.
  4. id: This field requests the unique identifier (ID) of each product. IDs are typically used to uniquely identify each item in a collection.
  5. title: This field requests the title of each product. Titles are common pieces of information associated with content items in WordPress.
  6. acfFields: This field requests custom fields associated with each product. In this case, it’s specifically asking for fields created using the Advanced Custom Fields (ACF) plugin.
  7. productName, productDescription, productImage: These are custom fields defined in ACF for products. The query requests data for each of these fields, including the product name, description, and image.
  8. sourceUrl, altText: These are sub-fields of the productImage field, requesting the source URL (i.e., the URL of the image) and alt text (i.e., the alternative text for the image) respectively.

For your own queries, you can replace the values such as productName, productDescription, and productImage with your own ACF field names.

Integrating ACF Data in a React App

Once we have our GraphQL query, we can integrate it into a React web application. This React component fetches the product data using the previous GraphQL query and displays the list of products.

import React from 'react';
import { useQuery, gql } from '@apollo/client';

const GET_PRODUCTS = gql`
{
  products {
    edges {
      node {
        id
        title
        acfFields {
          productName
          productDescription
          productImage {
            sourceUrl
            altText
          }
        }
      }
    }
  }
}
`;

const ProductList = () => {
  const { loading, error, data } = useQuery(GET_PRODUCTS);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return (
    <div>
    {data.products.edges.map(({ node }) => (
      <div key={node.id}>
        <h2>{node.title}</h2>
        <p>{node.acfFields.productName}</p>
        <p>{node.acfFields.productDescription}</p>
        <img src={node.acfFields.productImage.sourceUrl} alt={node.acfFields.productImage.altText} />
      </div>
    ))}
    </div>
  );
};

export default ProductList;
Code language: JavaScript (javascript)

Let’s take a look at how this React component works.

GraphQL Query Definition

The GET_PRODUCTS constant defines a GraphQL query using the gql tag template literal. This query requests data for products, including their IDs, titles, and custom fields (productName, productDescription, and productImage), from the headless WordPress backend.

ProductList Component

Inside the component, the useQuery hook is used to execute the GraphQL query defined in GET_PRODUCTS. It returns an object containing loading, error, and data properties. If the query is still loading (loading is true), the component renders a loading message (<p>Loading...</p>). If there is an error during the query execution (error is not null), the component renders an error message (<p>Error :(</p>). If the query is successful and there are no errors, the component renders a list of products.

The list of products is rendered using the map function on data.products.edges, which represents an array of product nodes. For each product node, a <div> element is rendered with the product’s title, productName, productDescription, and productImage (including source URL and alt text) displayed.

Conclusion

Many headless WordPress sites require the ability to create and query for custom content types. Leveraging Advanced Custom Fields (ACF) for content customization and WPGraphQL for seamless data retrieval offers a powerful solution for building flexible and customizable websites.