Auto-count #100DaysToOffload posts
— Kaushal ModiLet Hugo do the counting of how far along I got into the #100DaysToOffload challenge.
I learned about the #100DaysToOffload challenge from my Mastodon stream about a month back. Motivated by that, this year I have now already written a lot more blog posts than my last two years combined My grand total number of posts from the last two years is zero, and this is my 5th post this year. 😆 .
Sidenotes using only CSS was the first post of my first #100DaysToOffload challenge that I started on . May be I will get to 100 posts by 🤞 .. Just may be. But regardless, I am already enjoying writing once again, and it’s great to see the Day count (counting up to 100) increase with each new post!
But it’s not fun to manually type that Day count in each post. This post is about a little Hugo templating code, a Hugo partial Think of a Hugo partial as a function which you can then call anywhere in your template or theme files (not in the content files like Org or Markdown). , that does that job for me 😎.
- Definition of this mission
- I want to have a line at the bottom of all posts reading “This is Day NN of #100DaysToOffload.”. But that should happen only for the posts with a 100DaysToOffload tag .
Day count stub at the bottom of each post #
So I defined a partial that would calculate that Day count, and then I called that partial at the bottom of my single The single template is the template that will be used to render the content from a single content file, like a post page.. like the page you are seeing right now. Compared to that, the list template is used to render “list” type pages like the home page, pages listing all the posts , all the tags , etc. template.
The template file for single pages is typically
layouts/_default/single.html
in the site or theme directory. Below
snippet is added towards the bottom of that template.
{{ $day := (partial "get-post-index-with-tag.html"
(dict "page" . "tag" "100DaysToOffload")) }}
{{ if (gt $day 0) }}
{{ printf `<small id="day-counter">This is <strong>Day %d</strong> of <a href="https://100daystooffload.com/">#100DaysToOffload</a>.</small>` $day | safeHTML }}
{{ end }}
Explanation of the above snippet:
- Partial
get-post-index-with-tag.html
is called with adict
type input (think of a map or associative array) with keyspage
andtag
. - This partial will return a number representing the chronological index of the current page in a pool of the specified tag.
- Almost always, you would want to pass the current page’s
context1 – the dot – to the called partial so that it
can extract useful metadata from the page’s context, like the page
parameters, content, etc. So the “.” or the current page context is
passed to the partial using the
page
key. - The
tag
key is “100DaysToOffload” as we want to know which number post is the current post with that specific tag. For example, this is the 5th post so far. - If the partial returns a non-zero value, The partial call will return a value of 0 if a page is not tagged that “tag” key’s value. the Day count line is printed with the shown HTML formatting.
get-post-index-with-tag.html
Partial #
Below is the definition of the partial. It is saved as
layouts/partials/get-post-index-with-tag.html
in the site or theme
directory.
|
|
The partial was passed in a map with keys “page” and “tag”. We save those to local variables
$page
and$tag
.On line 3, a local variable
$index
is initialized to -1. Later in the code (line 14), we increment this variable by 1 and return that. So, if$tag
is not found for a page,$index
+ 1 = 0 is returned.Line 4 checks if the current page’s tags front-matter has the
$tag
(which is set to “100DaysToOffload” in Code Snippet 1).In line 6, we get an object
$weighted_pages
that has a collection or list of all pages with the$tag
tag set. That list will contain the current page too.In line 7, we sort this filtered page list
$weighted_pages.Pages
by date using the.ByDate
method, and then loop through that. Here, we just get a list of all the posts with that$tag
. We don’t deal with cases like.. “What if I were on my second or later attempts of #100DaysToOffload challenge?”. I will deal with that when I need to, and then probably I will have a followup post for that 😄. In this line,$idx
is the loop counter variable, and$p
will hold the page item from the list.In line 8, the permalink of each page (
$p
) in that page list is compared with the current page’s permalink. When we find a match, we update the$index
variable with that loop counter variable’s value. This match must happen only once because all pages have unique permalinks. I would have liked to use abreak
statement once the first match was found, to avoid wasting time going through other pages in the list. But the Hugo/Go templating doesn’t have that feature.The list indices begin with 0. So if this were the first page in the date sorted list,
$index
would be set to 0. But “Day 0 of 100” would sound weird. So in line 14, we first increment the$index
value, and then return that.
Closing #
That’s it!
With that little partial defined and then called in the single.html layout file, you can see how the automatic Day count shows up below.
Happy Hugo Templating! 🎉
You can learn more about Hugo’s dot notion and page context from this wonderfully written post by Regis Philibert. ↩︎