WordPress REST API pagination example

As I’m re-working on the blog archive page on linguinecode.com. I want to add pagination to the page. Is this possible with with the WordPress REST API?

The answer is yes! WordPress REST API has query parameters that you can pass to get a specific amount of posts per page, and fetch the next or previous set of posts. In this article I will use wpapi node library to show you how easy it is to paginate your results.

But first, if you’re looking to launch a WordPress site for your blog or business, you might want to look into launching your blog with Bluehost for just $3.95/mo (49.43% off). They make it really easy to select an affordable plan, and create or transfer a domain.

Get started with Bluehost.

Disclaimer: The two Bluehost links above are affiliate links which provide a small commission to me at no cost to you. These links track your purchase and credit it to this website. Affiliate links are a primary way that I make money from this blog and Bluehost is the best web hosting option for new bloggers.

Step 1: Install wpapi NPM module

linguinecode.com uses a node module called wpapi.

wpapi is a nice module with a clean, and easy to use API that works well with WordPress 5.0 and later.

You can install via NPM:


npm install --save wpapi

Or download the package locally and load it on your client. https://wp-api.github.io/node-wpapi/wpapi.zip

This module works for both client and server side JavaScript

Step 2: Using wpapi to fetch initial posts


import WPAPI from 'wpapi';

// Create WPAPI instance and add endpoint to /wp-json
const wp = new WPAPI({
  endpoint: 'http://<replace-with-domain>/wp-json',
});

// Fetch 10 posts
const posts = await wp.posts().get();
console.log(posts)

By default WordPress will return your 10 latest posts or whatever has been configured in the WP admin dashboard.

If you want to fetch more than the default amount, then you may do so by using the perPage() utility.


const posts = await wp.posts().perPage(20).get();

Now it’s looking for the 20 most recent posts instead of the default, 10.

If you have 100 articles, and you’re fetching 20 post per page, you should have 5 total pages to fetch.

Let me show you the code that I plan to use to grab the next page of data by using the wpapi library.

Step 3: Fetch the next page

When I use wp.posts().get(), it returns an array of WordPress posts and with additional data such as the total number of posts in general, and the total number of pages.


const posts = await wp.posts().get();

console.log(posts._paging);

Object {total: 93, totalPages: 10, links: Object}
total: 93
totalPages: 10
links: Object

If you’re using Node.js to fetch your posts, you get a little bit more information from the headers and it gets dumped into a property called previous or next.


// Next pagination URL request.
posts._paging.next;

// Previous pagination URL request
posts._paging.previous;

But for me, the totalPages property is enough.

I’m going to create a function called fetchPosts(), and it will accept an argument called pageNumber.


const fetchPosts = async (pageNumber) => {
  const request = wp.posts();

  if (pageNumber) {
    // Page number to fetch
    request.page(pageNumber);
  }

  const posts = await request.get();

  return {
    posts,
    nextPageNumber:
      posts._paging.totalPages > pageNumber ? pageNumber + 1 : null
  };
};

If pageNumber is passed, it will set a value to .page(), to let wpapi what page number it needs to get.

fetchPosts() will return an object with 2 properties:

  • posts – Array of WordPress posts from the request.
  • nextPageNumber – The next page number available.

Since we’re using the REST API, I need to attach this to an event listener. It could be on scroll or a click event.

For simplicity sake, I’m going to stick with a click event on my blog archive page, which is built on React.

Step 4: Add WordPress pagination to React

In my React component, I’m going to create 2 state properties using React.useState().


const [articles, setArticles] = React.useState([]);
const [pageNumber, setPageNumber] = React.useState(1);

I have 2 state properties called articles, and pageNumber.

articles will hold my array of WordPress posts. The initial value will be an empty array.

pageNumber will hold the current page that I’ve recently fetched. The initial value is the number 1, because we need to fetch the first page of data.

The next step is to create a handler function to load the initial WordPress posts or to load more.


const handleClick = async () => {
  const snapshot = await fetchPosts(pageNumber);

  setPageNumber(snapshot.nextPageNumber);
  setArticles([
    // Preserve previous WordPress posts
    ...articles,

    // Add new WordPress posts
    ...snapshot.posts
  ]);
};

I’ve created a function called handleClick(). When this function gets executed it will run fetchPosts().

Once the response from WordPress comes back, I update my state values.


// Update the next page number
setPageNumber(snapshot.nextPageNumber);

// Update our list of posts
setArticles([
  // Preserve previous WordPress posts
  ...articles,

  // Add new WordPress posts
  ...snapshot.posts
]);

It’s time to put this to an end, and connect the logic with with the UI markup.


const App = () => {
  // ...React.useState and handleClick function

  return (
    <>
      <h1>Articles</h1>
      <ul>
        {articles.map((article) => (
          <li key={article.id}>{article.title.rendered}</li>
        ))}
      </ul>
      {pageNumber && (
        <button onClick={handleClick}>
          {pageNumber > 1 ? "Load more" : "Get initial posts"}
        </button>
      )}
    </>
  );
};

Let’s break it down. The first thing I’m doing in the return statement is rendering the list of articles that have been collected.


<ul>
  {articles.map((article) => (
    <li key={article.id}>{article.title.rendered}</li>
  ))}
</ul>

The next element I’m adding, is a button HTML element to attach my handleClick() function on the onClick React event.


{pageNumber && (
  <button onClick={handleClick}>
    {pageNumber > 1 ? "Load more" : "Get initial posts"}
  </button>
)}

I’ve also added some rendering logic to display the button if pageNumber is not a falsy value.

And to change the text of the button after the initial load.

Full source code


import WPAPI from "wpapi";

const wp = new WPAPI({
  endpoint: "https://<replace-with-domain>/wp-json"
});

const fetchPosts = async (pageNumber?: number) => {
  const request = wp.posts();

  if (pageNumber) {
    request.page(pageNumber);
  }

  const posts = await request.get();

  return {
    posts,
    nextPageNumber:
      posts._paging.totalPages > pageNumber ? pageNumber + 1 : null
  };
};

const App = () => {
  const [articles, setArticles] = React.useState([]);
  const [pageNumber, setPageNumber] = React.useState(1);

  const handleClick = async () => {
    const snapshot = await fetchPosts(pageNumber);

    setPageNumber(snapshot.nextPageNumber);
    setArticles([
      // Preserve previous WordPress posts
      ...articles,

      // Add new WordPress posts
      ...snapshot.posts
    ]);
  };

  return (
    <>
      <h1>Articles</h1>
      <ul>
        {articles.map((article) => (
          <li key={article.id}>{article.title.rendered}</li>
        ))}
      </ul>
      {pageNumber && (
        <button onClick={handleClick}>
          {pageNumber > 1 ? "Load more" : "Get initial posts"}
        </button>
      )}
    </>
  );
};

Oh wow, you’ve made it this far! If you enjoyed this article perhaps like or retweet the thread on Twitter:

I like to tweet about JavaScript and post helpful code snippets. Follow me there if you would like some too!