Improve social media OG/Twitter meta for posts
Deploy / verify (push) Successful in 51s
Deploy / deploy (push) Successful in 1m2s

- Fix bug: post page was overriding og:image with 150x200 thumbnail
- og:type = "article" for posts (was always "website")
- article:published_time, article:modified_time, article:author, article:tag
- og:image:alt + twitter:image:alt (post headline)
- twitter:label1/data1 with reading time
- Remove thumbnail fallback from socialImage (falls back to site logo instead)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Peter Meier
2026-05-16 15:35:32 +02:00
parent d7a84aff0d
commit 44b991f7c1
3 changed files with 43 additions and 13 deletions
+31 -1
View File
@@ -52,6 +52,14 @@
seoTitle?: string;
seoDescription?: string;
socialImage?: string;
ogType?: string;
ogImageAlt?: string;
articlePublishedTime?: string | null;
articleModifiedTime?: string | null;
articleAuthor?: string | null;
articleTags?: string[];
twitterLabel1?: string;
twitterData1?: string;
robots?: string;
keywords?: string;
preview?: boolean;
@@ -218,7 +226,7 @@
{/if}
<link rel="canonical" href={canonical} />
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:type" content={pageData?.ogType ?? "website"} />
<meta property="og:url" content={canonical} />
<meta property="og:title" content={seoTitle} />
{#if seoDescription}
@@ -228,9 +236,24 @@
<meta property="og:image" content={socialImageUrl} />
<meta property="og:image:width" content={String(SOCIAL_IMAGE_DIMENSIONS.width)} />
<meta property="og:image:height" content={String(SOCIAL_IMAGE_DIMENSIONS.height)} />
{#if pageData?.ogImageAlt}
<meta property="og:image:alt" content={pageData.ogImageAlt} />
{/if}
{/if}
<meta property="og:locale" content="de_DE" />
<meta property="og:site_name" content={data.siteName} />
{#if pageData?.articlePublishedTime}
<meta property="article:published_time" content={pageData.articlePublishedTime} />
{/if}
{#if pageData?.articleModifiedTime}
<meta property="article:modified_time" content={pageData.articleModifiedTime} />
{/if}
{#if pageData?.articleAuthor}
<meta property="article:author" content={pageData.articleAuthor} />
{/if}
{#each pageData?.articleTags ?? [] as tag}
<meta property="article:tag" content={tag} />
{/each}
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:url" content={canonical} />
@@ -240,6 +263,13 @@
{/if}
{#if socialImageUrl}
<meta name="twitter:image" content={socialImageUrl} />
{#if pageData?.ogImageAlt}
<meta name="twitter:image:alt" content={pageData.ogImageAlt} />
{/if}
{/if}
{#if pageData?.twitterLabel1 && pageData?.twitterData1}
<meta name="twitter:label1" content={pageData.twitterLabel1} />
<meta name="twitter:data1" content={pageData.twitterData1} />
{/if}
<!-- JSON-LD WebSite + Organization -->
{@html jsonLdScript}
+12 -3
View File
@@ -303,13 +303,22 @@ export const load: PageServerLoad = async ({ params, locals, url, setHeaders })
translations,
seoTitle: post.seoTitle ?? postHeadline,
seoDescription: postDescription,
socialImage: postSocialImageAbs ?? postImageUrl ?? undefined,
socialImage: postSocialImageAbs ?? undefined,
ogType: 'article' as const,
ogImageAlt: postHeadline,
articlePublishedTime: postCreated,
articleModifiedTime: postUpdated,
articleAuthor: postAuthor ?? siteName,
articleTags: (() => {
const tags = (post as { postTag?: Array<{ name?: string }> }).postTag ?? [];
return tags.map((t) => (typeof t === 'string' ? t : (t?.name ?? ''))).filter(Boolean);
})(),
twitterLabel1: 'Lesezeit',
twitterData1: `${readingTimeMinutes} Min.`,
robots: (post as { seoMetaRobots?: string }).seoMetaRobots ?? 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() : ''))
-9
View File
@@ -14,15 +14,6 @@
let { data }: { data: PageData } = $props();
</script>
<svelte:head>
<title>{data.seoTitle}</title>
{#if data.seoDescription}
<meta name="description" content={data.seoDescription} />
{/if}
{#if data.postImageUrl}
<meta property="og:image" content={data.postImageUrl} />
{/if}
</svelte:head>
<div class="my-4 md:flex md:items-start md:gap-4">
{#if data.rawPostImageUrl}