Pagination In AngularJS WordPress Theme

In this tutorial, I’ll be showing you how to add a simple pagination to your AngularJS WordPress theme. We’ll create a custom directive with AngularJS which works like the WordPress built-in function posts_nav_link(), that will display previous and next posts links in your index and category pages.

Before we get started, let’s take a look at the posts_nav_link() function first. By its description from the WordPress Codex, posts_nav_link()displays links for next and previous pages. Useful for providing “paged” navigation of index, category and archive pages.’  So after we add our custom directive “postsNavLink” to our AngularJS app, we expect to see a paged navigation in our index and category pages:

Pagination in your AngularJS WordPress theme

You might notice that posts_nav_link() takes three parameters:

  • $sep: Text displayed between the links.
  • $prelabel: Link text for the previous page.
  • $nxtlabel: Link text for the next page.

Since we’re inspired by posts_nav_link() to build postsNavLink directive, we’d like to take the same parameters as attributes. We can use our custom directive as simple as:

<posts-nav-link></posts-nav-link>

Or we can pass values into the attributes to make some changes:

<posts-nav-link sep="//" prev-label="&laquo; Previous Page" next-label="Next Page &raquo;"></posts-nav-link>

Looks cool, right? If you’re ready, let’s dive into the code!

O. Getting Started

Please get the theme files from the GitHub repo. It would be easier to follow the steps in this tutorial with this ready made theme. After downloading the theme, you must change the “base hrefat line 4 in index.php.

For example, if you host your site at the root of the domain, you’ll need to change it to “/”; if you host your site in the “jsonapi” directory of the domain, which your website URL will be like “http://localhost/jsonapi”, you’ll need to set the base href to “/jsonapi/”.

And don’t forget to install and activate the WP REST API plugin.

To make the demonstration simple, I’ll set the blog to show only one post per page at the WordPress Administration “Reading Settings” Screen.

1. Setting up the routes

First step we’ll do is to set up the routes to our “paged” pages. At line 20 – 27, we add two new routes for the paged category and index page. As you can see, we set the route paths consist with the default WordPress URL structure. For example, the URL of page 2 for index page would be [site-url]/page/2/, and the URL of page 3 for uncategorized posts would be [site-url]/category/uncategorized/page/3/.

If you haven’t do so (I’ve mentioned the permalink settings in my previous tutorial), you need to set the permalink structure in WordPress as the following screenshot to get the best SEO performance. That when search engines crawl your website, they won’t run into a bunch of 404 pages or pages without correct content.

Change category base at Permalink Settings

2. Updating the Main controller

When we’re trying to add paged navigation to our AngularJS app, the most importance thing is to know what are the values of “current page” and “total pages“. Luckily WP REST API has passed them to us in headers.

We’ll need to add the headers parameter to our function (at line 9) to access it. At line 14 and 15, we also add two new properties: currentPage and totalPages to the $scope object. We set currentPage to 1 because we’re at homepage, and we get totalPages from headers which is a function passed by WP REST API, so we get the value with syntax like headers("X-WP-TotalPages").

We’ll use the values from these two properties to help our postsNavLink directive to show or hide the pagination links.

3. Creating the postsNavLink directive to display the previous / next posts links

If you’re not so familiar with custom directives in AngularJS, I’ve written a tutorial for you: Using AngularJS Custom Directive In A WordPress Theme. I’d like to analogize the custom directives in AngularJS to the template tags in WordPress, that we wrap some reusable code snippets into a function, and call it from our theme when we need it.

In this case, we need a function to display the previous / next posts links in our AngularJS app. Basically it would be exactly like an AngularJS version of posts_nav_link(). Let’s see how to create the postsNavLink directive:

  • Line 7: we’ll create a new template file for this custom directive. I named it posts-nav-link.html but you can choose any file name you like.
  • Line 9: we’ll get the current page number from the route parameter “page“.
  • Line 10: the linkPrefix can help us to set the different route paths for index and category page.
  • Line 12-18: we create a new property for $scope object called postsNavLink, which is an object to contain all information our custom directive will use.

Let’s take a look at the controller in our postsNavLink directive, we just pass a new parameter $element into it. The $element object represents the directive itself, and it’s a jqLite element. Since jqLite is a lite version of jQuery, we can manipulate it with some of the jQuery methods.

