I have content with hardcoded numbers in headings e.g 1. Hugo is great. Since the numbers appear in heading IDs and TOC links, I want to strip these out. What’s the Hugo way to do it?
Use markdown attributes to change the heading id attributes:
## 6. Section A {#section-a}
## 7. Section B {#section-b}
## 42. Section C {#section-c}
Then (optionally) use a regex to remove the numbers from the link text in the table of contents:
{{ .TableOfContents | strings.ReplaceRE `>\d+\.\s(.+)</a>` ">$1</a>" | safeHTML }}
The result is:
<nav id="TableOfContents">
<ul>
<li><a href="#section-a">Section A</a></li>
<li><a href="#section-b">Section B</a></li>
<li><a href="#section-c">Section C</a></li>
</ul>
</nav>
<h2 id="section-a">6. Section A</h2>
<h2 id="section-b">7. Section B</h2>
<h2 id="section-c">42. Section C</h2>
Rendered:
I don’t have that privilege because much of the content goes back 10 years.
Other than passing .Content through an ugly regex, which you really don’t want to do, I don’t have any other suggestions.
This addressed the IDs in headings (suggested by ChatGPT)
{{/* Get the raw text of the heading */}}
{{ $text := .Text | plainify }}
{{/* Clean the text for the id: remove leading numbers + dot + space (e.g. "1. Foo" → "Foo") */}}
{{ $cleanID := replaceRE `^[0-9]+\. ` "" $text | urlize }}
<h{{ .Level }}
id="{{ $cleanID }}"
{{- range $k, $v := .Attributes -}}{{- printf " %s=%q" $k $v | safeHTMLAttr -}}{{- end }}
>
{{ .Text | safeHTML }}
</h{{ .Level }}>
The TOC is the ‘culprit’ here now since it parses the headings rather than IDs for href.
I should clarify I just need to strip the number from ID and href. The rest of the automated id is okay.
As expected, because you can’t change the underlying id in a heading render hook. See https://github.com/gohugoio/hugo/issues/8383.
So if you’re going to change the rendered id in a heading render hook, you’ll have to pass the rendered TOC through yet another regex… yuck. Are you really sure you want to do this?
OK, I guess this isn’t so bad…
{{ .TableOfContents |
strings.ReplaceRE `>\d+\.\s(.+)</a>` ">$1</a>" |
strings.ReplaceRE `<a\shref="\#\d+-(.+)">` "<a href=\"$1\">" |
safeHTML
}}
I think "<a href=\"$1\">" should be "<a href=\"#$1\">", otherwise the TOC links return 404.
hugo --logLevel info
INFO timer: name HeadingRenderHook count 272 duration 17.629324ms average 64.813µs median 58.886µs
INFO timer: name TableOfContents count 431 duration 41.417421ms average 96.096µs median 10.542µs
I assume the time here is fast.
Yeah, I omitted the hash symbol. Should be:
{{ .TableOfContents |
strings.ReplaceRE `>\d+\.\s(.+)</a>` ">$1</a>" |
strings.ReplaceRE `<a\shref="\#\d+-(.+)">` "<a href=\"#$1\">" |
safeHTML
}}
And in the heading render hook you need to use anchorize not urlize, for example:
{{ $id := .PlainText | strings.ReplaceRE `^\d+\.\s` "" | urls.Anchorize }}
{{ $attr := merge .Attributes (dict "id" $id) }}
<h{{ .Level }}
{{- range $k, $v := $attr }}
{{- printf " %s=%q" $k $v | safeHTMLAttr }}
{{- end }}>
{{ .Text }}
</h{{ .Level }}>
The difference between the two functions is described here:
https://gohugo.io/functions/urls/anchorize/
Keep in mind that the above has no effect on Page.Fragments.
Perfect! Thanks. Btw, how is the anchor being added in the Hugo Docs on hover? I checked and there was no heading render hook.
JavaScript.
This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.
