Files
ipal-kit/src/modules/seo/buildArticleJsonLd.ts
T

83 lines
2.7 KiB
TypeScript

type MediaLike = { url?: string | null } | null | undefined
type ArticleJsonLdArgs = {
/** Article headline (the title). */
headline: string
/** Absolute URL of the article. */
url: string
description?: string
/** Cover/hero image. */
image?: MediaLike
/** ISO date the article was first published, e.g. '2026-01-15'. */
datePublished?: string
/** ISO date of the last modification. Defaults to datePublished. */
dateModified?: string
/** Author name (person or org). */
author?: string
/** Publisher (usually the site/organization) name. */
publisherName?: string
/** Publisher logo (for the Article rich result). */
publisherLogo?: MediaLike
/** 'Article' (default), 'BlogPosting', or 'NewsArticle'. */
type?: 'Article' | 'BlogPosting' | 'NewsArticle'
}
/**
* Builds Article / BlogPosting JSON-LD (schema.org) for blog posts and articles.
* Enables article rich results in Google (headline, date, author, image). Pairs
* with the plugin's content collections (blog/archives).
*
* Per-article (each post emits its own), data from the document + panel:
*
* import { buildArticleJsonLd } from '@intecion/ipal-kit'
* const jsonLd = buildArticleJsonLd({
* headline: post.title, url: postUrl, description: post.excerpt,
* image: post.coverImage, datePublished: post.publishedAt,
* author: post.author, publisherName: settings.siteName,
* publisherLogo: settings.logo, type: 'BlogPosting',
* })
*
* All data from the document/panel — nothing hardcoded. Google requires headline
* and dates for the rich result; supply them from the post's real fields.
*/
export function buildArticleJsonLd({
headline,
url,
description,
image,
datePublished,
dateModified,
author,
publisherName,
publisherLogo,
type = 'Article',
}: ArticleJsonLdArgs) {
const imageUrl = image?.url
const logoUrl = publisherLogo?.url
const abs = (u: string | null | undefined): string | undefined =>
u ? (u.startsWith('http') ? u : `${url.split('/').slice(0, 3).join('/')}${u}`) : undefined
return {
'@context': 'https://schema.org',
'@type': type,
headline,
url,
mainEntityOfPage: { '@type': 'WebPage', '@id': url },
...(description ? { description } : {}),
...(imageUrl ? { image: abs(imageUrl) } : {}),
...(datePublished ? { datePublished } : {}),
...(dateModified || datePublished ? { dateModified: dateModified ?? datePublished } : {}),
...(author ? { author: { '@type': 'Person', name: author } } : {}),
...(publisherName
? {
publisher: {
'@type': 'Organization',
name: publisherName,
...(logoUrl ? { logo: { '@type': 'ImageObject', url: abs(logoUrl) } } : {}),
},
}
: {}),
}
}