- CLIENTI: Bullaki
- PRODUCER: Samuele Lilliu
- SOFTWARE: Hugo, HTML, JSON
Breadcrumbs are a useful navigation tool for both users and search engines. They provide a clear hierarchy of a website’s pages, making it easier for users to understand the structure of the site and for search engines to crawl and index the content.
For users, breadcrumbs provide a clear path to the page they are currently on, as well as an easy way to navigate back to higher-level pages. This improves the user experience and makes it more likely that they will spend more time on the site and return in the future.
For search engines, breadcrumbs provide a clear hierarchy of a website’s pages, making it easier for them to crawl and index the content. This improves the visibility of a website in search results, making it more likely that users will find and click through to the site. Additionally, using breadcrumbs with structured data in the form of JSON-LD can further help search engines understand the content of the website.
Breadcrumbs also help search engines understand the relationship between pages on a website, which can improve the way a website is indexed. For example, if a website has a category page for “shoes” and several sub-pages for different types of shoes, such as “sneakers” and “boots”, the breadcrumb trail will show the relationship between the category page and the sub-pages, making it clear to search engines that the sub-pages are related to the category page.
In summary, breadcrumbs are an important aspect of SEO. They help users navigate a website and provide search engines with a clear structure of the site, improving visibility in search results and making it more likely that users will find and click through to the site. Additionally, using breadcrumbs with structured data can further help search engines understand the content of the website.
Breadcrumbs with Hugo
In this page you can see the breadcrumb just under the logo. This is the reference folder structure:
In header.html
we call two partials:
{{- partial "navigation/mainNavbar.html" . -}}
{{- partial "navigation/breadcrumb.html" . -}}
This is the breadcrumb.html
partial:
<nav aria-label="breadcrumb ">
<div class="container-fluid px-3 pt-5">
<ol class="breadcrumb pt-3 varelatxt">
{{- define "partials/inline/breadcrumb" -}}
{{- with .Parent }}
{{ partial "inline/breadcrumb" . }}
<li class="breadcrumb-item">
<a href="{{ .RelPermalink }}">{{ .Title | humanize | title }}</a>
</li>
{{- end }}
{{- end -}}
{{ partial "inline/breadcrumb" . }}
<li class="breadcrumb-item active" aria-current="page">
{{ .Title | humanize | title }}
</li>
</ol>
</div>
</nav>
We are essentially using code snippets from Bootstrap 5.
With {{ .Title | humanize | title }}
we display the title of the current page, humanise it and capitalise it.
The code the precedes .Title
needs to display the parent pages, for example: Home / Services / Web Development
. For this we use a Hugo feature called inline partials. This allows defining and using a partial within the current template. Our inline partial is:
{{- define "partials/inline/breadcrumb" -}}
{{- with .Parent }}
{{ partial "inline/breadcrumb" . }}
<li class="breadcrumb-item">
<a href="{{ .RelPermalink }}">{{ .Title | humanize | title }}</a>
</li>
{{- end }}
{{- end -}
This is a recursive partial, because the breadcrumb
partial is called within itself. This allows exploring the full path of parent pages. If the current context has a parent {{- with .Parent }}
we call breadcrumb
a display a list element showing the title of the parent page. This goes on until there is no parent, i.e. when we reach Home
.
Finally breadcrumb
must be called by the template ( .
indicates that we are passing the current context, the current page):
{{ partial "inline/breadcrumb" . }}
Structured Data for Breadcrumbs
Google suggests adding structured data for breadcrumbs. In this page we are using a single breadcrumb trail by including the json-ld.html
partial in baseof.html
:
<!DOCTYPE html>
<html lang="{{ .Language.Lang }}" class="no-js">
<html>
<head>
{{- partial "head.html" . -}}
{{- partial "json-ld.html" . -}}
{{- block "JSON-LD" . }}{{- end }}
</head>
<body>
<header>{{- partial "header.html" . -}}</header>
<main>{{- block "main" . }}{{- end }}</main>
<footer>{{- partial "footer.html" . -}}</footer>
{{ partial "script-footer" . }}
</body>
</html>
</html>
This is json-ld.html
:
{{- $scratch := newScratch -}}
{{- /* https://developers.google.com/search/docs/advanced/structured-data/breadcrumb#json-ld_1
breadcrumb structured markup json-ld */ -}}
{{- $scratch.Set "count" 1 -}}
{{- define "partials/inline/breadcrumbData" -}}
{{- $scratchCtx := .scratch -}}
{{- with .parent }}
{{ partial "inline/breadcrumbData" (dict "scratch" $scratchCtx "parent" .Parent) }}
{{- $scratchCtx.Add "listItem" (slice (dict
"@type" "ListItem"
"position" ($scratchCtx.Get "count")
"name" (.Title | humanize | title)
"item" .Permalink
)) -}}
{{- $scratchCtx.Add "count" 1 -}}
{{- end }}
{{- end -}}
{{ partial "inline/breadcrumbData" (dict "scratch" $scratch "parent" .Parent) }}
{{- $scratch.Add "listItem" (slice (dict
"@type" "ListItem"
"position" ($scratch.Get "count")
"name" (.Title | humanize | title)
)) -}}
{{- $scratch.SetInMap "breadcrumb" "@context" "https://schema.org" -}}
{{- $scratch.SetInMap "breadcrumb" "@type" "BreadcrumbList" -}}
{{- $scratch.SetInMap "breadcrumb" "itemListElement" ($scratch.Get "listItem") -}}
<script type="application/ld+json">
{{- $scratch.Get "breadcrumb" | jsonify (dict "prefix" " " "indent" " ") | safeJS -}}
</script>
As you can see from the inspector this generates the following JSON-LD script:
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"item": "http://localhost:1313/",
"name": "Home",
"position": 1
},
{
"@type": "ListItem",
"item": "http://localhost:1313/services/",
"name": "Services",
"position": 2
},
{
"@type": "ListItem",
"name": "Web Development",
"position": 3
}
]
}
The concept is similar to what we’ve done before, as we are again using a recursive partial to explore all parents and generate the JSON script.