Collecting my attempts to improve at tech, art, and life

Hugo Archetype Templates

Tags: hugo site bash tools

attachments/img/2017/cover-2017-07-01.png

I try out archetype templates from the Hugo static site generator, smoothing the whole thing into my workflow with a bash script.

Hugo Archetypes

Hugo archetypes are templates that Hugo uses when you tell it to create new content. Hugo allows both default archetypes and section archetypes for content that belongs in a particular section (such as Posts or Crafts).

As of release v0.24, archetypes are full templates. You can use variables and functions to fine-tune details of your archetype. This gives me a chance to simplify my content creation workflow.

My Default Archetype Template

My archetype focuses on front matter. Since the site sections share taxonomy rules, I use a single default archetype.

archetypes/default.md

---
title: "{{ replace .TranslationBaseName "-" " " | title }}"
date: {{ dateFormat "2006-01-02" .Date }}
year: "{{ dateFormat "2006" .Date }}"
draft: true
tags:
-
categories:
-
---
tl;dr
<!-- more -->

Notes

That’s good enough for hugo new. Since I have newContentEditor set to “vim” in my config, Hugo opens the new file in my editor after creating it.

$ hugo new post/2017/23-things-i-hate-about-lists.md

My workflow is a little more complicated than “create a draft and edit it” though.

My Workflow

I create and edit site content in its own git branch. With multiple drafts going at any one time, using separate branches lets me focus on the current content.

I follow these steps every time I add a new post.

  1. Create a branch
  2. Add a draft content file
  3. Start editing the draft file!

I can ignore the publishing part of the workflow for today, which involves running some tests and pushing to AWS S3. That deserves its own post.

I originally automated this with a small Ruby script which would create the branch and generate a content file for me. The file generating code is not needed now that Hugo archetypes are templates. My small, slightly clunky Ruby script can be replaced with a smaller, hopefully less clunky Bash script.

scripts/add

#!/usr/bin/env bash

# stricter bash
#  see http://redsymbol.net/articles/unofficial-bash-strict-mode/
set -euo pipefail
IFS=$'\n\t'

SECTION=${1:-}
TITLE=${2:-}

if [[ -z "$SECTION" || -z "$TITLE" ]]; then
  echo "Usage: $0 SECTION TITLE"
  exit 1
fi

TITLE_SLUG="$(echo -n "$TITLE" | sed -e 's/[^[:alnum:]]/-/g' | tr -s '-' | tr A-Z a-z)"
YEAR="$(date +"%Y")"
STUB="$SECTION/$YEAR/$TITLE_SLUG"

git checkout -b "$STUB"
hugo new "$STUB.md"
# newContentEditor set in Hugo config, expect Vim here.

Notes

Applying details like unofficial strict mode is part my process for getting more comfortable scripting Bash. The bit that’s important to me: this script fails loudly on encountering bad variables and bad processes.

The fun little slug-generating sed and tr pipe came directly from The Imposter’s Handbook. I know that I will lose punctuation and unusual capitalization between this and Hugo’s manipulation of .TranslationBaseName. It encourages me to keep titles simple. The title can edited in the front matter later if it is that important to me.

date comes from GNU Coreutils. I knew I could use date to get a simple description of the date. I recently discovered that it also accepts a format string! Turns out that GNU Coreutils gives the shell quite a bit of functionality that I usually ran to some programming language and its libraries for. Being self-taught produces weird gaps in my knowledge.

$ ./script/add post "23 Things I Hate About Lists"
Switched to a new branch 'post/2017/23-things-i-hate-about-lists'
/home/brian/Sites/rgb-hugo/content/post/2017/23-things-i-hate-about-lists.md created

Excuse me while I go write my masterpiece. Have fun!


Got a comment? A question? More of a comment than a question?

Talk to me about this page on:

Added to vault 2024-01-15. Updated on 2024-02-01