I like a good statistic. I also miss the web-of-old with all those hit counters at the bottom of the page. Oh, so geeky!
My intention was to have a total post count along with a word and code counter. This website is built with Hugo, and while it does have built-in functionality to count posts and words, the word count includes everything on-page in the total. I needed a (i) word count less the code blocks, and (ii) a code-line count, taken from the code blocks. Complicated much?
Yes, but not really!
A Hugo word and code counter
On hugo v0.92.2+extended, this partial template calculates and displays two metrics for all posts in a Hugo website:
- Word Count (excluding code blocks);
- Lines of Code (only counting code blocks).
On line #4, we specify that only words from post
pages should be counted.
For the code-line counting:
- Find all code blocks (marked by triple back ticks ```);
- For each code block, split it into lines and count them, subtracting 2 to exclude the opening and closing ``` lines.
For the word counting:
- Remove all code blocks from the content;
- Count all word characters using regex \w+.
I would like the output properly formatted, so the lang.FormatNumberCustom 0
formats the numbers with thousands separators.
The partial
Create a new file /layouts/partials/content-stats.html
and add the following to it:
{{- $totalWords := 0 -}}
{{- $totalCodeLines := 0 -}}
{{- range where .Site.RegularPages "Section" "post" -}}
{{- $content := .RawContent -}}
{{/* === COUNT LINES OF CODE === */}}
{{- $codeBlocks := findRE "```[^`]*\\n[\\s\\S]*?```" $content -}}
{{- range $codeBlocks -}}
{{- $lines := split . "\n" -}}
{{- $totalCodeLines = add $totalCodeLines (sub (len $lines) 2) -}}
{{- end -}}
{{/* === COUNT WORDS (EXCLUDING CODE) === */}}
{{- $content = replaceRE "```[\\s\\S]*?```" "" $content -}}
{{- $totalWords = add $totalWords (len (findRE "\\w+" $content)) -}}
{{- end -}}
<span class="word-count">Words: {{ lang.FormatNumberCustom 0 $totalWords }}</span> •
<span class="code-lines">Lines of code: {{ lang.FormatNumberCustom 0 $totalCodeLines }}</span>
The footer:
For the total post count, I am using Hugo’s built-in functionality:
{{ len (where .Site.RegularPages "Section" "=" "post") }}
.
Because I want to have everything combined in one line, I added the following to my /layouts/partials/footer.html
file.
<p class="stats">Total posts: {{ len (where .Site.RegularPages "Section" "=" "post") }} • {{ partial "content-stats.html" . }}</p>
That concludes my simple, no-fuss solution to add stats the way I want them to my pages. The stats are captured at build-time and then pushed, so no need to run real-time Javascript functions for such an easy thing. Find those stats at the bottom of my pages.