Jekyll Post Navigation Within a Category

October 16, 2013

Directions I’m not alone in using Jekyll to power a site which offers more than a blog. I use two Jekyll categories on my site, “Blog” for blog posts, and “Projects” for my portfolio pages. This allows me to keep two distinct default layouts, and make sure the posts only appear on the appropriate pages. However, when using or post.previous, no attention is paid to what category a post is in. It simply moves between them all based on the date that they were published.

The Solution

Jekyll has a very powerful plugin interface for writing “generators” which perform certain tasks when your site is built. After searching around there were a few different solutions to this problem, and one that was almost there but stopped just short. So I wrote my own generator. The logic is simple enough, as you will see from the code. It steps through each category, sorting the posts and adding both a next and previous in_category tag to the post data.

module Jekyll
  class WithinCategoryPostNavigation < Generator
    def generate(site)
      site.categories.each_pair do |category, posts|
        posts.sort! { |a,b| b <=> a}
        posts.each do |post|
          index = posts.index post
          next_in_category = nil
          previous_in_category = nil
          if index
            if index < posts.length - 1
              next_in_category = posts[index + 1]
          	if index > 0
              previous_in_category = posts[index - 1]
["next_in_category"] = next_in_category unless next_in_category.nil?
["previous_in_category"] = previous_in_category unless previous_in_category.nil?

Simply put that script into your _plugins directory (create it under your site root if it doesn’t exist). Here’s an example of how it is used on this site:

{{"{% if page.next_in_category != nil "}}%}
	<a href="{{"{{page.next_in_category.url"}}}}" class="next-link">Older Post</a>
{{"{% endif "}}%}
{{"{% if page.previous_in_category != nil "}}%}
	<a href="{{"{{page.previous_in_category.url"}}}}" class="previous-link">Newer Post</a>
{{"{% endif "}}%}

Note how no reference is made to the current category. This is by design, as it means I can share this code as a partial, and if I wanted to utilise this type of navigation on my portofolio items I could slot it in without the need to amend it.