Splitting .Content into sections based on header level

I’m using Algolia search for a large-ish documentation project and generating the search index JSON using Hugo itself (there are numerous great tutorials on how to do this). The barrier that I’m currently running into is that I’d like to split each documentation page into multiple “pages” based on the section header. So imagine splitting this Markdown…

---
title: My page
---

## Important

Here is some content.

### Kind of important

Some less important content.

…into this JSON for that specific page:

[
  {
    title: "My page",
    level: 2,
    header: "Important",
    content: "Here is some content."
  },
  {
    title: "My page",
    level: 3,
    header: "Kind of important",
    content: "Some less important content."
  }
]

The tricky part about this, of course, is that Hugo doesn’t really give you any native “hooks” to accomplish this (at least as far as I know!). The only way that I can think of would be via regex, but despite my best efforts and a lot of regex-related Googling I haven’t managed to split pages up in this fashion. Have any of you figured out a way to do this? Preferably in an elegant way? Are there any existing Hugo features (besides the regex functions) that might get me some of the way there?

Made a section shortcode and wrap it around each section in the markdown.

You could also separate the sections into their own markdown file in a content bundle then combine them in a template.

That solution definitely would work but unfortunately this is a large open source project and I think it would just be too tricky for potential contributors to figure out. Was hoping for an automated solution, though I suspect this may just be beyond Hugo’s grasp.

Really hacky but another thing you could try is to get the rawcontent, split it by something like \n# then as you’re looping though, add the # back and render it out.

If you work with page bundles you could put those chapters into sub-files and then with HTML create only the list page with all chapters and for your algolia content type all individual pages.

Like:

content/course/chapter1/index.md <-- course page
content/course/chapter1/text1.md <-- page section
content/course/chapter1/text2.md <-- page section
content/course/chapter1/text3.md <-- page section
content/course/chapter1/text4.md <-- page section
content/course/chapter1/text5.md <-- page section

layouts/_default/_markup/render-heading.html

{{ printf "<!-- end-chunk -->" | safeHTML }}
{{ printf "<!-- begin-chunk data-anchor=%q data-heading=%q data-level=%q data-permalink=%q data-title=%q -->" .Anchor .Text (string .Level) .Page.Permalink .Page.Title | safeHTML }}
<h{{ .Level }} id="{{ .Anchor | safeURL }}">{{ .Text | safeHTML }}</h{{ .Level }}>

template

{{ $chunks := slice }}

{{ range (findRE `(?s)<!-- begin-chunk.+?(?:<!-- end-chunk -->|$)` .Content) }}
  {{ $anchor := replaceRE `(?s).+data-anchor="(.+?)".+` "$1" . }}
  {{ $heading := replaceRE `(?s).+data-heading="(.+?)".+` "$1" . }}
  {{ $level := replaceRE `(?s).+data-level="(.+?)".+` "$1" . }}
  {{ $permalink := replaceRE `(?s).+data-permalink="(.+?)".+` "$1" . }}
  {{ $title := replaceRE `(?s).+data-title="(.+?)".+` "$1" . }}

  {{/* Result includes heading. */}}
  {{ $content := replaceRE `(?s)<!-- begin-chunk.+?-->(.+?)(?:<!-- end-chunk -->|$)` "$1" . }}
  {{/* Remove heading. */}}
  {{ $content = replaceRE `(?s)<h\d.*?>.*</h\d>(.+)` "$1" $content }}
  {{/* Remove leading and trailing newlines. */}}
  {{ $content = trim $content "\n" }}

  {{ $chunks = $chunks | append (dict
      "anchor" $anchor
      "content" $content
      "heading" $heading
      "level" (int $level)
      "permalink" $permalink
      "title" $title
    )
  }}
{{ end }}

