[object Object]

← back to Carmelwallpapers

fix: scrub p.vendor leaks from customer-facing UI (use "Designer Wallcoverings")

fafb00124ef9a8b6aff12ef194112913cb9f504b · 2026-05-25 20:52:56 -0700 · Steve

Replaces dynamic vendor renders on product detail card, grid card, rail card,
meta description, and schema.org brand with the literal "Designer Wallcoverings".
Drops the now-meaningless "Vendor A→Z" sort option from the dropdown and clears
the value from any existing localStorage to avoid stale state. Standing rule
per global CLAUDE.md: DW vendor names NEVER in customer-facing UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit fafb00124ef9a8b6aff12ef194112913cb9f504b
Author: Steve <steve@designerwallcoverings.com>
Date:   Mon May 25 20:52:56 2026 -0700

    fix: scrub p.vendor leaks from customer-facing UI (use "Designer Wallcoverings")
    
    Replaces dynamic vendor renders on product detail card, grid card, rail card,
    meta description, and schema.org brand with the literal "Designer Wallcoverings".
    Drops the now-meaningless "Vendor A→Z" sort option from the dropdown and clears
    the value from any existing localStorage to avoid stale state. Standing rule
    per global CLAUDE.md: DW vendor names NEVER in customer-facing UI.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 server.js | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/server.js b/server.js
index c6892cd..d200957 100644
--- a/server.js
+++ b/server.js
@@ -359,7 +359,7 @@ app.get('/p/:handle', (req, res) => {
   if (!p) return res.status(404).send('<h1>Not found</h1>');
 
   const title = `${p.title} — Carmel Wallpapers | Free Memo Samples, Trade Service`;
-  const desc = `${p.title} by ${p.vendor}. Order a free memo sample. Coastal California's curated wallpaper source — expert trade service, hand-holding from Carmel to Pebble Beach.`;
+  const desc = `${p.title} by Designer Wallcoverings. Order a free memo sample. Coastal California's curated wallpaper source — expert trade service, hand-holding from Carmel to Pebble Beach.`;
 
   const imgs = (p.images||[p.image_url]).filter(Boolean);
   const imgHtml = imgs.map((src,i) =>
@@ -376,7 +376,7 @@ ${HEADER_HTML()}
   <div class="detail-grid">
     <div class="detail-images">${imgHtml}</div>
     <div class="detail-info">
-      <p class="detail-vendor">${p.vendor}</p>
+      <p class="detail-vendor">Designer Wallcoverings</p>
       <h1 class="detail-title">${p.title}</h1>
       <div class="detail-tags">${tags.slice(0,10).map(t=>`<span class="tag">${t}</span>`).join('')}</div>
       <div class="detail-ctas">
@@ -398,7 +398,7 @@ ${HEADER_HTML()}
   </div>
 </footer>
 <script type="application/ld+json">${JSON.stringify({
-  "@context":"https://schema.org","@type":"Product","name":p.title,"brand":{"@type":"Brand","name":p.vendor},
+  "@context":"https://schema.org","@type":"Product","name":p.title,"brand":{"@type":"Brand","name":"Designer Wallcoverings"},
   "image":imgs[0]||'',
   "offers":{"@type":"Offer","priceCurrency":"USD","price":"0","description":"Free memo sample"},
   "description":desc
@@ -485,7 +485,6 @@ ${HEADER_HTML(q, sort, density)}
         <option value="style" ${sort==='style'?'selected':''}>Style</option>
         <option value="sku" ${sort==='sku'?'selected':''}>SKU A→Z</option>
         <option value="title" ${sort==='title'?'selected':''}>Title A→Z</option>
-        <option value="vendor" ${sort==='vendor'?'selected':''}>Vendor A→Z</option>
       </select>
       <label class="density-label" aria-label="Grid density">
         <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><rect x="0" y="0" width="4" height="4"/><rect x="6" y="0" width="4" height="4"/><rect x="12" y="0" width="4" height="4"/><rect x="0" y="6" width="4" height="4"/><rect x="6" y="6" width="4" height="4"/><rect x="12" y="6" width="4" height="4"/></svg>
@@ -557,9 +556,11 @@ const sortSel = document.getElementById('sortSelect');
 const densSlider = document.getElementById('densitySlider');
 const grid = document.getElementById('grid');
 
-const savedSort = localStorage.getItem('cw_sort');
+let savedSort = localStorage.getItem('cw_sort');
+if (savedSort === 'vendor') { savedSort = null; try { localStorage.removeItem('cw_sort'); } catch(e){} }
 const savedDensity = localStorage.getItem('cw_density');
-if(savedSort && !${JSON.stringify(!!req.query.sort)}) { sortSel.value = savedSort; STATE.sort = savedSort; }
+const validSortValues = new Set(['newest','color','style','sku','title']);
+if(savedSort && validSortValues.has(savedSort) && !${JSON.stringify(!!req.query.sort)}) { sortSel.value = savedSort; STATE.sort = savedSort; }
 if(savedDensity) { densSlider.value = savedDensity; grid.style.setProperty('--cols', savedDensity+'px'); }
 
 sortSel.addEventListener('change', () => {
@@ -586,7 +587,7 @@ function renderCard(p) {
         <img src="\${p.image_url}" alt="\${p.title.replace(/"/g,'&quot;')}" loading="lazy" class="card-img">
       </div>
       <div class="card-body">
-        <p class="card-vendor">\${p.vendor}</p>
+        <p class="card-vendor">Designer Wallcoverings</p>
         <p class="card-title">\${p.title}</p>
         <p class="card-aesthetic">\${p.aesthetic}</p>
       </div>
@@ -660,7 +661,7 @@ async function loadSliders() {
             <a href="/p/\${p.handle}" class="rail-card" aria-label="\${(p.title||'').replace(/"/g,'&quot;')}">
               <div class="rail-img-wrap"><img src="\${p.image_url}" alt="\${(p.title||'').replace(/"/g,'&quot;')}" loading="lazy" class="rail-img"></div>
               <p class="rail-card-title">\${p.title}</p>
-              <p class="rail-card-vendor">\${p.vendor}</p>
+              <p class="rail-card-vendor">Designer Wallcoverings</p>
             </a>
           \`).join('')}
         </div>

← 0b699bc pull-from-shopify: use shared classifier with rails primary,  ·  back to Carmelwallpapers  ·  fix: drop dead 'Raffia' nav links — 0 products tagged raffia ff4542f →