Implementing breadcrumb navigation in hugo?

@croffler you can adapt something like this :

<script language="JavaScript">
<!--
   String.prototype.capitalizeFirstLetter = function() {
      return this.charAt(0).toUpperCase() + this.slice(1);
   }

   //Bread crumb script - Kevin Lynn Brown
   //Duplicate directory names bug fix by JavaScriptKit.com
   //Visit JavaScript Kit (http://javascriptkit.com) for script

   var path = "<a href='{{ .Site.BaseURL}}'>Home</a>";
   var href = document.location.href;
   var s = href.split("/");
   for (var i=3;i<(s.length-2);i++) {
      path+=" &gt;  <a href=\""+href.substring(0,href.indexOf("/"+s[i])+s[i].length+1)+"/\">"+s[i].capitalizeFirstLetter()+"</a> ";
   }
   i=s.length-1;
   path+="<a href=\""+href.substring(0,href.indexOf(s[i])+s[i].length)+"\">"+s[i]+"</a>";
   path+="  &gt;   {{.Title}}";
   document.writeln(path);
//-->
</script>

Thanks. Your code works, but serious sites use headers in the breadcrumb instead of name of folders. On sites with languages other than English chain of folders looks ugly.

Home > Lib > Iskusstvo-na-zapade > 9. ŠŸŃ€ŠøŠ¼ŠøтŠøŠ²Ń‹ Šø Š“ŠµŠŗŠ°Š“ŠµŠ½Ń‚Ń‹

IMHO, For sites with academic publications, the most important elements of navigation is breadcrumbs and footnotes. Without the full support of these elements is difficult to make a friendly site.

+1

Totally agree with Mikail

I am happy to define parent for each page in the front matter. Wondering if there is code that I can use to develop breadcrumb based on Parent?

Doesnā€™t have to be headers, but I see your point. The name of folders works fine if the folder names match the logic of the site. Thatā€™s more a question of content organisation. The other option is to put something like an index.md in each folder with frontmatter for the alternative section name that works for that site.

Actually, I have a pretty specific opinion on what breadcrumbs should be. For me they should be the user route through the site, not just the hierachy of that page (with titles / headers), as this is just another menu.

I donā€™t like those breadcrumbs personally. I realise itā€™s a common way. But itā€™s just mimicking the side menu. So better to highlight the side menu item for each page the user is on, remove breadcrumbs and save screen space.

In my opinion, breadcrumbs like this exist mainly because CMS systems made them easy. I rarely see a site that has useful breadcrumbs (usually only useful when site menus are not clear)

However, I see no reason why you canā€™t do what you want in Hugo now. But how breadcrumbs should be for each person may be too varied (in my opinion) to have Hugo choose one approachā€¦

If the idea is that the breadcrumb should be a unique trail that shows the userā€™s path, I donā€™t see how this would happen with a static site, but I do think think this would be possible with client-side code that holds those values and leverages local storage and push state.
In such a case, Hugo would be a separate concern because itā€™s focus is content and markup.

That said, the non-dynamic breadcrumb (ie, a reflection of the URL, more or less) has some utility for sites with multiple layers of navigation, especially since most of your users enter via external search and come at your site sideways and it can provide an immediate indicator of their location. Something like this gets hard with Hugo because of the ability to create different permalinks in your configuration, which precludes the idea that a parent directory in your source is the same parent path in the URL. My guess is that setting this up as a separate data file (or even as params in your config) would work best here.

Sorry, I should have clarified I wasnā€™t lookng for ways to do this, just an opinion why header / menu based static breadcrumbs are not always thhe best option

Sure. In my experience such a need for breadcrumbs is more often either covering site navigation issues or mimicking them

1 Like

As an update to my solution further up this chain:

Iā€™m not sure if a newer version of hugo changed how .Permalink works, but this is a bit simpler now. You no longer have to pull the baseurl out of the permalink.

{{ $.Scratch.Add "path" .Site.BaseURL }}
<ol class="breadcrumbs">
  <li><a href="/" class="material-icons">home</a></li>
  {{ range $index, $element := split .Permalink "/" }}
    {{ $.Scratch.Add "path" $element }}
      {{ if ne $element "" }}
      <li><a href='{{ $.Scratch.Get "path" }}'>{{ replace . "-" " " }}</a></li>
      {{ $.Scratch.Add "path" "/" }}
      {{ end }}
  {{ end }}
