get rid of your twitter card tags

This commit is contained in:
Wouter Groeneveld 2022-11-27 10:13:41 +01:00
parent 7c3d650049
commit 76dd40f1ed
3 changed files with 203 additions and 97 deletions

View File

@ -0,0 +1,139 @@
---
title: Bloggers, Dump Your Twitter Card Tags
date: 2022-11-27T09:01:00+01:00
categories:
- webdesign
tags:
- html
- metadata
- blogging
---
It's astonishing how much influence a single company can have, even on the invisible part of the webdesign of your blog: the metadata. I still encounter countless sites---including my own, before cleaning up---that feel obliged to inject `<meta name="twitter:title">` tags in their `<head/>` segment of the HTML. Because otherwise the SEO isn't optimized, oh no! But since [Twitter has gone to shit](/post/2022/11/the-great-mastodon-influx/), I figure we don't need any tag or embed anymore that contains the term `twitter`.
To be honest, I wonder why we needed something like that in the first place. There are already countless of metadata systems out there that happily clog up bandwidth. Let's list a few:
### 1. Old school HTML tags
Remember these? The `<title/>` tag, together with the `<meta/>` tags named `keywords`, `description` and the optional viewport settings should be enough for any bot to get a first grasp on what the site is about. It baffles me that all proprietary newer systems push you to duplicate that information in their own version of a title or description tag, while that has been around for decades.
### 2. The Open Graph protocol
Arguably the most (in)famous, another one from a big company: the [Open Graph protocol](https://ogp.me/). Why they think it's important to us website builders:
> The Open Graph protocol enables any web page to become a rich object in a social graph. For instance, this is used on Facebook to allow any web page to have the same functionality as any other object on Facebook.
For this article, it looks like this:
```html
<meta property="og:site_name" content="Brain Baking">
<meta property="og:title" content="Bloggers, Dump Your Twitter Card Tags">
<meta property="og:description" content="It&rsquo;s astonishing how much influence one company can have, even on the invisible part of the …">
<meta property="og:url" content="https://brainbaking.com/post/2022/11/bloggers-dump-your-twitter-card-tags/" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://brainbaking.com/img/bblogo.png" />
```
As said before, why does `og:title` and `og:description` exist if there's a perfectly fine `<title/>` and description tag already in use? You can circumvent adding another description tag by adding that property to the previous meta tag. The attribute here is called "property" and not "name", meaning we can mix and match.
Meta's tags are not as bad as Twitter's---it's called `og:title` and not `facebook:title`. Furthermore, the OG "standard" has been adopted by other social media sites that want to display rich information for a link, such as LinkedIn, Mastodon, and Discord---even though nowadays they prefer yet another standard. Great!
Unfortunately, "adoption" also means "extension". For instance, Pinterest supposedly creates its own `og:` tags and makes use of the [semi-unofficial og:see_also tag](https://stackoverflow.com/questions/27913739/how-are-open-graph-ogsee-also-tags-intended-to-behave-in-facebook) that I used to support but easily adds 5+ lines of more junk and there's no sign of it on the official OG website, so I don't anymore.
### 3. LD+JSON
The JavaScript Object Notation for [Linked Data](https://json-ld.org/) should offer bots easier access to the gist of your article and help optimize search results. It's primarily used by search engines like Google and Bing to facilitate indexing since it's structured data. But it's still metadata that summarizes the content in very much the same way as the above Open Graph, which means that if you support both, you're serving bytes that contain a lot of **duplicate data**, which drives me crazy. Surely engineers at Google and Microsoft are smart enough to leverage existing other protocols?
For this article, it looks like this:
```js
{
"@context" : "https://schema.org",
"@type" : "BlogPosting",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://brainbaking.com/"
},
"articleSection" : "post",
"name" : "Bloggers, Dump Your Twitter Card Tags",
"description" : "It\u0026rsquo;s astonishing how much influence one company can have, even on the invisible part of the …",
"inLanguage" : "en-US",
"isFamilyFriendly": "true",
"image": "https://brainbaking.com/img/bblogo.png",
"author" : {
"@type": "Person",
"name": "Wouter Groeneveld"
},
"creator" : {
"@type": "Person",
"name": "Wouter Groeneveld"
},
"publisher": {
"@type": "Organization",
"name": "Brain Baking",
"url": "https://brainbaking.com/",
"logo": {
"@type": "ImageObject",
"url": "https://brainbaking.com/img/bblogo.png",
"width":"32",
"height":"32"
}
},
"accountablePerson" : "Wouter Groeneveld",
"copyrightHolder" : "Brain Baking",
"copyrightYear" : "2022",
"dateCreated": "2022-11-27T09:01:00+01:00",
"datePublished": "2022-11-27T09:01:00+01:00",
"dateModified": "2022-11-27T09:01:00+01:00",
"url" : "https://brainbaking.com/post/2022/11/bloggers-dump-your-twitter-card-tags/",
"wordCount" : "89",
"keywords" : [ "blogging","Bloggers, Dump Your Twitter Card Tags", "post" ]
}
```
That is _a lot_ of data, and I'm not even using half of the functionality---if you host a Wordpress site and optimize it with a plugin like Yoast, you'll be (most likely unconsciously) using twice as many properties. Great! *Sigh.* Since the schema supports nesting, you can add in comment sections, content within content, ... Don't forget to validate your JSON. Don't forget that Google has [its own validator](https://developers.google.com/search/docs/appearance/structured-data) that returns other warnings because it's Google.
We're not done yet.
### 4. Dublin Core metadata
Dublin what? The [Dublin Core Specification](https://www.dublincore.org/specifications/dublin-core/dc-html/), used by archivists and X/HTML enthusiasts, describes "DC-HTML" which can be added as metadata to hold... exactly the same information as the ones above.
For this article, it would look like this:
```html
<head prefix="dc: http://purl.org/dc/elements/1.1">
<meta property="dc:creator" itemprop="author" name="author" content="Wouter Groeneveld" />
<meta property="dc:date" itemprop="datePublished" name="date" content="2022-11-27T09:01:00+01:00" />
<meta property="dc:description" itemprop="description" name="description" content="It\u0026rsquo;s astonishing how much influence one company can have, even on the invisible part of the …" />
<meta property="dc:format" itemprop="encodingFormat" content="application/xhtml+xml" />
<meta property="dc:identifier" itemprop="sameAs url" content="https://brainbaking.com/post/2022/11/bloggers-dump-your-twitter-card-tags/" />
<meta property="dc:language" itemprop="inLanguage" content="en-US" />
<meta property="dc:publisher" itemprop="publisher" content="Brain Baking" />
<meta property="dc:subject" itemprop="keywords" name="keywords" content="blogging, post" />
<meta property="dc:title" itemprop="name" content="Bloggers, Dump Your Twitter Card Tags" />
<meta property="dc:type" content="text" />
</head>
```
Why would you use DC? The ultimate goal of the initiative is to create a digital "library card catalog" for the web, offering the above specialized properties to also help with indexing. In essence, the way I understand it, it's an alternative for JSON-LD, that is [heavily underused](https://w3techs.com/technologies/comparison/da-dublincore,da-jsonld) compared to JSON-LD.
DC goes way beyond cataloging and indexing web data: it is also widely used to describe a set of physical and non-web enabled digital resources.
Are we there yet? No.
### 5. Microformats
[Microformates](http://microformats.org/) adopt another strategy: re-use existing data that is already there by labeling them:
> Designed for humans first and machines second, microformats are a set of simple, open data formats built upon existing and widely adopted standards. Instead of throwing away what works today, microformats intend to solve simpler problems first by adapting to current behaviors and usage patterns.
Instead of adding junk in the `<head/>` tag, label specifics in your article body accordingly. An example can be found at https://microformats.io/ or just by looking at the source of this page. Author information is wrapped in a `h-card` class. Article content is identified by `e-content`. There's a slew of other tags available, but the gist is: don't add more junk! Except that you have to add junk classes to your existing tags. Hmm...
I've been critical about some of these tags before. For instance, `h-entry`, the "root", is useless: in 99% of the cases, there's supposed to be only one, so just machine-parse at the actual root: the `<html/>` tag. Then there's the ghost classes you easily mistake for genuine CSS classes. The biggest annoyance is having to redesign the structure of your page to be able to fit a `h-card` within an entry, making Microformats perhaps even a worse choice compared to slapping a few extra tags in your header and calling it a day. Do you want clutter up front or clutter in-between the rest?
---
Are we there yet? No---hi, [oEmbed](https://oembed.com/), sup?---but let's pull over here because my head is spinning.
Get rid of your `twitter:` metadata tags. It makes no sense to include the name of a (sinking) company instead of relying on a W3C-formalized standard to describe your metadata.

View File

@ -1,6 +1,6 @@
{{ $perm := .Permalink }}
{{ $base := .Site.BaseURL }}
{{ $logo := "img/bblogo.png" }}
{{- $isPost := eq .Section "post" -}}
{{- $perm := .Permalink -}}
{{- $base := .Site.BaseURL -}}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark light">
@ -10,71 +10,50 @@
<link rel="author" href="{{ $base }}humans.txt" type="text/plain" />
<link rel="webmention" href="{{ .Site.Params.webmentionServer }}/webmention" />
<link rel="pingback" href="{{ .Site.Params.webmentionServer }}/pingback" />
<!-- generate a thumbnail -->
{{- $logo := "img/bblogo.png" -}}
{{- $thumb := $logo | absURL -}}
{{- $match := findRE `!\[(.*)\]\((.+).(jpg|png|gif)` .RawContent 1 -}}
{{- range $match -}}
{{- $relthumb := replaceRE `!\[(.*)\]\(` "" . -}}
{{- if hasPrefix $relthumb "/" -}}
{{- $thumb = printf "%s%s" $base $relthumb -}}
{{- else -}}
{{- $thumb = printf "%s%s" $perm $relthumb -}}
{{- end -}}
{{- end -}}
<!-- determine description -->
{{- $description := printf "%s | %s" .Site.Title .Site.Params.description -}}
{{- if .Params.subtitle -}}
{{- $description = .Params.subtitle -}}
{{- else if .Summary -}}
{{- $description = .Summary | safeHTML | truncate 100 -}}
{{- end -}}
<!-- meta data tags, open graph -->
<meta name="twitter:title" content="{{ .Title }}" property="og:title">
{{ $isHomePage := eq .Title .Site.Title }}
{{ if .Params.subtitle }}
<meta name="description" content="{{ .Params.subtitle }}">
<meta name="twitter:description" content="{{ .Params.subtitle }}" property="og:description">
{{ else }}
{{ if .Summary }}
<meta name="description" content="{{ .Summary | safeHTML | truncate 50 }}">
<meta name="twitter:description" content="{{ .Summary | safeHTML | truncate 50 }}" property="og:description">
{{ else }}
<meta name="description" content="{{ .Site.Title }} | {{ .Site.Params.description }}">
<meta name="twitter:description" content="{{ .Site.Title }} | {{ .Site.Params.description }}" property="og:description">
{{ end }}
{{ end }}
{{ if .Keywords }}
<meta content="{{ delimit .Keywords ", " }}" name="keywords">
{{ else if .Params.tags }}
<meta content="{{ delimit .Params.tags ", " }}" name="keywords">
{{ end }}
<meta name="twitter:card" content="summary_large_image">
<meta property="og:site_name" content="{{ .Site.Title }}">
<meta property="og:title" content="{{ .Title }}">
<meta name="description" property="og:description" content="{{ $description }}">
<meta property="og:url" content="{{ $perm }}" />
<meta property="og:type" content="{{ if .Params.type }}{{ .Params.type }}{{ else }}website{{ end }}" />
{{ $thumb := $logo | absURL }}
{{ $match := findRE `!\[(.*)\]\((.+).(jpg|png|gif)` .RawContent 1 }}
{{ range $match }}
{{ $relthumb := replaceRE `!\[(.*)\]\(` "" . }}
{{ if hasPrefix $relthumb "/" }}
{{ $thumb = printf "%s%s" $base $relthumb }}
{{ else }}
{{ $thumb = printf "%s%s" $perm $relthumb }}
{{ end }}
{{ end }}
<meta name="twitter:image" property="og:image" content="{{ $thumb }}" />
{{ if .Params.subtitle }}
<meta name="twitter:image:alt" content="{{ .Params.subtitle }}">
{{ else }}
<meta name="twitter:image:alt" content="{{ .Summary | truncate 50 }}">
{{ end }}
<!-- zie sidebar.html, zelfde logica gebruikt -->
{{ $related := first 3 (where (where (where .Site.Pages.ByDate.Reverse ".Type" "==" "post") ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" $perm) }}
{{ if $related }}
{{ range $related }}
<meta property="og:see_also" content="{{ $perm }}" />
{{ end }}
{{ end }}
<meta property="og:type" content="{{ if $isPost }}article{{ else }}website{{ end }}" />
<meta property="og:image" content="{{ $thumb }}" />
<meta property="article:published_time" content="{{ .PublishDate }}" />
<meta property="article:modified_time" content="{{ .Date }}" />
<meta property="article:section" content="{{ .Section }}" />
{{ with .Params.tags }}{{ range first 6 . }}
<meta property="article:tag" content="{{ . }}" />
{{ end }}{{ end }}
{{ with .Params.tags }}
<meta name="keywords" content="{{ delimit . ", " }}">
{{ range . }}
<meta property="article:tag" content="{{ . }}" />
{{- end -}}
{{- end -}}
<!-- end og -->
<!-- structured data -->
{{ $ISO8601 := "2006-01-02T15:04:05-07:00" }}
{{- $ISO8601 := "2006-01-02T15:04:05-07:00" -}}
<script type="application/ld+json">
{
"@context" : "http://schema.org",
"@context" : "https://schema.org",
"@type" : "BlogPosting",
"mainEntityOfPage": {
"@type": "WebPage",
@ -82,17 +61,8 @@
},
"articleSection" : "{{ .Section }}",
"name" : {{ .Title }},
{{ if .Params.subtitle }}
"headline" : {{ .Params.subtitle }},
{{ else }}
"headline" : {{ .Summary | safeHTML | truncate 50 }},
{{ end }}
"description" : {{ if .Description }}{{ .Description }}{{ else }}{{if .IsPage}}{{ .Summary }}{{ end }}{{ end }},
{{ if isset .Params "language" }}
"inLanguage" : "{{ .Params.language }}",
{{ else }}
"inLanguage" : "en-US",
{{ end }}
"description" : {{ $description }},
"inLanguage" : "en-US",
"isFamilyFriendly": "true",
"image": {{ $thumb }},
"author" : {
@ -124,4 +94,4 @@
"wordCount" : "{{ .WordCount }}",
"keywords" : [ {{ if isset .Params "tags" }}{{ range .Params.tags }}{{ . }},{{ end }}{{ end }}{{ .Title }}, {{ .Section }} ]
}
</script>
</script>

View File

@ -1,29 +1,26 @@
{{ $currtitle := .Title }}
{{ $currRellink := substr .RelPermalink 0 -1 }}
{{ $currContent := .Content }}
<!-- find related pages for metadata and single-related.html -->
{{- $currtitle := .Title -}}
{{- $currRellink := substr .RelPermalink 0 -1 -}}
{{- $currContent := .Content -}}
{{- $backlinks := slice -}}
{{- $forwardlinks := slice -}}
{{- range (where (where .Site.Pages.ByDate.Reverse ".Section" "in" (slice "post")) ".Params.disableComments" "!=" "true") -}}
{{- $found := findRE $currRellink .Content 1 -}}
{{- if and ($found) (ne .Title $currtitle) -}}
{{- $backlinks = $backlinks | append . -}}
{{- else -}}
{{- $rellink := substr .RelPermalink 0 -1 -}}
{{- $found = findRE $rellink $currContent 1 -}}
{{- if and ($found) (ne .Title $currtitle) -}}
{{- $forwardlinks = $forwardlinks | append . -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- $tagslice := first 5 (where (where .Site.RegularPages.ByDate.Reverse ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) -}}
{{- $related := append $tagslice $forwardlinks -}}
{{- $related = append $related $backlinks -}}
{{ $backlinks := slice }}
{{ $forwardlinks := slice }}
{{ range (where (where .Site.Pages.ByDate.Reverse ".Section" "in" (slice "post")) ".Params.disableComments" "!=" "true") }}
{{ $found := findRE $currRellink .Content 1 }}
{{ if and ($found) (ne .Title $currtitle) }}
{{ $backlinks = $backlinks | append . }}
{{ else }}
{{ $rellink := substr .RelPermalink 0 -1 }}
{{ $found = findRE $rellink $currContent 1 }}
{{ if and ($found) (ne .Title $currtitle) }}
{{ $forwardlinks = $forwardlinks | append . }}
{{ end }}
{{ end }}
{{ end }}
{{ $tagslice := first 5 (where (where .Site.RegularPages.ByDate.Reverse ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) }}
{{ $related := append $tagslice $forwardlinks }}
{{ $related = append $related $backlinks }}
{{ if $related }}
{{- if $related -}}
<h3 class="page-header" id="related">
<a href="#related">
<svg class='icon icon-text' width='24' height='24'>
@ -36,7 +33,7 @@
<article>
<ul class="small">
{{ range first 7 $related | uniq }}
{{- range first 7 $related | uniq -}}
<li class="flexgrid flexgrid-8020" style="padding-bottom: 0.5rem">
<span>
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
@ -47,7 +44,7 @@
</time>
</small>
</li>
{{ end }}
{{- end -}}
</ul>
</article>
{{ end }}
{{- end -}}