← back to Blockprintedwallpaper
graphic-loop pass 12: niche keyword filter (no off-niche products like 'solid' on patterned sites)
07df85da628d811349be2ffe52177374d4c3a471 · 2026-05-07 13:20:06 -0700 · Steve
Files touched
M server.jsA server.js.pre-pass12.bak
Diff
commit 07df85da628d811349be2ffe52177374d4c3a471
Author: Steve <steve@designerwallcoverings.com>
Date: Thu May 7 13:20:06 2026 -0700
graphic-loop pass 12: niche keyword filter (no off-niche products like 'solid' on patterned sites)
---
server.js | 26 +++++++++---
server.js.pre-pass12.bak | 108 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 129 insertions(+), 5 deletions(-)
diff --git a/server.js b/server.js
index bf32b9d..a28537d 100644
--- a/server.js
+++ b/server.js
@@ -36,6 +36,22 @@ const PRODUCTS = DATA_RAW.filter(p => !isJunk(p));
const DROPPED = DATA_RAW.length - PRODUCTS.length;
console.log(`Loaded ${DATA_RAW.length}, kept ${PRODUCTS.length}, dropped ${DROPPED}`);
+// graphics-loop pass 12: niche keyword filter — only show products that fit this site's niche
+const NICHE_POS = ["woodblock","block-printed","block print","hand-stamped","artisan"];
+const NICHE_NEG = ["solid","blank","plain"];
+function nicheFit(p) {
+ const blob = ((p.title || '') + ' ' + (p.tags || []).join(' ')).toLowerCase();
+ if (NICHE_NEG.some(n => blob.includes(n.toLowerCase()))) return false;
+ return NICHE_POS.length === 0 || NICHE_POS.some(k => blob.includes(k.toLowerCase()));
+}
+const PRODUCTS_NICHE = PRODUCTS.filter(nicheFit);
+const NICHE_DROPPED = PRODUCTS.length - PRODUCTS_NICHE.length;
+console.log(`Niche filter: kept ${PRODUCTS_NICHE.length} of ${PRODUCTS.length}, dropped ${NICHE_DROPPED}`);
+// Replace PRODUCTS reference with the niche-filtered list for all downstream handlers.
+const PRODUCTS_ORIG = PRODUCTS;
+Object.defineProperty(global, '__products_niche_applied', { value: true });
+
+
const app = express();
app.use(express.json({ limit: "256kb" }));
const cfg = require('../_shared/site-config').load(__dirname);
@@ -46,7 +62,7 @@ app.use(express.static(path.join(__dirname, 'public')));
app.get('/api/products', (req, res) => {
const { q, aesthetic, vendor, page = 1, limit = 24 } = req.query;
- let list = PRODUCTS;
+ let list = PRODUCTS_NICHE;
if (q) {
const needle = q.toLowerCase();
list = list.filter(p => (p.title || '').toLowerCase().includes(needle) || (p.tags || []).some(t => t.toLowerCase().includes(needle)));
@@ -64,7 +80,7 @@ app.get('/api/sliders', (req, res) => {
const SLIDER_AESTHETICS = ["block","hand","screen","botanical","chinoiserie","geometric"];
const out = [];
for (const a of SLIDER_AESTHETICS) {
- const items = PRODUCTS.filter(p => p.aesthetic === a).slice(0, 12);
+ const items = PRODUCTS_NICHE.filter(p => p.aesthetic === a).slice(0, 12);
if (items.length >= 4) out.push({ aesthetic: a, items });
}
res.json({ rails: out });
@@ -72,17 +88,17 @@ app.get('/api/sliders', (req, res) => {
app.get('/api/facets', (req, res) => {
const aesthetics = {}; const vendors = {};
- for (const p of PRODUCTS) {
+ for (const p of PRODUCTS_NICHE) {
aesthetics[p.aesthetic] = (aesthetics[p.aesthetic] || 0) + 1;
vendors[p.vendor] = (vendors[p.vendor] || 0) + 1;
}
res.json({ aesthetics, vendors, total: PRODUCTS.length });
});
-app.get('/api/health', (req, res) => res.json({ status: 'ok', count: PRODUCTS.length, dropped: DROPPED }));
+app.get('/api/health', (req, res) => res.json({ status: 'ok', count: PRODUCTS_NICHE.length, dropped: DROPPED }));
app.get('/sample/:handle', (req, res) => {
- const p = PRODUCTS.find(x => x.handle === req.params.handle || x.sku === req.params.handle);
+ const p = PRODUCTS_NICHE.find(x => x.handle === req.params.handle || x.sku === req.params.handle);
if (!p) return res.status(404).send('Not found');
res.redirect(302, p.product_url || `${DW_SHOPIFY}/products/${encodeURIComponent(p.handle)}#sample`);
});
diff --git a/server.js.pre-pass12.bak b/server.js.pre-pass12.bak
new file mode 100644
index 0000000..bf32b9d
--- /dev/null
+++ b/server.js.pre-pass12.bak
@@ -0,0 +1,108 @@
+/**
+ * BLOCK-PRINTED WALLPAPER — DW family vertical
+ * Curated slice from live designerwallcoverings.com Shopify catalog.
+ */
+try { require('dotenv').config(); } catch (e) {}
+const express = require('express');
+const path = require('path');
+const fs = require('fs');
+
+const PORT = process.env.PORT || 9883;
+const DW_SHOPIFY = 'https://designerwallcoverings.com';
+const __SITE = path.basename(__dirname);
+let DATA_RAW;
+try {
+ const raw = fs.readFileSync(path.join(__dirname, 'data', 'products.json'), 'utf8');
+ DATA_RAW = JSON.parse(raw);
+ if (!Array.isArray(DATA_RAW)) throw new Error('products.json must be an array');
+} catch (e) {
+ console.error(`[${__SITE}] FATAL: could not load products.json — ${e.message}`);
+ console.error(`[${__SITE}] Starting with empty catalog. Run pull script to populate data/products.json.`);
+ DATA_RAW = [];
+}
+
+function isJunk(p) {
+ if (!p.image_url || !p.image_url.trim()) return true;
+ if (!p.handle && !p.sku) return true;
+ const t = p.title || '';
+ if (/lamp|rug|pillow|throw|tripod|frame|mirror|vase|candle|sculpture|figurine/i.test(t)) return true;
+ if (/visual.{0,3}merchandiser/i.test(t)) return true;
+ if (/(?:^|\W)image[ _-]?4(?:\W|$)/i.test(t)) return true;
+ if (/bh.?90210|beverly.?hills.?90210|iconic.{0,4}bh/i.test(t)) return true;
+ return false;
+}
+
+const PRODUCTS = DATA_RAW.filter(p => !isJunk(p));
+const DROPPED = DATA_RAW.length - PRODUCTS.length;
+console.log(`Loaded ${DATA_RAW.length}, kept ${PRODUCTS.length}, dropped ${DROPPED}`);
+
+const app = express();
+app.use(express.json({ limit: "256kb" }));
+const cfg = require('../_shared/site-config').load(__dirname);
+require("./_universal-contact")(app, cfg.contact);
+require("./_universal-auth")(app, cfg.auth);
+app.locals.siteConfig = cfg;
+app.use(express.static(path.join(__dirname, 'public')));
+
+app.get('/api/products', (req, res) => {
+ const { q, aesthetic, vendor, page = 1, limit = 24 } = req.query;
+ let list = PRODUCTS;
+ if (q) {
+ const needle = q.toLowerCase();
+ list = list.filter(p => (p.title || '').toLowerCase().includes(needle) || (p.tags || []).some(t => t.toLowerCase().includes(needle)));
+ }
+ if (aesthetic && aesthetic !== 'all') list = list.filter(p => p.aesthetic === aesthetic);
+ if (vendor && vendor !== 'all') list = list.filter(p => p.vendor === vendor);
+ const total = list.length;
+ const pageNum = Math.max(1, parseInt(page));
+ const lim = Math.min(60, parseInt(limit));
+ const start = (pageNum - 1) * lim;
+ res.json({ total, page: pageNum, limit: lim, pages: Math.ceil(total / lim), items: list.slice(start, start + lim) });
+});
+
+app.get('/api/sliders', (req, res) => {
+ const SLIDER_AESTHETICS = ["block","hand","screen","botanical","chinoiserie","geometric"];
+ const out = [];
+ for (const a of SLIDER_AESTHETICS) {
+ const items = PRODUCTS.filter(p => p.aesthetic === a).slice(0, 12);
+ if (items.length >= 4) out.push({ aesthetic: a, items });
+ }
+ res.json({ rails: out });
+});
+
+app.get('/api/facets', (req, res) => {
+ const aesthetics = {}; const vendors = {};
+ for (const p of PRODUCTS) {
+ aesthetics[p.aesthetic] = (aesthetics[p.aesthetic] || 0) + 1;
+ vendors[p.vendor] = (vendors[p.vendor] || 0) + 1;
+ }
+ res.json({ aesthetics, vendors, total: PRODUCTS.length });
+});
+
+app.get('/api/health', (req, res) => res.json({ status: 'ok', count: PRODUCTS.length, dropped: DROPPED }));
+
+app.get('/sample/:handle', (req, res) => {
+ const p = PRODUCTS.find(x => x.handle === req.params.handle || x.sku === req.params.handle);
+ if (!p) return res.status(404).send('Not found');
+ res.redirect(302, p.product_url || `${DW_SHOPIFY}/products/${encodeURIComponent(p.handle)}#sample`);
+});
+
+// sitemap.xml + robots.txt for SEO
+app.get('/robots.txt', (req, res) => {
+ res.type('text/plain').send(`User-agent: *
+Allow: /
+Sitemap: https://blockprintedwallpaper.com/sitemap.xml
+`);
+});
+app.get('/sitemap.xml', (req, res) => {
+ const urls = ['/'];
+ const xml = `<?xml version="1.0" encoding="UTF-8"?>
+<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+${urls.map(u => ` <url><loc>https://blockprintedwallpaper.com${u}</loc><changefreq>weekly</changefreq></url>`).join('\n')}
+</urlset>`;
+ res.type('application/xml').send(xml);
+});
+
+app.listen(PORT, '127.0.0.1', () => {
+ console.log(`blockprintedwallpaper listening on http://127.0.0.1:${PORT}`);
+});
← c6172d5 graphic-loop pass 11: add Ideas rails (New this week + Curat
·
back to Blockprintedwallpaper
·
graphic-loop pass 13: real footer brand + Facebook link + OG 1dc9634 →