[object Object]

← back to Stars of Design

add /sitemap.xml route + JSON-LD Person schema on designer detail

70b7912447cb10355582172303fcd9c145b444da · 2026-05-10 09:41:41 -0700 · Steve Abrams

- robots.txt already advertised /sitemap.xml; route was missing (404).
  Now serves all 4 static pages + every designer slug with lastmod/priority.
- Detail pages now emit schema.org Person JSON-LD (name, bio, styles via
  knowsAbout, city via workLocation, DW pairings as subjectOf) so SERP
  cards get rich-result eligibility.

Files touched

Diff

commit 70b7912447cb10355582172303fcd9c145b444da
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun May 10 09:41:41 2026 -0700

    add /sitemap.xml route + JSON-LD Person schema on designer detail
    
    - robots.txt already advertised /sitemap.xml; route was missing (404).
      Now serves all 4 static pages + every designer slug with lastmod/priority.
    - Detail pages now emit schema.org Person JSON-LD (name, bio, styles via
      knowsAbout, city via workLocation, DW pairings as subjectOf) so SERP
      cards get rich-result eligibility.
---
 routes/public.js          | 26 ++++++++++++++++++++++++++
 views/public/designer.ejs | 23 +++++++++++++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/routes/public.js b/routes/public.js
index ee08542..4bb4c3a 100644
--- a/routes/public.js
+++ b/routes/public.js
@@ -70,6 +70,32 @@ router.get('/submit', (req, res) => {
   res.render('public/submit', { title: 'Submit a designer — Stars of Design' });
 });
 
+router.get('/sitemap.xml', (req, res, next) => {
+  try {
+    const base = 'https://starsofdesign.com';
+    const all = data.load();
+    const today = new Date().toISOString().slice(0, 10);
+    const urls = [
+      { loc: `${base}/`,          priority: '1.0', changefreq: 'weekly' },
+      { loc: `${base}/designers`, priority: '0.9', changefreq: 'weekly' },
+      { loc: `${base}/about`,     priority: '0.5', changefreq: 'monthly' },
+      { loc: `${base}/submit`,    priority: '0.4', changefreq: 'monthly' },
+      ...all.map((d) => ({
+        loc: `${base}/designers/${d.slug}`,
+        priority: '0.8',
+        changefreq: 'monthly',
+      })),
+    ];
+    const xml = '<?xml version="1.0" encoding="UTF-8"?>\n' +
+      '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' +
+      urls.map((u) =>
+        `  <url><loc>${u.loc}</loc><lastmod>${today}</lastmod><changefreq>${u.changefreq}</changefreq><priority>${u.priority}</priority></url>`
+      ).join('\n') +
+      '\n</urlset>\n';
+    res.type('application/xml').send(xml);
+  } catch (e) { next(e); }
+});
+
 router.get('/healthz', (req, res) => res.type('text').send('ok'));
 
 module.exports = router;
diff --git a/views/public/designer.ejs b/views/public/designer.ejs
index be64287..ff4acab 100644
--- a/views/public/designer.ejs
+++ b/views/public/designer.ejs
@@ -1,4 +1,27 @@
 <%- include('../partials/head', { title, meta_desc_override: typeof meta_desc_override !== 'undefined' ? meta_desc_override : undefined }) %>
+<%
+  // JSON-LD Person schema for richer SERP cards. Mention=DW collections that
+  // pair with this designer; affiliation/image kept loose since we host neither
+  // images nor employment data.
+  var jsonld = {
+    '@context': 'https://schema.org',
+    '@type': 'Person',
+    name: designer.name,
+    description: designer.bio || designer.headline || ('Interior designer profile on Stars of Design.'),
+    url: 'https://starsofdesign.com/designers/' + designer.slug,
+    jobTitle: 'Interior Designer',
+    knowsAbout: (designer.styles || []).slice(0, 8),
+  };
+  if (designer.city) {
+    jsonld.workLocation = { '@type': 'Place', name: designer.city };
+  }
+  if (designer.preferred_dw && designer.preferred_dw.length) {
+    jsonld.subjectOf = designer.preferred_dw.map(function (p) {
+      return { '@type': 'CreativeWork', name: p.label, url: p.url };
+    });
+  }
+%>
+<script type="application/ld+json"><%- JSON.stringify(jsonld) %></script>
 <%- include('../partials/header') %>
 
 <main class="designer-detail">

← aa14a02 initial scaffold + GA gtag (G-YCT0F2Q692) + 27 designer prof  ·  back to Stars of Design  ·  starsofdesign tick0: PG schema + AI placeholder + scaffold bde4448 →