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:
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:
Or we can pass values into the attributes to make some changes:
<posts-nav-link sep="//" prev-label="« Previous Page" next-label="Next Page »"></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 href” at 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
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.
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:
totalPages to the
$scope object. We set
1 because we’re at homepage, and we get
headers which is a function passed by WP REST API, so we get the value with syntax like
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
- Line 7: we’ll create a new template file for this custom directive. I named it
posts-nav-link.htmlbut you can choose any file name you like.
- Line 9: we’ll get the current page number from the route parameter “
- 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
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
4. Creating the pagination template
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
postsNavLinkobject. And we use
ng-ifwith the condition that only show the previous link when
- Line 3: The
septext between two links should be displayed when
currentPage>1 && currentPage<totalPages.
- Line 4: We get the
postsNavLinkobject. And we use
ng-ifwith the condition that only show the next link when
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.
Paged controller is pretty much like the
Main controller, we just make some modification:
- Line 4: We add
$routeParamsto the controller function, that for us to get the
pageparameter from the route.
- Line 9: We query paged posts with endpoint like
- Line 10-12: Set
totalPagesproperties. Please note we use
$routeParam.pageto 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
page. And we also add
$scope object. These are important properties we’ll use in our directive, so we must make sure they’ve been attached to the
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
totalPages to “
1” because I don’t want to paginate the search results. (at line 13 – 18)
8. Add the
postsNavLink directive to
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:
next-label. (I set
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:
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!
I’m a senior web developer helping clients build their websites to grow businesses. Currently I’m based in Taipei, Taiwan.
I write things about WordPress, AngularJS and life. Whenever you’d like to find someone to talk about these topics, just get in touch!