Summary .Render

Having decided that I needed a custom summary rendering solution, I started whipping up a shortcode before realizing that wouldn’t work since I was calling it from a partial. So I started creating a partial, but an interesting conversation with Vic Hudson convinced me to create an alternate layout to call with .Render instead.

More on that conversation later. First, my summary.html layout file:

<article>
    <header>
        <div class="post-title">
            <a href="{{ .Params.linkurl | default .RelPermalink }}">
                <h1 class="title">{{- if .Params.linkurl -}}<i
                        class="fas fa-link fa-sm"></i>&ensp;{{- end -}}{{ .Title }}{{- if .Params.linkurl -}}&emsp;<i
                        class="fas fa-external-link-alt fa-xs"></i>{{- end -}}</h1>
            </a>
        </div>
        <div class="post-meta">
            <div class="date">
                <span class="posted-on">
                    <i class="fas fa-calendar"></i>
                    <time datetime='{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}'>
                        <a
                            href="{{ .RelPermalink }}">{{ .Date.Format (.Site.Params.dateFormat | default "January 2, 2006" ) }}</a>
                    </time>
                </span>
            </div>
        </div>
    </header>
    <div>
        {{ if gt ( sub (len (plainify .Content)) (len .Summary)) 10 }}
        {{ .Content | replaceRE "<sup.+>.+</sup>" "" | safeHTML | truncate (len .Summary) }}
        <p><i>(<a href="{{ .RelPermalink }}">Read More</a>)</i></p>
        {{ else }}
        {{ .Content | safeHTML }}
        {{- end -}}
        {{- if .Params.linkurl -}}
        <p><a href="{{ .RelPermalink }}"><i class="fas fa-level-down-alt fa-xs"></i>&ensp;Permalink</a></p>
        {{- end -}}
    </div>
</article>

Most of that isn’t super interesting, but that’s the entire file. The work of getting the text I want in the summary happens in this section:

<div>
    {{ if gt ( sub (len (plainify .Content)) (len .Summary)) 10 }}
    {{ .Content | replaceRE "<sup.+>.+</sup>" "" | safeHTML | truncate (len .Summary) }}
    <p><i>(<a href="{{ .RelPermalink }}">Read More</a>)</i></p>
    {{ else }}
    {{ .Content | safeHTML }}
    {{- end -}}
    {{- if .Params.linkurl -}}
    <p><a href="{{ .RelPermalink }}"><i class="fas fa-level-down-alt fa-xs"></i>&ensp;Permalink</a></p>
    {{- end -}}
</div>

First up is an if statement that checks to see if the post even needs to be truncated into a summary or not, or whether it’s short enough to just show the whole post.

The criteria for truncating the post into a summary is that the length of the plaintext (HTML stripped out) article body needs to be 10 characters longer than the plaintext summary in the Hugo .Summary page variable. I added the extra 10 characters to avoid situations I was seeing where the entire post was shown in the summary but still awkwardly displayed a “Read More” link underneath.

If the summary test condition is met and I need to truncate it, first I strip out tags related to footnotes. The reason for this is footnotes don’t work unless the text of the footnotes, which is located at the bottom of the post, are included in the summary too. I didn’t want to mess with finding them and dragging them into my summary, so summaries don’t get footnotes.

Next I pass it through safeHTML and then use the hugo truncate function to truncate the post content to the same length of the hugo generated summary in .Summary. I pass it through safeHTML first so that truncate doesn’t escape the HTML tags.

I use truncate because it handles HTML intelligently and looks ahead to make sure it doesn’t rip off important closing tags that will affect the formatting for following content on the page, and that’s a feature I most definitely need and want.

I haven’t tested whether or not the truncate function counts the length including the HTML tags or just the length of the standard text, so I’m not sure if the result I get is the exact same length as what’s in the .Summary page variable, or an approximation that’s offset by the number of html tag characters. Either way, it works fine for me.

Sometime soon I’ll write about the .Render function and how smart my friend Vic is, but for now this is how you can get post summaries on a list page that include their HTML and paragraphs up to the point of truncation without breaking HTML and messing up the following page formatting.

Hit me up on Twitter if you know a better way to do this or there are things about Hugo I clearly don’t understand!