mykiwi/mykiwi.blogpublic Fork
⑂ 559a65e
Commits
⬇ Clone ▾
git clone https://git.rickub.com/mykiwi/mykiwi.blog.git
git clone ssh://git@rickub.com/mykiwi/mykiwi.blog.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

Describe every page in JSON-LD as well

A search engine reading the markup alone has to infer what a post is and
who wrote it. jsonld.html states it outright: BlogPosting for a post -
headline, published and modified dates, author and publisher, image,
mainEntityOfPage - and WebSite for the home and section pages.

It takes the same (page, desc, image) dict as opengraph.html, so the
description matches the <meta name="description"> exactly and the image is
page-image.html's one choice rather than a second guess at it. The
document is assembled as a Hugo dict and passed through jsonify, so the
escaping is Hugo's rather than hand-written string concatenation.
Romain Gautier committed 2026-09-23T22:58:56+02:00 Browse files
559a65e parent: 0800aa7
modified blog/layouts/_default/baseof.html +1 -0
@@ -156,6 +156,7 @@
156156 <link rel="canonical" href="{{ .Permalink }}">
157157 {{- $pageImage := partial "page-image.html" . }}
158158 {{ partial "opengraph.html" (dict "page" . "desc" $desc "image" $pageImage) }}
159+ {{ partial "jsonld.html" (dict "page" . "desc" $desc "image" $pageImage) }}
159160
160161 <!-- Fonts are self-hosted, so there is no third-party DNS + TLS before first paint. -->
161162 <link rel="preload" href="/fonts/Newsreader-latin.woff2" as="font" type="font/woff2" crossorigin>
@@ -156,6 +156,7 @@
156 <link rel="canonical" href="{{ .Permalink }}">156 <link rel="canonical" href="{{ .Permalink }}">
157 {{- $pageImage := partial "page-image.html" . }}157 {{- $pageImage := partial "page-image.html" . }}
158 {{ partial "opengraph.html" (dict "page" . "desc" $desc "image" $pageImage) }}158 {{ partial "opengraph.html" (dict "page" . "desc" $desc "image" $pageImage) }}
159+ {{ partial "jsonld.html" (dict "page" . "desc" $desc "image" $pageImage) }}
159 160
160 <!-- Fonts are self-hosted, so there is no third-party DNS + TLS before first paint. -->161 <!-- Fonts are self-hosted, so there is no third-party DNS + TLS before first paint. -->
161 <link rel="preload" href="/fonts/Newsreader-latin.woff2" as="font" type="font/woff2" crossorigin>162 <link rel="preload" href="/fonts/Newsreader-latin.woff2" as="font" type="font/woff2" crossorigin>
added blog/layouts/partials/jsonld.html +43 -0
new file mode 100644
@@ -0,0 +1,43 @@
1+{{- /*
2+ JSON-LD structured data - BlogPosting for a post, WebSite for home/section
3+ pages, so a search engine gets headline/author/dates/image without having
4+ to infer them from the markup. Takes the same (page, desc, image) shape as
5+ opengraph.html; `image` is page-image.html's own dict so the two don't
6+ compute it twice and can't disagree on it.
7+*/ -}}
8+{{- $page := .page }}
9+{{- $desc := .desc }}
10+{{- $image := .image }}
11+{{- $author := site.Params.profile }}
12+{{- $authorName := "" }}
13+{{- with $author }}
14+ {{- $authorName = strings.TrimSpace (printf "%s %s" .firstName .lastName) }}
15+{{- end }}
16+
17+{{- $data := dict
18+ "@context" "https://schema.org"
19+ "url" $page.Permalink
20+ "inLanguage" site.Language.Lang
21+}}
22+{{- with $desc }}{{ $data = merge $data (dict "description" .) }}{{ end }}
23+{{- with $image.url }}{{ $data = merge $data (dict "image" .) }}{{ end }}
24+
25+{{- if $page.IsPage }}
26+ {{- $data = merge $data (dict
27+ "@type" "BlogPosting"
28+ "headline" $page.Title
29+ "datePublished" ($page.Date.Format "2006-01-02T15:04:05Z07:00")
30+ "dateModified" ($page.Lastmod.Format "2006-01-02T15:04:05Z07:00")
31+ "mainEntityOfPage" (dict "@type" "WebPage" "@id" $page.Permalink)
32+ ) }}
33+ {{- with $authorName }}
34+ {{- $data = merge $data (dict "author" (dict "@type" "Person" "name" .) "publisher" (dict "@type" "Person" "name" .)) }}
35+ {{- end }}
36+{{- else }}
37+ {{- $data = merge $data (dict
38+ "@type" "WebSite"
39+ "name" site.Title
40+ ) }}
41+{{- end }}
42+
43+<script type="application/ld+json">{{ $data | jsonify (dict "indent" " ") | safeJS }}</script>
new file mode 100644
@@ -0,0 +1,43 @@
1+{{- /*
2+ JSON-LD structured data - BlogPosting for a post, WebSite for home/section
3+ pages, so a search engine gets headline/author/dates/image without having
4+ to infer them from the markup. Takes the same (page, desc, image) shape as
5+ opengraph.html; `image` is page-image.html's own dict so the two don't
6+ compute it twice and can't disagree on it.
7+*/ -}}
8+{{- $page := .page }}
9+{{- $desc := .desc }}
10+{{- $image := .image }}
11+{{- $author := site.Params.profile }}
12+{{- $authorName := "" }}
13+{{- with $author }}
14+ {{- $authorName = strings.TrimSpace (printf "%s %s" .firstName .lastName) }}
15+{{- end }}
16+
17+{{- $data := dict
18+ "@context" "https://schema.org"
19+ "url" $page.Permalink
20+ "inLanguage" site.Language.Lang
21+}}
22+{{- with $desc }}{{ $data = merge $data (dict "description" .) }}{{ end }}
23+{{- with $image.url }}{{ $data = merge $data (dict "image" .) }}{{ end }}
24+
25+{{- if $page.IsPage }}
26+ {{- $data = merge $data (dict
27+ "@type" "BlogPosting"
28+ "headline" $page.Title
29+ "datePublished" ($page.Date.Format "2006-01-02T15:04:05Z07:00")
30+ "dateModified" ($page.Lastmod.Format "2006-01-02T15:04:05Z07:00")
31+ "mainEntityOfPage" (dict "@type" "WebPage" "@id" $page.Permalink)
32+ ) }}
33+ {{- with $authorName }}
34+ {{- $data = merge $data (dict "author" (dict "@type" "Person" "name" .) "publisher" (dict "@type" "Person" "name" .)) }}
35+ {{- end }}
36+{{- else }}
37+ {{- $data = merge $data (dict
38+ "@type" "WebSite"
39+ "name" site.Title
40+ ) }}
41+{{- end }}
42+
43+<script type="application/ld+json">{{ $data | jsonify (dict "indent" " ") | safeJS }}</script>