Breadcrumbs navigation plugin for Jekyll

There was no suitable plugin for creating a breadcrumbs navigation in Jekyll (a static site generator), so I decided to implement one.

By suitable, I mean following:

Example output

Let us have following file/page structure:

page1{url="/index.html", title="Home"}
page2{url="/company/index.html", title="The Company"}
page3{url="/company/products.html", title="Our Products"}

The breadcrumbs navigation on page3 would show Home > The Company > Our Products, the one on page2 Home > The Company.

The code

I implemented a plugin that monkey patches Jekylls’ Page and Post objects and adds another method that returns the Page’s/Post’s ancestry (all parent objects, not including the current one). To do that I also had to put the value inside the to_liquid hash so we are able to access it from the markup.

##
# Monkey patch Jekyll's Page and Post classes.
module Jekyll

	class Page
		def ancestors
			get_pages(self.url)
		end

		##
		# Make ancestors available.
		def to_liquid(attrs = ATTRIBUTES_FOR_LIQUID)
			super(attrs + %w[
				ancestors
			])
		end
	end

	class Post
		def ancestors
			get_pages(self.url)
		end

		##
		# Make ancestors available.
		def to_liquid(attrs = ATTRIBUTES_FOR_LIQUID)
			super(attrs + %w[
				ancestors
			])
		end
	end
end

##
# Returns ordered list 
def get_pages(url)
	a = []
	while url != "/index.html"
		pt = url.split("/")
		if pt[-1] != "index.html"
			# to to directory index
			pt[-1] = "index.html"
			url = pt.join("/")
		else
			# one level up
			url = pt[0..-3].join("/") + "/index.html"
		end
		a << get_page_from_url(url)
	end
	a.reverse
end

##
# Gets Page object that has given url. Very inefficient O(n) solution.
def get_page_from_url(url)
	(site.pages + site.posts).each do |page|
		return page if page.url == url
	end
end

Now we just have to write a simple loop to render the navigation.

<ol class="breadcrumbs">
{% for p in page.ancestors %}
	<li><a href="{{ p.url }}">{{ p.title }}</a>
	<li class="divider">&gt;</li>
{% endfor %}
	<li class="active">{{ page.title }}</li>
</ol>

I then used filters for generating better URLs: one that removes all ‘.html’ suffixes, and one that eliminates the redundant ‘index.html’ part after directories. You can learn more about it here (you may find beautify_directory() useful).

Update September 6, 2014: Modifications to the code. The plugin is also working with Jekyll posts now.

Update November, 2015: This plugin was written for Jekyll 2.x and does no longer work with the latest 3.x versions.

First published on June 23, 2013