feat(post): emit VideoObject JSON-LD for embedded YouTube videos
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:
@@ -171,6 +171,43 @@ export const load: PageServerLoad = async ({ params, locals, url, setHeaders })
|
|||||||
};
|
};
|
||||||
jsonLd.push(articleLd);
|
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) {
|
if (isEvent && eventDateRaw) {
|
||||||
const eventLd: Record<string, unknown> = {
|
const eventLd: Record<string, unknown> = {
|
||||||
'@context': 'https://schema.org',
|
'@context': 'https://schema.org',
|
||||||
|
|||||||
Reference in New Issue
Block a user