Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | 16x 16x 16x 16x 16x 25x 16x 4x 3x | // Builds the schema.org Article JSON-LD object for blog posts.
// Extracted into a plain function so it can be unit-tested without Astro.
import type { BlogPost } from "../api/types";
export interface ArticleSchemaInput {
blog: BlogPost;
canonicalUrl: string;
siteUrl?: string;
}
export function buildArticleSchema(input: ArticleSchemaInput): Record<string, unknown> {
const { blog, canonicalUrl } = input;
const SITE_URL = input.siteUrl ?? "https://interioring.com";
const SITE_NAME = "Interioring";
const LOGO_URL = `${SITE_URL}/logo.png`;
// Build deduplicated keywords array: primary first, then secondaries, no empties, no dupes.
const rawKeywords: (string | null | undefined)[] = [
blog.primaryKeyword,
...(blog.secondaryKeywords ?? []),
];
const keywords = [...new Set(rawKeywords.filter((k): k is string => Boolean(k)))];
return {
"@context": "https://schema.org",
"@type": "Article",
headline: blog.title,
description: blog.metaDescription,
image: blog.featuredImageUrl ?? `${SITE_URL}/og-image.jpg`,
datePublished: blog.publishedAt,
dateModified: blog.dateUpdated,
author: {
"@type": "Organization",
name: SITE_NAME,
url: SITE_URL,
logo: {
"@type": "ImageObject",
url: LOGO_URL,
},
},
publisher: {
"@type": "Organization",
name: SITE_NAME,
url: SITE_URL,
logo: {
"@type": "ImageObject",
url: LOGO_URL,
},
},
mainEntityOfPage: {
"@type": "WebPage",
"@id": canonicalUrl,
},
...(blog.pros && blog.pros.length > 0 && {
mentions: blog.pros
.filter((v) => v.pro)
.map((v) => ({
"@type": "LocalBusiness",
name: v.pro?.businessName,
url: `${SITE_URL}/pros/${v.pro?.slug ?? v.pro?.id}`,
})),
}),
...(keywords.length > 0 && {
keywords: keywords.join(", "),
}),
...(blog.primaryKeyword && {
about: {
"@type": "Thing",
name: blog.primaryKeyword,
},
}),
};
}
|