Beitraege optional, Unterstriche nur im Text, eigenes Symbol
Eine Website ohne Beitraege redet nirgends von Beitraegen: Archiv und Feed antworten mit 404, der Feedverweis faellt aus dem Kopf, und der Hinweiskasten der Beitragsliste bleibt im Editor statt oeffentlich zu erscheinen. Das gilt auch je Kategorie, sobald deren letzter Beitrag weg ist. Dabei gefunden: die Liste fragte je Beitrag nach Bild und Begriffen - jetzt je eine Abfrage fuer die ganze Liste (22 -> 16 Abfragen auf der Startseite des Nachbaus). Unterstrichene Links gibt es nur noch im Fliesstext, dort mit einem Schalter im Designbereich; Karten, Menue, Kontaktzeilen und der Ansehen-Streifen haben keinen mehr. Die aktuelle Seite im Menue wird ueber das Schriftgewicht kenntlich - die Akzentfarbe fiel im dunklen Fussmenue durch die Kontrastpruefung. Neu: das Symbol der Website laesst sich festlegen. Aus einem Bild der Mediathek entstehen beim Speichern quadratische PNG-Dateien in 32 und 180 px; schlaegt das fehl, wird die Einstellung nicht gespeichert. Die Browserpruefung laeuft jetzt gegen jede Installation statt nur gegen die Demo: geprueft wird, was in der Sitemap steht, und das Ladebudget trennt Bilder vom Beiwerk. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f0b634f0c1
commit
f2ef2a4901
28 files changed
+482
-64
No files matched your search
@@ -127,17 +127,24 @@ final class PostRepository
|
||||
$params,
|
||||
);
|
||||
|
||||
return ['posts' => array_map($this->present(...), $rows), 'total' => $total, 'pages' => $pages, 'page' => $page];
|
||||
// Bilder und Begriffe für die ganze Liste in je einer Abfrage: vorher fragte jeder Beitrag
|
||||
// einzeln nach seinem Bild und seinen Begriffen, eine Liste mit zwölf Einträgen kostete
|
||||
// also 24 Abfragen statt zwei. Bei neighbours(), das 500 Beiträge lädt, war das absurd.
|
||||
$images = $this->media->findMany(array_map(static fn (array $row) => (string) $row['featured_media_id'], $rows));
|
||||
$terms = $this->termsForMany(array_column($rows, 'id'));
|
||||
|
||||
return [
|
||||
'posts' => array_map(fn (array $row) => $this->present($row, $images, $terms[$row['id']] ?? ['category' => [], 'tag' => []]), $rows),
|
||||
'total' => $total,
|
||||
'pages' => $pages,
|
||||
'page' => $page,
|
||||
];
|
||||
}
|
||||
|
||||
private function present(array $row): array
|
||||
private function present(array $row, array $images, array $terms): array
|
||||
{
|
||||
$document = json_decode($row['document'], true, 512, JSON_THROW_ON_ERROR);
|
||||
$image = null;
|
||||
if (null !== $row['featured_media_id']) {
|
||||
$item = $this->media->find($row['featured_media_id']);
|
||||
$image = null === $item ? null : ['alt' => $item['alt'] ?? '', 'variants' => $item['variants']];
|
||||
}
|
||||
$item = $images[$row['featured_media_id']] ?? null;
|
||||
|
||||
return [
|
||||
'title' => $document['title'] ?? $row['path'],
|
||||
@@ -145,11 +152,37 @@ final class PostRepository
|
||||
'excerpt' => $row['excerpt'] ?? $document['description'] ?? '',
|
||||
'author' => $row['author'],
|
||||
'publishedAt' => $row['published_at'],
|
||||
'image' => $image,
|
||||
'terms' => $this->termsFor($row['id']),
|
||||
'image' => null === $item ? null : ['alt' => $item['alt'] ?? '', 'variants' => $item['variants']],
|
||||
'terms' => $terms,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Begriffe mehrerer Seiten auf einmal.
|
||||
*
|
||||
* @param list<string> $pageIds
|
||||
*
|
||||
* @return array<string, array<string, list<array{slug: string, name: string, href: string}>>>
|
||||
*/
|
||||
private function termsForMany(array $pageIds): array
|
||||
{
|
||||
$pageIds = array_values(array_unique(array_filter($pageIds)));
|
||||
if ([] === $pageIds) {
|
||||
return [];
|
||||
}
|
||||
$terms = [];
|
||||
foreach ($this->db->fetchAllAssociative(
|
||||
'SELECT pt.page_id, t.kind, t.slug, t.name FROM term t JOIN page_term pt ON pt.term_id = t.id WHERE pt.page_id IN ('
|
||||
.implode(',', array_fill(0, count($pageIds), '?')).') ORDER BY t.name',
|
||||
$pageIds,
|
||||
) as $row) {
|
||||
$terms[$row['page_id']] ??= ['category' => [], 'tag' => []];
|
||||
$terms[$row['page_id']][$row['kind']][] = ['slug' => $row['slug'], 'name' => $row['name'], 'href' => '/'.self::ARCHIVE_PREFIX[$row['kind']].'/'.$row['slug']];
|
||||
}
|
||||
|
||||
return $terms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<array{slug: string, name: string, href: string}>>
|
||||
*/
|
||||
@@ -192,6 +225,23 @@ final class PostRepository
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt es überhaupt einen veröffentlichten Beitrag?
|
||||
*
|
||||
* Eine Website ohne Blog soll nirgends von Beiträgen reden: kein leeres Archiv, kein Feed mit
|
||||
* null Einträgen, kein Kasten „hier erscheinen Beiträge“ auf einer Seite. Die Antwort wird für
|
||||
* die Dauer einer Anfrage gemerkt, weil mehrere Stellen sie brauchen.
|
||||
*/
|
||||
public function anyPublished(string $locale = 'de'): bool
|
||||
{
|
||||
return $this->anyPublished ??= (bool) $this->db->fetchOne(
|
||||
"SELECT 1 FROM page WHERE website_id = ? AND locale = ? AND type = 'post' AND published_revision_id IS NOT NULL AND deleted_at IS NULL LIMIT 1",
|
||||
['default', $locale],
|
||||
);
|
||||
}
|
||||
|
||||
private ?bool $anyPublished = null;
|
||||
|
||||
public function termsFor(string $pageId): array
|
||||
{
|
||||
$terms = ['category' => [], 'tag' => []];
|
||||
|
||||
Reference in new issue
Block a user