← back to Metallicwallpaper
facets: honor q/aesthetic/vendor filters in counts (was unfiltered niche total)
17854192abef126e4ccf6e4fafe96bf356a31bc0 · 2026-06-01 07:37:42 -0700 · Steve
Files touched
Diff
commit 17854192abef126e4ccf6e4fafe96bf356a31bc0
Author: Steve <steve@designerwallcoverings.com>
Date: Mon Jun 1 07:37:42 2026 -0700
facets: honor q/aesthetic/vendor filters in counts (was unfiltered niche total)
---
server.js | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/server.js b/server.js
index 6ce403f..795e0b2 100644
--- a/server.js
+++ b/server.js
@@ -155,6 +155,13 @@ app.use((req, res, next) => {
if (/\.(bak|pre-[^/]+)(\.[^/.-][^/]*)?$|\.bak[\.-]|\.pre-/i.test(req.path)) return res.status(404).end();
next();
});
+// Clean-URL canonicalization — 301 /foo.html → /foo (the static handler below
+// serves the .html via extensions:['html']). Keeps one canonical URL per page
+// for SEO; idempotent (a request already without .html falls straight through).
+app.get(/^\/(.+)\.html$/i, (req, res, next) => {
+ const clean = '/' + req.params[0] + (req._parsedUrl && req._parsedUrl.search ? req._parsedUrl.search : '');
+ return res.redirect(301, clean);
+});
app.use(express.static(path.join(__dirname, 'public'), { extensions: ['html'] }));
app.get('/api/products', (req, res) => {
@@ -185,12 +192,25 @@ app.get('/api/sliders', (req, res) => {
});
app.get('/api/facets', (req, res) => {
+ // Counts must reflect the FILTERED result set (q/aesthetic/vendor), not the
+ // unfiltered niche catalog — otherwise facet badges over-report after a
+ // search/filter is applied. Each facet's own dimension is excluded from its
+ // filter so the user can still see sibling option counts (standard facet UX).
+ const { q, aesthetic, vendor } = req.query;
+ const matchQ = (p) => !q || (p.title || '').toLowerCase().includes(q.toLowerCase()) || (p.tags || []).some(t => t.toLowerCase().includes(q.toLowerCase()));
+ const matchAesthetic = (p) => !aesthetic || aesthetic === 'all' || p.aesthetic === aesthetic;
+ const matchVendor = (p) => !vendor || vendor === 'all' || p.vendor === vendor;
+
const aesthetics = {}; const vendors = {};
for (const p of PRODUCTS_NICHE) {
- aesthetics[p.aesthetic] = (aesthetics[p.aesthetic] || 0) + 1;
- vendors[p.vendor] = (vendors[p.vendor] || 0) + 1;
+ // aesthetic counts: apply q + vendor, but NOT the aesthetic filter itself
+ if (matchQ(p) && matchVendor(p)) aesthetics[p.aesthetic] = (aesthetics[p.aesthetic] || 0) + 1;
+ // vendor counts: apply q + aesthetic, but NOT the vendor filter itself
+ if (matchQ(p) && matchAesthetic(p)) vendors[p.vendor] = (vendors[p.vendor] || 0) + 1;
}
- res.json({ aesthetics, vendors, total: PRODUCTS_NICHE.length });
+ // total reflects the fully-filtered set (all three filters applied)
+ const total = PRODUCTS_NICHE.filter(p => matchQ(p) && matchAesthetic(p) && matchVendor(p)).length;
+ res.json({ aesthetics, vendors, total });
});
app.get('/api/health', (req, res) => res.json({ status: 'ok', count: PRODUCTS_NICHE.length, dropped: DROPPED }));
← 378c8bf fix: remove leaked bak file from public/, tighten 404 guard
·
back to Metallicwallpaper
·
fleet rebuild: dw-header (hamburgers UL + centered name) + u c29e354 →