For example, we use $element.attr('sep') to get the value of the sep attribute in the postsNavLink directive.

 4. Creating the pagination template posts-nav-link.html

Let’s create a new file posts-nav-link.html in the partials directory. In the template file we add all required HTML there with some AngularJS attributes and markups:

  • Line 2: We get the preLink and prevLabel from postsNavLink object. And we use ng-if with the condition that only show the previous link when currentPage>1.
  • Line 3: The sep text between two links should be displayed when currentPage>1 && currentPage<totalPages.
  • Line 4: We get the nextLink and nextLabel from postsNavLink object. And we use ng-if with the condition that only show the next link when currentPage<totalPages.

5. Creating the Paged controller

When we set the new route for paged index page, we added a new “Paged” controller. Now let’s create it.

Basically the Paged controller is pretty much like the Main controller, we just make some modification:

  • Line 4: We add $routeParams to the controller function, that for us to get the page parameter from the route.
  • Line 9: We query paged posts with endpoint like [site-url]/wp-json/posts?page=3.
  • Line 10-12: Set currentPage and totalPages properties. Please note we use parseInt to convert $routeParam.page to be an integer, or it would be a string and can’t be used to compare with integers.
  • Line 15-16: Update the page and document title.

6. Updating the Category controller

Let’s take a look at the Category controller. The Category controller looks a bit messy at this time, and so do other controllers. I’ll write another tutorials about how to use AngularJS service to tidy up our code later.

For now let’s just focus on line 15 – 24, where we add pagination to category pages by changing the endpoint to query posts with category_name and page. And we also add currentPage and totalPages to $scope object. These are important properties we’ll use in our directive, so we must make sure they’ve been attached to the $scope.

7. Updating the searchForm directive

After the steps above, we’ve almost got everything done. But there might be a feature we have broken – the search function.

Because we add pagination to the index and category pages, the search results will be paginated either. For technically the search results page is also one of the archive pages in WordPress. But when I built the searchForm directive in previous tutorial, I made it very simple to only demonstrate the search function, and I didn’t make it a standalone page so it didn’t get its own route.

Here I still want to keep it simple so the quick and dirty method is to add “posts_per_page” to filter and set it to “-1“. I also set the currentPage and totalPages to “1” because I don’t want to paginate the search results. (at line 13 – 18)

8. Add the postsNavLink directive to main.html

Now it’s the final step! Just add the postsNavLink directive to the bottom of the main.html. Remember you can set three attributes value: sep, prev-label and next-label. (I set prev-label and next-label in the following example.)


After these steps we finally add pagination links to index and category pages in our AngularJS WordPress theme. Here’s the screencast to show how it works in category pages:

Pagination in Category Pages

You can get the final theme files from the project repo on GitHub. I hope you enjoy this tutorial as much as I do. If you have any problem when following the instructions, just send me an email. I’d love to get back to you as soon as I can. Talk to you soon!

