[object Object]

← back to Carmelwallpapers

seo: add per-page canonical + Open Graph + Twitter card (HTML_HEAD threads canonical+ogImage; index collapses facets to type per DTD-B, detail uses redacted product slug)

9753035ac930f7e610ba9ad40099ee35757f50af · 2026-06-04 08:06:22 -0700 · Steve

Files touched

Diff

commit 9753035ac930f7e610ba9ad40099ee35757f50af
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Jun 4 08:06:22 2026 -0700

    seo: add per-page canonical + Open Graph + Twitter card (HTML_HEAD threads canonical+ogImage; index collapses facets to type per DTD-B, detail uses redacted product slug)
---
 server.js | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/server.js b/server.js
index 563e3c0..6c58a64 100644
--- a/server.js
+++ b/server.js
@@ -231,7 +231,7 @@ app.use(express.static(path.join(__dirname, 'public')));
 IMGP.mount(app);
 
 // ── HTML helpers ─────────────────────────────────────────────────────────────
-const HTML_HEAD = (title, desc) => `<!DOCTYPE html>
+const HTML_HEAD = (title, desc, canonical='', ogImage='') => `<!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="utf-8">
@@ -242,6 +242,11 @@ const HTML_HEAD = (title, desc) => `<!DOCTYPE html>
 <script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','G-ENN0QV40F8');</script>
 <title>${title}</title>
 <meta name="description" content="${desc}">
+${canonical?`<link rel="canonical" href="${canonical}">\n`:''}<meta property="og:type" content="website">
+<meta property="og:site_name" content="Carmel Wallpapers">
+<meta property="og:title" content="${title}">
+<meta property="og:description" content="${desc}">
+${canonical?`<meta property="og:url" content="${canonical}">\n`:''}${ogImage?`<meta property="og:image" content="${ogImage}">\n`:''}<meta name="twitter:card" content="${ogImage?'summary_large_image':'summary'}">
 <meta name="theme-color" content="#f7f3ec" media="(prefers-color-scheme: light)">
 <meta name="theme-color" content="#12100d" media="(prefers-color-scheme: dark)">
 <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -436,7 +441,8 @@ app.get('/p/:handle', (req, res) => {
 
   const tags = (p.tags||[]).filter(t => !/^\d+$/.test(t));
 
-  res.send(`${HTML_HEAD(title, desc)}
+  const canonical = `https://carmelwallpapers.com/p/${encodeURIComponent(redactVendorSlug(p.handle))}`;
+  res.send(`${HTML_HEAD(title, desc, canonical, imgs[0]||'')}
 <body>
 ${HEADER_HTML()}
 <main class="detail-wrap">
@@ -518,7 +524,9 @@ app.get('/', (req, res) => {
       return `<a href="${href}" class="chip${active}">${a.charAt(0).toUpperCase()+a.slice(1)} <span class="chip-count">${aestheticCounts[a]}</span></a>`;
     }).join('');
 
-  res.send(`${HTML_HEAD(pageTitle, pageDesc)}
+  const canonical = 'https://carmelwallpapers.com/' + (type ? `?type=${encodeURIComponent(type)}` : '');
+  const ogImg = (PRODUCTS[0] && PRODUCTS[0].image_url) ? IMGP.proxyImg(PRODUCTS[0].image_url) : '';
+  res.send(`${HTML_HEAD(pageTitle, pageDesc, canonical, ogImg)}
 <body>
 ${HEADER_HTML(q, sort, density)}
 

← 06b4f59 Scrub residual vendor names from products.json (title/vendor  ·  back to Carmelwallpapers  ·  carmelwallpapers: rails fire again — wire sliders + grid fil 69a8d92 →