Migrate WordPress site to Hugo

Replaces the WordPress 7.0.2 / HitMag site with a static Hugo build,
deployed by Gitea Actions over rsync/SSH.

Content: 26 files (9 pages + 17 posts) as Markdown page bundles, plus
127 of 165 media attachments. The remaining 38 are media-library
leftovers that appear nowhere on the live site; they are listed in
MIGRATION.md.

The WXR export contains neither media binaries nor widgets, so both were
recovered from the live host before it is retired:
  - tools/fetch_media.py downloads all uploads, capping them at 2000px
  - tools/build_data.py scrapes the "Unsere Mitglieder" and
    "In Erinnerung" widgets into data/*.yaml

TablePress' six Termine tables became data/termine.yaml, rendered with
the newest year expanded and earlier years collapsed. Old permalinks are
not preserved (clean slugs, no redirects, as agreed).

Custom layouts, no third-party theme. Plain CSS, since the pinned Hugo
0.164.0 is the non-extended build and cannot compile Sass.

Verified: clean build with zero warnings, 718 internal links checked and
none broken, no surviving wp-content URLs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-28 19:20:11 +02:00
parent eccf30584a
commit bef5182545
188 changed files with 2770 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
<footer class="site-footer">
<div class="container">
<p class="footer-contact">
<strong>{{ site.Title }}</strong><br>
<a href="mailto:{{ site.Params.email }}">{{ site.Params.email }}</a>
</p>
<nav class="footer-nav" aria-label="Fußzeile">
<a href="{{ "/impressum/" | relURL }}">Impressum</a>
{{ with .OutputFormats.Get "rss" }}<a href="{{ .Permalink }}">RSS</a>{{ end }}
</nav>
<p class="footer-copyright">© {{ now.Year }} {{ site.Title }}</p>
</div>
</footer>
@@ -0,0 +1,15 @@
{{- /*
Resolve a page's featured image to a Resource.
Looks at the `featured` front-matter key first (set by the WordPress import),
then falls back to the first image in the page bundle.
Returns the Resource, or nothing.
*/ -}}
{{- $img := "" -}}
{{- with .Resources.GetMatch (printf "%s" (.Params.featured | default "")) -}}
{{- $img = . -}}
{{- else -}}
{{- with .Resources.ByType "image" -}}
{{- $img = index . 0 -}}
{{- end -}}
{{- end -}}
{{- return $img -}}
+32
View File
@@ -0,0 +1,32 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ if .IsHome }}{{ site.Title }}{{ else }}{{ .Title }} {{ site.Title }}{{ end }}</title>
{{ $description := or .Description .Summary site.Params.description }}
<meta name="description" content="{{ $description | plainify | truncate 160 }}">
<meta property="og:site_name" content="{{ site.Title }}">
<meta property="og:title" content="{{ if .IsHome }}{{ site.Title }}{{ else }}{{ .Title }}{{ end }}">
<meta property="og:description" content="{{ $description | plainify | truncate 160 }}">
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}">
<meta property="og:url" content="{{ .Permalink }}">
{{ with partial "func/featured-image.html" . }}
<meta property="og:image" content="{{ .Permalink }}">
{{ end }}
{{ with resources.Get "css/main.css" | minify | fingerprint }}
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}">
{{ end }}
{{ with resources.Get site.Params.logo }}
{{ $icon := .Resize "180x180 png" }}
<link rel="icon" href="{{ $icon.RelPermalink }}" type="image/png">
<link rel="apple-touch-icon" href="{{ $icon.RelPermalink }}">
{{ end }}
{{ with .OutputFormats.Get "rss" }}
<link rel="alternate" type="application/rss+xml" href="{{ .Permalink }}" title="{{ site.Title }}">
{{ end }}
<link rel="canonical" href="{{ .Permalink }}">
</head>
+38
View File
@@ -0,0 +1,38 @@
<header class="site-header">
<div class="container site-branding">
<a class="site-logo" href="{{ "/" | relURL }}" rel="home">
{{ with resources.Get site.Params.logo }}
{{ $l := .Resize "160x png" }}
<img src="{{ $l.RelPermalink }}" width="{{ $l.Width }}" height="{{ $l.Height }}"
alt="Wappen des Motorradclub Giebelwald">
{{ end }}
</a>
<div class="site-titles">
<p class="site-title"><a href="{{ "/" | relURL }}" rel="home">{{ site.Title }}</a></p>
<p class="site-tagline">{{ site.Params.tagline }}</p>
</div>
</div>
{{ with resources.Get site.Params.banner }}
{{ $banner := .Resize "1600x webp q80" }}
<img class="site-banner" src="{{ $banner.RelPermalink }}"
width="{{ $banner.Width }}" height="{{ $banner.Height }}"
alt="" loading="eager" decoding="async">
{{ end }}
<nav class="site-nav" aria-label="Hauptnavigation">
<div class="container">
<input type="checkbox" id="nav-toggle" class="nav-toggle">
<label for="nav-toggle" class="nav-toggle-label">
<span aria-hidden="true"></span> Menü
</label>
<ul class="nav-list">
<li><a href="{{ "/" | relURL }}"{{ if .IsHome }} aria-current="page"{{ end }}>Start</a></li>
{{ range site.Menus.main }}
{{ $active := or ($.IsMenuCurrent "main" .) ($.HasMenuCurrent "main" .) }}
<li><a href="{{ .URL }}"{{ if $active }} aria-current="page"{{ end }}>{{ .Name }}</a></li>
{{ end }}
</ul>
</div>
</nav>
</header>
+17
View File
@@ -0,0 +1,17 @@
{{- /* Teaser card for a news post. Context: the page. */ -}}
<article class="post-card">
{{ with partial "func/featured-image.html" . }}
{{ $thumb := .Fill "480x300 Center webp q80" }}
<a class="post-card-image" href="{{ $.RelPermalink }}" tabindex="-1" aria-hidden="true">
<img src="{{ $thumb.RelPermalink }}" width="{{ $thumb.Width }}" height="{{ $thumb.Height }}"
alt="" loading="lazy" decoding="async">
</a>
{{ end }}
<div class="post-card-body">
<h3 class="post-card-title"><a href="{{ .RelPermalink }}">{{ .Title }}</a></h3>
<p class="post-card-meta">
<time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date | time.Format site.Params.dateFormat }}</time>
</p>
<p class="post-card-summary">{{ .Summary | plainify | truncate 160 }}</p>
</div>
</article>
+12
View File
@@ -0,0 +1,12 @@
{{- /* Context: a slice of {date, description} rows from data/termine.yaml.
Cells may contain newlines (rendered as line breaks) and inline HTML. */ -}}
<table class="termine">
<tbody>
{{ range . }}
<tr>
<th scope="row">{{ .date | strings.Replace "\n" "<br>" | safeHTML }}</th>
<td>{{ .description | strings.Replace "\n" "<br>" | safeHTML }}</td>
</tr>
{{ end }}
</tbody>
</table>