[object Object]

← back to Prestige Car Wash

SEO: enrich AutoWash JSON-LD with hasOfferCatalog (real service prices, quote-only safe)

157f32aaff995a29585514f788e218b19b91eb3c · 2026-07-26 14:37:04 -0700 · steve@designerwallcoverings.com

Files touched

Diff

commit 157f32aaff995a29585514f788e218b19b91eb3c
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date:   Sun Jul 26 14:37:04 2026 -0700

    SEO: enrich AutoWash JSON-LD with hasOfferCatalog (real service prices, quote-only safe)
---
 server.js | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/server.js b/server.js
index ff91204..3a050ea 100644
--- a/server.js
+++ b/server.js
@@ -404,6 +404,20 @@ function buildJsonLd() {
   const ig = p.instagram ? (/^https?:\/\//.test(p.instagram) ? p.instagram : `https://instagram.com/${String(p.instagram).replace(/^@/, '')}`) : null;
   const same = [ig, p.yelp_url].filter(Boolean);
   if (same.length) ld.sameAs = same;
+  // Service catalog with REAL prices (only where a numeric price exists — quote-only
+  // services list the Service without a fabricated price). Strengthens rich results.
+  const svc = (services() || []).filter(s => s && s.name);
+  if (svc.length) {
+    ld.hasOfferCatalog = {
+      '@type': 'OfferCatalog', name: 'Car Wash & Detailing Services',
+      itemListElement: svc.map(s => {
+        const offer = { '@type': 'Offer', itemOffered: { '@type': 'Service', name: s.name } };
+        if (s.blurb) offer.itemOffered.description = s.blurb;
+        if (s.price != null && !isNaN(Number(s.price))) { offer.price = Number(s.price); offer.priceCurrency = 'USD'; }
+        return offer;
+      })
+    };
+  }
   return ld;
 }
 // Open Graph / Twitter tags for the homepage — reuses the page's own <title> and meta

← 82b259c SEO infra: robots.txt + generated /sitemap.xml + homepage OG  ·  back to Prestige Car Wash  ·  Admin: lead-status pipeline (new→contacted→booked/won/lost) 7c77409 →