[object Object]

← back to Designer Wallcoverings

Stage gated G1/G2/G3 memo + DEV-theme staging script for Boost filter topbar

4573b89ed239e603280404faf4c0b9da1ec665e7 · 2026-06-25 16:08:16 -0700 · Steve Abrams

Files touched

Diff

commit 4573b89ed239e603280404faf4c0b9da1ec665e7
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Jun 25 16:08:16 2026 -0700

    Stage gated G1/G2/G3 memo + DEV-theme staging script for Boost filter topbar
---
 .../boost-filter-topbar-2026-06-25/MEMO.md         | 134 +++++++++++++++++++++
 .../stage-on-dev-theme.sh                          |  87 +++++++++++++
 2 files changed, 221 insertions(+)

diff --git a/pending-approval/boost-filter-topbar-2026-06-25/MEMO.md b/pending-approval/boost-filter-topbar-2026-06-25/MEMO.md
new file mode 100644
index 00000000..a72e1ff3
--- /dev/null
+++ b/pending-approval/boost-filter-topbar-2026-06-25/MEMO.md
@@ -0,0 +1,134 @@
+# Horizontal Boost dropdown filter toolbar — STAGED (gated)
+
+**Owner:** vp-dw-commerce · **Date:** 2026-06-25 · **DTD verdict:** B (S1 surface
+UNANIMOUS 3/3; architecture B 2/3, Codex dissent honored — custom code is UX-only,
+Boost stays the engine) · came through **officer-yolo**.
+
+**Target:** the LIVE Boost-rendered page
+`https://www.designerwallcoverings.com/collections/all?pf_t_product_type=Wallcovering`
+(and all `/collections/*` since the toolbar is param-driven, not collection-specific).
+
+**Goal (Steve, verbatim intent):** add HORIZONTAL dropdown filters for common
+processes — color, style, material, brand, process — each individually
+toggleable ON/OFF, PLUS filter/sort on price, vendor, swatch, contents, pattern,
+color, sku, created. Reuse the left-hand filter UX/logic from
+new.designerwallcoverings.com (new-import-viewer). Bring it into the live build.
+
+---
+
+## What landed LOCALLY (reversible, committed — NOT pushed)
+
+| File | Commit |
+|---|---|
+| `shopify/sections/dw-boost-filter-topbar.liquid` (the toolbar — Liquid + JS) | `a5a75bec` |
+| `shopify/sections/dw-boost-filter-topbar.README.md` (field→Boost mapping + data-layer spec) | `3ebc8cd9` |
+
+The section is a self-contained custom horizontal **dropdown** toolbar that:
+- Reads Boost's filter-tree DOM + the URL's `pf_*` params (READ-ONLY) and writes
+  `pf_*` / `sort_by` / `q` params, then navigates. **Never mutates Boost's result
+  grid DOM** → zero grid-init-abort surface (ref `reference_dw_theme_grid_init_abort`).
+- Renders one dropdown per field: Color (swatch dots), Style, Material, Brand,
+  Process, Vendor, Swatch, Contents, Pattern, SKU, Durability, Era, Price.
+- Lets the shopper **toggle each field ON/OFF** via the ⚙ gear menu, persisted to
+  `localStorage('dw_topbar_fields')` (same convention as sort/density/search).
+- Ports the new-import-viewer UX: Sort dropdown (incl. **Created · Newest/Oldest**),
+  density slider (drives the existing `--dw-grid-cols` var, desktop-only), search
+  (`q`, debounced). All persisted to localStorage.
+- Coexists with infinite scroll (deletes `page` on change; never paginates) and
+  scrubs private-label vendor names (Brewster/York/WallQuest/Command54/…) from
+  any Brand/Vendor option (belt-and-suspenders deny-list).
+
+`node --check` on the embedded JS: **PASS**.
+
+> **IMPORTANT — relationship to the OTHER staged folder
+> `boost-filter-consolidation-2026-06-25/`:** that earlier folder (DTD verdict
+> C-hybrid) restyles Boost's OWN native tree into pills + re-enables the density
+> slider via `dw-boost-overrides.liquid`. This NEW folder is the verdict-B
+> *dropdown toolbar* Steve asked for in this task. They are **not duplicates and
+> not conflicting if sequenced**: the consolidation folder owns the
+> density-var + pill restyle; THIS toolbar reuses that same `--dw-grid-cols` var
+> and adds the dropdown field bar on top. **Decision for Steve at execution:**
+> ship the consolidation override first (so `--dw-grid-cols` is bound), then wire
+> this toolbar; OR ship this toolbar alone (its density has a node-level
+> fallback). Do NOT also re-enable the abandoned `collection-filters-horizontal`
+> / `dw-filter-horizontal.*` "Approach B" assets — they are a competing bar.
+
+---
+
+## GATED actions (DO NOT execute autonomously — Steve's go)
+
+### G1 — Boost SD dashboard: configure the missing filter facets (customer-facing)
+For the dropdowns to carry options, Boost must emit each `pf_t_*` facet. Already
+live (verified 2026-06-25): `pf_t_color`, `pf_t_style`, `pf_t_durability`,
+`pf_t_historical_era`, `pf_v_brand`, `pf_p_price`. **Add these facets:**
+
+| Add facet | Param it must emit | Source field (priority) | Display |
+|---|---|---|---|
+| Material | `pf_t_material` | `global.Contents`/`Content`/`Construction` → material tag | List |
+| Process | `pf_t_process` | `global.Finish`/`Finishing`/`FINISH` → process tag | List |
+| Contents | `pf_t_contents` | `global.Contents`/`Content` → tag | List |
+| Pattern | `pf_t_pattern` | pattern-FAMILY tag (Floral/Stripe/Toile…), NOT unique name | List |
+| SKU (optional) | `pf_t_sku` | leave OFF by default; search box covers SKU lookup | List |
+
+Click-path: Shopify Admin → Apps → **Boost AI Search & Filter** → **Filter** →
+**Filter Tree** → **+ Add filter** → pick source field → set param/label → Save →
+**Settings → Re-index/Sync**. (Same dashboard as the consolidation runbook
+`../boost-filter-consolidation-2026-06-25/BOOST-SD-DASHBOARD-RUNBOOK.md`, which
+also covers the Color-swatch display config.) Run via Steve / computer-use /
+Chrome-MCP — not autonomous.
+
+### G2 — Stage the toolbar on the DEV theme (customer-facing surface, but dev)
+Push `dw-boost-filter-topbar.liquid` to the DEV theme + add it to the collection
+template so it renders above the grid, then preview.
+
+```bash
+# from repo root, with SHOPIFY_THEME_TOKEN in env (or secrets-manager/.env):
+bash pending-approval/boost-filter-topbar-2026-06-25/stage-on-dev-theme.sh
+# → resolves the DEV theme "Updated copy of NewWall Template [Dev]" (or a fresh
+#   dup of role==main), uploads sections/dw-boost-filter-topbar.liquid, prints the
+#   ?preview_theme_id=<id> URL for /collections/all?pf_t_product_type=Wallcovering
+```
+Preview checklist: dropdowns open/close, a Color/Style pick changes the URL +
+grid, density slider moves columns, infinite scroll still loads, NO blank grid,
+NO private-label name in Brand/Vendor, ⚙ toggle hides/shows a field and survives
+reload.
+
+### G3 — Publish to the LIVE theme (customer-facing, highest gate)
+Only after G1 facets exist AND G2 preview is signed off. Re-use the
+consolidation folder's race-safe pusher pattern (dynamic role==main,
+backup-before-PUT, byte-verify) extended to also PUT the new section + the
+updated collection template JSON. Built on Steve's go — not staged to auto-run.
+
+---
+
+## Grid-break risk mitigations (why this is low-risk)
+1. The toolbar is **purely additive** — it inserts one sibling node above the
+   grid and **never removes or restyles** any Boost node. All Boost queries are
+   read-only (`querySelector`, `textContent`, `getAttribute`). Dropping a Boost
+   DOM hook is what historically broke every grid; this code drops none.
+2. All filter actions are **URL navigations** (`pf_*`/`sort_by`/`q`) — Boost
+   re-renders its own grid server/client-side as designed. No DOM surgery.
+3. Density touches only the `--dw-grid-cols` CSS var (already bound live); the
+   node-level fallback runs only if the var is absent and still never removes
+   children.
+4. The `MutationObserver` only re-reads options into OUR dropdowns; it never
+   writes to Boost's tree.
+5. Deny-list guarantees no Brewster/York/WallQuest/Command54 name reaches the UI.
+6. Staged on DEV first (G2) before any LIVE publish (G3).
+
+---
+
+## OFFICER SIGN-OFF (vp-dw-commerce)
+
+**Verdict: APPROVE (staged) — hold for Steve's go on G1/G2/G3.**
+
+The local section is reversible, committed (no remote push), `node --check`-clean,
+additive-only against Boost's DOM, param-driven (Boost stays the engine — honoring
+Codex's dissent), and preserves sort+density+infinite-scroll. It matches the
+verbatim ask (5 toggleable process dropdowns + the full filter/sort field set +
+ported new-import-viewer UX). G1 (Boost facets), G2 (DEV stage), G3 (LIVE publish)
+are all customer-facing and remain **BLOCKED from auto-execution** by the hard
+gate. Recommended go-path: **G1 facets → G2 DEV preview → sign → G3 LIVE**, ideally
+sequenced after (or merged with) the `boost-filter-consolidation` density-var push.
+
+  APPROVE / REVISE / BLOCK: __________   Steve sign: ____________  Date: ________
diff --git a/pending-approval/boost-filter-topbar-2026-06-25/stage-on-dev-theme.sh b/pending-approval/boost-filter-topbar-2026-06-25/stage-on-dev-theme.sh
new file mode 100755
index 00000000..3079075c
--- /dev/null
+++ b/pending-approval/boost-filter-topbar-2026-06-25/stage-on-dev-theme.sh
@@ -0,0 +1,87 @@
+#!/usr/bin/env bash
+# =============================================================================
+# DW Boost Filter Topbar — STAGE on the DEV theme (G2)
+# DW VP Commerce | staged 2026-06-25 | DTD verdict B (officer-yolo)
+#
+# Uploads ONE section asset to the DEV theme so it can be previewed:
+#   sections/dw-boost-filter-topbar.liquid
+#
+# Resolves the DEV theme DYNAMICALLY by name ("Updated copy of NewWall Template
+# [Dev]" — fallback: the newest UNPUBLISHED theme). NEVER touches role==main.
+# Backs up the asset if it already exists on the dev theme, then PUTs, then
+# re-reads to byte-verify. Prints the preview URL.
+#
+# This is the DEV-theme stage. It is customer-facing-adjacent but NOT live, so
+# it is the lower gate (G2). It does NOT add the section to a template JSON —
+# after upload, position it in the theme editor (Customize → collection
+# template → Add section → "DW Boost Filter Topbar", drag above the grid), OR
+# uncomment the OPTIONAL template-merge block at the bottom.
+#
+# GATED — run only on Steve's go.
+#   Approved by Steve: ____________________________   Date: __________
+# =============================================================================
+set -euo pipefail
+
+SHOP="designer-laboratory-sandbox.myshopify.com"
+API="2024-10"
+DEV_THEME_NAME="${DEV_THEME_NAME:-Updated copy of NewWall Template [Dev]}"
+
+TOKEN="${SHOPIFY_THEME_TOKEN:-}"
+if [ -z "$TOKEN" ]; then
+  TOKEN="$(grep -E '^SHOPIFY_THEME_TOKEN=' "$HOME/Projects/secrets-manager/.env" 2>/dev/null | head -1 | cut -d= -f2-)"
+fi
+[ -z "$TOKEN" ] && { echo "FATAL: SHOPIFY_THEME_TOKEN not found (env or secrets-manager/.env)"; exit 1; }
+
+HERE="$(cd "$(dirname "$0")" && pwd)"
+REPO_SECTION="$HERE/../../shopify/sections/dw-boost-filter-topbar.liquid"
+[ -f "$REPO_SECTION" ] || { echo "FATAL: section not found at $REPO_SECTION"; exit 1; }
+BACKUPS="$HERE/backups"; mkdir -p "$BACKUPS"; TS="$(date +%Y%m%d-%H%M%S)"
+
+hdr=(-H "X-Shopify-Access-Token: $TOKEN" -H "Content-Type: application/json")
+base="https://$SHOP/admin/api/$API"
+
+echo "→ resolving DEV theme '$DEV_THEME_NAME' …"
+themes_json="$(curl -s "${hdr[@]}" "$base/themes.json")"
+DEV_ID="$(printf '%s' "$themes_json" | python3 -c '
+import sys,json
+name=sys.argv[1]
+d=json.load(sys.stdin).get("themes",[])
+# exact name match first; else newest non-main (development) theme
+m=[t for t in d if t.get("name")==name]
+if not m:
+    m=sorted([t for t in d if t.get("role")!="main"], key=lambda t:t.get("id",0), reverse=True)
+print(m[0]["id"] if m else "")
+' "$DEV_THEME_NAME")"
+[ -z "$DEV_ID" ] && { echo "FATAL: no DEV/unpublished theme found. Create a dup of role==main named '$DEV_THEME_NAME' first."; exit 1; }
+echo "  DEV theme id = $DEV_ID"
+
+KEY="sections/dw-boost-filter-topbar.liquid"
+
+# backup if it already exists on the dev theme
+existing="$(curl -s "${hdr[@]}" "$base/themes/$DEV_ID/assets.json?asset[key]=$KEY")"
+if printf '%s' "$existing" | grep -q '"value"'; then
+  printf '%s' "$existing" | python3 -c 'import sys,json;print(json.load(sys.stdin)["asset"]["value"])' > "$BACKUPS/dw-boost-filter-topbar.liquid.$TS.bak" || true
+  echo "  backed up prior dev value → backups/dw-boost-filter-topbar.liquid.$TS.bak"
+fi
+
+echo "→ uploading section to DEV theme …"
+payload="$(python3 -c 'import json,sys;print(json.dumps({"asset":{"key":sys.argv[1],"value":open(sys.argv[2]).read()}}))' "$KEY" "$REPO_SECTION")"
+resp="$(curl -s -X PUT "${hdr[@]}" -d "$payload" "$base/themes/$DEV_ID/assets.json")"
+printf '%s' "$resp" | grep -q '"key"' || { echo "FATAL: upload failed: $resp"; exit 1; }
+
+# byte-verify
+sent_len=$(wc -c < "$REPO_SECTION" | tr -d ' ')
+got="$(curl -s "${hdr[@]}" "$base/themes/$DEV_ID/assets.json?asset[key]=$KEY" | python3 -c 'import sys,json;print(len(json.load(sys.stdin)["asset"]["value"]))')"
+echo "  uploaded ($sent_len B) · verified on theme ($got B)"
+
+echo
+echo "✓ STAGED on DEV theme $DEV_ID."
+echo "  PREVIEW: https://$SHOP/?preview_theme_id=$DEV_ID  → then visit:"
+echo "  https://www.designerwallcoverings.com/collections/all?pf_t_product_type=Wallcovering&preview_theme_id=$DEV_ID"
+echo "  NEXT: in the theme editor for theme $DEV_ID, add section 'DW Boost Filter"
+echo "        Topbar' to the collection template, dragged ABOVE the product grid."
+
+# --- OPTIONAL: auto-merge into the collection template JSON ------------------
+# Uncomment to insert the section into templates/collection.json automatically
+# (review the merged JSON before relying on it; templates vary by theme).
+# ----------------------------------------------------------------------------

← 3ebc8cd9 Add field->Boost mapping + data-layer spec README for dw-boo  ·  back to Designer Wallcoverings  ·  v5.6.0 DEPLOYED (PDP light tidy live); Anna French 146 price 85a7206d →