</ol>

As a user I donā€™t necessarily expect a dynamic set of breadcrumbs. I generally view breadcrumbs as a hierarchical way of navigating between pages. To each his/her own!

So thereā€™s ā€œhistory breadcrumbsā€ and ā€œposition breadcrumbsā€ each has a benefit, and each has a drawback. The solution to position breadcrumbs is in this thread already. However the ā€œhistory breadcrumbsā€ arenā€™t. I happend to stumble upon this old article that uses javascript and cookies to solve it.

It certainly can be improved by popping multiple entries off the stack when the user clicks one of the breadcrumbs, but itā€™s a starting place.

http://www.whitford.id.au/webmonkey/code/breadcrumbs/history_crumbs/javascript.php

Iā€™m an advocate of what are called here ā€˜history breadcrumbsā€™ (nice term that). Nice link to add to the thread. For me with this, with ā€˜postionā€™ breadcrumbs as a menu, creates a very user friendly and relevant form of navigation

Sure this is a simple issue to this topic and the working solution from @rhewitt. I am new to hugo and go. Now I am working on a multilingual site and I would appreciate to know how this looks like with the languagecode included. Also I am wondering if there is no way to get the titles of the pages/taxonomies/nodes with the path known. Thanks in advance

There is a problem with this. Imagine you have /content/section/category/article.md

The breadcrumb will be generated like: home / section / category / article/

You can click ā€˜homeā€™. You can click ā€˜sectionā€™. They will take you to those list pages etc. You can also click ā€˜categoryā€™ but that doesnā€™t exist, so you get an error. You donā€™t get a 404 but httpd says forbidden b/c no empty directories will be displayed in my config.

Meaning, if you have subdirectories in your content/web-dev/hugo/ or content/web-dev/php/, hugo and php are not taxanomies or sections or categories with pages. Hugo doesnā€™t generate anything for that.

How would you counter this?

If you go to https://stoned.io/authors/yash-akasha/Thoughts-On-Standing-Rock-Dakota-Pipeline-Conflict/ and look at the breadcrumbs, yoā€™ull see it like

Authors > Yash Akasha > article name here.

Clicking Authors is fine. You get a list of articles from all authors. If I wanted to get only Yash, I go to authors/yash-akasha/ and that doesnā€™t exist b/c Hugo never generated anything for this.

Iā€™ve been through the docs many times. Iā€™m unsure what Iā€™m missing. How would you feature multiple authors in said organization?

 <section>
 <div class="bread-container shadow">
 {{ $url := replace .Permalink ( printf "%s" .Site.BaseURL) "" }}
 {{ $.Scratch.Add "path" .Site.BaseURL }}
 <ol class="breadcrumbs">
 <li>Navigation: </li>
   <li><a href="/">home</a></li>
   {{ range $index, $element := split $url "/" }}
     {{ $.Scratch.Add "path" $element }}
       {{ if ne $element "" }}
       <li>&rarr; <a href='{{ $.Scratch.Get "path" }}'>{{ . }}</a></li>
       {{ $.Scratch.Add "path" "/" }}
       {{ end }}
   {{ end }}
 </ol>
 </div>
 </section>

EDIT: https://gohugo.io/templates/views/ I bet I need to create a custom content display for authors? How would that create a list of articles by E ACH Author though?

Iā€™m looking to have site.com/authors/authornamehere/all their articles here

EDIT2: That doesnā€™t sem to work. creating /themes/stoned.io/layouts/authors/li.html|single.html only affect how content/authors archetype/content type is displayed.

I still canā€™t figure out how to make hugo generate a page for the sub directories of content types.

I also have site.com/web-development/hugo/ and site.com/web-development/php etc. etc. Same thing with that.

How can I diplay that using hugo?

EDIT3 : I think I figured it out.

config.toml

[taxonomies]
author = "authors"

content/authors/yash-akasha/Thoughts-On-Standing-Rock-Dakota-Pipeline-Conflict.md

+++
authors=ā€œyash-akashaā€
+++

And now stoned.io/authors/yash-akasha/ (per the breadcrumbs from the content sub folder organization) shows the list of articles by Yash Akasha.

