Can I improve this code that writes all content to a single file?

I’ve been working on making a documentation site for a project using hugo. The HTML renders fine and I have a handle on that, but I’m trying to generate a PDF of the entire site.

My approach thus far is to render all the content into a single HTML file, then using weasyprint to transform the HTML to PDF.

You can find the here here, but the short of it is, I render all the content into the main index.html file. The template for index calls a partial that gets the pages by weight, then the children of the weighted pages, and recurses down the content tree.

The templates in question are:
content_gen.html:

<div id="body">
    {{ with .Site.GetPage "/" }}
        {{ range .Sections.ByWeight }}
            {{/* We don't want a menu item for specific pages listed here */}}
            {{ if (and (ne .Title "Posts") (ne .Title "Test Page")) }}
                <div class="section">
                    <h1 class="title">
			{{ .Title }}
		    </h1>
		    <div class="content">
			{{ .Content }}
		    </div>
                    {{ partial "content_recursive.html" . }}
                </div>
            {{ end }}
        {{ end }}
    {{ end }}
</div>

and content_recursive.html:

{{ range $child_pages.ByWeight }}
<div class="section">
    <h1 class="title">
	{{ .Title }}
    </h1>
    <div class="content">
	{{ .Content }}
    </div>
    {{ partial "content_recursive.html" . }}
</div>
{{ end }}

As of now, links to other pages and images don’t work, as the images are rendered as relative links and content links point to pages in the website.

Are there any improvements I can make here? Or a better strategy to render the content into one file?

1 Like

If you have control over the content you could use the ref shortcode to so you get Permalinks?

Or you could insert some logic into render-link and render-image templates so you get absolute urls instead of relative ones: https://gohugo.io/getting-started/configuration-markup#render-hook-templates

@pointyfar thank you for the pointer to the render-link and render-image templates. I’ve got the images working now.

For the links, since I’m writing all the content into one file, each link that is a relative link needs to be transformed to point at an anchor link. I had thought of doing {{ .Page.Title | urlize }} to generate the id, but since this is docs, we have a lot of pages in the content hierarchy that have the same name, such as “Overview.” When this is converted to the anchor id in the single page, the value is not unique. Do you have an ideas of how to make unique anchor ids in this instance? .Anchor is not available in this context.

I’m thinking of requiring id metadata in each page, and using that as the anchor link for each section. I’ve mostly done that using this template:

{{ $link := .Destination }}

{{ $isRemote := strings.HasPrefix $link "http" }}

{{- if not $isRemote -}}
{{ $url := urls.Parse .Destination }}
{{- if $url.Path -}}
{{ $fragment := "" }}
{{- with $url.Fragment }}{{ $fragment = printf "#%s" . }}{{ end -}}
{{- with .Page.GetPage $url.Path }}{{ $link = printf "%s%s" .Params.id $fragment }}{{ end }}{{ end -}}
{{- end -}}

{{ if $isRemote }}
<a href="{{ $link | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }} target="_blank">{{ .Text | safeHTML }}</a>
{{ else }}
<a href="#{{ $link | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}>{{ .Text | safeHTML }}</a>
{{ end }}

Are you aware of any tooling to check metadata in each page in the project and see if it is unique?

You could use the .Page's .File.UniqueID: https://gohugo.io/variables/files/

So something like (untested)

{{ $u := "" }}
{{ with .Page.File }}{{ $u = .UniqueID }}{{ end }}
{{ $id = print $u .Destination }}
1 Like

Success! So many thanks for your help @pointyfar!

Changing .Param.id in the above template to .Page.File.UniqueID does the trick!