SchmidtHappens

Paginate Like a Boss

My blog has finally gotten to the point where pagination is required. In this post I walk you through the steps I took to add pagination to my own Jekyll driven blog. Aren't I awesome?

In order to tell Jekyll that you want to use pagination you will need to modify your _config.yml file.

...
  paginate: 10

By adding this to our config file, we are telling Jekyll that we would like to activate the pagination module and that each paginated page should show a maximum of 10 entries. Now, you can obviously change this to any number you would like. This also gives us access to the paginator object which we will look at next.

Getting to Know the Paginator

Once Jekyll sees that we want to use pagination we have access to the paginator object. You can go here to get more information on what methods you can call on this object. The 2 that we are going to look at right now are #previous_page and #next_page.

As you may have deduced, #previous_page and #next_page return the previous page number of paginated results and the next page number of paginated results. If there is no previous or next result then nil is returned. We can use this to our advantage when we are creating our simple navigation.

The next thing to be aware of is the naming convention used for the pagination pages. Jekyll labels these "page2", "page3", "page4", and so on. This means that in order to reference the URL for our paginated page we would write something like http://mysite.com/page2/. Keen readers may have noticed I didn't start with "page1". Keep that in mind as we work through this exercise.

I should mention here that in order to KISS, I have opted to only show a previous and next link if it's appropriate. There are methods available that tell you the number of pages, the current page number, and so on if you would like to add this information. I may update this post at a later date with how to do that if there is a demand for it.

The Nitty Gritty

Before we start coding, let's think about how we will implement this feature. Since I want this to be as simple as possible I want to just have 2 links for navigation: next page and previous page. These will most likely be wrapped in a container of some sort. Since this is technically "navigation" it only makes sense to use the <nav> element.

<nav id="pagination">
    ...
  </nav>

Since I'm already using a <nav> element to wrap the main navigation at the top I have also added an ID to the pagination nav. I chose to go with an ID because I don't anticipate having more than one pagination navigation element per page. Next, we need to think about the links themselves.

The easiest solution would to just put 2 links in this container and call it a day.

<nav id="pagination">
    <a href="/page{{ paginator.previous_page }}/" title="Previous Page">&laquo; Previous</a>
    <a href="/page{{ paginator.next_page }}/" title="Next Page">Next &raquo;</a>
  </nav>

Unfortunately, there are a couple of problems with this approach. Let's start with the "next page" link since it is the simpler of the 2. The problem with just putting the link there is that there may not be a "next page" of articles. Let's say we have 15 articles published and we are listing 10 articles per-page. Page 2 would only have 5 articles listed which would mean there is no page 3 eliminating the need for a "next page" link.

Luckily we can address this problem. Remember when I mentioned that the #next_page method returns nil if there is no next page? We can take advantage of that in an if statement.

<nav id="pagination">
    <a href="/page{{ paginator.previous_page }}/" title="Previous Page">&laquo; Previous</a>
    {% if paginator.next_page %} 
    <a href="/page{{ paginator.next_page }}/" title="Next Page">Next &raquo;</a>
    {% endif %} 
  </nav>

Now, the "next page" link will only display if there is actually a next page. Let's tackle the "previous page" link.

There are 2 problems we need to address with the "previous page" link. The first is similar to the "next page" so we can address that in a similar manner.

<nav id="pagination">
    {% if paginator.previous_page %} 
    <a href="/page{{ paginator.previous_page }}/" title="Previous Page">&laquo; Previous</a>
    {% endif %}
    
    {% if paginator.next_page %} 
    <a href="/page{{ paginator.next_page }}/" title="Next Page">Next &raquo;</a>
    {% endif %} 
  </nav>

Now that the link will only be displayed if there is a previous page of articles, we need to address the problem with linking to the first page of results. Since the paginator labels each page as '/pageN' the first page would be a URL that looks like 'http://mysite.com/page1'. Unfortunately, this will result in a 404 error since there is no '/page1'. The first page of results is actually at the root ('http://mysite.com/'). Luckily, we can easily handle this scenario with an if-else statement and the #previous_page method.

<nav id="pagination">
    {% if paginator.previous_page %}
      {% if paginator.previous_page == 1 %}
      <a href="/" title="Previous Page">&laquo; Previous</a>
      {% else %}
      <a href="/page{{ paginator.previous_page }}/" title="Previous Page">&laquo; Previous</a>
      {% endif %}
    {% endif %}
    
    {% if paginator.next_page %} 
    <a href="/page{{ paginator.next_page }}/" title="Next Page">Next &raquo;</a>
    {% endif %} 
  </nav>

And there you go. We now have pagination for our site. Everything is awesome and we can party like it's the end of the Mayan Calendar. Unfortunately, if you have a site similar to mine where you have separate index pages by category -- for example I have "Articles", "Tips", and "Rants" -- this approach will not work on those category pages. In part 2, I will show you how to deal with this situation. According to the Jekyll documentation, pagination on tags and categories is not currently supported. Hopefully, this will become available in future versions.

Something missing? Need more explanation? Let me know in the c-c-c-comments!

blog comments powered by Disqus