<pre>{{ jsonify (dict "indent" "  ") $chunks }}</pre>
This produces something like:
[
  {
    "anchor": "section-1",
    "content": "\u003cp\u003eLorem voluptate ullamco consectetur consectetur labore dolor est nulla excepteur irure deserunt. Velit incididunt fugiat id eiusmod non elit excepteur ullamco Lorem cillum ipsum do esse dolore. Fugiat cillum laboris sint et dolor in culpa Lorem incididunt ex in irure. Ea occaecat aliquip consequat velit ipsum aliquip fugiat do ullamco fugiat consectetur. Elit culpa ut commodo sit aliquip Lorem consectetur occaecat reprehenderit ea velit ipsum incididunt magna. Consequat eu magna officia cillum velit incididunt et anim dolore duis consectetur duis. Adipisicing velit ea labore amet et elit minim Lorem.\u003c/p\u003e\n\u003cp\u003eElit culpa ut commodo sit aliquip Lorem consectetur occaecat reprehenderit ea velit ipsum incididunt magna. Consequat eu magna officia cillum velit incididunt et anim dolore duis consectetur duis. Adipisicing velit ea labore amet et elit minim Lorem.\u003c/p\u003e",
    "heading": "Section 1",
    "level": 2,
    "permalink": "http://example.org/articles/articles-0001/",
    "title": "Articles 0001"
  },
  {
    "anchor": "section-11",
    "content": "\u003cp\u003eEst sint elit commodo occaecat laboris nostrud consequat aliqua mollit dolore laborum fugiat cillum. Et deserunt deserunt voluptate Lorem aliquip sunt dolore. Aliqua culpa fugiat in incididunt labore velit occaecat Lorem adipisicing eu pariatur reprehenderit tempor nulla. Veniam deserunt Lorem aliquip labore mollit sit reprehenderit incididunt est ex veniam id ad laborum. Laborum esse ut duis eu occaecat aute labore amet. Cupidatat in adipisicing minim incididunt. Ullamco sint id voluptate anim id aliqua dolore pariatur fugiat in aliquip enim occaecat.\u003c/p\u003e\n\u003cp\u003eElit culpa ut commodo sit aliquip Lorem consectetur occaecat reprehenderit ea velit ipsum incididunt magna. Consequat eu magna officia cillum velit incididunt et anim dolore duis consectetur duis. Adipisicing velit ea labore amet et elit minim Lorem.\u003c/p\u003e",
    "heading": "Section 1.1",
    "level": 3,
    "permalink": "http://example.org/articles/articles-0001/",
    "title": "Articles 0001"
  },
  {
    "anchor": "section-12",
    "content": "\u003cp\u003eEst sint elit commodo occaecat laboris nostrud consequat aliqua mollit dolore laborum fugiat cillum. Et deserunt deserunt voluptate Lorem aliquip sunt dolore. Aliqua culpa fugiat in incididunt labore velit occaecat Lorem adipisicing eu pariatur reprehenderit tempor nulla. Veniam deserunt Lorem aliquip labore mollit sit reprehenderit incididunt est ex veniam id ad laborum. Laborum esse ut duis eu occaecat aute labore amet. Cupidatat in adipisicing minim incididunt. Ullamco sint id voluptate anim id aliqua dolore pariatur fugiat in aliquip enim occaecat.\u003c/p\u003e\n\u003cp\u003eElit culpa ut commodo sit aliquip Lorem consectetur occaecat reprehenderit ea velit ipsum incididunt magna. Consequat eu magna officia cillum velit incididunt et anim dolore duis consectetur duis. Adipisicing velit ea labore amet et elit minim Lorem.\u003c/p\u003e",
    "heading": "Section 1.2",
    "level": 3,
    "permalink": "http://example.org/articles/articles-0001/",
    "title": "Articles 0001"
  },
  {
    "anchor": "section-2",
    "content": "\u003cp\u003eEst sint elit commodo occaecat laboris nostrud consequat aliqua mollit dolore laborum fugiat cillum. Et deserunt deserunt voluptate Lorem aliquip sunt dolore. Aliqua culpa fugiat in incididunt labore velit occaecat Lorem adipisicing eu pariatur reprehenderit tempor nulla. Veniam deserunt Lorem aliquip labore mollit sit reprehenderit incididunt est ex veniam id ad laborum. Laborum esse ut duis eu occaecat aute labore amet. Cupidatat in adipisicing minim incididunt. Ullamco sint id voluptate anim id aliqua dolore pariatur fugiat in aliquip enim occaecat.\u003c/p\u003e\n\u003cp\u003eElit culpa ut commodo sit aliquip Lorem consectetur occaecat reprehenderit ea velit ipsum incididunt magna. Consequat eu magna officia cillum velit incididunt et anim dolore duis consectetur duis. Adipisicing velit ea labore amet et elit minim Lorem.\nAs all the species of the same genus are supposed, on my theory, to have descended from a common parent, it might be expected that they would occasionally vary in an analogous manner; so that a variety of one species would resemble in some of its characters another species; this other species being on my view only a well-marked and permanent variety. But characters thus gained would probably be of an unimportant nature, for the presence of all important characters will be governed by natural selection, in accordance with the diverse habits of the species, and will not be left to the mutual action of the conditions of life and of a similar inherited constitution. It might further be expected that the species of the same genus would occasionally exhibit reversions to lost ancestral characters. As, however, we never know the exact character of the common ancestor of a group, we could not distinguish these twocases: if, for instance, we did not know that the rock-pigeon was not feather-footed or turn-crowned, we could not have told, whether these characters in our domestic breeds were reversions or only analogous variations; but we might have inferred that the blueness was a case of reversion, from the number of the markings, which are correlated with the blue tint, and which it does not appear probable would all appear together from simple variation. More especially we might have inferred this, from the blue colour and marks so often appearing when distinct breeds of diverse colours are crossed. Hence, though under nature it must generally be left doubtful, what cases are reversions to an anciently existing character, and what are new but analogous variations, yet we ought, on my theory, sometimes to find the varying offspring of a species assuming characters (either from reversion or from analogous variation) which already occur in some other members of the same group. And this undoubtedly is the case in nature.\u003c/p\u003e\n\u003cp\u003eA considerable part of the difficulty in recognising a variable species in our systematic works, is due to its varieties mocking, as it were, some of the other species of the same genus. A considerable catalogue, also, could be given of forms intermediate between two other forms, which themselves must be doubtfully ranked as either varieties or species; and this shows, unless all these forms be considered as independently created species, that the one in varying has assumed some of the characters of the other, so as to produce the intermediate form. But the best evidence is afforded by parts or organs of an important and uniform nature occasionally varying so as to acquire, in some degree, the character of the same part or organ in an allied species. I have collected a long list of such cases; but here, as before, I lie under a great disadvantage in not being able to give them. I can only repeat that such cases certainly do occur, and seem to me very remarkable.\u003c/p\u003e\n\u003cp\u003eI will, however, give one curious and complex case, not indeed as affecting any important character, but from occurring in several species of the same genus, partly under domestication and partly under nature. It is a case apparently of reversion. The ass not rarely has very distinct transverse bars on its legs, like those on the legs of the zebra: it has been asserted that these are plainest in the foal, and from inquiries which I have made, I believe this to be true. It has also been asserted that the stripe on each shoulder is sometimes double. The shoulder-stripe is certainly very variable in length and outline. A white ass, but \u003cem\u003enot\u003c/em\u003e an albino, has been described without either spinal or shoulder stripe; and these stripes are sometimes very obscure, or actually quite lost, in dark-coloured asses. The koulan of Pallas is said to have been seen with a double shoulder-stripe. The hemionus has no shoulder-stripe; but traces of it, as stated by Mr. Blyth and others, occasionally appear: and I have been informed by Colonel Poole that the foals of this species are generally striped on the legs, and faintly on the shoulder. The quagga, though so plainly barred like a zebra over the body, is without bars on the legs; but Dr. Gray has figured one specimen with very distinct zebra-like bars on the hocks.\u003c/p\u003e",
    "heading": "Section 2",
    "level": 2,
    "permalink": "http://example.org/articles/articles-0001/",
    "title": "Articles 0001"
  }
]

For a 1000 page site, this approach increased the build time from 0.5s to 1.8s.

6 Likes