Implementing breadcrumb navigation in hugo?

Does anybody have an example of providing breadcrumb navigation in Hugo? For instance I’m using hugo on the lowRISC hompage. Ideally a page like this one would have a link at the top to its ‘parent’ (which can easily be found just from the page hierarchy).

1 Like

For the time being, I’m manually using a ‘parent’ parameter, and using this to decide when and how to link to the parent. e.g.

            {{ range where .Site.Pages "RelPermalink" .Params.parent }}
                  <a href="{{ .Permalink }}">⇡ {{ .Title }}</a>
            {{ end }}
1 Like

There is a hugo site that uses breadcrumb navigation http://chimeraarts.org

You can check out the site repository to see how it was implemented over here: https://github.com/chimera/chimeraarts.org/search?utf8=✓&q=BREADCRUMB

Not sure if it’s much help though since your solution seems smarter…

@bep I’m trying to do something similar, but by chopping up the {{ .Permalink }} in order to create breadcrumbs. I’d like to remove {{ .Site.BaseURL }} from the string so I can split what’s left on "/" characters. This would give me a slice that I can use to construct the breadcrumbs.

I’m running into an error where I’m unable to remove the {{ .Site.BaseURL }} before running split.

{{ $url := replace .Permalink .Site.BaseURL "/" }}
<ol class="breadcrumbs">
  {{ range split $url "/" }}
    <li><a href="{{ . | absURL }}">{{ . }}</a></li>
  {{ end }}
</ol>

Shouldn’t {{ .Site.BaseURL }} already be a string? Why is it trying to cast, and what’s with the error?

ERROR: executing "partials/breadcrumbs.html" at <replace .Permalink ....>: error calling replace: Unable to Cast "http://127.0.0.1/" to string in partials/breadcrumbs.html

If I pass the baseurl in as a string manually it works, but I don’t want to hardcode this value as baseurl changes between dev and production environments.

You would think that .Site.BaseURL is a string?

No, it’s a template.URL – which is a typed string telling the Go template engine that this is safe to render.

Haven’t tested it, but this looks like a flaw in Cast, see:

Not sure how to get around it … maybe (totally untested):

{{ $url := replace ( printf "%s" .Permalink .Site.BaseURL) "/" }}

Excellent, here’s the slightly modified solution:

{{ $url := replace .Permalink ( printf "%s" .Site.BaseURL) "/" }}
1 Like

I’ll throw this one out there as I’ve hit a roadblock. The following is an attempt to implement breadcrumbs by splitting up the .Permalink.

If the .Permalink is equal to: http://www.example.com/tags/foo the example below outputs a list of links.

{{ $url := replace .Permalink ( printf "%s" .Site.BaseURL) "/" }}

<ol class="breadcrumbs">
  <li><a href="/">home</a></li>
  {{ range $index, $element := split $url "/" }}
    {{ if ne $element "" }}
      <li><a href="{{ . | absURL }}">{{ . }}</a></li>
    {{ end }}
  {{ end }}
</ol>

Output:

<ol>
  <li><a href="/">home</a></li>
  <li><a href="/tags">tags</a></li>
  <li><a href="/foo">foo</a></li> <!-- needs to be /tags/foo -->
</ol>

I need a way to build up the url string inside of the loop.

{{ $url := replace .Permalink ( printf "%s" .Site.BaseURL) "/" }}
{{ $path := "/" }}

<ol class="breadcrumbs">
  <li><a href="/">home</a></li>
  {{ range $index, $element := split $url "/" }}
    {{ if ne $element "" }}
      <!-- Need to concatenate $element with $path -->
      <!-- {{ $path += $element }} Dunno how in Go -->
      <li><a href="{{ $path }}">{{ . }}</a></li>
    {{ end }}
  {{ end }}
</ol>

I haven’t thought this through, but I throw it out:

Try

{{ $.Scratch.Add ... Set ... Get }}}

Add concatenates when used with strings (+ operator).

Working solution, thanks @bep

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

3 Likes

That’s great. I think a lot of people (me included) will find this code useful.

Is it possible to modify this to use the actual page title to display instead ?

Presumably you could just replace the last loop of range with .Title, that’s assuming this code adds the current page on the end. If not then you could add it in another li tag after the range has finished.

I am looking for a way to build the breadcrumbs from the page titles which should come from the front matter.

How can I get the parent page of a page so I can build the breadcrumbs from there ?

Breadcrumbs are hard with static sites because a page can have multiple parents. It’s possible, but you need to define “the parent”

2 Likes

I think real breadccrumbs should be the route the user took to get there, ignoring any other parents of a page. So yes, difficult for a static site, or more to the point diffiicult without user sessions. Perhaps user sessions with a static site could work.

Otherwise really it is just another menu,

When I hear “user session” my assumption is that a server is required.

A server is always required. But a db would be required along with server side dynamic code. So not a good fit for a static site unless this was a real need. I wasn’t suggesting it was a good idea, just that I think what breadcrumbs should be has become a little vague.

For me I’m happy with the page path as breadcrumbs as, in my opinion, a well designed site should only need that.

You could also implement this via JavaScript without any server side at
all.

Ah yes… good point. I’m going to look into that at some point. I’m more in favour of breadcrumbs as the user route rather than a dynamic menu.

Have a look at this site : http://docs.gigaspaces.com

This site is implemented with Hugo.

For example, navigate to this page : http://docs.gigaspaces.com/xap102/pojo-xml-metadata-class.html

You see that there are two levels missing in the breadcrumbs … would be really nice if there is a solution for this.

When you talk about JavaScript, how would you go about this ?