Update - January 2022
As of Hugo version 0.91, this method no longer works. :(
Hugo introduced a new security policy, and the only argument that can be passed to Pandoc seems to be --mathjax
. Which of course, is the whole point of this article - to pass other options!
I am staying on version 0.90 for now, but will likely look for a long term solution down the road.
Some Context
I use a tool called Hugo to build this site. Hugo takes my Markdown-formatted blog posts, and converts them into HTML, a web-friendly format.
This conversion process works great. But for some blog posts, I need more control over how my content is rendered. For these cases, Hugo supports alternative rendering methods, including Pandoc.
The Problem…
The limitation, however, is that I can’t tell Hugo how to call Pandoc. Hugo will simply call pandoc --mathjax
. If I want to supply different options to Pandoc, then I’m out of luck.
With the official Hugo software, at least.
…and the Workaround
If you don’t mind a minor workaround, this GitHub comment shows us how to customize the Pandoc command Hugo calls. We essentially create a light wrapper around Hugo, and it only takes a few steps.
In this blog post, I’ll be walking you through his solution, and adding my own commentary on the side.
TL;DR: Read that GitHub comment, and if you are on Windows, swap out the Bash script for this.
Customizing Pandoc
Step One: Tell Hugo to use Pandoc
Add markup: "pandoc"
to your YAML frontmatter.
---
title: "My Blog Post"
date: "2021-03-21"
markup: "pandoc"
---
This blog post will be rendered with Pandoc.
And just like that, Hugo will use Pandoc. But we want to avoid Hugo’s built-in Pandoc command, so we’ll write our own.
Step Two: Write your Pandoc Command
Create a folder called bin
at the root of your Hugo project.
Place one of these two files in there – either pandoc.bat
for Windows users, or pandoc
for Linux/Mac users.
Windows
bin/pandoc.bat
@echo off
%PANDOC_ORIGINAL% --filter .\katex.py
Mac or Linux
bin/pandoc
#!/bin/bash
$PANDOC_ORIGINAL --filter ./katex.py
This is the pandoc
command Hugo will end up using, so modify it to suit your needs!
In my case, I use a filter to pre-render the math content on my blog.
Step Three: Create a light wrapper around Hugo
At the root of your project, create a file called hugo
.
hugo
#!/bin/bash
export PANDOC_ORIGINAL=$(which pandoc)
# Overrides pandoc.
PATH=$PWD/bin:$PATH
hugo "$@"
Step Four: Set permissions (Mac and Linux Only)
Setting executable permissions.
chmod +x hugo
chmod +x bin/pandoc
(I don’t think this is necessary on Windows.)
Step Five: Run your Hugo script
We’re done! Run these commands to test it out.
# Build the site
./hugo
# Start the dev server
./hugo server
We just need to call ./hugo
to invoke our script (rather than just hugo
), but everything else is identical. This includes the use of any subcommands or options the original Hugo takes.
How does this work?
When we created our Hugo wrapper in step three, we modified the PATH
.
The PATH
determines how the pandoc
command finds the actual “Pandoc” program. By putting our bin
folder first in the path, we are prioritizing our custom pandoc program (step two) over the “real” Pandoc.
So Hugo will end up calling our custom pandoc
, which of course just calls the “real” Pandoc with the arguments we want.
Conclusion
Whenever we depend on a tool, we are subject to both the features and constraints of that tool. Hugo is no exception. However, I’m glad we can leverage Pandoc with a fairly simple workaround, and still get to keep all the benefits of a static site generator.
Hopefully you’re now able to customize a bit more of how your content is rendered with Hugo.