Hugo Tag Could

I recently started to look at migrating this blog from WordPress to a static site engine. Hugo got my attention and I decided to try it out. One thing I have in WordPress is a tag cloud. I couldn’t find an example of how to create one with varying font sizes in Hugo, so I tried creating my own. Hugo discussion forum topics Weighted tag cloud and Tag Cloud talk about this.

Hugo is written in Go and thus uses Go templates. Go is a language I haven’t written a single line of code in, but I looked at how the tag cloud is implemented in WordPress and tried to steal the logic, see the function wp_generate_tag_cloud. Here is what I came up with:

Update 2017-07-03: Code is updated to solve an issue that would cause a crash when all posts have the same number of tags (causing a division by 0). Thanks to @MunifTanjim in the Hugo discussion thread Weighted tag cloud.

Update 2017-07-27: Artem Sidorenko posted an improved version of this code where he uses logarithmic distribution for calculation of tag sizes. It doesn’t make a big difference with my current content, but clearly does on his, so maybe on yours too.

 1{{- if gt (len .Site.Taxonomies.tags) 0 -}}
 2    {{- $fontUnit := "rem" -}}
 3    {{- $largestFontSize := 1.8 -}}
 4    {{- $smallestFontSize := 1.0 -}}
 5    {{- $fontSizeSpread := sub $largestFontSize $smallestFontSize -}}
 6    <!--<div>Font size unit: {{ $fontUnit }}</div>
 7    <div>Font min size: {{ $smallestFontSize }}</div>
 8    <div>Font max size: {{ $largestFontSize }}</div>
 9    <div>Font size spread: {{ $fontSizeSpread }}</div>-->
10
11    {{- $maxCount := 1 -}}
12    <!--<div>Max tag count: {{ $maxCount }}</div>-->
13
14    {{- $minCount := 1 -}}
15    <!--<div>Min tag count: {{ $minCount }}</div>-->
16
17    {{- $countSpread := sub $maxCount $minCount -}}
18    <!--<div>Tag count spread: {{ $countSpread }}</div>-->
19
20    {{- $.Scratch.Set "sizeStep" 0 -}}
21    {{- if gt $countSpread 0 -}}
22        {{- $.Scratch.Set "sizeStep" ( div $fontSizeSpread $countSpread ) -}}
23    {{- end -}}
24    {{- $sizeStep := ( $.Scratch.Get "sizeStep" ) -}}
25    <!--<div>Font step: {{ $sizeStep }}</div>-->
26
27    <div class="widget">
28        <div class="widget-title">Tags</div>
29        <div class="tag-cloud-tags widget-content">
30        {{- range $name, $taxonomy := $.Site.Taxonomies.tags -}} 
31            {{- $currentTagCount := len $taxonomy.Pages -}}
32            {{- $currentFontSize := (add $smallestFontSize (mul (sub $currentTagCount $minCount) $sizeStep) ) -}}
33            <!--Current font size: {{$currentFontSize}}-->
34            <a href="{{ "/tags/" | relLangURL }}{{ $name | urlize }}" aria-label="{{ $name }} ({{$currentTagCount}} posts)" style="font-size:{{$currentFontSize}}{{$fontUnit}}">{{- $name -}}</a>
35        {{- end -}}
36        </div>
37    </div>
38{{- end -}}

You can uncomment the commented lines for debugging. Also, if the tag keys instead of the tag names are rendered, set preserveTaxonomyNames = true in your config.toml or preserveTaxonomyNames: true in your config.yaml file. This took a while for me as a beginner to figure out.

No matching posts found. You can use wildcards and search only in titles, e.g. title:iot
Loading search index, please try again in a few seconds.
Index has completed downloading. Please search again.