How to Link to Next and Previous Posts for Same Blog Category

Greetings,

My company’s Jekyll website effectively has three different blogs. Each of them has their own folder and _posts folder relative to the root folder, and posts for each are assigned a distinct category.

I recently found this AWESOME page, which shows how to link to next and previous posts with Jekyll:

http://david.elbe.me/jekyll/2015/06/20/how-to-link-to-next-and-previous-post-with-jekyll.html

Ignoring the CSS, the post gives us this base code which works perfectly for 99% of needs since most Jekyll websites (presumably) only use one main blog:

<div class="PageNavigation">
    {% if page.previous.url %}
        <a class="prev" href="{{page.previous.url}}">&laquo; {{page.previous.title}}</a>
    {% endif %}
    {% if page.next.url %}
        <a class="next" href="{{page.next.url}}">{{page.next.title}} &raquo;</a>
    {% endif %}
</div>

The problem is this code pulls the Next and Previous posts across ALL blogs, so the Next post might be from one blog, and the Previous post from another.

I was wondering if there were a clever way with Jekyll to pull only posts from the same category as the current page. Something like this:

<div class="PageNavigation">
    {% for post in site.categories.BLOGS-FROM-THIS-CATEGORY-ONLY %}
     {% if page.previous.url %}
            <a class="prev" href="{{page.previous.url}}">&laquo; {{page.previous.title}}</a>
     {% endif %}
     {% if page.next.url %}
        <a class="next" href="{{page.next.url}}">{{page.next.title}} &raquo;</a>
     {% endif %}
    {% end for %}
 </div>

Our website only uses one layout for our blogs, and while I know I could make a different layout for each, this would be a much more elegant solution.

Thanks for your help! :slight_smile:

I’ve used Liquid like the following to do just this, but it really really really slowed my build times down.

{% assign cat = page.category %}

{% for post in site.categories[cat] %}
  {% if post.url == page.url %}
    {% assign post_index0 = forloop.index0 %}
    {% assign post_index1 = forloop.index %}
  {% endif %}
{% endfor %}

{% for post in site.categories[cat] %}
  {% if post_index0 == forloop.index %}
    {% assign next_post = post %}
  {% endif %}
  {% if post_index1 == forloop.index0 %}
    {% assign prev_post = post %}
  {% endif %}
{% endfor %}

{% if prev_post %}
  <div class="article__previous">
    <a href="{{ prev_post.url }}">{{ prev_post.title }}</a>
  </div>
{% endif %}

{% if next_post %}
  <div class="article__next">
    <a href="{{ next_post.url }}">{{ next_post.title }}</a>
  </div>
{% endif %}

Instead I use a Jekyll plugin that gives you previous_in_category and next_in_category arrays that you can use like this:

{% if page.previous_in_category %}
  <a href="{{ page.previous_in_category.url }}">{{ page.previous_in_category.title }}</a>
{% endif %}

{% if page.next_in_category %}
  <a href="{{ page.next_in_category.url }}">{{ page.next_in_category.title }}</a>
{% endif %}
2 Likes

That is a very interesting solution, thank you for sharing! Out of curiosity, how much did it slow your build times down by? If we are talking seconds, it might be plausible. If minutes, then we will ignore that for now haha.

In any case, I am going to run the build times problem across my team, experiment a bit, and see if we will implement it.

Thanks again! :slight_smile:

It slowed it down to the point that after 10 minutes I killed the build because it still hadn’t finished :wink:

I have over 1,000 posts so you’re mileage may vary. The plugin was way more efficient than the Liquid snippet.

Here’s an alternate version of the Liquid code snippet above. It only iterates over the categories list once, and it exits as soon as it finds a match, so it should be substantially faster, in case you are not able to use the plugin. Note that in case of multiple categories for the post, this uses the first one.

{% assign cat = page.categories[0] %}
{% assign cat_list = site.categories[cat] %}
{% for post in cat_list %}
  {% if post.url == page.url %}
  	{% assign pOffset = forloop.index0 | minus: 1 %}
  	{% assign nOffset = pOffset | plus: 2 %}
  	{% if forloop.first == false %}
  	  {% assign next_post = cat_list[pOffset] %}
  	{% endif %}
  	{% if forloop.last == false %}
  	  {% assign previous_post = cat_list[nOffset] %}
  	{% endif %}
  	{% break %}
  {% endif %}
{% endfor %}
2 Likes