Product JSON-LD: add sku + gallery images, single-source the meta description

sku was tracked in Payload but never exposed to the frontend at all —
added to the Product type and wired into buildProductSchema (a real
Schema.org property Google's rich-result validator checks for).
image is now an array (main + gallery) when a product has gallery
photos, instead of always just the one main image.

/der-eine's page metadata description was a separately hardcoded
string that had drifted from Products.description (the one JSON-LD/
cart/checkout actually use) — now reads from the live product via
generateMetadata, same pattern /tasse-die-pause already uses. Updated
Payload's own description field to the more product-descriptive text
that used to live only in that hardcoded string.
This commit is contained in:
Marco
2026-08-26 21:20:44 +00:00
parent 39ebf2604d
commit 56fae6ff13
4 changed files with 24 additions and 17 deletions
+1
View File
@@ -7,6 +7,7 @@ const product = (overrides: Partial<Product> = {}): Product => ({
numericId: 1,
name: "ToDo-Karten",
description: "",
sku: null,
price: 12.9,
compareAtPrice: null,
image: "",
+6
View File
@@ -182,6 +182,10 @@ export type Product = {
numericId: number;
name: string;
description: string;
// Not shown anywhere in the UI today — only consumed by
// buildProductSchema (JSON-LD's Product.sku), a real Schema.org property
// Google's rich-result validator looks for.
sku: string | null;
price: number;
compareAtPrice: number | null;
image: string;
@@ -264,6 +268,7 @@ type PayloadProduct = {
name: string;
slug: string;
description: string | null;
sku: string | null;
price: number;
compareAtPrice: number | null;
image: { url: string } | number | null;
@@ -330,6 +335,7 @@ export function mapPayloadProduct(product: PayloadProduct): Product {
numericId: product.id,
name: product.name,
description: product.description ?? "",
sku: product.sku || null,
price: product.price,
compareAtPrice: product.compareAtPrice ?? null,
image: typeof product.image === "object" && product.image ? product.image.url : "",
+2 -1
View File
@@ -54,8 +54,9 @@ export function buildProductSchema(product: Product, url: string, seller: Compan
"@type": "Product",
name: product.name,
description: product.description,
image: product.image,
image: product.gallery.length > 0 ? [product.image, ...product.gallery] : product.image,
url,
...(product.sku ? { sku: product.sku } : {}),
// No reviews/ratings system exists yet — `aggregateRating` is
// optional in the spec and deliberately omitted rather than faked;
// add it here once real reviews exist, not before.