Vanilla blogdown
This site is generated using the excellent Yihui Xie’s blogdown package. It also use the default theme, a fork of Jonathan Rutheiser’s lithium-theme for Hugo.
The theme doesn’t fully implement the <meta> tags necessary for creating cards on twitter. To see what tags are currently generated, we can check the template file head.html in themes/hugo-lithium-theme/layouts/partials/.
...
{{ if eq .URL "/" }}
<title>{{ .Site.Title }}</title>
<meta property="og:title" content="{{ .Site.Title }}">
<meta property="og:type" content="website">
{{ else }}
<title>{{ .Title }}{{ with .Params.subtitle }} - {{ . }} {{ end }} - {{ .Site.Title }}</title>
<meta property="og:title" content="{{ .Title }} - {{ .Site.Title }}">
{{ end }}
{{ if eq .URL "/" }}
<meta property="description" content="{{ .Site.Params.description }}">
{{ else }}
{{ if .Description }}
<meta property="description" content="{{ .Description }}">
{{ end }}
{{ end }}
...
In addition to normal HTML, the template uses Hugo templating syntax elements to get dynamic html output (everything between double curly brackets):
- Hugo variables to gather data about the site and the post, or to create your own reusable variables. There are different types of variables:
- variables starting with
. are defined in the top metadata of the page
- variables starting with
.Site are defined in the config.toml file
- variables starting with
$ are defined in the template
I don’t enough about the details but it looks like the most common variable like Title and Description have “shortcuts” (i.e you access them simply with .Title/.Site.Title and .Description), whereas other variable need .Params.
<!-- insert the title of the site between a <title> tag -->
<title>{{ .Site.Title }}</title>
<!-- insert the title of the post between a <title> tag -->
<title>{{ .Title }}</title>
<!-- insert the title stored in variable mytitle -->
{{ $defaultTitle := "This is a title" }}
<title>{{ $defaultTitle }}</title>
- if/else conditional to add different tags depending on a condition.
<!-- if the relative url of the page is "/", insert title "coconut" -->
{{ if eq .URL "/" }}
<title>coconut</title>
{{ end }}
<!-- if there is a "description" metadata on the post, insert it -->
<!-- in a "description" meta tag, otherwise insert default text -->
{{ if .Description }}
<meta property="description" content="{{ .Description }}">
{{ else }}
<meta property="description" content="Default description">
{{ end }}
Let’s deconstruct the Hugo templating syntax. I’ll keep it brief so, if it doesn’t make sense, read this introduction.
If the page is the homepage ({{ if eq .URL "/" }}):
{{ if eq .URL "/" }}
<title>{{ .Site.Title }}</title>
<meta property="og:title" content="{{ .Site.Title }}">
<meta property="og:type" content="website">
{{ else }}
...
{{ end }}
{{ if eq .URL "/" }}
<meta property="description" content="{{ .Site.Params.description }}">
{{ else }}
...
{{ end }}
- Add a
og:title tag with the name of site (.Site.Title refers to the title key in config.toml)
- Add a
og:type tag of type “website”.
- Add a
description tag with the description of the site (.Site.Params.description refers to the description key from the params section defined in config.toml)
If the page is not the homepage:
{{ if eq .URL "/" }}
...
{{ else }}
<title>{{ .Title }}{{ with .Params.subtitle }} - {{ . }} {{ end }} - {{ .Site.Title }}</title>
<meta property="og:title" content="{{ .Title }} - {{ .Site.Title }}">
{{ end }}
{{ if eq .URL "/" }}
...
{{ else }}
{{ if .Description }}
<meta property="description" content="{{ .Description }}">
{{ end }}
{{ end }}
- Add a
og:title tag with the name of the post (.Title refers to the title key at the top of the post) and the name of the site (.Site.Title refers to the title key in config.toml)
- Only if a
description key is defined on the post, add it as description key.
Social graph tags and blogdown
Vanilla blogdown
This site is generated using the excellent Yihui Xie’s blogdown package. It also use the default theme, a fork of Jonathan Rutheiser’s lithium-theme for Hugo.
The theme doesn’t fully implement the
<meta>tags necessary for creating cards on twitter. To see what tags are currently generated, we can check the template filehead.htmlinthemes/hugo-lithium-theme/layouts/partials/.In addition to normal HTML, the template uses Hugo templating syntax elements to get dynamic html output (everything between double curly brackets):
.are defined in the top metadata of the page.Siteare defined in theconfig.tomlfile$are defined in the templateI don’t enough about the details but it looks like the most common variable like
TitleandDescriptionhave “shortcuts” (i.e you access them simply with.Title/.Site.Titleand.Description), whereas other variable need.Params.Let’s deconstruct the Hugo templating syntax. I’ll keep it brief so, if it doesn’t make sense, read this introduction.
If the page is the homepage (
{{ if eq .URL "/" }}):og:titletag with the name of site (.Site.Titlerefers to thetitlekey inconfig.toml)og:typetag of type “website”.descriptiontag with the description of the site (.Site.Params.descriptionrefers to thedescriptionkey from theparamssection defined inconfig.toml)If the page is not the homepage:
og:titletag with the name of the post (.Titlerefers to thetitlekey at the top of the post) and the name of the site (.Site.Titlerefers to thetitlekey inconfig.toml)descriptionkey is defined on the post, add it asdescriptionkey.Adding tags
We do have
og:title. We want to add:og:description: support for description, the currentdescriptiontag isn’t pulled asog:description.twitter:creatorandtwitter:site: twitter handles of the site/authortwitter:cardandog:image: the type of twitter card and image addressPost description with
og:descriptionIn the current template, a
descriptiontag is already added. Note that if there is no description for the post, nodescriptiontag is added.We want (1) to add logic for
og:descriptiontag and (2) to add a default description for when no description was written for the post.Add logic for
og:descriptionRather than using the
{{ if eq .URL "/" }}twice we will wrap everything in the firstifstatement.Add default for
og:descriptionWhat happen if the post has no description? We could write an
ifstatement to check first if there is adescriptionkey ({{ if .Description }}...), but we can also provide adefault, which goes like{{ variable-name | default default-value }}. To avoid writing thedefault-valuetwice (for tagsdescriptionandog:description), we can store it in a Go template variable.Below we create the, on ”. Then we add it as default for the tags
$defaultDescriptionvariable, defined as a string “Article posted byog:descriptionanddescription.and in context:
Twitter creator and site
We could make twitter creator and site dependent of posts metadata if multiple authors were writing on your site. In this case, I just added two keys
twitterAuthorandtwitterSiteinto theparamssection ofconfig.tomland used this for all posts (i.e outside of the if/else homepage conditional).and in the template:
and in context:
Twitter card type with
twitter:cardThree scenarios:
summarycard (small image) with the site logo as image.summarycard with the site logo as image.summary_large_imagecard (image should be on a size ratio 2x1).In the default template, the site logo is located in
https://<site-url>/imageswith a name defined inconfig.toml(see theparams.logosection) and accessible via.Site.params.logo.urlvariable.For images, I place them all in a dir called
imginstatic. So I refer them in posts with/img/myimagefile.jpg. At the top of the post, I can add a metadata key namedtwitterImgand then refer to it in the template with.Params.twitterImg.A post metadata could look like this:
The template syntax would be something like:
and the final template:
Using the card validator, you can try your new cards: