refactor: Enhance JSON-LD structure in category and product generation functions for improved SEO and consistency across URLs

This commit is contained in:
sebseb7
2026-03-28 17:10:14 +01:00
parent c503de3a11
commit 21d86565f1
3 changed files with 396 additions and 278 deletions

View File

@@ -7,41 +7,82 @@ const generateCategoryJsonLd = (category, products = [], baseUrl, config) => {
return '';
}
const categoryUrl = `${baseUrl}/Kategorie/${category.seoName}`;
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 jsonLd = {
"@context": "https://schema.org/",
const id = {
business: `${root}#business`,
website: `${root}#website`,
breadcrumb: `${categoryUrl}#breadcrumb`,
itemList: `${categoryUrl}#itemlist`,
};
const logoUrl =
config.images && config.images.logo
? `${root}${config.images.logo}`
: undefined;
const businessNode = {
"@id": id.business,
"@type": ["GardenStore", "LocalBusiness", "Organization"],
name: config.brandName,
url: root,
...(logoUrl && {
logo: { "@type": "ImageObject", url: logoUrl },
image: { "@type": "ImageObject", url: logoUrl },
}),
};
const websiteNode = {
"@id": id.website,
"@type": "WebSite",
name: config.siteName || config.brandName,
url: root,
publisher: { "@id": id.business },
};
const breadcrumbNode = {
"@id": id.breadcrumb,
"@type": "BreadcrumbList",
itemListElement: [
{
"@type": "ListItem",
position: 1,
name: "Home",
item: root,
},
{
"@type": "ListItem",
position: 2,
name: category.name,
item: categoryUrl,
},
],
};
const collectionPageNode = {
"@id": categoryUrl,
"@type": "CollectionPage",
name: category.name,
url: categoryUrl,
description: `${category.name} - Entdecken Sie unsere Auswahl an hochwertigen Produkten`,
breadcrumb: {
"@type": "BreadcrumbList",
itemListElement: [
{
"@type": "ListItem",
position: 1,
name: "Home",
item: baseUrl,
},
{
"@type": "ListItem",
position: 2,
name: category.name,
item: categoryUrl,
},
],
},
isPartOf: { "@id": id.website },
breadcrumb: { "@id": id.breadcrumb },
};
const graph = [businessNode, websiteNode, breadcrumbNode, collectionPageNode];
// Add product list if products are available
if (products && products.length > 0) {
jsonLd.mainEntity = {
collectionPageNode.mainEntity = { "@id": id.itemList };
graph.push({
"@id": id.itemList,
"@type": "ItemList",
numberOfItems: products.length,
itemListElement: products.slice(0, 20).map((product, index) => ({
@@ -50,14 +91,14 @@ const generateCategoryJsonLd = (category, products = [], baseUrl, config) => {
item: {
"@type": "Product",
name: product.name,
url: `${baseUrl}/Artikel/${product.seoName}`,
url: `${root}/Artikel/${product.seoName}`,
image:
product.pictureList && product.pictureList.trim()
? `${baseUrl}/assets/images/prod${product.pictureList
? `${root}/assets/images/prod${product.pictureList
.split(",")[0]
.trim()}.avif`
: `${baseUrl}/assets/images/nopicture.jpg`,
description: product.description
: `${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,
@@ -67,22 +108,23 @@ const generateCategoryJsonLd = (category, products = [], baseUrl, config) => {
},
offers: {
"@type": "Offer",
url: `${baseUrl}/Artikel/${product.seoName}`,
price: product.price && !isNaN(product.price) ? product.price.toString() : "0.00",
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: {
"@type": "Organization",
name: config.brandName,
},
seller: { "@id": id.business },
itemCondition: "https://schema.org/NewCondition",
hasMerchantReturnPolicy: {
"@type": "MerchantReturnPolicy",
applicableCountry: "DE",
returnPolicyCategory: "https://schema.org/MerchantReturnFiniteReturnWindow",
returnPolicyCategory:
"https://schema.org/MerchantReturnFiniteReturnWindow",
merchantReturnDays: 14,
returnMethod: "https://schema.org/ReturnByMail",
returnFees: "https://schema.org/FreeReturn",
@@ -91,7 +133,7 @@ const generateCategoryJsonLd = (category, products = [], baseUrl, config) => {
"@type": "OfferShippingDetails",
shippingRate: {
"@type": "MonetaryAmount",
value: 5.90,
value: 5.9,
currency: "EUR",
},
shippingDestination: {
@@ -117,11 +159,16 @@ const generateCategoryJsonLd = (category, products = [], baseUrl, config) => {
},
},
})),
};
});
}
const categoryGraph = {
"@context": "https://schema.org",
"@graph": graph,
};
return `<script type="application/ld+json">${JSON.stringify(
jsonLd
categoryGraph
)}</script>`;
};