const generateProductMetaTags = (product, baseUrl, config) => { const productUrl = `${baseUrl}/Artikel/${product.seoName}`; const pictureFirstId = product.pictureList && product.pictureList.trim() ? product.pictureList.split(",")[0].trim() : null; const imageUrl = pictureFirstId ? `${baseUrl}/assets/images/prod${pictureFirstId}.avif` : `${baseUrl}/assets/images/nopicture.jpg`; const twitterImageUrl = pictureFirstId ? `${baseUrl}/assets/images/prod${pictureFirstId}.jpg` : `${baseUrl}/assets/images/nopicture.jpg`; // Clean description for meta (remove HTML tags and limit length) const cleanDescription = product.kurzBeschreibung ? product.kurzBeschreibung .replace(/<[^>]*>/g, "") .replace(/\n/g, " ") .substring(0, 160) : product.description ? product.description .replace(/<[^>]*>/g, "") .replace(/\n/g, " ") .substring(0, 160) : `${product.name} - Art.-Nr.: ${product.articleNumber}`; return ` ${product.gtin ? `` : ''} ${product.articleNumber ? `` : ''} ${product.manufacturer ? `` : ''} `; }; const generateProductJsonLd = (product, baseUrl, config, categoryInfo = null) => { const root = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl; const productUrl = `${root}/Artikel/${product.seoName}`; const pictureFirstId = product.pictureList && product.pictureList.trim() ? product.pictureList.split(",")[0].trim() : null; const imageUrl = pictureFirstId ? `${root}/assets/images/prod${pictureFirstId}.avif` : `${root}/assets/images/nopicture.jpg`; // Clean description for JSON-LD (remove HTML tags) const cleanDescription = product.description ? product.description.replace(/<[^>]*>/g, "").replace(/\n/g, " ") : product.name; // Calculate price valid date (current date + 3 months) const priceValidDate = new Date(); priceValidDate.setMonth(priceValidDate.getMonth() + 3); const id = { business: `${root}#business`, website: `${root}#website`, product: `${productUrl}#product`, breadcrumb: `${productUrl}#breadcrumb`, }; 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 offer = { "@type": "Offer", url: productUrl, priceCurrency: config.currency, price: product.price.toString(), priceValidUntil: priceValidDate.toISOString().split("T")[0], itemCondition: "https://schema.org/NewCondition", availability: product.available ? "https://schema.org/InStock" : "https://schema.org/OutOfStock", seller: { "@id": id.business }, 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", }, }, }, }; const productNode = { "@id": id.product, "@type": "Product", name: product.name, image: [imageUrl], description: cleanDescription, sku: product.articleNumber, ...(product.gtin && { gtin: product.gtin }), brand: { "@type": "Brand", name: product.manufacturer || "Unknown", }, offers: offer, }; const hasBreadcrumb = categoryInfo && categoryInfo.name && categoryInfo.seoName; const breadcrumbList = hasBreadcrumb ? { "@id": id.breadcrumb, "@type": "BreadcrumbList", itemListElement: [ { "@type": "ListItem", position: 1, name: "Home", item: root, }, { "@type": "ListItem", position: 2, name: categoryInfo.name, item: `${root}/Kategorie/${categoryInfo.seoName}`, }, { "@type": "ListItem", position: 3, name: product.name, item: productUrl, }, ], } : null; const itemPageNode = { "@id": productUrl, "@type": "ItemPage", url: productUrl, name: product.name, isPartOf: { "@id": id.website }, mainEntity: { "@id": id.product }, ...(hasBreadcrumb && { breadcrumb: { "@id": id.breadcrumb } }), }; const graph = [ businessNode, websiteNode, itemPageNode, ...(breadcrumbList ? [breadcrumbList] : []), productNode, ]; const productGraph = { "@context": "https://schema.org", "@graph": graph, }; return ``; }; module.exports = { generateProductMetaTags, generateProductJsonLd, };