How I Wish Hugo Partials Worked
Improving Hugo’s Code Snippets
As of v0.53 Hugo lacks support for code snippets which can be easily used in both templates and content files. Snippets serve this purpose for .md
content files and partials serve this purpose for .html
templates. But there is no universal format. If I want to make the same functionality available in both contexts, I have to first duplicate it, then make a few slight modifications.
Working example of a partial
One of my sites has a map block with most of the contact information hard coded. As you can see - only the heading and phone number use parameters - there was a requirement that these should change depending on the homepage language, but for the actual address I simply hard coded it.
<div class="widget__block map">
<h2>{{ .heading }} <i class="fas fa-car fa-lg"></i></h2>
<div class="widget__block--inner">
<div class="address__box">
<h3>Address</h3>
<address>
Korean United Methodist Church<br>
601 Tyler Rd NE<br>
Albuquerque, NM 87113
</address>
<h3>Directions</h3>
<div class="directions">
<a href="http://maps.apple.com/?address=601,Tyler+Rd,Albuquerque,New+Mexico">Apple Maps</a>
<a href="https://goo.gl/maps/FBwHxFDtaCo">Google Maps</a>
</div>
</div>
</div>
<p class="phone">{{ .phone | markdownify }}</p>
</div>
Currently, the map block is included with this line of code {{ partial “widget-map” .Params.contact }}
.
After learning how data files are used in Hugo I thought “this could be refactored into a generic map block and I would just define address, phone number, and map links in a data file…”
Unfortunately that means I would need to call it this way {{ partial “widget-map” (dict “context” $ “params” .Params.contact )}}
. It still looks relatively simple, but took me a long time to figure out. The key problem is that shortcodes and partials handle context differently. If you want to understand more, I have a whole post explaining what I learned about hugo shortcodes and partials.
In the process of untangling this, I started wondering, “what if I want to give users the ability to add an address box into any post?” That’s when I discovered that shortcodes cannot be used in templates and partials cannot be used in post content. I haven’t looked into the Hugo source code or spoken with anyone involved on the project, but I assume this is related to if not driven by the different ways of handling context. Or perhaps it is for easier testing, like you get with stateless functional components in React?
Proposed: better partial / shortcode all in one!
Making some guesses here, it seems that if partials utilized a passed context when it was provided, but define their own context as a fallback, they could be used as shortcodes. This might also eliminate the need to provide a global context in some cases, such as when a partial queries data files.
It might look something like this:
<!-- WARNING: untested code -->
{{ $data := $.Site.Data.company_globals }}
<div class="widget__block map">
{{ $heading := (or .heading "Default Map Heading" )}}
<h2>{{ $heading }} <i class="fas fa-car fa-lg"></i></h2>
<div class="widget__block--inner">
<div class="address__box">
<h3>Address</h3>
<address>
{{ $data.address }}
</address>
<h3>Directions</h3>
<div class="directions">
{{ with $data.map_links.apple }}
<a href="{{ . }}">Apple Maps</a>
{{ end }}
{{ with $data.map_links.google }}
<a href="{{ . }}">Google Maps</a>
{{ end }}
</div>
</div>
</div>
<p class="phone">
Or call us:
<a href="tel:+1-{{ $data.phone }}">{{ $data.phone }}</a>
</p>
</div>
The key pieces are lines 2 and 4. Now, wouldn’t that be nice?