, * siehe public/index.php (Prefix-Match, da app/routes.php nur exakte Slugs * kennt). Ermittelt den Ausgaben-Slug selbst wieder aus der URL, Daten aus * data/stadionzeitung.json (maschinenverwaltet von bin/stadionzeitung-add.php). * * Bewusst OHNE das übliche hero-Component: der Swipe-Viewer soll so viel * Bildschirmhöhe wie möglich bekommen (gerade am Handy) — stattdessen ein * schmaler Kopfbereich direkt über dem Viewer. */ $urlSlug = trim((string) parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH), '/'); $ausgabeSlug = substr($urlSlug, strlen('stadionzeitung/')); /* * Reservierter Slug „aktuell": leitet auf die neueste veröffentlichte Ausgabe * weiter. Damit zeigt ein GEDRUCKTER QR-Code (Plakat, Aushang) dauerhaft auf die * jeweils aktuelle Ausgabe, ohne dass zu jedem Heimspiel ein neuer Code * entstehen muss. Kollision ausgeschlossen: Ausgaben-Slugs beginnen immer mit * dem Datum (2026-08-01-…). * * Drei Dinge sind hier load-bearing: * 1. **302, nie 301.** Ein 301 wird von Browsern und Crawlern dauerhaft * gemerkt — das Plakat zeigte dann für immer auf die erste Ausgabe, und * zwar unreparierbar auf allen Geräten, die ihn einmal gesehen haben. * 2. `no-store`, damit ein Handy, das im letzten Monat gescannt hat, nicht * das alte Ziel wiederverwendet. * 3. Ohne veröffentlichte Ausgabe geht es aufs Archiv statt in einen 404 — * ein gedruckter Code darf nie ins Leere führen. */ if ($ausgabeSlug === 'aktuell') { $latest = stadionzeitung_latest(); header('Cache-Control: no-store'); header( 'Location: ' . ($latest !== null ? url('stadionzeitung/' . $latest['slug']) : url('stadionzeitung')), true, 302 ); // exit, nicht return: nach einem `return` liefe in public/index.php noch // layout.php und hängte einen kompletten HTML-Body an die Weiterleitung. // Der Ausgabepuffer aus render_page() ist hier noch leer, es geht also // nichts verloren. exit; } $issue = null; foreach (json_load('stadionzeitung')['issues'] ?? [] as $entry) { if (($entry['slug'] ?? '') === $ausgabeSlug) { $issue = $entry; break; } } if ($issue === null) { // http_response_code(404) ist globaler Engine-State (kein Scope-Problem wie // $meta/$current) — public/index.php liest ihn nach render_page() wieder aus, // um $current auf '404' zu setzen (noindex + kein Self-Canonical in meta.php). http_response_code(404); require APP_PATH . '/pages/404.php'; return; } // Entwurf vs. veröffentlicht (Interview-Beschluss 29.07.2026): Entwürfe sind // „unsichtbar, aber offen" — sie fehlen im Archiv und in der Sitemap und // tragen noindex, die direkte URL funktioniert aber (zum Gegenlesen ohne // Login-System). Die Druckfassung (?druck=1) montiert dieselben Seiten in // Broschüren-Reihenfolge fürs gefaltete A5-Heft. $isDraft = !stadionzeitung_is_published($issue); $isDruck = isset($_GET['druck']); // Erste Seite ist seit dem automatischen Cover (Phase 3) eine Live-Seite ohne // eigenes Bild — og_image gibt es nur, wenn die Ausgabe (noch/wieder) mit // einem Bild beginnt, sonst greift das globale Default-OG-Bild (meta.php). $firstImage = $issue['images'][0] ?? null; $cover = ($firstImage !== null && ($firstImage['type'] ?? 'image') === 'image') ? $firstImage : null; $meta = [ 'title' => 'Stadionzeitung gegen ' . $issue['opponent'] . ($isDruck ? ' (Druckfassung)' : ''), 'description' => 'Stadionzeitung zum Heimspiel gegen ' . $issue['opponent'] . ' am ' . german_date($issue['date']) . ' – digital zum Durchblättern.', 'scripts' => [$isDruck ? 'stadionzeitung-druck.js' : 'stadionzeitung-viewer.js'], 'schema' => page_schema([ ['name' => 'Startseite', 'slug' => ''], ['name' => 'Fußball', 'slug' => 'fussball'], ['name' => 'Stadionzeitung', 'slug' => 'stadionzeitung'], ['name' => 'Gegen ' . $issue['opponent'], 'slug' => 'stadionzeitung/' . $issue['slug']], ]), ]; if ($cover !== null) { $meta['og_image'] = $cover['base'] . '-' . max($cover['widths']) . '.jpg'; } // Entwürfe und die Druckfassung (parametrisierte Zweitansicht derselben // Inhalte) gehören nicht in den Index. if ($isDraft || $isDruck) { $meta['noindex'] = true; } ?>

Gegen

Entwurf Druckfassung · Blätter · Seiten

$issue]); ?>