Adding Sequence IDs to Hugo Post Filenames

Published: 2022 May 29

system administration Linux Bash shell script software development web development static site generator Hugo

Background

This project is built with Hugo and uses the Minimal Hugo theme.

Currently, when new posts are created with the hugo new <file_name> command, a new file is created named with the file_name parameter passed to the command. With the help of the post archetype file, that filename is also used to create the post title.

That approach is fine for a small number of posts, but as the number of posts grows it becomes harder to find a specific post when looking, because files are sorted alphabetically by filename, which isn’t particularly helpful in many cases.

Objective

In this post we’re going to alter the post creation process to prepend a unique sequence ID to each filename so that posts are sorted by their creation order.

Building the solution

In a previous post we developed a Bash script that helps with the Hugo post creation process that we can use as a starting point to build our updated solution.

Also in a previous post, we developed a script for creating unique sequence IDs, which we can also use in our updated solution.

Updating the file creating script

Step 0: Original script

The original hugo-new.sh script from a previous post (linked above) is below:

#!/bin/bash

# VARIABLES
directoryofhugoproject=/home/user/hugo-project-directory
subdirectoryofcontent=article/
input_parameters=$@

# MAIN program flow
echo
echo "Executing $BASH_SOURCE"
echo

new_post_name=${input_parameters// /-}.md
new_post_path_and_name="$subdirectoryofcontent$new_post_name"

echo "For input parameters: $input_parameters"
echo
echo "Creating file: $new_post_path_and_name"
echo "In the Hugo project directory: $directoryofhugoproject"
echo

cd $directoryofhugoproject

hugo new $new_post_path_and_name

Step 1: Refactoring to move post creation logic into a function

We’ll start by moving the logic for Hugo post creation into a function and adding comments to explain each step.

#!/bin/bash

# VARIABLES
directoryofhugoproject=/home/user/hugo-project-directory
subdirectoryofcontent=article/
input_parameters=$@

# FUNCTION - hugo_post_creation
# Creates the file name from the input parameter string separated by dashes and appended with ".md", outputs the input values, and creates the new post in the directory specified in the "directoryofhugoproject" variable.
hugo_post_creation() {

	# Takes the input parameter string, replaces spaces with dashes ("-"), and assigns it to the "new_post_title" variable.
	new_post_name=${input_parameters// /-}.md
	
	# Concatenates the new post subdirectory and new_post_name and assigns it to the variable "new_post_path_and_name".
	new_post_path_and_name="$subdirectoryofcontent$new_post_name"

	# Outputs contextual information.
	echo "For input parameters: $input_parameters"
	echo "Creating file: $new_post_path_and_name"
	echo "In the Hugo project directory: $directoryofhugoproject"
	echo

	# Change directory to the specified directory for the Hugo project.
	cd $directoryofhugoproject

	# Creates a new Hugo post in the specified subdirectory with the specified post name.
	hugo new $new_post_path_and_name

	echo

}

# MAIN program flow
echo
echo "Executing $BASH_SOURCE"
echo

hugo_post_creation

With the exception of a few echo commands that were rearranged to make the output easier to read, this script is functionally identical to the original.

Step 2: Refactoring to move outputting of script info into a function

Next, we’ll update the logic for outputting script info by replacing it with a function we use in other scripts.

The altered lines are highlighted.

#!/bin/bash

# VARIABLES
directoryofhugoproject=/home/user/hugo-project-directory
subdirectoryofcontent=article/
input_parameters=$@

# FUNCTION script_info
# Prints contextual output about the script.
script_info() {
	echo
	echo
	
	echo
	echo
	echo =============================================================
	echo ==================== script info - START ====================
	echo
	echo "Executing $BASH_SOURCE"
	echo
	echo "This script creates a new Hugo post with a seqid followed by the input parameter string."
	echo
	echo ===================== script info - END =====================
	echo =============================================================
	echo
	echo
}

# FUNCTION - hugo_post_creation
# Creates the file name from the input parameter string separated by dashes and appended with ".md", outputs the input values, and creates the new post in the directory specified in the "directoryofhugoproject" variable.
hugo_post_creation() {

	# Takes the input parameter string, replaces spaces with dashes ("-"), and assigns it to the "new_post_title" variable.
	new_post_name=${input_parameters// /-}.md
	
	# Concatenates the new post subdirectory and new_post_name and assigns it to the variable "new_post_path_and_name".
	new_post_path_and_name="$subdirectoryofcontent$new_post_name"

	# Outputs contextual information.
	echo "For input parameters: $input_parameters"
	echo "Creating file: $new_post_path_and_name"
	echo "In the Hugo project directory: $directoryofhugoproject"
	echo

	# Change directory to the specified directory for the Hugo project.
	cd $directoryofhugoproject

	# Creates a new Hugo post in the specified subdirectory with the specified post name.
	hugo new $new_post_path_and_name

	echo

}

# MAIN program flow
script_info

hugo_post_creation

These changes only update the script’s visual output and leave the rest of the script’s logic unchanged.

Step 3: Adding logic to incorporate an incrementing sequence ID

Next, we’ll incorporate the logic that we developed previously for getting an incremented sequence ID and prepend that seqID to the post filename.

The altered lines are highlighted.

#!/bin/bash

# VARIABLES
directoryofhugoproject=/home/user/hugo-project-directory
subdirectoryofcontent=article/

filepath_of_persistent_counter=/home/user/variables/counter_next_Hugo_post.txt

input_parameters=$@

# FUNCTION script_info
# Prints contextual output about the script.
script_info() {
	echo
	echo
	
	echo
	echo
	echo =============================================================
	echo ==================== script info - START ====================
	echo
	echo "Executing $BASH_SOURCE"
	echo
	echo "This script creates a new Hugo post with a seqid followed by the input parameter string."
	echo
	echo ===================== script info - END =====================
	echo =============================================================
	echo
	echo
}

# FUNCTION - incrementer
# Reads the first line from the persistent counter file, assigns it to the "next_seqid" variable, prints the next_seqid, increments the next_seqid by 1, and overwrites the persistent counter file with the new value.
incrementer() {

	# Read the first line of the specified file into the "next_seqid" variable.
	read next_seqid < "$filepath_of_persistent_counter"

	# Echo the contents of the "next_seqid" variable.
	echo "The next seqid is: $next_seqid"

	# Add 1 to the contents of the "next_seqid" variable and store the result in the "plus_one" variable.
	plus_one=$((next_seqid+1))

	# Overwrite the specified file with the contents of the "plus_one" variable.
	echo $plus_one > $filepath_of_persistent_counter

}

# FUNCTION - hugo_post_creation
# Assembles the file name from the latest next_seqid and the input parameter string separated by dashes and appended with ".md", outputs the input values, and creates the new post in the directory specified in the "directoryofhugoproject" variable.
hugo_post_creation() {

	# Takes the input parameter string, replaces spaces with dashes ("-"), and assigns it to the "new_post_title" variable.
	new_post_title=${input_parameters// /-}
	
	# Pads the seqid with leading zeroes if the seqid is less than 3 digits.
	padded_seqid=`printf "%03d" $next_seqid`
	
	# Concatenates the next_seqid, the new_post_title, and ".md" and assigns it to the variable "new_post_name" variable.
	new_post_name=$padded_seqid-$new_post_title.md
	
	# Concatenates the new post subdirectory and new_post_name and assigns it to the variable "new_post_path_and_name".
	new_post_path_and_name="$subdirectoryofcontent$new_post_name"

	# Outputs contextual information.
	echo "For input parameters: $input_parameters"
	echo "Creating file: $new_post_path_and_name"
	echo "In the Hugo project directory: $directoryofhugoproject"
	echo

	# Change directory to the specified directory for the Hugo project.
	cd $directoryofhugoproject

	# Creates a new Hugo post in the specified subdirectory with the specified post name.
	hugo new $new_post_path_and_name

	echo

}

# MAIN program flow
script_info

incrementer && hugo_post_creation

The only syntax new to this project is the printf command, which is a Bash Builtin command. There are a lot of ways to use printf, but to pad a decimal number with leading zeroes we just use the format "%03d" to pad up to three characters.

These updates allow the hugo-new.sh script to create a new Hugo post with a filename prepended with a unique incremented seqID.

Updating the Hugo project post archetype

Now that the post creation script is creating files with seqIDs in the filename, we need to update our Hugo project files to parse and use that information.

Specifically, we need to update the frontmatter section of the post.md file in the /archetypes/ directory.

Step 1: Updating creation of post titles

Previously, post titles were created directly from post filenames. But now filenames include a seqID that we want to exclude from the post title.

Currently, the title is created by replacing dashes in the .TranslationBaseName property with spaces via this line of code:

title: "{{ replace .TranslationBaseName "-" " " | title }}"

Because of the zero padding we added to seqIDs in our hugo-new.sh script, post filenames will always begin with ###-, which we don’t want to include in the post title. So, the only change we need to make to create the title from the updated format is first using slicestr to remove the first 4 characters (thanks to maiki for outlining this solution approach.) before passing it to the current process:

title: "{{ replace ( slicestr .TranslationBaseName 4 ) "-" " " | title }}"

Step 2: Adding post seqIDs

Next, we’ll add a field for post seqIDs to the frontmatter and we’ll again use slicestr - this time to select the first three characters of the filename.

seqid: {{slicestr .TranslationBaseName 0 3}}

Conclusion

We now have an updated Hugo post creation script and an updated post archetype working together to create new posts with the filenames, titles, and seqIDs in the formats that we want for the project.

Copying Directory Structure With a Bash Script - With Help From ChatGPT AI

Published: 2024 January 22

Setting Up a Raspberry Pi as a Linux Print Server with CUPS

Published: 2024 January 19

Setting Up a Raspberry Pi Zero 2 W with Ubuntu Server

Published: 2024 January 04