An image of a phone with the Twitter Logo in front of an abstract background

Another slightly left-field post from me today, which follows directly from my previous post. Since transitioning the blog to Hugo, social sharing hasn’t been working in quite the way it should. I noticed this after sharing a link on Twitter only to find that the Twitter Card didn’t render in the way I’d become used to with WordPress. I’ll be honest, I’ve never really given any thought to how this works, assuming that this is just “native in the way various social media platforms interpret links. It turns out there’s actually (and perhaps unsurprisingly) a host of things that influence the format and content that gets pulled, all of which are done for you when you use a platform like WordPress (with a decent theme). Cue a lazy Saturday morning, the rabbit trail that is the internet, and I’m now much more informed.

I thought I’d take a moment to document my findings in the hope that it helps someone else down the line.

It’s all about the Meta…

The net result of my findings is that meta tags are all important. When you post a link to Twitter, LinkedIn, or various other sites there are attributes those sites look for that define how the media should be displayed. These are often (although not in all cases) based on the common “Open Graph” protocol, allowing developers to use a single set of “standard” properties that work consistently across different social platforms. These attributes set out the important characteristics of the media; the title, description, type of content, image that should be displayed, source URL etc.

That nice thumbnail and detail that gets generated when you post a link on LinkedIn or Facebook? That’s Open Graph in practice and you’ll see it used almost ubiquitously.

Take the (slightly edited) example below from BBC News:

<meta property="og:title" content="Home - BBC News">
<meta property="og:type" content="website">
<meta property="og:description" content="Visit BBC News for up-to-the-minute news, breaking news, video, audio and feature stories.">
<meta property="og:site_name" content="BBC News">
<meta property="og:locale" content="en_GB">
<meta property="article:author" content="">
<meta property="article:section" content="Home">
<meta property="og:url" content="">
<meta property="og:image" content="">

Some sites - Twitter being a prime example - have their own requirements. These allow further customisation of the way that media is presented. In the case of Twitter, “Cards” are used which are rendered based on proprietary meta tags. In some cases Twitter make use of Open Graph tags to assume content for these (saving the need to double up on tags, see here) but this isn’t always the case so you will often see Twitter specific tags listed alongside Open Graph metadata in source code.

The below extract is taken from the same BBC News page used above:

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@BBCNews">
<meta name="twitter:title" content="Home - BBC News">
<meta name="twitter:description" content="Visit BBC News for up-to-the-minute news, breaking news, video, audio and feature stories.">
<meta name="twitter:creator" content="@BBCNews">
<meta name="twitter:image:src" content="">
<meta name="twitter:image:alt" content="BBC News">
<meta name="twitter:domain" content="">

Why are these tags important? Well without them you can get some “odd” behaviour when posting links. In some cases you’ll see a basic interpretation of the link content in a vanilla format. Worst case you may find that content doesn’t present as a “media” entry at all - just an ugly, naked URL.

We all know and appreciate the importance of getting this right on social media. In a world of swiping and scrolling not standing out can be the difference between your content being noticed or not…

I mentioned above that some platforms, like WordPress, take care of meta tagging for you. This is also true of static site generators like Hugo, however the additional (relative) complexity of these solutions vs. “do it for you” services introduces margin for error and puts more emphasis on understanding how this metadata is generated in the background. For the most part with Hugo, metadata is generated based on the Front Matter defined in your input content and couples this with internal templates (not theme specific) to convert this into the required properties for social sharing.

Let’s look at some of the key properties needed to make this work “elegantly” with Twitter cards and the Hugo properties that feed them, specifically the “Summary Card with Large Image” option which provides the most prominent summary for Twitter sharing:

  • Title: Generated from the post name, typically set with the “title” property in front matter
  • Description: Automatically generated based on the post content, or set manually using th “description” property in front matter
  • Site: The Twitter user associated with the content, best set in the config.toml file (.Site.Social.twitter)
  • Image: The thumbnail to be used when sharing (required to use the “card with large image” option)

It’s worth referring to the internal template (twitter_cards) used to generate Twitter metadata which can be found here to explain some of these properties and how they are used in more detail:

