Automating Hugo New Posts

This is one of those notes that’s irrelevant to about 99 percent of readers. Skip to the next one. But maybe you found this through Google search. I spent ages hunting for this Hugo automation trick and figured I’d jot it down before I forget.

Publishing to the web with Hugo works brilliantly. If I was still wrestling with WordPress, I’d never create this many notes. My setup lets me write notes anywhere (with internet) in simple Markdown files, then publish with a single command.

Faster, simpler Hugo posts

One thing still felt clunky: creating the text file. From the terminal, you can run

hugo new posts/somefile.md

This creates a new file and Hugo helpfully inserts front matter. But if you want specific front matter, you’re diving deep into your theme’s folders to customise the archetype. I’ve done this before, but it’s fiddly. And I’m not always at the terminal.

The alternative is firing up an editor (I use Visual Studio Code everywhere) and creating a new file. But then there’s no Hugo front matter and I have to open an existing file to copy the front matter across. Tedious and time-consuming.

A short script makes it easier

Make it easy to take it easy: I needed a bash script to quickly create a note in the right folder with my chosen name and my front matter.

After some digging, I found a script by Sebastien Taggart. He uses the Academic theme, which structures Hugo posts like this: each post gets its own directory. Inside that directory sits an index.md file and a subfolder for images, videos, and PDFs. Looks like this:

/content/posts/directory-name

/content/posts/directory-name/index.md

/content/posts/directory-name/assets

The approach: you’re in your website directory and simply type ./new “Directory Name”. The script creates a new directory in content/posts with that name, drops in an index.md file with your front matter, plus an /assets/ folder. Then you just edit index.md and upload to your server. I use a simple deploy script to my Uberspace.

Hugo New Post in /content/posts/content/index.md

You can check out Sebastian’s script - he’s commented it well. Here’s my version, tweaked for my needs.

What you do with it:

  1. Create a file called “new” (no extension) in your Hugo website’s main directory.
  2. Copy the following script into the file (with your adjustments, see comments).
  3. Make the script executable:

    chmod +x new

  4. Run the script:

    ./new “Your new directory name”

  5. If it worked, you should now have a new directory in /content/posts/ with your chosen name, containing an assets folder and the index.md file.
#!/bin/bash
 
TARGETDIR="./content/posts"
 
# Sanitize the input 
 
TITLE=${1} # take the input as-is for the Title before sanitizing for directory name 
SANIN=${1// /-} # replace spaces with dashes
SANIN=${SANIN//_/-} # replace underscores with dashes
SANIN=${SANIN//[^a-zA-Z0-9\-]/} # remove everything except alphanumeric or dash
 
# Your own Hugo Front Matter - adjust to your requirements
 
ISOTIME=$(date -u +'%Y-%m-%dT%H:%M:%SZ') 
PREFILLTPL="--- 
weight: 4 
title: "xxx"
date: 2021-
draft: true 
author: "Reiner"
authorLink: "https://reinergaertner.au" 
description: "xxx" 
 resources:
 - name: "featured-image" 
   src: "assets/" 
 - name: "featured-image-preview" 
   src: "assets/"

tags: ["xxx", "xxx"] 
categories: ["xxx"]
toc: false 
autoCollapseToc: false
lightgallery: true  ---
"
# Create File and prefill
if [[ ! -e "${TARGETDIR}/${SANIN}/" ]]; then
 mkdir -p "${TARGETDIR}/${SANIN}/assets/"
 touch "${TARGETDIR}/${SANIN}/index.md"
 echo "${PREFILLTPL}" >> "${TARGETDIR}/${SANIN}/index.md"
 
else 
   echo "The directory ${TARGETDIR}/${SANIN}/ already exists!  Aborting."
 
   exit 1 
fi

Hugo posts without subdirectories in /content/posts/whatever.md

Some templates are built differently and look directly in /content/posts for .md files. I’ve got a Hugo site like that too. I simplified this version in a few places. Just adjust the data in your front matter.

#!/bin/bash
TARGETDIR="./content/posts"

# Sanitize the input (we need this for the pre-filled template)
TITLE=${1} # take the input as-is for the Title before sanitizing for directory name
SANIN=${1// /-} # replace spaces with dashes
SANIN=${SANIN//_/-} # replace underscores with dashes
SANIN=${SANIN//[^a-zA-Z0-9\-]/} # remove everything except alphanumeric or dash

ISOTIME=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
 
# Pre-fill the new file with your own Front Matter below
PREFILLTPL="
---
title: "xxx"
date: 2021-xx
author: "Reiner"
authorLink: "https://reinergaertner.au"
description: "xxx"
license: ""
weight: 2
tags: ["xxx", "xxx"]
categories: ["xxx"]
hiddenFromHomePage: false
toc: false
autoCollapseToc: false
---
"
 
# Create file and prefill
touch "${TARGETDIR}/${SANIN}.md"
echo "${PREFILLTPL}" >> "${TARGETDIR}/${SANIN}.md"

exit 0

Happy Hugo blogging. Let me know if there’s room to optimise this script or if you’ve got other ideas. I’m just a script-daddy. This is about my limit.


This started life in German on reinergaertner.de, my blog since 1997. The English version was AI-assisted. My German-trained eyes may have missed a few things along the way. She’ll be right.