feat(post): emit VideoObject JSON-LD for embedded YouTube videos
Deploy / verify (push) Failing after 38s
Deploy / deploy (push) Has been skipped

Posts whose row*Content contains a `youtube_video` block now ship a
schema.org VideoObject per video alongside the existing BlogPosting /
Event JSON-LD. Lets Google attach a video rich-result to the post URL
(thumbnail, duration where available, embed/content URLs) instead of
treating the page as plain text whose body happens to be a single
iframe.

Thumbnail uses YouTube's predictable maxresdefault + hqdefault URLs;
upload date falls back to post.created when the embed has none.
This commit is contained in:
Peter Meier
2026-04-25 09:16:33 +02:00
parent 5b82d37be4
commit 7264ad6707
+37
View File
@@ -171,6 +171,43 @@ export const load: PageServerLoad = async ({ params, locals, url, setHeaders })
};
jsonLd.push(articleLd);
// Collect YouTube embeds from row*Content and emit a VideoObject per video.
// Helps Google index the post as a video page (rich result eligibility).
type RowItem = { _type?: string; youtubeId?: string; title?: string; description?: string };
const rows: RowItem[] = [
...(((post as { row1Content?: RowItem[] }).row1Content) ?? []),
...(((post as { row2Content?: RowItem[] }).row2Content) ?? []),
...(((post as { row3Content?: RowItem[] }).row3Content) ?? []),
];
const videos = rows.filter(
(r) => r && r._type === 'youtube_video' && typeof r.youtubeId === 'string' && r.youtubeId,
);
for (const v of videos) {
const id = v.youtubeId as string;
jsonLd.push({
'@context': 'https://schema.org',
'@type': 'VideoObject',
name: v.title ?? postHeadline,
description: v.description ?? postDescription ?? postHeadline,
thumbnailUrl: [
`https://i.ytimg.com/vi/${id}/maxresdefault.jpg`,
`https://i.ytimg.com/vi/${id}/hqdefault.jpg`,
],
uploadDate: postCreated ?? new Date().toISOString(),
contentUrl: `https://www.youtube.com/watch?v=${id}`,
embedUrl: `https://www.youtube.com/embed/${id}`,
...(siteBaseUrl
? {
publisher: {
'@type': 'Organization',
name: siteName,
url: siteBaseUrl,
},
}
: {}),
});
}
if (isEvent && eventDateRaw) {
const eventLd: Record<string, unknown> = {
'@context': 'https://schema.org',