Skip To Main Content

Add pagination to your Faust.js site

This guide covers how to set up Pagination in your Faust.js site with Apollo and WPGraphQL.

Setup

To get started, create a folder in the root of your Faust.js project called plugins. In this plugins folder, create a file called RelayStylePagination.js and insert this content:

// RelayStylePagination.js

import { relayStylePagination } from "@apollo/client/utilities";

export class RelayStylePaginationPlugin {
  apply(hooks) {
    const { addFilter } = hooks;

    addFilter("apolloClientInMemoryCacheOptions", "faust", (options) => {
      return {
        ...options,
        typePolicies: {
          ...options.typePolicies,
          RootQuery: {
            ...options.typePolicies.RootQuery,
            fields: {
              posts: relayStylePagination(),
            },
          },
          ContentType: {
            fields: {
              contentNodes: relayStylePagination(),
            },
          },
        },
      };
    });
  }
}
Code language: JavaScript (javascript)

The Apollo client can implement relay-style pagination with the relay spec using merge and read functions, which means all the details of connections, edges and pageInfo can be abstracted away, into a single, reusable helper function. WPGraphQL follows the relay spec as well.
We are importing the relayStylePagination function from Apollo and then a class component is created which is the basic syntax of the Faust plugin.

Next, we have an apply method with the hooks parameter which is an object that gives you a function called addFilter. The addFilter function allows us to modify the Apollo Client’s InMemoryCacheOptions.

The addFilter hook is taken and calls the memory cache function options. The options are coming from the Apollo Client Cache configuration. These options allow for configuring the cache for pagination. The faust namespace follows that.

Register the Plugin for Pagination

NOTE:
experimentalPlugins is being deprecated and replaced with plugins in the faust.config.js file. Please update your configuration accordingly.

Import and register your plugin for pagination in faust.config.js by adding it to the plugins array:

import { setConfig } from "@faustwp/core";
import templates from "./wp-templates";
import possibleTypes from "./possibleTypes.json";
import { RelayStylePaginationPlugin } from "./plugins/RelayStylePagination";

/**
 * @type {import('@faustwp/core').FaustConfig}
 **/
export default setConfig({
  templates,
  plugins: [new RelayStylePagination()],
  possibleTypes,
});
Code language: JavaScript (javascript)

Example WPGraphQL Pagination Query

This is an example of a query with the fields for pagination being hasNextPage and endCursor:

const GET_POSTS = gql`
  query getPosts($first: Int!, $after: String) {
    posts(first: $first, after: $after) {
      pageInfo {
        hasNextPage
        endCursor
      }
      edges {
        node {
          id
          databaseId
          title
          slug
        }
      }
    }
  }
`;
Code language: PHP (php)

How to query for your paginated data

Now that you have your query with paginantion setup, Apollo provides a fetchMore helper function along with the useQuery hook to assist with fetching paginated queries. This enables you to execute the same query with different values for varibles like the current cursor and the batch size number of posts you want to grab.

Go to the components directory of your Faust project and create a file. For this guide, let’s call it LoadMorePost.js, and insert this content:

import { useQuery, gql } from "@apollo/client";
import Link from "next/link";

const GET_POSTS = gql`
  query getPosts($first: Int!, $after: String) {
    posts(first: $first, after: $after) {
      pageInfo {
        hasNextPage
        endCursor
      }
      edges {
        node {
          id
          databaseId
          title
          slug
        }
      }
    }
  }
`;

const BATCH_SIZE = 5;

export default function LoadMorePost() {
  const { data, loading, error, fetchMore } = useQuery(GET_POSTS, {
    variables: { first: BATCH_SIZE, after: null },
    
  });

  console.log(data);

  if (error) {
    return <p>Sorry, an error happened. Reload Please</p>;
  }

  if (!data && loading) {
    return <p>Loading...</p>;
  }

  if (!data?.posts.edges.length) {
    return <p>no posts have been published</p>;
  }

  const posts = data.posts.edges.map((edge) => edge.node);
  const haveMorePosts = Boolean(data?.posts?.pageInfo?.hasNextPage);

  return (
    <>
      <ul style={{ padding: "0" }}>
        {posts.map((post) => {
          const { databaseId, title, slug } = post;
          return (
            <li
              key={databaseId}
              style={{
                border: "2px solid #ededed",
                borderRadius: "10px",
                padding: "2rem",
                listStyle: "none",
                marginBottom: "1rem",
              }}
            >
              <Link href={`${slug}`}>{title}</Link>
            </li>
          );
        })}
      </ul>
      {haveMorePosts ? (
        <form
          method="post"
          onSubmit={(event) => {
            event.preventDefault();
            fetchMore({ variables: { after: data.posts.pageInfo.endCursor } });
          }}
        >
          <button type="submit" disabled={loading}>
            {loading ? "Loading..." : "Load more"}
          </button>
        </form>
      ) : (
        <p>✅ All posts loaded.</p>
      )}
    </>
  );
}

Code language: JavaScript (javascript)

Once gql and useQuery are imported at the top of the file coming from Apollo, That allows you to use those helpers in the file. We called our query GET_POSTS and we are passing that in with the useQuery hook.

The variables I have set are batch size which are defined to be 5 and after null which tells the query to start from the beginning of the batch. This function gets fired off each time a use clicks the load more button.

The onSubmit handler in this guide example calls the fetchMore function in Apollo and passes that variable called after that grabs the current end cursor whcih is the unique ID that represents the last post in the data set to grab the next 5 after that end cursor.

Lastly, do not forget to run npm run generate since the schema was updated with WPGraphQL and Pagination. You should now be able to query for cursor based paginated content in your Faust.js site.

Once this is all done, to make sure it is working, go to the pages directory in the root of the Faust project, and create a file. Let’s call it pagination.js. Insert this content:

import Head from "next/head";

import LoadMorePost from "../components/LoadMorePost";

export default function LoadMore() {
  return (
    <>
      <Head>
        <title>Load More</title>
      </Head>

      <main>
        <h1>Load More Example</h1>
        <LoadMorePost />
      </main>
    </>
  );
}
Code language: JavaScript (javascript)

This is the component we are using in this page file to render our paginated post. Once this is all done, visit http://localhost:3000/pagination after running your dev server and you should see your paginated post!

The pagination displays upon loading the page on an example site's pagination endpoint.

If you need an in depth start to finish article with an example, please visit the developer relations article on working with Apollo in Faust.js.