[object Object]

← back to Prestige Car Wash

SEO: broaden OG/Twitter + per-page canonical to /services + /contact (shared pageHtml); robust 500 fallback + canonical dup-guard — contrarian-gated

aa47ccf277006804615ae769ad7fb242972cbdc0 · 2026-07-26 16:15:25 -0700 · steve@designerwallcoverings.com

Files touched

Diff

commit aa47ccf277006804615ae769ad7fb242972cbdc0
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date:   Sun Jul 26 16:15:25 2026 -0700

    SEO: broaden OG/Twitter + per-page canonical to /services + /contact (shared pageHtml); robust 500 fallback + canonical dup-guard — contrarian-gated
---
 server.js | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/server.js b/server.js
index 887b37f..4963f5a 100644
--- a/server.js
+++ b/server.js
@@ -445,9 +445,9 @@ function buildJsonLd() {
 // Open Graph / Twitter tags for the homepage — reuses the page's own <title> and meta
 // description so social previews stay in sync with on-page SEO. og:image is a real asset.
 function buildSocialTags(html, pagePath) {
-  // Bail if the HTML already carries og: tags (e.g. added directly to the file) so we
-  // never emit duplicates that make Facebook's debugger flag the markup. (contrarian gate)
-  if (/property=["']og:title["']/i.test(html)) return '';
+  // Bail if the HTML already carries og: tags OR a canonical (e.g. added directly to the
+  // file) so we never inject a duplicate that makes Facebook/Google flag the markup.
+  if (/property=["']og:title["']/i.test(html) || /<link\b[^>]*\brel=["']canonical["']/i.test(html)) return '';
   const p = places() || {};
   const base = (p.website || '').replace(/\/$/, '');
   const url = base ? base + (pagePath || '') : '';   // page-specific canonical + og:url
@@ -481,8 +481,10 @@ function pageHtml(file, pagePath, ld) {
   return html.replace('</head>', inject + '\n</head>');
 }
 const sendPage = (res, file, pagePath, ld) => {
+  // If tag INJECTION throws, still serve the raw page (graceful degradation). If the file
+  // itself is unreadable, sendFile's callback guarantees a clean 500 — never a hung response.
   try { res.type('html').send(pageHtml(file, pagePath, ld)); }
-  catch { res.sendFile(path.join(__dirname, 'public', file)); }
+  catch { res.sendFile(path.join(__dirname, 'public', file), err => { if (err && !res.headersSent) res.status(500).end(); }); }
 };
 app.get('/', (req, res) => sendPage(res, 'index.html', '', buildJsonLd()));
 app.get('/services', (req, res) => sendPage(res, 'services.html', '/services', null));

← 1b0a067 auto-save: 2026-07-26T16:14:26 (1 files) — server.js  ·  back to Prestige Car Wash  ·  Analytics: GA4 gtag injection on customer pages, gated on GA 10e7bf1 →