Creating a new shortcode with Hugo

For those of you not familiar with Hugo, it’s the tool with which I’m generating this blog. Hugo is a static website engine similar to Jekyll or Hexo if you’re familiar with those. You write your content in markdown format, and it generates a set of static files, from which your blog is served. It’s written in Go and it’s very fast.

Just in case if you get featured on Reddit, Slashdot or Hackernews, this might be the difference between your server failing under high traffic, or smoothly delivering all the content to a larger than usual viewership. Static files mean a minimal CPU impact to your web server, so you can rest assured that it would take a very extraordinary event to kill your server, even if it’s not very new or fast.

There were many improvements that I did to Hugo, but most of them have just been made to handle certain social features that improve how this blog is shared, or to improve the look and feel of the blog. In fact, there’s an “About the author” section lower down on the page, where I collect peoples e-mails so I can notify them about new posts. This might be the only dynamic content on the page, your email is sent to an API via HTTPS and stored in a database. And a few times per month, I write an e-mail to you guys by hand and let you know of any new posts.

Hugo supports writing content plugins, or “shortcodes”, which enable you to embed external content or provide functionality in addition to the text content which you write. For example, I wrote a shortcode that makes it easy for people to tweet quotes from your article. You can see it in use like this:

"Adding a "Tweet this" shortcode to Hugo, step-by-step tutorial" via @TitPetric

Click to Tweet

The short code for this looks a little bit (exactly) like this:

There’s only a few steps to creating a shortcode like this.

Create the HTML snippet

In order to create a snippet, I needed to create a new template file for it. This template file needs to be created in the theme, saved into layouts/shortcodes/tweet.html. In case this folder doesn’t exists, you can create it.

As you can see, this HTML file is basically a standard Go html/template file. There are only a few notable things about this shortcode:

  1. I added a class .tweet-this so I can style the contents appropriately,
  2. The variable .Page.Permalink containes the link to the post which we want to share to twitter,
  3. Using {{ .Get 0 }} retrieves the first argument to the shortcode,

Depending on your theme, you might need to provide a Twitter icon. I am using FontAwesome. Using .tweet-this as the selector, we can style the widget we’re creating appropriately.

Styling the widget

Styling the widget is a bit more complex. Due to the theme this blog is using as a base, many CSS properties have a higher specificity than just referencing the .tweet-this class. We can solve this using only two possible approaches:

  1. We can increase CSS specificity by using more explicit selectors or IDs,
  2. We can use the !ignore keyword for our CSS properties to make them “sticky”.

Generally the second one is pretty bad practice, but unfortunately, the issue here is with the theme itself, which also doesn’t exactly follow best practices for writing CSS. Just in case you need a reminder how CSS specificity works, look at an older article of mine, CSS resets are broken. It’s just as true today as it was then.

.tweet-this {
	background: #fff;
	border: 1px solid #ccc;
	padding: 0.6em 1em;
	font-size: 1.3em;
}
.tweet-this > p {
	letter-spacing: 1px;
	line-height: 1.42 !important;
}
.tweet-this > p > a {
	text-decoration: none !important;
	color: #555 !important;
}
.tweet-this > p > a:hover {
	color: #333 !important;
}
.tweet-this > a {
	color: #55acee !important;
	text-decoration: none !important;
	display: block;
	text-align: right;
	font-size: 0.8em;
}
.tweet-this > a > i {
	margin-right: 0.3em;
	vertical-align: middle;
}

I am using a method called “nesting” to prevent the pollution to the global namespace. Unfortunately, I had to use a number of !important rules here to override defaults that apply to the article, but are unfortunately more specific. As I didn’t want to resort to IDs (#tweet-this) or similar, this does become somewhat of a best effort approach to style the widget within the current theme.

Conclusion

If you want to write a widget for Hugo, it’s very easy to do so. You might struggle with the finer points of Go template system if you want to take advantage of it, but if your widget can be represented in pure HTML and Javascript, then adding pretty much anything to your blog contents is possible. And here’s one more example of seeing our widget in action:

"Writing a Hugo Widget that lets readers share your content on Twitter" via @TitPetric

Click to Tweet

About the author

I'm the author of API Foundations in Go and 12 Factor Apps with Docker and Go. You should read both books if you want to learn more about Docker and Go. I'm currently writing The SaaS Handbook which more broadly deals with the subject of setting up a SaaS or product business.

I'm available for consulting / development jobs. Fixing bottlenecks and scaling services to cope with high traffic is my thing. I specialize in back-end development with a focus on providing back-end APIs for consumption in Angular, React, Vue.js and other front-end technology stacks.