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:
- A single include that automatically generates the navigation.
- The navigation points are named after the sites’ page titles.
- The name of the breadcrumbs directory is determined by the page title of the index.html inside the directory, not by the real directory name.
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">></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.