What are some good ways to implement breadcrumbs on a Jekyll site?

Philip Durbin picture Philip Durbin · Mar 8, 2012 · Viewed 8.1k times · Source

I'm aware that there are single-level breadcrumbs in http://raphinou.github.com/jekyll-base/ but I'm looking for some good ways to have breadcrumbs on a Jekyll site when directories get to a depth of four or five levels.

(Yes, I'm well aware that Jekyll is primarily a blogging engine and that perhaps I shouldn't use it for a general purpose website, especially with many directory levels. I'm also aware of http://octopress.org but haven't found a suitable plugin.)

Based heavily on http://forums.shopify.com/categories/2/posts/22172 I came up with the following Jekyll layout for breadcrumbs, a variation of which you can see in action at http://crimsonfu.github.com/members/pdurbin . You should see the breadcrumbs "home » members »" at the top.

Here's my layout. Yes, it's ugly. I haven't studied Liquid much. Can you suggest a better way?

<html>
<head>
<title>{{ page.title }}</title>
<style type="text/css">
#bread ul {
  padding-left: 0;
  margin-top: 2px;
  margin-bottom: 2px;
} 
#bread ul li {
  display: inline;
  font-size: 70%;
}
</style>
</head>
<body>
<div id="bread">
<ul>

{% assign url = {{page.url}} %}
{% assign delimiter = '/' %}
{% capture allparts %}{{ url | replace: delimiter, ' ' }}{% endcapture %}

{% capture myFirstWord  %}{{ allparts    | truncatewords: 1 | remove: '...' }}{% endcapture %}
{% capture minusFirst   %}{{ allparts    | replace_first: myFirstWord, ''   }}{% endcapture %}

{% capture mySecondWord %}{{ minusFirst  | truncatewords: 1 | remove: '...' }}{% endcapture %}
{% capture minusSecond  %}{{ minusFirst  | replace_first: mySecondWord, ''  }}{% endcapture %}

{% capture myThirdWord  %}{{ minusSecond | truncatewords: 1 | remove: '...' }}{% endcapture %}
{% capture minusThird   %}{{ minusSecond | replace_first: myThirdWord, ''   }}{% endcapture %}

{% capture myFourthWord %}{{ minusThird  | truncatewords: 1 | remove: '...' }}{% endcapture %}
{% capture minusFourth  %}{{ minusThird  | replace_first: myFourthWord, ''  }}{% endcapture %}

{% capture myFifthWord  %}{{ minusFourth | truncatewords: 1 | remove: '...' }}{% endcapture %}

{% if myFirstWord contains '.html' %}
  <li><a href="/">home</a> &nbsp; </li>
{% elsif mySecondWord contains '.html' %}
  <li><a href="/">home</a> &#187; </li>
  {% unless mySecondWord == 'index.html' %}
  <li><a href="/{{myFirstWord}}">{{myFirstWord}}</a> &#187; </li>
  {% endunless %}
{% elsif myThirdWord contains '.html' %}
  <li><a href="/">home</a> &#187; </li>
  <li><a href="/{{myFirstWord}}">{{myFirstWord}}</a> &#187; </li>
  {% unless myThirdWord == 'index.html' %}
  <li><a href="/{{myFirstWord}}/{{mySecondWord}}">{{mySecondWord}}</a> &#187; </li>
  {% endunless %}
{% elsif myFourthWord contains '.html' %}
  <li><a href="/">home</a> &#187; </li>
  <li><a href="/{{myFirstWord}}">{{myFirstWord}}</a> &#187; </li>
  <li><a href="/{{myFirstWord}}/{{mySecondWord}}">{{mySecondWord}}</a> &#187; </li>
  {% unless myFourthWord == 'index.html' %}
  <li><a href="/{{myFirstWord}}/{{mySecondWord}}/{{myThirdWord}}">{{myThirdWord}}</a> &#187; </li>
  {% endunless %}
{% elsif myFifthWord contains '.html' %}
  <li><a href="/">home</a> &#187; </li>
  <li><a href="/{{myFirstWord}}">{{myFirstWord}}</a> &#187; </li>
  <li><a href="/{{myFirstWord}}/{{mySecondWord}}">{{mySecondWord}}</a> &#187; </li>
  <li><a href="/{{myFirstWord}}/{{mySecondWord}}/{{myThirdWord}}">{{myThirdWord}}</a> &#187; </li>
  {% unless myFifthWord == 'index.html' %}
  <li><a href="/{{myFirstWord}}/{{mySecondWord}}/{{myThirdWord}}/{{myFourthWord}}">{{myFourthWord}}</a> &#187; </li>
  {% endunless %}
{% else %}
  <li><a href="/">home</a> &#187; </li>
  <li><a href="/{{myFirstWord}}">{{myFirstWord}}</a> &#187; </li>
  <li><a href="/{{myFirstWord}}/{{mySecondWord}}">{{mySecondWord}}</a> &#187; </li>
  <li><a href="/{{myFirstWord}}/{{mySecondWord}}/{{myThirdWord}}">{{myThirdWord}}</a> &#187; </li>
  <li><a href="/{{myFirstWord}}/{{mySecondWord}}/{{myThirdWord}}/{{myFourthWord}}">{{myFourthWord}}</a> &#187; </li>
{% endif %}
</ul>
</div>
<h1>{{ page.title }}</h1>
{{ content }}
</body>
</html>

Answer

JoostS picture JoostS · Aug 14, 2015

I have improved slightly on the answers given earlier. I have removed the unordered list and seperated the items with a character (forward slash). I have added a filter for 'index.html' and '.html', so urls like 'mysite.com/path/index.html' and 'mysite.com/path/item-name.html' are also supported. Finally I have capitalized the titles. This results in something that looks like this:

Home / Path / Item name

{% assign crumbs = page.url | remove:'/index.html' | split: '/' %}

<a href="/">Home</a>
{% for crumb in crumbs offset: 1 %}
  {% if forloop.last %}
    / {{ crumb | replace:'-',' ' | remove:'.html' | capitalize }}
  {% else %}
    / <a href="{% assign crumb_limit = forloop.index | plus: 1 %}{% for crumb in crumbs limit: crumb_limit %}{{ crumb | append: '/' }}{% endfor %}">{{ crumb | replace:'-',' ' | remove:'.html' | capitalize }}</a>
  {% endif %}
{% endfor %}

PS. I have created an online resource for snippets like this: jekyllcodex.org/without-plugins