Iā€™ll further test this w/ more authors. But it seems like it was as simple as adding another taxonomy. Nice.

This is a great Static Site Gen. You guys are awesome! :slightly_smiling: <3

EDIT 4: It seems that if you only specify the custom taxanomy, it will disable the default tags/category taxanomies.

So you have to specify the defautl ones, plus the custom ones you want

[taxonomies]
author="authors"
tag = "tags"
category = "categories"

EDIT 5: Seems this this would be manually done for each sub-dir?

I have site.com/web-dev/hugo and /web-dev/foo and /web-dev/bar

would I need to custom add taxanomies for each?

There has got to be a better more abstracted method? Anyone care to rub some neurons together with me? :slightly_smiling:

1 Like

Is there a way to style the link of the ā€œactiveā€ page?

Perhaps with isMenuCurrent?

Option that does not include the name of the current page in the breadcrumbs. Also this code allows to make custom headers for the elements of the chain.

{{ $baseurl := .Site.BaseURL }}
{{ $fullurl := print ( .RelPermalink | replaceRE "[^/]+/$" "") }}
<ol class="breadcrumbs">
  <li><a href="/" class="crumb">&#8962;</a></li>
  {{ range $index, $element := split $fullurl "/" }}
    {{ $.Scratch.Add "path" $element }}
      {{ if ne $element "" }}
      <li><a href='{{ $baseurl }}{{ $.Scratch.Get "path" }}'>{{ if isset $.Site.Data.titles . }} {{ index $.Site.Data.titles . }} {{ else }} {{ . }} {{ end }}</a></li>
      {{ $.Scratch.Add "path" "/" }}
      {{ end }}
  {{ end }}
</ol>

Custom headers should be written to the file \data\titles.yaml. They should look like this:

lib: "Š‘ŠøŠ±Š»ŠøŠ¾Ń‚ŠµŠŗŠ°"
book: "ŠšŠ½ŠøŠ³Š°"
book1: "ŠšŠ½ŠøŠ³Š° 1"

If you have the folders structure lib/book/article/, it will look like: Š‘ŠøŠ±Š»ŠøŠ¾Ń‚ŠµŠŗŠ° > ŠšŠ½ŠøŠ³Š°.

2 Likes

hi,

I was just looking for a breadcrumb solution and came up with this solution.
Maybe this is a possibilty for others as well?

<ol class="breadcrumb">
  {{ template "breadcrumb" dict "currentPage" .Page "id" .UniqueID }}
</ol>

<!-- templates -->
{{ define "breadcrumb" }}
  {{ if .currentPage.Parent }}
    {{ template "breadcrumb" dict "currentPage" .currentPage.Parent }}
  {{ end }}
  <li>
    {{ if eq .id .currentPage.UniqueID }}
      {{ .currentPage.Title }}
    {{ else }}
      <a href="{{ .currentPage.URL }}">{{ .currentPage.Title }}</a>
    {{ end }}
  </li>
{{ end }}
6 Likes

I just to test the reply style.

This works absolutely perfectly! Thanks!

Thank you @maltesa, this works like a dream!

It would be great if this could be added to the Hugo docs. Itā€™s such a common navigational element that it would help a lot of people. I think it would belong well alongside Menu Templates, Pagination and so on.

@maltesa Yours is by far the simplest solution for Breadcrumb Navigation. Thank you!

I modified it a bit to exclude the homepage link as I needed to give it a different name than the title.

Here is the modified snippet.

<span class="breadcrumb">
<a href="/">Custom Homepage Title</a>
  {{ template "breadcrumb" dict "currentPage" .Page "id" .UniqueID }}
</span>

<!-- templates -->
{{ define "breadcrumb" }}
 {{ if .currentPage.Parent }}
 {{ if ne .currentPage.Parent .IsHome }}
    {{ template "breadcrumb" dict "currentPage" .currentPage.Parent }}
  {{ end }}
    {{ if eq .id .currentPage.UniqueID }}
      {{ .currentPage.Title }}
    {{ else }}
      <a href="{{ .currentPage.URL }}">{{ .currentPage.Title }}</a> >
    {{ end }}
{{ end }}
{{ end }}
1 Like