Struggle with making breadcrumbs for JSON-LD format

My content is like this:

  • /content/sectionA/_index.md
  • /content/sectionA/subsection1/_index.md
  • /content/sectionA/subsection1/my-post.md
  • /content/sectionA/subsection2/_index.md
  • /content/sectionA/subsection2/my-second-post.md

This means that a single post can belong to two sections: the main section (/content/sectionA/) and its ‘subsection’ (/content/sectionA/subsectionA/).

And so for the breadcrumbs JSON-LD format I have up to four levels:

  • The homepage,
  • The main section page,
  • The ‘subsection’ page (if applicable),
  • And the post itself.

How can I make this in Hugo?

Here’s what I have so far:

<!-- Breadcrumbs for single post pages -->
{{ if and (ne .Section "") .IsPage }}
	<script type="application/ld+json">
	{
		"@context": "http://schema.org",
		"@type": "BreadcrumbList",
		"itemListElement": [{
			"@type": "ListItem",
			"position": 1,
			"name": "Home",
			"item": "{{ .Site.BaseURL }}"
		},{
			"@type": "ListItem",
			"position": 2,
			"name": "{{ .CurrentSection.Parent.Title }}",
			"item": "{{ .CurrentSection.Parent.Permalink }}"
		},{
			"@type": "ListItem",
			"position": 3,
			"name": "{{ .CurrentSection.Title }}",
			"item": "{{ .CurrentSection.Permalink }}"
		},{
			"@type": "ListItem",
			"position": 4,
			"name": "{{ .Title }}",
			"item": "{{ .Permalink }}"
		}]
	}
	</script>
{{ else }}
	<!-- Breadcrumbs for main section -->
	<script type="application/ld+json">
	{
		"@context": "http://schema.org",
		"@type": "BreadcrumbList",
		"itemListElement": [{
			"@type": "ListItem",
			"position": 1,
			"name": "Home",
			"item": "{{ .Site.BaseURL }}"
		},{
			"@type": "ListItem",
			"position": 2,
			"name": "{{ .Title }}",
			"item": "{{ .Permalink }}"
		}]
	}
	</script>
{{ end }}

Problem is that this code does not work for ‘subsection’ pages, since the else code block kicks into gear for those pages (while it should not).

I know there’s a .Sections variable that lists all the ‘subsections’ of a particular page. But I need to look the other way, and get all sections that a particular page belongs to.

Things I’ve failed with:

  • Split the permalink and derive sections that way.
  • Use .Site.GetPage to fetch pages.
  • Build up a custom dictionary with dict,
  • And more.

Given your content structure and template code, here’s the output I get. So I’m trying to understand what you want this to do, that it’s not currently doing?

<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "name": "Home",
    "item": "https://example.org/"
  },{
    "@type": "ListItem",
    "position": 2,
    "name": "SectionA",
    "item": "https://example.org/sectiona/"
  },{
    "@type": "ListItem",
    "position": 3,
    "name": "Subsection2",
    "item": "https://example.org/sectiona/subsection2/"
  },{
    "@type": "ListItem",
    "position": 4,
    "name": "My Second Post",
    "item": "https://example.org/sectiona/subsection2/my-second-post/"
  }]
}
</script>

<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "name": "Home",
    "item": "https://example.org/"
  },{
    "@type": "ListItem",
    "position": 2,
    "name": "SectionA",
    "item": "https://example.org/sectiona/"
  },{
    "@type": "ListItem",
    "position": 3,
    "name": "Subsection1",
    "item": "https://example.org/sectiona/subsection1/"
  },{
    "@type": "ListItem",
    "position": 4,
    "name": "My Post",
    "item": "https://example.org/sectiona/subsection1/my-post/"
  }]
}
</script>

Thanks for the quick reply, much appreciated.

My goal is to get JSON-LD breadcrumb information for my three different content types:

  • Post pages (like /content/sectionA/subsection1/my-post.md)
  • ‘Subsection’ pages (such as /content/sectionA/subsection1/_index.md)
  • And the main section page (like /content/sectionA/_index.md)

My challenge is to write the proper Hugo code for this. I’m happy with three if code blocks to check the three content pages, as a workable solution.

Rendering the breadcrumbs JSON-LD for a single post is easy. For that I simply check:

{{ if and (ne .Section "") .IsPage }}

{{ end }}

But I cannot figure out how to differentiate between the main section and the ‘subsection’ pages in reliable. But I need to do that because the main section page has 2 breadcrumbs levels, and the subsection page 3.

Thanks again for your post. It made me think about the problem in a new way, and that led me to the solution.

Now I simply count how many URL parts there are, and use that to determine between the 3 different possible JSON-LD breadcrumbs.

It isn’t the most clean or best solution because there’s plenty of repetitive Hugo code, but it works and I’m quite happy with that. :slight_smile: Thanks!


Here’s what I currently use:

<!-- Breadcrumbs for articles -->
{{ $urlParts := sub (len (split .RelPermalink "/")) 2 }}

<!-- Post pages -->
{{ if eq $urlParts 3 }}
<script type="application/ld+json">
{
	"@context": "http://schema.org",
	"@type": "BreadcrumbList",
	"itemListElement": [{
		"@type": "ListItem",
		"position": 1,
		"name": "Site",
		"item": "{{ .Site.BaseURL }}"
	},{
		"@type": "ListItem",
		"position": 2,
		"name": "{{ .CurrentSection.Parent.Title }}",
		"item": "{{ .CurrentSection.Parent.Permalink }}"
	},{
		"@type": "ListItem",
		"position": 3,
		"name": "{{ .CurrentSection.Title }}",
		"item": "{{ .CurrentSection.Permalink }}"
	},{
		"@type": "ListItem",
		"position": 4,
		"name": "{{ .Title }}",
		"item": "{{ .Permalink }}"
	}]
}
</script>
<!-- Subsection pages -->
{{ else if eq $urlParts 2 }}
<script type="application/ld+json">
{
	"@context": "http://schema.org",
	"@type": "BreadcrumbList",
	"itemListElement": [{
		"@type": "ListItem",
		"position": 1,
		"name": "Site",
		"item": "{{ .Site.BaseURL }}"
	},{
		"@type": "ListItem",
		"position": 2,
		"name": "{{ .CurrentSection.Parent.Title }}",
		"item": "{{ .CurrentSection.Parent.Permalink }}"
	},{
		"@type": "ListItem",
		"position": 3,
		"name": "{{ .Title }}",
		"item": "{{ .Permalink }}"
	}]
}
</script>
<!-- Check for main section pages and meta pages (about, disclaimer) -->
{{ else if eq $urlParts 1 }}
<script type="application/ld+json">
{
	"@context": "http://schema.org",
	"@type": "BreadcrumbList",
	"itemListElement": [{
		"@type": "ListItem",
		"position": 1,
		"name": "Site",
		"item": "{{ .Site.BaseURL }}"
	},{
		"@type": "ListItem",
		"position": 2,
		"name": "{{ .Title }}",
		"item": "{{ .Permalink }}"
	}]
}
</script>
{{ end }}

Glad you have it working now :slightly_smiling_face:

1 Like