feat(post): add h-entry microformat + tag-name keywords fallback
Microformats: - Wrap the post <article> in h-entry with p-name on the headline, p-summary on the subheadline (or sr-only fallback from excerpt), e-content on the rendered body, dt-published on the created date (hidden time element) and an invisible p-author h-card. Tag names are mirrored as hidden p-category entries so crawlers see them even though the visual Tags component already links them. - itemscope/itemtype maps to schema.org BlogPosting (or Event when `isEvent`), aligning the invisible microdata with the existing JSON-LD. Keywords: - When post.seoKeywords is empty, fall back to the comma-joined tag names so <meta name="keywords"> still ships something meaningful.
This commit is contained in:
@@ -232,7 +232,17 @@ export const load: PageServerLoad = async ({ params, locals, url, setHeaders })
|
||||
seoDescription: postDescription,
|
||||
socialImage: postSocialImageAbs ?? postImageUrl ?? undefined,
|
||||
robots: (post as { seoMetaRobots?: string }).seoMetaRobots ?? undefined,
|
||||
keywords: (post as { seoKeywords?: string }).seoKeywords ?? undefined,
|
||||
keywords: (() => {
|
||||
const explicit = ((post as { seoKeywords?: string }).seoKeywords ?? '').trim();
|
||||
if (explicit) return explicit;
|
||||
// Fallback: join tag names so published posts without explicit keywords
|
||||
// still ship a meaningful <meta name="keywords">.
|
||||
const tags = (post as { postTag?: Array<{ name?: string }> }).postTag ?? [];
|
||||
const names = tags
|
||||
.map((t) => (typeof t?.name === 'string' ? t.name.trim() : ''))
|
||||
.filter(Boolean);
|
||||
return names.length > 0 ? names.join(', ') : undefined;
|
||||
})(),
|
||||
jsonLd,
|
||||
breadcrumbItems: [
|
||||
{ href: '/', label: 'Start' },
|
||||
|
||||
@@ -72,21 +72,36 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<article class="mt-8">
|
||||
<article
|
||||
class="mt-8 h-entry"
|
||||
itemscope
|
||||
itemtype={data.isEvent ? 'https://schema.org/Event' : 'https://schema.org/BlogPosting'}
|
||||
>
|
||||
<a class="u-url" href="#" aria-hidden="true" hidden></a>
|
||||
{#if data.post._created || data.post.created}
|
||||
<time
|
||||
class="dt-published"
|
||||
datetime={String(data.post.created ?? data.post._created ?? '')}
|
||||
hidden
|
||||
>{data.post.created ?? data.post._created}</time>
|
||||
{/if}
|
||||
{#if data.contentHeadlineHtml}
|
||||
<div class="content markdown max-w-none prose prose-zinc">
|
||||
<div class="content markdown max-w-none prose prose-zinc p-name">
|
||||
{@html data.contentHeadlineHtml}
|
||||
</div>
|
||||
{:else if data.post.headline || data.post.subheadline}
|
||||
<header class="content markdown max-w-none prose prose-zinc mb-4">
|
||||
{#if data.post.headline}
|
||||
<h1>{data.post.headline}</h1>
|
||||
<h1 class="p-name">{data.post.headline}</h1>
|
||||
{/if}
|
||||
{#if data.post.subheadline}
|
||||
<p class="text-zinc-600 lead">{data.post.subheadline}</p>
|
||||
<p class="text-zinc-600 lead p-summary">{data.post.subheadline}</p>
|
||||
{/if}
|
||||
</header>
|
||||
{/if}
|
||||
{#if !data.post.subheadline && data.post.excerpt}
|
||||
<p class="p-summary sr-only">{data.post.excerpt}</p>
|
||||
{/if}
|
||||
{#if data.isEvent && (data.eventDateLabel || data.eventLocationText)}
|
||||
<div class="mb-6">
|
||||
<EventBadges
|
||||
@@ -97,13 +112,25 @@
|
||||
</div>
|
||||
{/if}
|
||||
{#if data.contentBodyHtml}
|
||||
<div class="content markdown max-w-none prose prose-zinc">
|
||||
<div class="content markdown max-w-none prose prose-zinc e-content">
|
||||
{@html data.contentBodyHtml}
|
||||
</div>
|
||||
{/if}
|
||||
{#if data.hasRowContent}
|
||||
<ContentRows layout={data.post} translations={data.translations} />
|
||||
{/if}
|
||||
{#if (data.post.postTag ?? []).length > 0}
|
||||
<div hidden>
|
||||
{#each data.post.postTag ?? [] as tag}
|
||||
{#if tag && typeof tag === 'object' && 'name' in tag && tag.name}
|
||||
<span class="p-category">{tag.name}</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="p-author h-card" hidden>
|
||||
<span class="p-name">{data.post.author ?? 'Bürgerinitiative Vachdorf'}</span>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
{#if data.isEvent && (data.mapEmbedUrl || data.mapLinkUrl)}
|
||||
|
||||
Reference in New Issue
Block a user