Table of Contents Render Hook

I am trying to do two things with the Table of Contents (ToC), neither of which seem to be possible without the existence of a Markdown render hook for the ToC.


Firstly, I would like to be able to parse multiple files for headings. For example, say I have a Page Bundle that looks like so:

foo/
├── index.md
├── appendices.md

Both index.md and appendices.md contain Markdown-formatted headings. Then, in my template, I have something like:

<section>
    {{ .Content }}
</section>
  
{{ if fileExists ( path.Join $.Page.File.Dir "appendices.md" ) }}
<section>
    <h2 id="appendices">Appendices</h2>
    {{ $file := path.Join $.Page.File.Dir "appendices.md" | readFile }}
    {{ $file | .RenderString }}
</section>
{{ end }}

Currently, .TableOfContents only takes into the account the headings in the index.md file. As a workaround, I’ve added a appendices field to the content front-matter where I list the headings, and then I manually add the second list after the call to .TableOfContents in my template, but an automated solution would be preferable (perhaps with some sort of .TableOfContents.ParseAdditionalHeadings method that would be provided a filepath, parse it for headings and then append them to the existing .TableOfContents tree).

There’s one unresolved six-year-old thread about being able to access the Table of Contents tree, but that’s all I found.


Secondly, none of the settings for autoHeadingIDType in the Goldmark config seem to be able to handle HTML within a Markdown heading. For example:

## Something with a <q>quote</q>

…will get converted to an anchor of #something-with-a-qquoteq.

It is possible to manually specify the desired ID (e.g., ## Something with a <q>quote</q> {#something-with-a-quote}), but I have a lot of content and an automated solution would be far preferable. If there were a render hook available, I could manually run the heading title through plainify when coming up with the IDs for the headings.

You are adding headings outside of .Content, so you will need to use something like tocbot (which works great).

Alternatively, you could use a shortcode to pull the supplemental material into .Content.

I don’t know anything about your project, but the vast majority of sites that I have seen (and I’ve see a lot), contain very few headings with markdown or HTML.

You can use a heading render hook to render the heading element however you want, but in that case you will have to use something like tocbot due to rendering sequence.

1 Like

You are going to the trouble of writing some html, why not just write the whole thing in html? Markdown is not intended to be a replacement for html.

Am I reading this correctly as a suggestion to use a shortcode within my content file to bring in the additional file, headings and all, and then the whole lot will be in .Content, which will be parsed to generate .TableOfContents?

A within-content-file shortcode would be an ideal solution (and solve a couple other minor issues I was facing with my approach), but as far as I can tell this doesn’t affect .TableOfContents; here’s an MRE and a screenshot of the result:

Fixing yours

content/blog/test.md

{{% extra-file %}}

layouts/shortcodes/extra-file.html

{{ path.Join $.Page.File.Dir "other-file.md" | readFile }}

Less fragile

content/
└── blog/
    └── test/
        ├── index.md        <-- use a page bundle
        └── other-file.md   <-- now it's a page resource

content/blog/test/index.md

{{% extra-file "other-file.md" %}}

layouts/shortcodes/extra-file.html

{{ $path := .Get 0 }}
{{ with .Page.Resources.Get $path }}
  {{ .RawContent }}
{{ else }}
  {{ errorf "The %q shortcode was unable to find %s. See %s" .Name $path .Position }}
{{ end }}

I’ve accepted this answer as it will work for many cases, but not in mine as my additional Markdown files contain shortcodes (but this would be solved if #7297 is ever implemented).

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.

A PR for Add .RenderShortcodes · Issue #7297 · gohugoio/hugo · GitHub Is now merged into the main branch and I suspect this will be something that people would want sooner rather than later, so I will push a new release early next week.

1 Like