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.html
inthemes/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.Site
are defined in theconfig.toml
file$
are defined in the templateI don’t enough about the details but it looks like the most common variable like
Title
andDescription
have “shortcuts” (i.e you access them simply with.Title
/.Site.Title
and.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:title
tag with the name of site (.Site.Title
refers to thetitle
key inconfig.toml
)og:type
tag of type “website”.description
tag with the description of the site (.Site.Params.description
refers to thedescription
key from theparams
section defined inconfig.toml
)If the page is not the homepage:
og:title
tag with the name of the post (.Title
refers to thetitle
key at the top of the post) and the name of the site (.Site.Title
refers to thetitle
key inconfig.toml
)description
key is defined on the post, add it asdescription
key.Adding tags
We do have
og:title
. We want to add:og:description
: support for description, the currentdescription
tag isn’t pulled asog:description
.twitter:creator
andtwitter:site
: twitter handles of the site/authortwitter:card
andog:image
: the type of twitter card and image addressPost description with
og:description
In the current template, a
description
tag is already added. Note that if there is no description for the post, nodescription
tag is added.We want (1) to add logic for
og:description
tag and (2) to add a default description for when no description was written for the post.Add logic for
og:description
Rather than using the
{{ if eq .URL "/" }}
twice we will wrap everything in the firstif
statement.Add default for
og:description
What happen if the post has no description? We could write an
if
statement to check first if there is adescription
key ({{ if .Description }}...
), but we can also provide adefault
, which goes like{{ variable-name | default default-value }}
. To avoid writing thedefault-value
twice (for tagsdescription
andog:description
), we can store it in a Go template variable.Below we create the, on ”. Then we add it as default for the tags
$defaultDescription
variable, defined as a string “Article posted byog:description
anddescription
.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
twitterAuthor
andtwitterSite
into theparams
section ofconfig.toml
and 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:card
Three scenarios:
summary
card (small image) with the site logo as image.summary
card with the site logo as image.summary_large_image
card (image should be on a size ratio 2x1).In the default template, the site logo is located in
https://<site-url>/images
with a name defined inconfig.toml
(see theparams.logo
section) and accessible via.Site.params.logo.url
variable.For images, I place them all in a dir called
img
instatic
. So I refer them in posts with/img/myimagefile.jpg
. At the top of the post, I can add a metadata key namedtwitterImg
and 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: