Breadcrumb JSON LD Structured Data in Hugo Partial Template

Updated: , Published:

If you want to add structured data to your website for rich search result then Breadcrumb structured data is something that can be added to every single page that is indexed by search engine. Structured data is not required to rank your webpage in google search but you will see many website referring to it as required. There is no search ranking penalty if you don’t provide it. But it will provide the google search Artificial Intelligence more understanding of how your website is structured. And it will have interesting use cases in future but for right now it can be used to show rich search results.

Whenever adding structured data it is very important to read google search documentation instead of just using Schema.org. Because according to google documentation

You should rely on the documentation on developers.google.com as definitive for Google Search behavior, rather than the schema.org documentation. Attributes or objects not described here are not required by Google Search, even if marked as required by schema.org.

So this blog post is biased towards google search compatibility. And it may not work with other search engines. I am going to use JSON-ld for writing structured data. Again because google recommends using JSON-ld whenever possible.

For breadcrumbs you can generate everything you need with using .Permalink. Here I am assuming that you have not added custom slug for a page. Just create new partial template and add the following code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{{ $url := replace .Permalink (printf "%s" .Site.BaseURL) ""}}
{{ .Scratch.Add "path" .Site.BaseURL }}
{{ .Scratch.Add "breadcrumb" (slice (dict "url" .Site.BaseURL "name" "Home"))}}
{{ $pScratch := .Scratch }}

{{ range $index, $element := split $url "/" }}
    {{ $pScratch.Add "path" $element }}
    {{ $pScratch.Add "path" "/" }}
    {{ if ne $element "" }}
        {{ $pScratch.Add "breadcrumb" (slice (dict "url" ($pScratch.Get "path") "name" (humanize .)))}}
    {{ end }}
{{ end}}

<script type="application/ld+json">
    {
        "@context": "https://schema.org",
        "@type": "BreadcrumbList",
        "itemListElement": [
            {{ range $index, $breadcrumb := .Scratch.Get "breadcrumb" }}
                {{ if ne $index 0 }},{{ end }}
                {
                    "@type": "ListItem",
                    "position": {{ add $index 1 }},
                    "name": "{{ $breadcrumb.name }}",
                    "item": {{ printf "%s" $breadcrumb.url }}
                }
            {{ end }}
        ]
    }
</script>

I make extensive use of scratch so if you are not familiar with scratch then brush up on scratch fundamentals before moving forward.

  • Line 1 I removed the base url e.g. https://example.com/ from the page url and store it into url variable
  • Line 2 This partial will be added to the baseof template. And not inside another partial or range. So the dot context will have access to page context. And you can access scratch on page context. I am storing base url value for key “path” into the scratch. And this will be used to build full url later.
  • Line 3 In scratch I have added an array or a slice starting with high level breadcrumb. So base url is going to be Home. You can change to appropriate name for your section e.g. blog post or news etc. Then we add more breadcrumb later into this array.
  • Line 4 After this line we are going inside range. And we won’t have access to page scratch. So I am saving page scratch into a variable pScratch.
  • Line 6 So imagine your url was https://example.com/blog/my-post/. So on first line I already removed base url then you are left with blog/my-post/. Now you are going to split this using / as separator. This will return ["blog", "my-post", ""] and we are going to range over it.
  • Line 7 and 8 Now I am going to add first element to base url that will generate https://example.com/blog/ and so on.
  • Line 9 and 10 Last element on slice maybe empty so skip this step if the element is empty. Then add url into slice. Humanize will convert my-post into “My post”. And if you had custom slug here instead then you have to manually change it to post title.
  • Line 14 onwards Now you have all the necessary information in the slice. So add fixed values for breadcrumb and range over the slice to add variable values. And index starts with 0 hence use add function to increase index. When adding url it was treating url text as normal string and unsafe for html. So I had to use print function to get around that problem.

Make sure to add the partial above in <head> tag of baseof template.

After deploying website don’t forget to test with Structured Data Testing Tool to check for any errors. Fix them as per google’s suggestion.

Have you found any mistake or improvement for this post then let me know in the comments below.

Load more