ldeso
August 13, 2024, 11:55am
1
Hello,
I would like to render markdown posts with different heading levels depending on whether a post is seen from its own single page or from the home page.
I have tried to do this by setting a variable in a scratchpad that tracks a heading level offset, which is set to 0 on single pages and set to 1 on the home page.
The heading level is then modified accordingly in the file render-heading.html.
Unfortunately, this produces inconsistent random results on each build.
Minimum working example
Templates
File layouts/_default/baseof.html:<!DOCTYPE html>
<html lang="{{ site.Language.LanguageCode }}">
<head>
<meta charset="utf-8">
</head>
{{- block "main" . }}{{- end }}
</html>
File layouts/_default/single.html:{{- define "main" }}
{{- .Scratch.Set "offset" 0 }}
{{- .Content }}
<p>(single.html) .Scratch.Get "offset" = {{ .Scratch.Get "offset" }} (should be 0)
{{- end }}
File layouts/_default/home.html:{{- define "main" }}
{{- range .Paginator.Pages }}
{{- .Scratch.Set "offset" 1 }}
{{- .Content }}
<p>(home.html) .Scratch.Get "offset" = {{ .Scratch.Get "offset" }} (should be 1)
{{- end }}
{{- end }}
File layouts/_default/_markup/render-heading.html:{{- $offset := .Page.Scratch.Get "offset" }}
{{- $level := add .Level $offset }}
<h{{ $level }}>
<a class="Heading-link u-clickable" href="{{ .Page.RelPermalink }}">{{ safeHTML .Text }} (H{{ $level }})</a>
</h{{ $level }}>
<p>(render-heading.html) .Scratch.Get "offset" = {{ $offset }} (should be 0 on single page and 1 on home page)
Website built by Hugo v0.132.0
File index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="generator" content="Hugo 0.132.0">
<meta charset="utf-8">
</head>
<h2>
<a class="Heading-link u-clickable" href="/hugo-conditional-render-heading/post/1/">Heading (H2)</a>
</h2>
<p>(render-heading.html) .Scratch.Get "offset" = 1 (should be 0 on single page and 1 on home page)
<p>(home.html) .Scratch.Get "offset" = 0 (should be 1)
<h1>
<a class="Heading-link u-clickable" href="/hugo-conditional-render-heading/post/2/">Heading (H1)</a>
</h1>
<p>(render-heading.html) .Scratch.Get "offset" = 0 (should be 0 on single page and 1 on home page)
<p>(home.html) .Scratch.Get "offset" = 0 (should be 1)
</html>
File post/1/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<h2>
<a class="Heading-link u-clickable" href="/hugo-conditional-render-heading/post/1/">Heading (H2)</a>
</h2>
<p>(render-heading.html) .Scratch.Get "offset" = 1 (should be 0 on single page and 1 on home page)
<p>(single.html) .Scratch.Get "offset" = 0 (should be 0)
</html>
File post/2/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<h1>
<a class="Heading-link u-clickable" href="/hugo-conditional-render-heading/post/2/">Heading (H1)</a>
</h1>
<p>(render-heading.html) .Scratch.Get "offset" = 0 (should be 0 on single page and 1 on home page)
<p>(single.html) .Scratch.Get "offset" = 0 (should be 0)
</html>
Is there a way to do this using render hooks? If not, could this be possible by manipulating the home page content with regular expressions?
bep
August 13, 2024, 1:23pm
2
What about:
{{- $offset := cond .Page.IsHome 1 0 }}
ldeso
August 13, 2024, 1:33pm
3
Thank you for your answer @bep . With this change, the offset seems to always be 0, even on the home page:
File render-heading.html with your change
{{- $offset := cond .Page.IsHome 1 0 }}
{{- $level := add .Level $offset }}
<h{{ $level }}>
<a class="Heading-link u-clickable" href="{{ .Page.RelPermalink }}">{{ safeHTML .Text }} (H{{ $level }})</a>
</h{{ $level }}>
<p>(render-heading.html) .Scratch.Get "offset" = {{ $offset }} (should be 0 on single page and 1 on home page)
Resulting index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="generator" content="Hugo 0.132.0">
<meta charset="utf-8">
</head>
<h1>
<a class="Heading-link u-clickable" href="/hugo-conditional-render-heading/post/1/">Heading (H1)</a>
</h1>
<p>(render-heading.html) .Scratch.Get "offset" = 0 (should be 0 on single page and 1 on home page)
<p>(home.html) .Scratch.Get "offset" = 0 (should be 1)
<h1>
<a class="Heading-link u-clickable" href="/hugo-conditional-render-heading/post/2/">Heading (H1)</a>
</h1>
<p>(render-heading.html) .Scratch.Get "offset" = 0 (should be 0 on single page and 1 on home page)
<p>(home.html) .Scratch.Get "offset" = 0 (should be 1)
</html>
Resulting post/1/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<h1>
<a class="Heading-link u-clickable" href="/hugo-conditional-render-heading/post/1/">Heading (H1)</a>
</h1>
<p>(render-heading.html) .Scratch.Get "offset" = 0 (should be 0 on single page and 1 on home page)
<p>(single.html) .Scratch.Get "offset" = 0 (should be 0)
</html>
Resulting post/2/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<h1>
<a class="Heading-link u-clickable" href="/hugo-conditional-render-heading/post/2/">Heading (H1)</a>
</h1>
<p>(render-heading.html) .Scratch.Get "offset" = 0 (should be 0 on single page and 1 on home page)
<p>(single.html) .Scratch.Get "offset" = 0 (should be 0)
</html>
Any idea how to get the offset to be 0 on single pages and 1 on the home page?
bep
August 13, 2024, 1:38pm
4
OK, but note that I didn’t read your original code that carefully, so I’m not sure what offset you want to have on home page. The above means: Home => 1, others => 0.
But OK, reading your original code I see what happens.
The .Content
gets rendered once and cached, so there’s no simple way (that I can think of now) to have different headings for a given regular page when rendered on the home page vs on its own.
ldeso
August 13, 2024, 1:56pm
5
Thanks for taking the time to read my code.
The reason I would like to do this is because having several h1 elements on the same page used to be valid HTML5, but it was removed from the specification a couple of years ago (source , follow up ). Now, the specification says that each page should have a single h1 element.
For example, a spec-compliant home page may have this outline:
(h1) Site title
(h2) Post 1
(h3) Heading 1
(h3) Heading 2
(h2) Post 2
(h3) Heading 1
(h3) Heading 2
And a spec-compliant post, when viewed on its own, may have this outline:
(h1) Post 1
(h2) Heading 1
(h2) Heading 2
In my opinion, it would be quite nice if Hugo would allow to easily create such an outline. Should I create an issue for this feature that links to this post?
bep
August 13, 2024, 1:58pm
6
I agree that it would be useful, for several reasons.
I had a quick scan, and this issue should solve this:
opened 01:50PM - 21 Jun 21 UTC
Enhancement
https://github.com/gohugoio/hugo/issues/8670 might be a good opportunity to regr… oup content related methods into one object? Currently we have:
- `.FuzzyWordCount`
- `.RawContent`
- `.Plain`
- `.PlainWords`
- `. ReadingTime`
- `.ToC`
- `.WordCount`
- `.ContentMap` (proposed)
Ideally while still supporting the above, we could have:
- `.Content.Raw`
- `.Content.Plain`
- `.Content.PlainWords`
- `.Content.WordCount`
- `.Content.WordCountFuzzy`
- `.Content.ReadingTime`
- `.Content.Rendered` (alias for `.Content`)
- `.Content.TableOfContent`
- `.Content.Map`
Note that this could be done in steps when a current method name is changed or parameters/UX is improved.
My plan was to add a (optional) scope key to the .Contents
method, so you could do:
(.Contents "home").Render
Or something like that … It should not be too hard to add …
1 Like
bep
August 13, 2024, 6:44pm
7
1 Like
system
Closed
August 15, 2024, 6:44pm
8
This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.