26 responses

  1. […] themes with AngularJS and JSON REST API series, I hope you enjoy the previous tutorial about pagination in AngularJS WordPress theme. Today I want to show you how to deal with “page not found” scenario in our project. […]

  2. Hi Yoren Chang,

    Your posts are so great. I’m a new babie so please advise me in case I set up searching posts in WordPress with AngularJS and the data is about 2-3 million rows (posts- terms).

    How to make it fast? Tks much for any advise. Hai

    1. Yoren Chang Avatar
      Yoren Chang

      Hey Hai,

      I have no experience on dealing with such significant amount of data in WordPress, but I believe ElasticSearch is what you’re looking for.

      You can check out ElasticPress by 10up: https://github.com/10up/ElasticPress. I haven’t test it but since it integrates with WP_Query, it should work with WP API.

      Cheers!

  3. Hello, thank you for this great tutorial,
    I tried your code in my project, the search results give the match post first and after a tiny delay it adds all the posts.
    snipped screen

    1. Yoren Chang Avatar
      Yoren Chang

      Strange, it works with my demo, as the gif showed in my post.

      I’ll add a live demo site soon so people can be sure that it does work like my tutorials.

  4. that_bman_again Avatar
    that_bman_again

    I couldn’t see any pagination at first – currentPage always = totalPages (1)
    so I added the extra ‘posts_per_page’ filter parameter to the Category controller to get it to work.
    i.e. changed

    var request = 'wp-json/posts/?filter[category_name]=' + res[0].name;

    to

    var request = 'wp-json/posts/?filter[category_name]=' + results[0].name + '&filter[posts_per_page]=2';

    In this example 2 posts are shown per page and you’d get a previous/next link in the pager (when there are more than 2 results)

    1. Yoren Chang Avatar
      Yoren Chang

      hey in WP-API the posts_per_page goes with the same value in WordPress settings. So the default value is “10”. I actually changed the default value to “1” to get this demo work.

      1. that_bman_again Avatar
        that_bman_again

        No worries Yoren 🙂 I figured it was something like that.
        I can see from your gif that only one was appearing, but in the code example on this page I can’t see where you’ve set it.
        …and thank you for a clear tutorial 🙂

        1. Yoren Chang Avatar
          Yoren Chang

          Glad I can help! 😉

    2. Dragan Milunovic Avatar
      Dragan Milunovic

      I think that your comment is good for custom post types….with small fixes….

      1. Dragan Milunovic Avatar
        Dragan Milunovic

        Answer about THAT_BMAN_AGAIN comment

  5. Hi Yoren,
    Thanks for this tutorial,

    I am having issues with the headers, this is my console message:

    ReferenceError: headers is not defined
    at scripts.js:50 ($scope.totalPages = headers(‘X-WP-TotalPages’);
    )
    at angular.min.js:87
    at angular.min.js:119
    at n.$eval (angular.min.js:133)
    at n.$digest (angular.min.js:130)
    at n.$apply (angular.min.js:133)
    at h (angular.min.js:87)
    at K (angular.min.js:91)
    at XMLHttpRequest.z.onload (angular.min.js:93)

  6. Hi Yoren,
    All good I found the issue was a syntax error! Crisis averted!
    thanks

    1. Yoren Chang Avatar
      Yoren Chang

      Hey, glad you figured that out. 🙂

    2. Fernando Silva Avatar
      Fernando Silva

      Hi. Could you please explain what was the error? I have the same problem, but could not find the solution.
      Thanks in advance.

      1. Yoren Chang Avatar
        Yoren Chang

        Hello Fernando,
        You need to take “headers” as the third params to your success function at https://gist.github.com/yoren/5114bc80065e566e2f30#file-scripts-main-controller-js-L9.

        1. It worked! Thanks for the answer! =]
          I am still following the tutorial posts for a brand new project and I am enjoying a lot.

  7. Hi,
    about the posts-nav-link.html, just a correction. The links for previous and next should be the oposite:
    <a data-ng-if="currentPage{{postsNavLink.prevLabel}}
    1 && currentPage{{postsNavLink.sep}}
    1″ href=”{{postsNavLink.nextLink}}” class=”next-link”>{{postsNavLink.nextLabel}}

  8. Hi, is it possible to set a pagination (just prev and next) also in the content? to show the previous/next post in the same category? I would appreciate if you can help me out on this
    Thanks in advance
    Luca

    1. Yoren Chang Avatar
      Yoren Chang

      Ah I think you need a custom endpoint to do that. Try to create one and feel free to come back when you need my help to check your code.

      1. It would be cool when using a ” wp-json/wp/v2/posts?slug= ” endpoint if the next and previous post slug were returned together with the post data. I’ll try to work on this! Thanks for your guide Yoren, I’m trying to rework my wordpress site using your angular js theme.

      2. I found this issue https://github.com/WP-API/WP-API/issues/783 not sure if it’s the right way to do this.

        1. Yoren Chang Avatar
          Yoren Chang

          Hey Luca, Ah I think you’re in the right direction! Have you tried this solution: https://github.com/WP-API/WP-API/issues/783#issuecomment-94033307?

          And please note you might need to update the filter name to “rest_prepare_post” if you’re using WP API v2.

          1. Hi Yoren, I tryed to inject the previous and next in my json for each posts, but the code seems not working, I changed correctly the filter as your thumbnail image injection.. 🙁

          2. Well, I’ve fixed with this Plugin: https://github.com/akmur/add-prev-next-to-wp-api it’s works like a charm 🙂

          3. Yoren Chang Avatar
            Yoren Chang

            Hi Luca, Sorry for my late reply and good job for digging such awesome plugin!

Leave a Reply

Your email address will not be published. Required fields are marked *