Browse Source
Descriptions (meta description, Open Graph, Twitter cards, JSON-LD): the description front matter parameter, the site description for the home page, "Articles related to <term>" for the term pages, the page summary truncated to 160 characters, or the site description. The meta description used to be the title of the page. Social images: the images front matter parameter, a *feature*, *cover* or *thumbnail* page resource, the first image of the page content or the default image of the site. The image is converted to JPEG and resized to 1200 px wide max, without cropping, and its dimensions are given in the Open Graph tags. The default image (avatar) uses a small Twitter card. Structured data: BlogPosting for the blog, Article for the talks and publications, with the description, the image and the author. Refs #11 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YNHsWYTXPThURz6TbVS1j3master
6 changed files with 252 additions and 26 deletions
@ -0,0 +1,82 @@ |
|||
{{- /* |
|||
-- Based on the Hugo embedded opengraph.html partial (v0.167.0). |
|||
-- |
|||
-- Changes: the description comes from page-description.html and the image |
|||
-- from social-image.html (JPEG, 1200 px wide max). |
|||
*/ -}} |
|||
<meta property="og:url" content="{{ .Permalink }}"> |
|||
|
|||
{{- with or site.Title site.Params.title | plainify }} |
|||
<meta property="og:site_name" content="{{ . }}"> |
|||
{{- end }} |
|||
|
|||
{{- with or .Title site.Title site.Params.title | plainify }} |
|||
<meta property="og:title" content="{{ . }}"> |
|||
{{- end }} |
|||
|
|||
{{- with partialCached "page-description.html" . .Permalink }} |
|||
<meta property="og:description" content="{{ . }}"> |
|||
{{- end }} |
|||
|
|||
{{- with or .Params.locale site.Language.Locale }} |
|||
<meta property="og:locale" content="{{ replace . `-` `_` }}"> |
|||
{{- end }} |
|||
|
|||
{{- if .IsPage }} |
|||
<meta property="og:type" content="article"> |
|||
{{- with .Section }} |
|||
<meta property="article:section" content="{{ . }}"> |
|||
{{- 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 }} |
|||
{{- range .GetTerms "tags" | first 6 }} |
|||
<meta property="article:tag" content="{{ .Page.Title | plainify }}"> |
|||
{{- end }} |
|||
{{- else }} |
|||
<meta property="og:type" content="website"> |
|||
{{- end }} |
|||
|
|||
{{- with (partialCached "social-image.html" . .Permalink).image }} |
|||
<meta property="og:image" content="{{ .Permalink }}"> |
|||
<meta property="og:image:type" content="{{ .MediaType.Type }}"> |
|||
<meta property="og:image:width" content="{{ .Width }}"> |
|||
<meta property="og:image:height" content="{{ .Height }}"> |
|||
<meta property="og:image:alt" content="{{ $.Title | plainify }}"> |
|||
{{- end }} |
|||
|
|||
{{- with .Params.audio }} |
|||
{{- range . | first 6 }} |
|||
<meta property="og:audio" content="{{ . | absURL }}"> |
|||
{{- end }} |
|||
{{- end }} |
|||
|
|||
{{- with .Params.videos }} |
|||
{{- range . | first 6 }} |
|||
<meta property="og:video" content="{{ . | absURL }}"> |
|||
{{- end }} |
|||
{{- end }} |
|||
|
|||
{{- range .GetTerms "series" }} |
|||
{{- range .Pages | first 7 }} |
|||
{{- if ne $ . }} |
|||
<meta property="og:see_also" content="{{ .Permalink }}"> |
|||
{{- end }} |
|||
{{- end }} |
|||
{{- end }} |
|||
|
|||
{{- with site.Params.social }} |
|||
{{- if reflect.IsMap . }} |
|||
{{- with .facebook_app_id }} |
|||
<meta property="fb:app_id" content="{{ . }}"> |
|||
{{- else }} |
|||
{{- with .facebook_admin }} |
|||
<meta property="fb:admins" content="{{ . }}"> |
|||
{{- end }} |
|||
{{- end }} |
|||
{{- end }} |
|||
{{- end }} |
|||
@ -0,0 +1,28 @@ |
|||
{{- /* |
|||
-- Returns the description of a page (plain text), used by the meta |
|||
-- description, Open Graph, Twitter cards and structured data. |
|||
-- |
|||
-- In order of preference: |
|||
-- 1. the "description" front matter parameter |
|||
-- 2. the description of the site, for the home page |
|||
-- 3. "Articles related to <term>" for the taxonomy term pages |
|||
-- 4. the summary of the page, truncated to ~160 characters |
|||
-- 5. the description of the site |
|||
-- 6. the title of the page |
|||
*/ -}} |
|||
{{- $description := "" -}} |
|||
{{- if .Description -}} |
|||
{{- $description = .Description -}} |
|||
{{- else if and .IsHome site.Params.description -}} |
|||
{{- $description = site.Params.description -}} |
|||
{{- else if eq .Kind "term" -}} |
|||
{{- $description = printf "%s %s" (i18n "articles_related_to" | strings.TrimSpace) .Title -}} |
|||
{{- else -}} |
|||
{{- $summary := .Summary | plainify | htmlUnescape | replaceRE `\s+` " " | strings.TrimSpace -}} |
|||
{{- with $summary -}} |
|||
{{- $description = truncate 160 . -}} |
|||
{{- else -}} |
|||
{{- $description = or site.Params.description .Title -}} |
|||
{{- end -}} |
|||
{{- end -}} |
|||
{{- return ($description | plainify | htmlUnescape | strings.TrimSpace) -}} |
|||
@ -0,0 +1,76 @@ |
|||
{{- /* |
|||
-- Returns the image used when the page is shared on social networks |
|||
-- (Open Graph, Twitter cards) and in the structured data, as a dict: |
|||
-- - image: the processed image resource |
|||
-- - isDefault: true if the default image of the site is used |
|||
-- |
|||
-- The image is chosen in this order: |
|||
-- 1. the first image of the "images" front matter parameter |
|||
-- 2. a page resource named *feature*, *cover* or *thumbnail* |
|||
-- 3. the first image displayed in the page content |
|||
-- 4. the first image of the "images" site parameter |
|||
-- |
|||
-- The image is converted to JPEG (WebP is not supported everywhere) and |
|||
-- resized to 1200 px wide max, without cropping: the social networks crop |
|||
-- it to their own aspect ratio. |
|||
*/ -}} |
|||
{{- $formats := slice "jpeg" "png" "webp" "gif" "bmp" "tiff" -}} |
|||
{{- $images := slice -}} |
|||
{{- range .Resources.ByType "image" -}} |
|||
{{- if in $formats .MediaType.SubType -}} |
|||
{{- $images = $images | append . -}} |
|||
{{- end -}} |
|||
{{- end -}} |
|||
|
|||
{{- $source := false -}} |
|||
{{- $isDefault := false -}} |
|||
|
|||
{{- /* 1. The "images" front matter parameter */ -}} |
|||
{{- range $name := .Params.images -}} |
|||
{{- if not $source -}} |
|||
{{- range $images -}} |
|||
{{- if and (not $source) (eq .Name $name) -}}{{- $source = . -}}{{- end -}} |
|||
{{- end -}} |
|||
{{- end -}} |
|||
{{- end -}} |
|||
|
|||
{{- /* 2. A page resource named *feature*, *cover* or *thumbnail* */ -}} |
|||
{{- if not $source -}} |
|||
{{- range $images -}} |
|||
{{- if and (not $source) (findRE `(?i)(feature|cover|thumbnail)` .Name) -}}{{- $source = . -}}{{- end -}} |
|||
{{- end -}} |
|||
{{- end -}} |
|||
|
|||
{{- /* 3. The first image displayed in the page content */ -}} |
|||
{{- if and (not $source) $images -}} |
|||
{{- range findRESubmatch `<img[^>]*\ssrc="([^"]+)"` .Content -}} |
|||
{{- $src := index . 1 -}} |
|||
{{- if not $source -}} |
|||
{{- range $images -}} |
|||
{{- if and (not $source) (or (eq .RelPermalink $src) (eq .Permalink $src)) -}}{{- $source = . -}}{{- end -}} |
|||
{{- end -}} |
|||
{{- end -}} |
|||
{{- end -}} |
|||
{{- end -}} |
|||
|
|||
{{- /* 4. The default image of the site */ -}} |
|||
{{- if not $source -}} |
|||
{{- with index site.Params.images 0 -}} |
|||
{{- with resources.Get (strings.TrimPrefix "/" .) -}} |
|||
{{- $source = . -}} |
|||
{{- $isDefault = true -}} |
|||
{{- end -}} |
|||
{{- end -}} |
|||
{{- end -}} |
|||
|
|||
{{- $result := dict -}} |
|||
{{- with $source -}} |
|||
{{- $image := . -}} |
|||
{{- if gt .Width 1200 -}} |
|||
{{- $image = .Resize "1200x jpg q85" -}} |
|||
{{- else -}} |
|||
{{- $image = .Process "jpg q85" -}} |
|||
{{- end -}} |
|||
{{- $result = dict "image" $image "isDefault" $isDefault -}} |
|||
{{- end -}} |
|||
{{- return $result -}} |
|||
@ -0,0 +1,36 @@ |
|||
{{- /* |
|||
-- Based on the Hugo embedded twitter_cards.html partial (v0.167.0). |
|||
-- |
|||
-- Changes: the description comes from page-description.html and the image |
|||
-- from social-image.html (JPEG, 1200 px wide max). |
|||
*/ -}} |
|||
{{- /* The default image (avatar) is better displayed as a small card. */}} |
|||
{{- $social := partialCached "social-image.html" . .Permalink }} |
|||
{{- with $social.image }} |
|||
<meta name="twitter:card" content="{{ cond $social.isDefault "summary" "summary_large_image" }}"> |
|||
<meta name="twitter:image" content="{{ .Permalink }}"> |
|||
<meta name="twitter:image:alt" content="{{ $.Title | plainify }}"> |
|||
{{- else }} |
|||
<meta name="twitter:card" content="summary"> |
|||
{{- end }} |
|||
|
|||
{{- with or .Title site.Title site.Params.title | plainify }} |
|||
<meta name="twitter:title" content="{{ . }}"> |
|||
{{- end }} |
|||
|
|||
{{- with partialCached "page-description.html" . .Permalink }} |
|||
<meta name="twitter:description" content="{{ . }}"> |
|||
{{- end }} |
|||
|
|||
{{- $twitterSite := "" }} |
|||
{{- with site.Params.social }} |
|||
{{- if reflect.IsMap . }} |
|||
{{- with .twitter }} |
|||
{{- $content := . }} |
|||
{{- if not (strings.HasPrefix . "@") }} |
|||
{{- $content = printf "@%v" . }} |
|||
{{- end }} |
|||
<meta name="twitter:site" content="{{ $content }}"> |
|||
{{- end }} |
|||
{{- end }} |
|||
{{- end }} |
|||
Loading…
Reference in new issue