cybrkyd

A Hugo word and code counter

 Mon, 21 Jul 2025 09:27 UTC
A Hugo word and code counter
Image: CC BY 4.0 by cybrkyd

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:

  1. Word Count (excluding code blocks);
  2. 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:

  1. Find all code blocks (marked by triple back ticks ```);
  2. For each code block, split it into lines and count them, subtracting 2 to exclude the opening and closing ``` lines.

For the word counting:

  1. Remove all code blocks from the content;
  2. 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.

»
Tagged in: #Hugo

Visitors: Loading...