Exposing Table of Contents entries on .Page

There seem to be several issues and forum threads looking for more control over the presentation of the table of contents for a page. I threw together a PR 2852 which hooks into Blackfriday to get the headers in the page, and then exposes it as an array of entries in Page, allowing for a template to control how it is presented.

Does this make sense? If so, let me know what reasonable next steps would be.


The code and the feature itself makes sense – but we’ll have to think a little about this. We have added some custom hooks to Blackfriday and MMark in the past because adding them in markdown libraries themselves were not an option. But better ToC handling does belong in Blackfriday etc., and not in Hugo. We should be careful so we’re not ending up as maintainer of a markdown renderer with a very hard upgrade path to, say, Blackfriday 2.0.

Ah, that’s a reasonable concern. If I understand the concern, I think there are two parts – (1) ToC information becoming available directly which would obviate this code or (2) the hook going away or changing in signature.

I think the cleanest solution to (1) might be to separate the structs. One would be exposed on .Page and focused on being easy for templates to process. Let’s call it TocNode for now. The other would be built up by the header hook in Blackfriday. Let’s call this hookedTocNode (but happy to hear better names). The hookedTocNode wouldn’t be exposed, instead, there would be a method on the rendering context to get the TocNodes out.

The implementation in the PR then gets divided into recording these hookedTocNodes (possibly as a flat array) and extracting the cleaned up TocNode entries (replacing Clone). This allows the extract method to act as an adapter between the information produced by the renderer and the TocNode struct. If the markdown renderer changes to place the information somewhere else,

If Blackfriday 2.0 makes the ToC available more cleanly, we get rid of the hook and the hookedTocNode and change the implementation of the method for extracting the TocNode information out (eg., adapt Blackfriday’s ToC to the TocNode structure).

I think this also helps with problem (2) if the hook changes, as long as the information is still available somewhere then we’d just need to change the code to record information during rendering and extract the TocNode, but those changes are isolated to the hook and extraction.