Hugo - angepasste Open Graph Integration

Open Graph ist ein Protokoll, mit dem sich beeinflussen lässt wie eine Webseite dargestellt wird, wenn sie auf Social Media geteilt wird. Über Meta Einträge im Head jeder Webseite kann man selber beeinflussen welche Daten dafür benutzt werden. In diesem Artikel beschreibe ich meine in einem Partial zusammengefassten Open Graph Meta-Tags.
Allgemeine Informationen zu Open Graph
Ursprünglich wurde Open Graph von Facebook entwickelt. Seither wurde es aber auch von anderen Social-Media-Kanälen wie Twitter, Pinterest und LinkedIn übernommen.
Die meisten Inhalte werden als URL auf Facebook und anderen (Open Graph Protokoll) OGP-unterstützenden Websites geteilt. Aus diesem Grund kann es nur positiv sein, wenn die eigene Website mit Open Graph Meta-Tags ausgestattet ist. Nur so hat man die Kontrolle, welche Inhalte dort angezeigt werden.
Da ich verstehen möchte was zu einer entsprechenden Ausgabe im Sourcecode führt und was für Möglichkeiten es gibt, habe ich mir unter anderem die folgenden Webseiten angeschaut:
Hugo Open Graph Template
Hugo stellt ein Template für die Integration der Open Graph Meta-Tags zur Verfügung. Das Template wird im Head aufgerufen und integriert die Meta-Tags. Wenn Sie das Template benutzen möchten reicht der folgende Aufruf:
{{ template "_internal/opengraph.html" . }}
Für ein besseres Verständnis was das Template so macht, gibt es eine Hugo Doku und einen Link zum Template Sourcecode:
Mein Partial ogData.html
Das Hugo Template ist für viele Einsatzzwecke konzipiert. Da ich nur die für meine Website angepassten Inhalte ausgeben möchte, habe ich Teile des Templates übernommen bzw. neu geschrieben. Dazu weiter unten mehr.
Das Partial ogData.html habe ich wie folgt im head
-Tag meiner baseof.html
eingebunden:
{{ partial "ogData" . }}
Der Sourcecode des Partials themes/tekki/layouts/partials/ogData.html
sieht wie folgt aus:
<meta property="og:title" content="{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} · {{ .Site.Title }}{{ end }}">
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}">
<meta property="og:description" content="{{ if .Description }}{{ .Description }}{{ else }}{{ .Site.Params.description }}{{ end }}">
<meta property="og:site_name" content="{{ .Site.Title }}">
<meta property="og:url" content="{{ .Permalink }}">
{{ if eq .Site.Language.Lang "de" }}
<meta property="og:locale" content="de_DE">
<meta property="og:locale:alternate" content="en_GB">
{{ else }}
<meta property="og:locale" content="en_GB">
<meta property="og:locale:alternate" content="de_DE">
{{ end }}
{{ if and (.IsPage) (ne .Section "") }}<meta property="article:section" content="{{ .Section }}">{{ end }}
{{ $iso8601 := "2006-01-02T15:04:05-07:00" }}
{{ with .PublishDate }}<meta property="article:published_time" {{ .Format $iso8601 | printf "content=%q" | safeHTMLAttr }}>{{ end }}
{{ with .Lastmod }}<meta property="article:modified_time" {{ .Format $iso8601 | printf "content=%q" | safeHTMLAttr }}>{{ end }}
{{ $image := .Resources.GetMatch "featured" }}
{{ with $image }}
<meta property="og:image" content="{{ .Permalink }}">
<meta property="og:image:secure_url" content="{{ .Permalink }}">
<meta property="og:image:type" content="{{ .MediaType }}">
<meta property="og:image:width" content="{{ .Width }}">
<meta property="og:image:height" content="{{ .Height }}">
<meta property="og:image:alt" content="{{ .Title }}">
{{ else }}
{{ $ogimage := resources.Get "tekki-tipps-og.png" }}
{{ with $ogimage }}
<meta property="og:image" content="{{ .Permalink }}">
<meta property="og:image:secure_url" content="{{ .Permalink }}">
<meta property="og:image:type" content="{{ .MediaType }}">
<meta property="og:image:width" content="{{ .Width }}">
<meta property="og:image:height" content="{{ .Height }}">
<meta property="og:image:alt" content="Blog about Hugo, web design, CSS/SCSS, SEO, Tools">
{{ end}}
{{ end }}
Zum besseren Verständnis werde ich jedes Meta-Tag einzelnd beschreiben.
meta property=“og:title”
<meta property="og:title" content="{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} · {{ .Site.Title }}{{ end }}">
Wenn die aktuelle Webseite die Startseite ist, wird der title
aus der hugo.toml
übernommen. Ansonsten, also für alle anderen Webseiten, wird der title
dem Front Matter Eintrag der aktuellen Webseite entnommen. Ein Bindestrich eingefügt und der title
aus der hugo.toml
angefügt.
Die Einträge der hugo.toml
für deutsch und englisch sehen wie folgt aus:
[languages]
[languages.de]
languageName = "Deutsch"
weight = 1
title = "tekki-tipps.de 🇩🇪"
description = "Blog über Hugo, Webdesign, CSS/SCSS, SEO, Tools"
..
..
[languages.en]
languageName = "English"
weight = 2
title = "tekki-tipps.de/en 🇬🇧"
description = "Blog about Hugo, web design, CSS/SCSS, SEO, Tools"
meta property=“og:type”
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}">
Auf meiner Website wird der og:type website
für die Startseite, die Tag-Cloud und auf Tag-Listen angezeigt. Also auf allen Übersichtslisten. Alle anderen Webseiten erhalten den og:type article
.
meta property=“og:description”
<meta property="og:description" content="{{ if .Description }}{{ .Description }}{{ else }}{{ .Site.Params.description }}{{ end }}">
Wenn die aktuelle Webseite im Front Matter eine description
hat, wird diese durch .Description
übernommen. Ansonsten wird die description
der hugo.toml
benutzt.
meta property=“og:site_name”
<meta property="og:site_name" content="{{ .Site.Title }}">
Der Title aus der hugo.toml
.
meta property=“og:url”
<meta property="og:url" content="{{ .Permalink }}">
Die permanente URL der aktuellen Webseite.
meta property=“og:locale” und “og:locale:alternate”
{{ if eq .Site.Language.Lang "de" }}
<meta property="og:locale" content="de_DE">
<meta property="og:locale:alternate" content="en_GB">
{{ else }}
<meta property="og:locale" content="en_GB">
<meta property="og:locale:alternate" content="de_DE">
{{ end }}
og:locale
definiert die Sprache der aktuellen Webseite. og:locale:alternate
teilt mit, dass für die aktuelle Webseite eine Übersetzung in einer alternativen Sprache vorhanden ist.
meta property=“article:section”
{{ if and (.IsPage) (ne .Section "") }}<meta property="article:section" content="{{ .Section }}">{{ end }}
Wenn die aktuelle Webseite eine Page ist und die .Section
kein leerer String ist, dann soll das Meta-Tag in den Head geschrieben werden. Auf meiner Website gibt es nur die Section blog
. Damit bei Webseiten die keine Section haben das Meta-Tag nicht in den Head geschrieben wird, erfolgt die Abfrage ob der String in .Section
leer ist.
meta property=“article:published_time” und article:modified_time
{{ $iso8601 := "2006-01-02T15:04:05-07:00" }}
{{ with .PublishDate }}<meta property="article:published_time" {{ .Format $iso8601 | printf "content=%q" | safeHTMLAttr }}>{{ end }}
{{ with .Lastmod }}<meta property="article:modified_time" {{ .Format $iso8601 | printf "content=%q" | safeHTMLAttr }}>{{ end }}
Die Übersichtsseiten - Startseite, Tag-Cloud und Tag-Listen - habe kein .PublishDate
deshalb die Abfrage. Alle anderen Webseiten haben eventuell noch kein .Lastmod
.
meta property=“og:image”
{{ $image := .Resources.GetMatch "featured" }}
{{ with $image }}
<meta property="og:image" content="{{ .Permalink }}">
<meta property="og:image:secure_url" content="{{ .Permalink }}">
<meta property="og:image:type" content="{{ .MediaType }}">
<meta property="og:image:width" content="{{ .Width }}">
<meta property="og:image:height" content="{{ .Height }}">
<meta property="og:image:alt" content="{{ .Title }}">
{{ else }}
{{ $ogimage := resources.Get "tekki-tipps-og.png" }}
{{ with $ogimage }}
<meta property="og:image" content="{{ .Permalink }}">
<meta property="og:image:secure_url" content="{{ .Permalink }}">
<meta property="og:image:type" content="{{ .MediaType }}">
<meta property="og:image:width" content="{{ .Width }}">
<meta property="og:image:height" content="{{ .Height }}">
<meta property="og:image:alt" content="Blog about Hugo, web design, CSS/SCSS, SEO, Tools">
{{ end}}
{{ end }}
Nun wird es etwas komplizierter. Deshalb muss ich etwas mehr erklären. Meine Webseiten sind multilingual in zwei Sprachen. Ich benutze PageBundles wegen der Übersichtlichkeit - alles für eine Webseite, in einem Verzeichnis. Die jeweiligen Bilder werden innerhalb des PageBundle Verzeichnis im img
-Verzeichnis gespeichert. Meine Blogbeitragsseiten haben ein Artikelbild und ein als featured
bezeichnetes Bild. Alle anderen Webseiten haben kein als featured
bezeichnetes Bild.
Im Front Matter für diese Webseite sehen die Einträge wie folgt aus:
resources:
- name: featured
src: img/featured.png
title: Customized Open Graph integration
- name: article-img
src: img/open-graph.png
title: Customized Open Graph integration
Mit .Resources.GetMatch
hole ich das als featured
bezeichnete Bild aus dem PageBundle und speicher es in der Variablen $image
. Wenn ein featured
Bild vorhanden ist, gebe ich die entsprechenden Meta-Tags für dieses Bild aus.
Wenn kein featured
Bild vorhanden ist, suche ich mit resources.Get
nach dem Bild tekki-tipps-og.png
und speicher es in der Variablen $ogimage
. Das Bild habe ich im static
Verzeichnis auf der obersten Ebene gespeichert.
Die Bilder sollten eine Auflösung von 1200px X 600px haben, damit auch auf hochauflösenden Bildschirmen ein gutes Bild angezeigt wird. Siehe dazu auch den oben genannten Facebook Link.
meta property=“og:image:secure_url”
Heutzutage gibt es ja kaum noch Websites die kein SSL-Zertifikat haben. Das Meta-Tag kommt noch aus einer anderen Zeit. Muss aber angegeben werden. Auch hier übergebe ich den .Permalink
des Bildes.
meta property=“og:image:type”
Ich benutze Bilddateien vom Typ png
und jpg
. png
sind von der Größe her kleiner, wenn ein großer Teil des Bildes die gleichen Farbanteile enthält. Der Typ wird durch .MediaType
automatisch festgestellt.
meta property=“og:image:width”
Mit .Width
wird die Breite des Bildes festgestellt.
meta property=“og:image:height”
Mit .Height
wird die Höhe des Bildes festgestellt.
meta property=“og:image:alt”
Bei den Blogbeiträgen entnehme ich den alternativen Text des Bildes aus dem Resource Title. Für alle anderen Webseiten, mit dem allgemeinen Bild, speicher ich meinen alt-Text manuell.
Kontrolle der Open Graph Parameter
Im head
des HTML-Sourcecodes kann man die entsprechenden Meta-Tags anschauen. Da ich die Open Graph Meta-Tags erst im nachhinein erstellt habe, ist es sehr aufwändig dies für jeden Beitrag und jeder Sprache zu kontrollieren.
Auch dafür gibt es eine Lösung - Browser Extensions. Für Safari habe ich gar keine Extension gefunden. Für Edge gibt eine Textlösung, aber der relevante Teil muss gescrollt werden. Da kann man sich dann auch den HTML-Sourcecode anschauen.
Für Firefox und Chrome gibt es entsprechende Extension. Das für Firefox finde ich hübscher und setze es auch ein:


Fazit
Ich habe keinen Facebook Account und kann deshalb die Weitergabe von Links innerhalb von Facebook nicht kontrollieren. Die Weitergabe meiner Kontaktadressen ist mir zu wertvoll um sie gezwungenermaßen mit Facebook zu teilen. Andere sehen dies anders und für diese Menschen habe ich die OG Meta-Tags integriert.
Linkliste zu diesem Beitrag
Kommentare werden bei deutscher Spracheinstellung nicht in der englischen Variante der Webseite angezeigt und umgekehrt.