← back to Prestige Car Wash
Path B: self-canonicalize to prestige.agentabrams.com (stop feeding GoDaddy) + ship guides
61afb843b80e4e99fce6ce8f7b8c92c3088b617c · 2026-07-26 21:19:32 -0700 · Steve Abrams
Steve chose B. New SITE_ORIGIN constant drives all self-referential SEO (canonical, og:url,
sitemap, article URLs, AutoWash.url) to prestige.agentabrams.com — the domain this app is
actually served from — instead of the apex prestigehandcarwash.com, which serves a SEPARATE
GoDaddy site. Resolves the contrarian NO-GO by its own stated A-grade bar. Also: og:type=article
on individual guide pages. Unblocks the held /guides deploy. Flip SITE_ORIGIN to the apex once
its DNS is cut over to Kamatera. (publisher.logo intentionally omitted — no real logo asset.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
Diff
commit 61afb843b80e4e99fce6ce8f7b8c92c3088b617c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sun Jul 26 21:19:32 2026 -0700
Path B: self-canonicalize to prestige.agentabrams.com (stop feeding GoDaddy) + ship guides
Steve chose B. New SITE_ORIGIN constant drives all self-referential SEO (canonical, og:url,
sitemap, article URLs, AutoWash.url) to prestige.agentabrams.com — the domain this app is
actually served from — instead of the apex prestigehandcarwash.com, which serves a SEPARATE
GoDaddy site. Resolves the contrarian NO-GO by its own stated A-grade bar. Also: og:type=article
on individual guide pages. Unblocks the held /guides deploy. Flip SITE_ORIGIN to the apex once
its DNS is cut over to Kamatera. (publisher.logo intentionally omitted — no real logo asset.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
server.js | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/server.js b/server.js
index 068b93c..365dbb1 100644
--- a/server.js
+++ b/server.js
@@ -406,12 +406,20 @@ function parseHoursLine(line) {
if (!days.length || !opens || !closes) return null;
return { '@type': 'OpeningHoursSpecification', dayOfWeek: days.map(d => DOW[d]), opens, closes };
}
+// Canonical serving origin (Path B, 2026-07-26). This app is actually served at
+// prestige.agentabrams.com, while the apex prestigehandcarwash.com still serves a SEPARATE
+// GoDaddy site. All self-referential SEO (canonical, og:url, sitemap, article URLs, entity
+// url) points HERE so we self-canonicalize to where the content really lives instead of
+// handing authority to GoDaddy. FLIP to 'https://prestigehandcarwash.com' (or '') once the
+// apex DNS is cut over to this app — one line, everything follows.
+const SITE_ORIGIN = 'https://prestige.agentabrams.com';
+function siteOrigin() { return (SITE_ORIGIN || '').replace(/\/$/, ''); }
function buildJsonLd() {
const p = places();
if (!p || !p.name) return null;
const ld = { '@context': 'https://schema.org', '@type': 'AutoWash', name: p.name };
if (p.legal_name && p.legal_name !== p.name) ld.alternateName = p.legal_name;
- if (p.website) ld.url = p.website;
+ if (siteOrigin()) ld.url = siteOrigin();
if (p.phone) ld.telephone = p.phone;
if (p.address) {
const parts = p.address.split(',').map(s => s.trim());
@@ -670,7 +678,7 @@ function buildSocialTags(html, pagePath) {
// 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 base = siteOrigin();
const url = base ? base + (pagePath || '') : ''; // page-specific canonical + og:url
const title = (html.match(/<title>([^<]*)<\/title>/i) || [])[1] || p.name || 'Prestige Car Wash';
// Attribute-order-independent description extraction, with a real fallback (never a
@@ -680,8 +688,10 @@ function buildSocialTags(html, pagePath) {
const desc = (descMatch || [])[1] || `${p.name || 'Prestige Car Wash'} — no-pressure flat pricing, two-bucket hand wash, detailing & ceramic coating in the San Fernando Valley.`;
const img = base ? base + '/media/svc-full-service.png' : '';
const esc = s => String(s).replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<');
+ // Individual guide articles are og:type "article"; everything else is a "website".
+ const ogType = /^\/guides\/.+/.test(pagePath || '') ? 'article' : 'website';
const tags = [
- ['og:type', 'website'], ['og:site_name', p.name || 'Prestige Car Wash'],
+ ['og:type', ogType], ['og:site_name', p.name || 'Prestige Car Wash'],
['og:title', title], ['og:description', desc], url && ['og:url', url], img && ['og:image', img],
['twitter:card', img ? 'summary_large_image' : 'summary'],
['twitter:title', title], ['twitter:description', desc], img && ['twitter:image', img]
@@ -759,7 +769,7 @@ app.get('/guides', (req, res) => {
});
app.get('/guides/:slug', (req, res) => {
const g = guides().find(x => x.slug === req.params.slug);
- const base = (((places() || {}).website) || '').replace(/\/$/, '');
+ const base = siteOrigin();
if (!g) {
const nf = guideLayout('Guide Not Found — Prestige Car Wash', 'That guide could not be found.',
`<section class="section"><div class="wrap"><h1>Guide not found</h1><p class="sub">That guide may have moved. <a href="/guides">Browse all car-care guides →</a></p></div></section>`);
@@ -781,7 +791,7 @@ app.get('/guides/:slug', (req, res) => {
// XML sitemap generated from the public URL — kept in one place, no static file to drift.
app.get('/sitemap.xml', (req, res) => {
- const base = ((places() || {}).website || '').replace(/\/$/, '');
+ const base = siteOrigin();
if (!base) return res.status(404).end();
const urls = ['/', '/services', '/contact', '/guides', ...guides().map(g => '/guides/' + g.slug)];
const xml = '<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' +
← 2cec353 Guides: evergreen car-care articles (/guides + 3 posts) — BU
·
back to Prestige Car Wash
·
Harden booking form: honeypot + validation + dupe-guard + re 7c66f9d →