[object Object]

← back to Wallco Ai

wallco.ai · /designs JSON-LD — ItemList of Products + BreadcrumbList

1d2bb76a631a2655699fd05f9fc82e69f9e00e0f · 2026-05-12 06:46:14 -0700 · SteveStudio2

ItemList was bare (name/url only) — Google saw a list of links, not a list
of products. Now each ListItem embeds a full Product (sku/productID/category/
color/material/brand/offers) so Google can render list-of-products rich
results (carousel-style snippet in SERP).

Adds BreadcrumbList as a second JSON-LD block. Adapts when a category filter
is active: Home → Designs → {cat}. Hue family derived from dominant_hex via
the same algorithm as /design/:id (rose/amber/honey/olive/sage/marine/
sapphire/mauve/plum/neutral).

Reversible: schema generation isolated; two JSON-LD blocks concatenated via
a single </script><script> seam so the existing template stays one expression.

Files touched

Diff

commit 1d2bb76a631a2655699fd05f9fc82e69f9e00e0f
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Tue May 12 06:46:14 2026 -0700

    wallco.ai · /designs JSON-LD — ItemList of Products + BreadcrumbList
    
    ItemList was bare (name/url only) — Google saw a list of links, not a list
    of products. Now each ListItem embeds a full Product (sku/productID/category/
    color/material/brand/offers) so Google can render list-of-products rich
    results (carousel-style snippet in SERP).
    
    Adds BreadcrumbList as a second JSON-LD block. Adapts when a category filter
    is active: Home → Designs → {cat}. Hue family derived from dominant_hex via
    the same algorithm as /design/:id (rose/amber/honey/olive/sage/marine/
    sapphire/mauve/plum/neutral).
    
    Reversible: schema generation isolated; two JSON-LD blocks concatenated via
    a single </script><script> seam so the existing template stays one expression.
---
 server.js | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 51 insertions(+), 4 deletions(-)

diff --git a/server.js b/server.js
index e6d9211..ab48b0f 100644
--- a/server.js
+++ b/server.js
@@ -1017,18 +1017,65 @@ app.get('/designs', (req, res) => {
       ).join(' ')
     : '';
 
-  const schema = JSON.stringify({
+  // Each ListItem embeds a full Product object so Google can render
+  // list-of-products rich results (not just bare URLs). Mirrors the
+  // per-design Product schema from /design/:id but trimmed to grid-card
+  // essentials: name, image, sku, category, brand, offers.
+  const _hueOf = (hex) => {
+    const h = (hex || '').toLowerCase();
+    if (!/^#[0-9a-f]{6}$/.test(h)) return '';
+    const r=parseInt(h.slice(1,3),16), g=parseInt(h.slice(3,5),16), b=parseInt(h.slice(5,7),16);
+    const max=Math.max(r,g,b), min=Math.min(r,g,b), s=max?(max-min)/max:0;
+    if (s<0.12) return 'neutral';
+    const hh = ((max===r ? (g-b)/(max-min)+(g<b?6:0) : max===g ? (b-r)/(max-min)+2 : (r-g)/(max-min)+4) * 60 + 360) % 360;
+    if (hh<15||hh>=345) return 'rose'; if (hh<40) return 'amber'; if (hh<60) return 'honey';
+    if (hh<90) return 'olive';  if (hh<160) return 'sage';  if (hh<200) return 'marine';
+    if (hh<250) return 'sapphire'; if (hh<290) return 'mauve'; return 'plum';
+  };
+
+  const itemList = {
     "@context": "https://schema.org",
     "@type": "ItemList",
     "name": "Original Wallpaper Designs — wallco.ai",
+    "url": `https://wallco.ai/designs${page > 1 ? `?page=${page}` : ''}`,
     "numberOfItems": total,
+    "itemListOrder": "https://schema.org/ItemListOrderDescending",
     "itemListElement": slice.map((d,i) => ({
       "@type": "ListItem",
       "position": (page-1)*PER+i+1,
-      "name": d.title,
-      "url": `https://wallco.ai/design/${d.id}`
+      "item": {
+        "@type": "Product",
+        "@id": `https://wallco.ai/design/${d.id}`,
+        "name": d.title,
+        "url": `https://wallco.ai/design/${d.id}`,
+        "image": `https://wallco.ai${d.image_url}`,
+        "sku": d.handle || `wallco-${String(d.id).padStart(4,'0')}`,
+        "productID": String(d.id),
+        "category": d.category,
+        "color": _hueOf(d.dominant_hex) || undefined,
+        "material": "Wallpaper",
+        "brand": { "@type": "Brand", "name": "wallco.ai" },
+        "offers": {
+          "@type": "Offer",
+          "availability": "https://schema.org/InStock",
+          "url": `https://wallco.ai/samples?design=${d.id}`,
+          "priceCurrency": "USD",
+          "description": "Free sample available"
+        }
+      }
     }))
-  });
+  };
+
+  const breadcrumb = {
+    "@context": "https://schema.org",
+    "@type": "BreadcrumbList",
+    "itemListElement": [
+      { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://wallco.ai/" },
+      { "@type": "ListItem", "position": 2, "name": "Designs", "item": "https://wallco.ai/designs" }
+    ].concat(cat ? [{ "@type": "ListItem", "position": 3, "name": cat, "item": `https://wallco.ai/designs?cat=${encodeURIComponent(cat)}` }] : [])
+  };
+
+  const schema = `${JSON.stringify(itemList)}</script>\n<script type="application/ld+json">${JSON.stringify(breadcrumb)}`;
 
   res.type('html').send(`${htmlHead({
     title: `All Designs — wallco.ai | AI-Original Wallpaper & Murals`,

← 0772bf0 security — prototype-pollution + pin-spam DoS guards in src/  ·  back to Wallco Ai  ·  spoonflower upload — fix hydration race + add --batch CSV mo f4354f9 →