feat(seo): image sitemap, Article schemas on apologetik pro + katechese, edge caching
Sitemap now declares the image:image namespace and emits an entry per recipe photo (loc, title from recipe name, caption from alt text) — Google Image Search can discover all recipe images directly instead of relying on crawl. Pro arg pages get Article JSON-LD (headline, claim as description, layer as articleSection, voice names as keywords, deduped voice cites as citations) plus BreadcrumbList. Katechese/zehn-gebote gets inline Article + Breadcrumb with a Thing reference to "Dekalog" and CreativeWork citation of P. Martin Ramm FSSP's Glaubenskurs. Static-content load functions now set Cache-Control: public,max-age=300,s-maxage=3600,stale-while-revalidate=86400 — applied to apologetik layout, contra index/arg, pro index/arg, and the new katechese +page.ts files. Recipe detail uses s-maxage=1800. Picked HTTP caching over SvelteKit prerender to avoid baking session=null into the navbar of routes shared with the auth-aware faithLang layout.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { Argument, Archetype } from '$lib/data/apologetik';
|
||||
import type { Argument, Archetype, PosArgument, PosVoice } from '$lib/data/apologetik';
|
||||
import type { FaithLang } from '$lib/js/faithI18n';
|
||||
import { faithSlugFromLang, apologetikSlug } from '$lib/js/faithI18n';
|
||||
|
||||
@@ -66,3 +66,51 @@ export function generateContraQaJsonLd(
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export interface ProArgArticleJsonLd {
|
||||
'@context': 'https://schema.org';
|
||||
'@type': 'Article';
|
||||
headline: string;
|
||||
description: string;
|
||||
inLanguage: FaithLang;
|
||||
url: string;
|
||||
mainEntityOfPage: string;
|
||||
author: { '@type': 'Person'; name: string; url: string };
|
||||
publisher: { '@type': 'Person'; name: string; url: string };
|
||||
articleSection: string;
|
||||
keywords?: string;
|
||||
citation?: Array<{ '@type': 'CreativeWork'; name: string }>;
|
||||
}
|
||||
|
||||
/** Build an Article JSON-LD for a positive (pro) apologetik argument. */
|
||||
export function generateProArgArticleJsonLd(
|
||||
arg: PosArgument,
|
||||
voices: Record<string, PosVoice>,
|
||||
lang: FaithLang
|
||||
): ProArgArticleJsonLd {
|
||||
const faithSeg = faithSlugFromLang(lang);
|
||||
const apolSeg = apologetikSlug(lang === 'la' ? 'en' : lang);
|
||||
const url = `https://bocken.org/${faithSeg}/${apolSeg}/pro/${arg.id}`;
|
||||
|
||||
const allCites = Object.values(arg.voices).flatMap((v) => v.cites ?? []);
|
||||
const uniqueCites = Array.from(new Set(allCites));
|
||||
const voiceNames = Object.keys(arg.voices)
|
||||
.map((id) => voices[id]?.name ?? id)
|
||||
.join(', ');
|
||||
|
||||
const article: ProArgArticleJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Article',
|
||||
headline: arg.title,
|
||||
description: arg.claim,
|
||||
inLanguage: lang,
|
||||
url,
|
||||
mainEntityOfPage: url,
|
||||
author: { '@type': 'Person', name: 'Alexander Bocken', url: 'https://bocken.org/' },
|
||||
publisher: { '@type': 'Person', name: 'Alexander Bocken', url: 'https://bocken.org/' },
|
||||
articleSection: arg.layer,
|
||||
};
|
||||
if (voiceNames) article.keywords = voiceNames;
|
||||
if (uniqueCites.length) article.citation = uniqueCites.map((name) => ({ '@type': 'CreativeWork', name }));
|
||||
return article;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user