How to have `urlize` behave like TOC/header ID?

I have a page on which I list articles, and each article links back to where it appears on that page. That page’s TOC is generated with:

{{ .TableOfContents }}

To have an article point back on the page where it is listed, I use in single.html:

<a href="/allarticles/#{{ index .Params.categories 1 | urlize }}">

This works fine in 95% of cases: the URL that is generated for the header on my ‘all articles page’ is the same that urlize makes. (And so refers to the same URL that TOC uses.)

But in edge cases the header ID is something else than urlize makes:

  • .NET -> page ID heading becomes #net, urlize makes it
  • Hello & bye -> page ID heading becomes #hello-bye, urlize comes up with #hello--bye.

I currently work around this by renaming my categories (so ‘hello & bye’ becomes ‘hello and bye’). But in the case of .NET I cannot drop the .: that would mean something else.

Is there a way to make urlize work like the URLs that the TOC and header IDs use?

The only workaround I can think of is to execute a {{ replace .TableofContents "#net" "" | safeHTML }} or vice versa if you run replace within .Content.

It seems that .TableOfContents and urlize produce IDs in a different way. Maybe you should create a Github issue. Maybe urlize should ignore dots or .TableOfContents should do the opposite. But then again I’m not sure if such a change would be a breaking change. Only the Hugo Devs on Github could tell.

Thanks for your reply. :slight_smile:

I was also thinking about such a thing, but that only grows over time (the & will need to be fixed too, and there are likely more). I can of course test each URL that I make with urlize with the different categories, but that’s a lot of manual work since they don’t show up as broken links.

I agree but from how I understand it, discussions should be kept on Discourse here and only clear bugs on GitHub. I don’t know if this is a bug or that urlize behaves like intended.

But what you’re asking is also a feature request: Make the generation of IDs with TableofContents follow the same pattern as the IDs generated with urlize or vice versa.

As you said above:

.NET -> page ID heading becomes #net with TableofContents, whereas urlize makes it

There is a missing dot in the id that is generated with TOC.

Looks like a fair request to post on Github to me. But then again maybe @bep could give you an answer right here.

I’ve made a GitHub issue here. I also added more cases in which urlize differs considerably compared with other Hugo/Blackfriday generated URLs.

Thanks for your help in this topic onedrawingperday. :slight_smile:

1 Like

@Jura since the Github Issue is unassigned and you’ve also helped me a lot in the past.

Here is how to do a multiple replace for these IDs. It’s an old trick involving dict

{{ $pairs := (dict "#net" "" "#hello-bye" "#hello--bye") }}
{{ $.Scratch.Set "specialTOC" .TableofContents }}
{{ range $key, $val := $pairs }}
 {{ $.Scratch.Set "specialTOC" (replace ($.Scratch.Get "specialTOC") $key $val) }}
{{ end }}
{{ $.Scratch.Get "specialTOC" | safeHTML }}

This is battle tested and I’ve used it for my own mischievous purposes before Page Bundles became available. :sunglasses:

The dict can have as many pairs as you need. You can modify it as you need. If you run into any issues just post them here.

Hope this helps until/if there is another kind of fix.

1 Like

Thanks @alexandros that’s very kind of you. :smile: I’ll try & adapt that code. :slight_smile:

Also very educational code, I wouldn’t have thought of this. Cool!

1 Like

From what I’ve seen Bjørn Erik has assigned the Github issue to himself and added it (for now) to the 0.33 milestone.

It will be more efficient to use the anchorize template function, whenever it becomes available. :wink:

1 Like

I have not assigned it to anyone, so it is an open game. It should be fairly straightforward to implement. Much simpler than the Liquorice func … :slight_smile:


I didn’t know that there’s a Hugo func for Scandinavian salt candy. LOL! :rofl:

1 Like