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 sit
This plugin seems a tad more robust.
This is how I implemented breadcrumbs in a site I inherited, which is based off some of the other versions here. In our case, some of our folders didn't contain an index.html page. Therefore, clicking on a breadcrumb that linked to a folder with no index.html in it would cause an error. This could have been eliminated with a better file structure, but I wasn't able to change that.
Here is what I came up with.
<ol class="pull-right breadcrumb">
<li><a href="/">Home</a></li>
{% assign crumbs = page.url | split: '/' %}
{% assign crumbs_total = crumbs | size | minus: 1 %}
{% for crumb in crumbs offset: 1 %}
{% if forloop.index == crumbs_total %}
<li class="active"><a href="{{ site.baseurl }}{{ page.url }}">{{page.title}}</a></li>
{% else %}
{% assign crumb_limit = forloop.index | plus: 1 %}
{% capture crumb_url %}{% for c in crumbs limit: crumb_limit %}{{ c | append: '/' }}{% endfor %}{% endcapture %}
{% capture crumb_with_index %}{{ crumb_url | append: 'index.html' }}{% endcapture %}
{% capture current_page %}{{ site.baseurl }}{{ page.url }}{% endcapture %}
{% for p in site.pages %}
{% if crumb_with_index != current_page and crumb_with_index == p.url %}
<li><a href="{{ crumb_with_index }}">{{ crumb | replace:'-',' ' | capitalize}}</a>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</ol>
This should give breadcrumbs at any depth (with a caveat, see end). Unfortunately, the Liquid filters are fairly limited, so this is an unstable solution: any time /index.html
appears, it is deleted, which will break URLs that have a folder that starts with index.html
(e.g. /a/index.html/b/c.html
), hopefully that won't happen.
{% capture url_parts %} {{ page.url | remove: "/index.html" | replace:'/'," " }}{% endcapture %}
{% capture num_parts %}{{ url_parts | number_of_words | minus: 1 }}{% endcapture %}
{% assign previous="" %}
<ol>
{% if num_parts == "0" or num_parts == "-1" %}
<li><a href="/">home</a> </li>
{% else %}
<li><a href="/">home</a> » </li>
{% for unused in page.content limit:num_parts %}
{% capture first_word %}{{ url_parts | truncatewords:1 | remove:"..."}}{% endcapture %}
{% capture previous %}{{ previous }}/{{ first_word }}{% endcapture %}
<li><a href="{{previous}}">{{ first_word }}</a> » </li>
{% capture url_parts %}{{ url_parts | remove_first:first_word }}{% endcapture %}
{% endfor %}
{% endif %}
</ol>
How it works is:
index.html
(e.g. /a/b/index.html
becomes a b
, /a/b/c.html
becomes a b c.html
), url_parts
, to iterate through all but the last word (e.g. it goes a b c.html
-> (a
, b c.html
) -> (b
, c.html
); then we stop). first_word
, and previous
which is all the previous directories seen (for the example above, it would go ""
-> "/a"
-> "/a/b"
)NB. the page.content
in the for loop is just to give something to iterate over, the magic is done by the limit:num_parts
. However, this means that if page.content
has fewer paragraphs than num_parts
not all breadcrumbs will appear, if this is likely one might define a site variable in _config.yml
like breadcrumb_list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
and use site.breadcrumb_list
as the placeholder instead of page.content
.
Here is an example (it doesn't use precisely the same code as above, but it's just a few little modifications).
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
I thought of an automatic breadcrumb also displaying nice breadcrumb element text from the frontmatter.
It works perfectly on GitHub Pages.
Check it out here: http://blog.comsysto.com/2015/04/25/automatic-breadcrumb-for-jekyll-on-github-pages/
If you have this setup:
/mypage1/index.html
---
layout: default
title: My Page 1 - My Homepage
breadcrumb: My Page 1
---
<div class="container">
<div class="row">
<div class="col-md-12">
peace yo!
</div>
</div>
</div>
/mypage1/subpage1/index.html
---
layout: default
title: My Sub Page 1 - My Homepage
breadcrumb: My Sub Page 1
---
<div class="container">
<div class="row">
<div class="col-md-12">
foobar!
</div>
</div>
</div>
The breadcrumb will render the following
<ol class="breadcrumb">
<li><a href="/">Home</a></li>
<li><a href="/mypage1/index.html">My Page 1</a></li>
<li class="active"><a href="/mypage1/subpage1/index.html">My Sub Page 1</a></li>
</ol>
Here's another way to approach this: rather than generating the breadcrumbs for a post from its URL, instead use the post's collection, categories, date (year, month and day) and title to form the breadcrumbs. This means that the breadcrumbs don't have to match with the URL (although they can still do if you want them to). And it means that the breadcrumbs for categories, years, etc can find and link to pages for those categories, years, etc if the pages exist.
The generated breadcrumbs look like this:
Home > Posts > Example Category > 2019 > Dec > 23 > Breadcrumbs in Jekyll
There are options for omitting each of the home, collection, categories, date and title components, so you can customize the breadcrumbs to look how you want.
Breadcrumbs will automatically link to a corresponding page, if the page exists. For example the home breadcrumb will link to a page at URL "/". A breadcrumbs for a "foo" category will link to a page at "/foo/" if one exists (otherwise the breadcrumb will just not be linked). A breadcrumb for the year 2019 will link to a "/2019/" page. And so on.
The templates are pasted below. Usage: {% include breadcrumbs.html %}
. See my gist and blog post for more detail.
_includes/breadcrumbs.html
:
{% assign omit_home = include.omit_home %}
{% if omit_home == nil %}
{% assign omit_home = site.breadcrumbs_omit_home %}
{% endif %}
{% assign omit_collection = include.omit_collection %}
{% if omit_collection == nil %}
{% assign omit_collection = site.breadcrumbs_omit_collection %}
{% endif %}
{% assign omit_categories = include.omit_categories %}
{% if omit_categories == nil %}
{% assign omit_categories = site.breadcrumbs_omit_categories %}
{% endif %}
{% assign omit_date = include.omit_date %}
{% if omit_date == nil %}
{% assign omit_date = site.breadcrumbs_omit_date %}
{% endif %}
{% assign omit_year = include.omit_year %}
{% if omit_year == nil %}
{% assign omit_year = site.breadcrumbs_omit_year %}
{% endif %}
{% assign omit_month = include.omit_month %}
{% if omit_month == nil %}
{% assign omit_month = site.breadcrumbs_omit_month %}
{% endif %}
{% assign omit_day = include.omit_day %}
{% if omit_day == nil %}
{% assign omit_day = site.breadcrumbs_omit_day %}
{% endif %}
{% assign breadcrumbs = "" | split: "" %}
{% if page.url == "/" %}
{% assign is_front_page = true %}
{% else %}
{% assign is_front_page = false %}
{% endif %}
{% unless is_front_page %}
{% assign page = include.page | default: page %}
{% unless omit_home %}
{% capture breadcrumb_text %}{% include breadcrumb_text.html url="/" default="Home" %}{% endcapture %}
{% assign breadcrumb_text = breadcrumb_text | split: "