Twitter card and opengraph templates seem to be to not link images for leaf bundle articles

Hi everyone,

I’ve been trying to get the metadata done properly for sharing posts, and I have been using the inbuilt templates. However, I noticed the card images never worked, and dug down into the issue.

The summary of the issue is that if you define the images tag in your post markdown metadata, the twitter and opengraph templates will use it, but will not produce the correct paths for images.

Heres the first few lines of the metadata produced:

<link rel="canonical" href="https://blog.arenko.group/posts/2022-12-14-battery_infrastructure/">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://blog.arenko.group/cover.jpg">

This is almost right, but the | absURL in use does not actually give the correct URL. The image should be at

<meta name="twitter:image" content="https://blog.arenko.group/posts/2022-12-14-battery_infrastructure/cover.jpg">

Ive got a workaround in place by copy/pasting the twitter and opengraph templates, and manually building the path via {{ $img := (path.Join (path.Dir $page.Page.File.Path) ( index . 0 ) ) }}, however Im worried I’ve missed some easier config solution.

I note theres a previous forum post about this (Links for images, videos, audio in internal templates twitter_cards and opengraph - #4 by alexandros), but (like my solution), reimplementing the wheel feels clunky.

Please provide:

  • An example of your front matter
  • The path to where your images are stored

And please confirm that you are using this template:
https://github.com/gohugoio/hugo/blame/master/tpl/tplimpl/embedded/templates/twitter_cards.html

Thanks.

Hey mate, thanks for the quick response! I can confirm thats the right template. :slight_smile:

Here’s the layout and frontmatter for the post. Im following the leaf bundle layout of content from Page Bundles | Hugo

TLDR: Remove the images key from your front matter.


First, overriding the internal templates is by no means clunky. I view them as guides for creating my own. What they should do depends on the structure of your site, how you manage images, etc.

Second, I’ve reformatted the internal twitter card template with some warning messages so that you can see what parts of the code are exercised:

layouts/partials/twitter_cards.html
{{- with $.Params.images -}}
  {{ warnf "A" }}
  <meta name="twitter:card" content="summary_large_image"/>
  <meta name="twitter:image" content="{{ index . 0 | absURL }}"/>
{{ else -}}
  {{ warnf "B" }}
  {{- $images := $.Resources.ByType "image" -}}
  {{- $featured := $images.GetMatch "*feature*" -}}
  {{- if not $featured }}
    {{ warnf "C" }}
    {{ $featured = $images.GetMatch "{*cover*,*thumbnail*}" }}
  {{ end -}}
  {{- with $featured -}}
    {{ warnf "D" }}
    <meta name="twitter:card" content="summary_large_image"/>
    <meta name="twitter:image" content="{{ $featured.Permalink }}"/>
  {{- else -}}
    {{ warnf "E" }}
    {{- with $.Site.Params.images -}}
      {{ warnf "F" }}
      <meta name="twitter:card" content="summary_large_image"/>
      <meta name="twitter:image" content="{{ index . 0 | absURL }}"/>
    {{ else -}}
      {{ warnf "G" }}
      <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 -}}
  {{ warnf "H" }}
  <meta name="twitter:site" content="@{{ . }}"/>
{{ end -}}

Run this yourself by calling {{ partial "twitter_cards.html" . }} from the single page template, just so you can limit the usage to single pages. It would be even clearer if you only had one page to render.

With this structure…

content/
├── posts/
│   └── 2022-12-14-battery_infrastructure/
│       ├── cover.jpg
│       └── index.md
└── _index.md

… the modified template emits Warning A. If you read about the absURL function, you can see that it simply prepends the site’s baseURL to whatever path you provide. So it’s doing the right thing, but not giving you the result you want.

You could fix this in front matter with:

images = ['posts/2022-12-14-battery_infrastructure/cover.jpg']

But don’t. I suspect that reading the images array in front matter was to accommodate those who place their images in the static directory (opinion: don’t do that either).

Instead, remove the images key from your front matter, and build the site again. Now the modified template emits:

  • Warning B (there’s nothing in front matter)
  • Warning C (it didn’t find an image in your page bundle matching the *feature* pattern)
  • Warning D (it found an image in your page bundle matching the *cover* or *thumbnail* pattern)

Because it now has a page resource, it uses the .Permalink method to get the absolute URL. The .Permalink and .RelPermalink methods on page and global resources (in the assets directory) are always right. They consider the subdirectory (if any) from which the site is served, url values in front matter, slug values in front matter, permalinks in your site configuration, etc.

1 Like

Hi Joe!

Happy to report that, as you pointed out, my image names do match the featured GetMatch and it all looks good with the head metadata now. I’ve fixed up a few other places/shortcodes which were also using images frontmatter, and its a much more intuitive setup now.

Thanks for the assistance mate :slight_smile:

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.