refactor: Simplify JSON-LD generation in category SEO by removing unnecessary product details and focusing on URLs for improved compliance with Google guidelines

This commit is contained in:
sebseb7
2026-03-28 17:34:00 +01:00
parent 36360df648
commit 5e5a733d36

View File

@@ -50,11 +50,6 @@ const generateCategoryJsonLd = (category, products = [], baseUrl, config) => {
const root = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
const categoryUrl = `${root}/Kategorie/${category.seoName}`;
// Calculate price valid date (current date + 3 months)
const priceValidDate = new Date();
priceValidDate.setMonth(priceValidDate.getMonth() + 3);
const priceValidUntil = priceValidDate.toISOString().split("T")[0];
const id = {
business: `${root}#business`,
website: `${root}#website`,
@@ -117,87 +112,19 @@ const generateCategoryJsonLd = (category, products = [], baseUrl, config) => {
const graph = [businessNode, websiteNode, breadcrumbNode, collectionPageNode];
// Add product list if products are available
if (products && products.length > 0) {
// ItemList: URLs only — full Product/Offer markup belongs on each /Artikel/… page (Google guidelines).
const withUrls = (products || []).filter((p) => p && p.seoName);
if (withUrls.length > 0) {
collectionPageNode.mainEntity = { "@id": id.itemList };
graph.push({
"@id": id.itemList,
"@type": "ItemList",
numberOfItems: products.length,
itemListElement: products.slice(0, 20).map((product, index) => ({
numberOfItems: withUrls.length,
itemListElement: withUrls.map((product, index) => ({
"@type": "ListItem",
position: index + 1,
item: {
"@type": "Product",
name: product.name,
url: `${root}/Artikel/${product.seoName}`,
image:
product.pictureList && product.pictureList.trim()
? `${root}/assets/images/prod${product.pictureList
.split(",")[0]
.trim()}.avif`
: `${root}/assets/images/nopicture.jpg`,
description: product.description
? product.description.replace(/<[^>]*>/g, "").substring(0, 200)
: `${product.name} - Hochwertiges Growshop Produkt`,
sku: product.articleNumber || product.seoName,
brand: {
"@type": "Brand",
name: product.manufacturer || config.brandName,
},
offers: {
"@type": "Offer",
url: `${root}/Artikel/${product.seoName}`,
price:
product.price && !isNaN(product.price)
? product.price.toString()
: "0.00",
priceCurrency: config.currency,
priceValidUntil: priceValidUntil,
availability: product.available
? "https://schema.org/InStock"
: "https://schema.org/OutOfStock",
seller: { "@id": id.business },
itemCondition: "https://schema.org/NewCondition",
hasMerchantReturnPolicy: {
"@type": "MerchantReturnPolicy",
applicableCountry: "DE",
returnPolicyCategory:
"https://schema.org/MerchantReturnFiniteReturnWindow",
merchantReturnDays: 14,
returnMethod: "https://schema.org/ReturnByMail",
returnFees: "https://schema.org/FreeReturn",
},
shippingDetails: {
"@type": "OfferShippingDetails",
shippingRate: {
"@type": "MonetaryAmount",
value: 5.9,
currency: "EUR",
},
shippingDestination: {
"@type": "DefinedRegion",
addressCountry: "DE",
},
deliveryTime: {
"@type": "ShippingDeliveryTime",
handlingTime: {
"@type": "QuantitativeValue",
minValue: 0,
maxValue: 1,
unitCode: "DAY",
},
transitTime: {
"@type": "QuantitativeValue",
minValue: 2,
maxValue: 3,
unitCode: "DAY",
},
},
},
},
},
item: `${root}/Artikel/${product.seoName}`,
})),
});
}