← back to Designer Wallcoverings
pending-approval/done/collection-toolbar-consolidation.DONE.md
97 lines
# Pending Approval — DW Collection-Page Toolbar Consolidation (LIVE push)
**Owner:** vp-dw-commerce · **Date:** 2026-06-23 · **Decision:** DTD 3/3 unanimous (fix-forward, Option A canonical, Option B on the dataset error)
**Gate:** Live-theme write — classifier blocks direct live writes. This memo hands Steve the exact ready-to-run script.
---
## TL;DR
Five concurrent dev sessions layered **three** grid-density controls + **two** sort controls onto the live collection page, and it threw two non-fatal JS pageerrors. This consolidates to **exactly one sort + one density control + the existing filter chips** (Steve's HARD rule), kills the `addEventListener of null` error, and scopes the stray infinite-scroll graft off Boost pages.
Validated on a **faithful clone of live + these 3 edits** (dev theme created for preview). Pre-flight Playwright on the dev clone: the consolidated toolbar renders, all 3 duplicate controls are gone, the density slider functionally changes the grid columns, and the `addEventListener` error is gone.
---
## What was wrong (empirically reproduced on live)
Live collection page (e.g. `/collections/1838-wallcoverings`) rendered, simultaneously:
| Control | Source | Disposition |
|---|---|---|
| `.collection-toolbar` (`#collectionSort` + `#densitySlider`) | `snippets/collection-toolbar.liquid` (newest, 2026-06-22) | **KEEP — canonical** |
| `#dw-density-slider` / `#dw-col-range` (~290-line inline block) | `layout/theme.liquid` | **REMOVE** |
| `.dw-gc` injected bar | `assets/dw-grid-control.js` (loaded ×2 in `layout/theme.liquid`) | **REMOVE (stop loading)** |
| dead density script | `assets/collection-grid-density.js` (loaded by `sections/collection.liquid`; queried selectors that never render) | **REMOVE (stop loading)** |
| native `#sort-by` dropdown | `sections/collection.liquid` (Shopify default options only — no Color/Style/SKU) | **REMOVE** |
**Two pageerrors on live:**
1. `Cannot read properties of null (reading 'addEventListener')` — **root cause: the toolbar snippet's own inline script wired `searchInput.addEventListener(...)` unguarded**, but `#collectionSearch` only renders when `section.settings.show_search` is on (off here), so `searchInput` was null. (The briefing's "stale `dw-grid-range`/`dw-grid-num` IDs" theory was a red herring — those IDs are not in the live DOM and no current asset references them.) **→ FIXED by null-guarding the inline script.**
2. `Cannot read properties of null (reading 'dataset')` — **PRE-EXISTING, not toolbar debt.** Source is `assets/grid.js` (2 MB compiled webpack bundle), `ProductListItem` constructor: `this.el.closest('[data-product-hover]').dataset.productHover`. `.closest()` returns null for Boost-app-injected cards that render outside the theme section's `data-product-hover` wrapper. **Out of scope per DTD 3/3** — fixing it means patching a 2 MB vendor bundle (fragile, unrelated). Tracked as a separate template-level follow-up (see below).
**Stray infinite-scroll graft:** `assets/newwall-infinite.js` was loaded globally at `layout/theme.liquid`; on Boost collection pages it hides `ul.pagination` and tries to AJAX-append onto a grid Boost owns. **→ Scoped to load only on non-collection / non-search templates** (`{% unless template contains 'collection' or template contains 'search' %}`).
---
## The 3 edited assets (staged, validated)
Local copies live at `~/Projects/Designer-Wallcoverings/pending-approval/toolbar-consolidation-assets/`:
1. **`snippets/collection-toolbar.liquid`** — null-guard the inline script: bail early `if (!sortSelect || !densitySlider || !densityLabel) return;`, and gate all `searchInput` use behind `if (searchInput)`. (Markup/CSS unchanged.)
2. **`sections/collection.liquid`** — removed the native `#sort-by` sort block; removed the dead `collection-grid-density.js` `<script>` include. (Both replaced with explanatory `{% comment %}` blocks.)
3. **`layout/theme.liquid`** — removed both `dw-grid-control.js` includes; removed the ~290-line inline `#dw-density-slider` block; scoped `newwall-infinite.js` to non-collection/non-search templates only.
Liquid tag balance verified unchanged (the pre-existing `{{ }}` off-by-one is JS template-literal `}` chars, present in the original too). Inline toolbar JS passes `node --check`.
---
## Dev preview (eyeball BEFORE approving)
A faithful clone of live + these 3 edits was created as an unpublished theme:
- **Dev preview theme id:** `143953264691` — *"[Dev] Toolbar Consolidation Preview 2026-06-23"*
- **Preview URL (collection):**
`https://designer-laboratory-sandbox.myshopify.com/collections/1838-wallcoverings?preview_theme_id=143953264691`
- **Home preview:** `https://designer-laboratory-sandbox.myshopify.com/?preview_theme_id=143953264691`
**Pre-flight result on the dev clone (Playwright):**
- `addEventListener` pageerror: **GONE** (was present on live).
- `.collection-toolbar` count: **1**; `#collectionSort` + `#densitySlider`: **present**.
- `#dw-density-slider`, `#dw-col-range`, `.dw-gc`, native `#sort-by`: **all 0 / gone**.
- Density slider functional: moving it changed grid `repeat(4,1fr)` → `repeat(6,1fr)`. ✅
- Remaining error on dev = the pre-existing `dataset` one (unchanged, out of scope).
> NOTE: Boost's app-embed and `dw-hfilter.js` (the filter chips) do **not** fully hydrate under `?preview_theme_id` — a known Shopify preview limitation, NOT a regression. On the published theme the chips render (verified: live has `#dw-hfilter-toggle` + 122 `.dw-hfilter` elements today). My edits do not touch the chips or `dw-hfilter.js`.
---
## APPROVAL — paste this to push to LIVE
After eyeballing the dev preview, run:
```
! bash ~/Projects/Designer-Wallcoverings/pending-approval/toolbar-consolidation-assets/push-to-live.sh
```
The script: resolves `role==main` dynamically (never hardcoded), **backs up each asset** to `shopify/theme-backups/toolbar-consolidation-<timestamp>/` before PUT, PUTs each edited asset, and verifies the byte-size after. Rollback = restore any backed-up file via the same endpoint.
**Post-push verification (hard-refresh / incognito):**
`https://www.designerwallcoverings.com/collections/1838-wallcoverings`
Expect: 1 sort dropdown + 1 density slider + filter chips; density slider changes columns; `addEventListener` pageerror gone.
---
## Follow-up ticket (separate, NOT in this push)
**`dataset of null` in `assets/grid.js`** — pre-existing Boost-vs-theme defect. Fix at the **template level** (ensure every product-list-item is inside a `data-product-hover` wrapper, or have Boost's product template inherit it) — do NOT patch the 2 MB webpack bundle. DTD 3/3.
---
## Cleanup after approval
Once live is confirmed good, delete the dev preview theme:
```
TOKEN=$(grep -E '^SHOPIFY_THEME_TOKEN=' ~/Projects/secrets-manager/.env | cut -d= -f2-)
curl -s -X DELETE "https://designer-laboratory-sandbox.myshopify.com/admin/api/2024-10/themes/143953264691.json" -H "X-Shopify-Access-Token: $TOKEN"
```