Beiträge mit Archiven, Beitragsliste und Feed (Arbeitspaket B)
Migration 20260912000600 ergänzt page.excerpt, author,
featured_media_id und published_at sowie die Tabellen term und
page_term. Beitragsmetadaten beschreiben die Seite, nicht ihren
Inhalt, und liegen deshalb als Spalten statt im Blockdokument: das
Archiv sortiert und paginiert damit in SQL, statt für jede
Auflistung alle Dokumente zu dekodieren.
Kategorien und Schlagwörter teilen sich eine Tabelle mit einem
kind-Feld. Beim Löschen einer Seite verschwinden ihre Zuordnungen,
die Begriffe bleiben als wiederverwendbare Etiketten; ein leer
gewordenes Archiv antwortet weiter mit 200 und leerer Liste.
Der Block postlist (Dokumentschema v5) speichert nur Anzahl und
Filter. Die Beiträge stellt der Controller beim Ausliefern zusammen,
damit ein gespeichertes Dokument keinen unveröffentlichten Beitrag
zeigen kann. Archive unter /beitraege, /kategorie/{slug} und
/schlagwort/{slug}, Feed unter /feed.xml; alle vier Segmente sind
für Wurzelseiten reserviert.
Geprüft: 91 PHP-Tests / 347 Assertions unter PHP 8.2.12 und 8.4.22,
12 JavaScript-Modelltests, Lint/Format/Container, Migration zuerst
gegen eine Datenbankkopie. Keine Browser- oder Lighthouse-Läufe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
de9d6e3da8
commit
ebd5883593
25 files changed
+808
-21
No files matched your search
@@ -9,7 +9,7 @@ final class DocumentValidator
|
||||
public function validate(array $document): void
|
||||
{
|
||||
$schemaVersion = $document['schemaVersion'] ?? null;
|
||||
$this->require(in_array($schemaVersion, [1, 2, 3, 4], true), 'Unsupported document schema.');
|
||||
$this->require(in_array($schemaVersion, [1, 2, 3, 4, 5], true), 'Unsupported document schema.');
|
||||
$this->text($document['title'] ?? null, 160);
|
||||
$this->text($document['description'] ?? null, 320);
|
||||
$this->require(is_array($document['blocks'] ?? null) && array_is_list($document['blocks']), 'Blocks must be a list.');
|
||||
@@ -34,7 +34,7 @@ final class DocumentValidator
|
||||
// page: a deactivated plugin must never make stored content unreadable. Nothing from
|
||||
// props is rendered for such a block, so unvalidated values never reach the output.
|
||||
$plugin = $schemaVersion >= 4 && is_string($type) && 1 === preg_match('/^[a-z][a-z0-9]{1,30}\.[a-z][a-z0-9-]{1,40}$/D', $type);
|
||||
$this->require(in_array($type, ['section', 'row', 'column', 'heading', 'text', 'image', 'button'], true) || ($schemaVersion >= 3 && 'gallery' === $type) || $plugin, 'Unknown block type. Preserve source until its plugin is available.');
|
||||
$this->require(in_array($type, ['section', 'row', 'column', 'heading', 'text', 'image', 'button'], true) || ($schemaVersion >= 3 && 'gallery' === $type) || ($schemaVersion >= 5 && 'postlist' === $type) || $plugin, 'Unknown block type. Preserve source until its plugin is available.');
|
||||
$props = $block['props'] ?? [];
|
||||
$layout = $block['layout'] ?? [];
|
||||
$this->require(is_array($props) && is_array($layout), 'Props and layout must be objects.');
|
||||
@@ -61,6 +61,16 @@ final class DocumentValidator
|
||||
$this->require(is_int($props['level'] ?? null) && $props['level'] >= 1 && $props['level'] <= 6, 'Invalid heading level.');
|
||||
$headings += 1 === $props['level'] ? 1 : 0;
|
||||
}
|
||||
if ('postlist' === $type) {
|
||||
// The list is filled by the renderer, never by stored content: the block only says
|
||||
// how many posts to show and which term to limit them to.
|
||||
$this->require(is_int($props['count'] ?? null) && $props['count'] >= 1 && $props['count'] <= 24, 'Die Anzahl der Beiträge liegt zwischen 1 und 24.');
|
||||
foreach (['category', 'tag'] as $kind) {
|
||||
if (isset($props[$kind]) && '' !== $props[$kind]) {
|
||||
$this->require(is_string($props[$kind]) && 1 === preg_match('/^[a-z0-9]+(?:-[a-z0-9]+)*$/D', $props[$kind]) && strlen($props[$kind]) <= 80, 'Ungültiger Filter für die Beitragsliste.');
|
||||
}
|
||||
}
|
||||
}
|
||||
if ('button' === $type) {
|
||||
$this->url($props['href'] ?? null);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user