Tag & Categories Cloud for Hugo

Tags and categories are a great choice for organizing content. In this post I’d like to show how to program a tag cloud for hugo, a static site generator.

When creating a page, the “tags” and “categories” taxonomy information is almost a default entry for every page created.

The following tag cloud code could be used either as “partial” (/partials/tag_cloud.html) or as a “shortcode” (/shortcodes/tag_cloud.html) whereas the code to produce the html output could be almost identical.

Remember: Shotcodes are to be used within markdown text directly, whereas partials are related to the pre-defined layout of the theme.

Source code

As mentioned the code in this use-case is identical for both use-cases, either as shortcode or as partial:

	--- shortcode/widgets/tag_cloud.html
		This code was inspired by the academic theme.
		Thanks to: George Cushen
		This function does not take any arguments into account.
		Read all "tags" and "categories" from the site's taxonomies
		and create a test cloud which can be used to navigate the site.
	(c) 2020, Johann Oberdorfer - Engineering Support | CAD | Software
	This source file is distributed under the MIT license.
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	See the MIT License for more details.

{{ $fontSmall := .Page.Params.design.font_size_min | default 0.9 }}
{{ $fontBig := .Page.Params.design.font_size_max | default 2.5 }}
{{ $fontDelta := sub $fontBig $fontSmall }}

{{/* read "tags"... */}}
{{ $data := .Site.Taxonomies.tags.ByCount }}

{{/* read "categories"
     and add this information to the data array... */}}

{{ $categories := .Site.Taxonomies.categories.ByCount }}
{{ if ne (len $categories) 0 }}
	{{ $data = $data | append $categories }}
{{ end }}

{{/* output goes here...  */}}

{{ if ne (len $data) 0 }}

	{{/* Warning:
			Hugo's `Reverse` function appears to operate in-place,
			hence the order of performing $max/$min matters.

	{{ $max := add (len (index $data 0).Pages) 1 }}
	{{ $min := len (index ($data).Reverse 0).Pages }}
	{{ $delta := sub $max $min }}
	{{ $fontStep := div $fontDelta $delta }}

	<div class="row" style="background-color:HoneyDew;padding:5px">
	<div class="heading text-center" style="margin-top: 5px;">

	<!-- unused for the moment:
	<div class="heading text-center" style="margin-top: 5px;">
		<h4><i class="icon-line-flag"></i> Categories: & <i class="icon-tag2"></i> Tags: </h4>

	<div class="col-12 text-center">

		<div class="tag-cloud">
		{{ range $item := (sort $data ".Page.Title" "asc") }}

			{{ $tagCount := len $item.Pages }}
			{{ $weight := div (sub (math.Log $tagCount) (math.Log $min)) (sub (math.Log $max) (math.Log $min)) }}
			{{ $fontSize := add $fontSmall (mul (sub $fontBig $fontSmall) $weight) }}

			<!-- class="button button-border button-mini button-border-thin button-blue button-circle" -->

			{{ if ne (upper .Page.Title) "ARCHIVED" }}
				<a href="{{ .Page.RelPermalink }}" style="font-size:{{ $fontSize }}rem">
					{{ .Page.Title | upper }}
					<span style="color: LightGrey; font-size:{{ $fontSmall }}rem"> ({{ $tagCount }}) </span>
			{{ end }}

		{{ end }}

{{ end }}


After copying the code and saving it to: shortcodes/widgets/tag_cloud.html the following line needs to be inserted into the markdown text whereever it’s suitable:

{{/* < widgets/tag_cloud > */}}

This will produce a tag cloud which e.g. could look like the following.
In our case, the tag cloud is based on the taxonomy of this site and therefore is “live” and fully functional.

That’s all.