← back to Permit Radar
cross-sell strip: use price_display + product_url, prefer buyable products
12a1e8e49bc1a568dbd64b5a4b648fb23685cce5 · 2026-07-16 08:48:31 -0700 · Steve Abrams
- /api/shopify-crosssell now returns price_display (pre-formatted string),
sample_only, and product_url for each pick instead of raw numeric price
- Pool is filtered to buyable products first (167 available >> 6 needed),
so "Roll price on request" cards are suppressed in normal operation
- Frontend uses esc(p.price_display) — no manual \$+toFixed() formatting,
eliminates any \$null/\$NaN risk
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Files touched
M public/index.htmlM server.js
Diff
commit 12a1e8e49bc1a568dbd64b5a4b648fb23685cce5
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Jul 16 08:48:31 2026 -0700
cross-sell strip: use price_display + product_url, prefer buyable products
- /api/shopify-crosssell now returns price_display (pre-formatted string),
sample_only, and product_url for each pick instead of raw numeric price
- Pool is filtered to buyable products first (167 available >> 6 needed),
so "Roll price on request" cards are suppressed in normal operation
- Frontend uses esc(p.price_display) — no manual \$+toFixed() formatting,
eliminates any \$null/\$NaN risk
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---
public/index.html | 2 +-
server.js | 13 +++++++++----
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/public/index.html b/public/index.html
index f20e74d..f9ddce2 100644
--- a/public/index.html
+++ b/public/index.html
@@ -629,7 +629,7 @@ async function submitLead(e) {
<div class="xsell-info">
<div class="xsell-product-title">${esc(p.title)}</div>
<div class="xsell-vendor">${esc(p.vendor)}</div>
- <div class="xsell-price">${p.price ? '$' + Number(p.price).toFixed(2) : ''}</div>
+ <div class="xsell-price">${esc(p.price_display || '')}</div>
</div>
</a>`).join('');
} catch (err) {
diff --git a/server.js b/server.js
index 5e6ef75..6d5f282 100644
--- a/server.js
+++ b/server.js
@@ -198,9 +198,13 @@ const server = http.createServer(async (req, res) => {
if (pathname === '/api/shopify-crosssell' && method === 'GET') {
const catalog = loadShopifyCatalog();
const prods = catalog.products || [];
- const n = Math.min(6, prods.length);
+ // Prefer buyable products so most cards show a real price; fall back to all if needed
+ const pool = prods.filter(p => p.buyable).length >= 6
+ ? prods.filter(p => p.buyable)
+ : prods;
+ const n = Math.min(6, pool.length);
// Fisher-Yates shuffle then take n
- const shuffled = prods.slice();
+ const shuffled = pool.slice();
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
@@ -209,10 +213,11 @@ const server = http.createServer(async (req, res) => {
title: p.title,
handle: p.handle,
image: p.image,
- price: p.price,
+ price_display: p.price_display || 'Roll price on request',
+ sample_only: p.sample_only || false,
vendor: p.vendor,
type: p.type,
- url: 'https://' + catalog.checkout_domain + '/products/' + p.handle
+ url: p.product_url || ('https://' + catalog.checkout_domain + '/products/' + p.handle)
}));
res.writeHead(200, { 'Content-Type': 'application/json' });
return res.end(JSON.stringify({ products: picks, checkout_domain: catalog.checkout_domain }));
← ed3fea7 shopify: refresh catalog — real roll prices, no $4.25 sample
·
back to Permit Radar
·
shopify: refresh catalog — keep sample-only as 'by request' fdc840b →