{{- with $.Params.images -}}
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="{{ index . 0 | absURL }}"/>
{{ else -}}
{{- $images := $.Resources.ByType "image" -}}
{{- $featured := $images.GetMatch "*feature*" -}}
{{- if not $featured }}{{ $featured = $images.GetMatch "{*cover*,*thumbnail*}" }}{{ end -}}
{{- with $featured -}}
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="{{ $featured.Permalink }}"/>
{{- else -}}
{{- with $.Site.Params.images -}}
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="{{ index . 0 | absURL }}"/>
{{ else -}}
<meta name="twitter:card" content="summary"/>
{{- end -}}
{{- end -}}
{{- end }}
<meta name="twitter:title" content="{{ .Title }}"/>
<meta name="twitter:description" content="{{ with .Description }}{{ . }}{{ else }}{{if .IsPage}}{{ .Summary }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}{{ end -}}"/>
{{ with .Site.Social.twitter -}}
<meta name="twitter:site" content="@{{ . }}"/>
{{ end -}}
{{ range .Site.Authors }}
{{ with .twitter -}}
<meta name="twitter:creator" content="@{{ . }}"/>
{{ end -}}
{{ end -}}

Here, we can see exactly how Hugo generates the “twitter:” metadata, and how the decision is made as to which “card” type to use. This is based entirely on the presence of a suitable image which is identified by looking (in order) for the following:

  1. A specified image, defined in the front matter as noted above
  2. An image within the post content containing the word feature, cover, or thumbnail within the name
  3. An image specified within the site configuration (i.e. the config.toml file defining global site properties)

If any of the above are identified, the “twitter:card” tag is set to “summary_large_image”. In all other scenarios, this is set to “summary” which is far less prominent…

In my case, I’d not specified any of these so when sharing a post on Twitter only the summary card template was being used. In addition, the Open Graph “image” property wasn’t set - so sites other than Twitter depending on this value to render “rich” content may also have failed. I say “may” because some sites (for example, LinkedIn) will render images present within a post if they aren’t set explicitly in metadata. This caused me some extra head-scratching yesterday when I was trying to get to the bottom of what was happening with this site…

I’ve since modified my “posts” archetype so that my front matter is pre-populated with an “images” option for me to specify… hopefully preventing me from forgetting in future (or needing to remember to name my post images in a certain way). I will also be setting a fallback image in my site configuration, just in case. An example of the front matter I’m now defining is as follows:

title: "Migrating the Blog to GitHub and Hugo"
author: Kelvin Papp
type: posts
date: 2021-03-23T20:05:45Z
draft: false
toc: false
  - /img/2021/03/Hugo-Logo-Social.png
url: /migrating-the-blog-to-github-and-hugo/
  - Azure
  - Personal
  - Microsoft
  - Azure
  - Hugo
  - Blog

This results in the following tag creation for those interested:

<meta itemprop="name" content="Migrating the Blog to GitHub and Hugo">
<meta itemprop="description" content="Ever since I started the blog (two years ago today as it happens!) I've been using self-hosted WordPress as my platform of choice...">
<meta itemprop="datePublished" content="2021-03-23T20:05:45+00:00" />
<meta itemprop="dateModified" content="2021-03-23T20:05:45+00:00" />
<meta itemprop="wordCount" content="1213">
<meta itemprop="image" content="">
<meta itemprop="keywords" content="Azure,Hugo,Blog," />
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content=""/>
<meta name="twitter:title" content="Migrating the Blog to GitHub and Hugo"/>
<meta name="twitter:description" content="Ever since I started the blog (two years ago today as it happens!) I've been using self-hosted WordPress as my platform of choice..."/>
<meta name="twitter:site" content="@kelvinpapp"/>
<meta property="og:title" content="Migrating the Blog to GitHub and Hugo" />
<meta property="og:description" content="Ever since I started the blog (two years ago today as it happens!) I've been using self-hosted WordPress as my platform of choice..." />
<meta property="og:type" content="article" />
<meta property="og:url" content="" />
<meta property="og:image" content="" />
<meta property="article:published_time" content="2021-03-23T20:05:45+00:00" />
<meta property="article:modified_time" content="2021-03-23T20:05:45+00:00" />

Some useful tools…

I discovered, during my troubleshooting, that both LinkedIn and Twitter have validation tools which allow you to test how your media will present when used in posts on their sites… these are super useful and worth bearing in mind if you encounter issues like me…

They can be found as follows:

I hope this helps someone… a niggly issue for sure, but if you’re at all like me it’ll drive you mad to see links being posted with inane “summary” cards on Twitter, or appearing elsewhere with random images associated (or perhaps none at all!)! All power to the meta!