← back to Designer Wallcoverings
Add consolidated single-pass LIVE push for all 5 collection memos (gated on Steve's dev-Preview verify)
9ae1ee0e210e0dc3435badc7349628f342f52306 · 2026-06-23 16:22:20 -0700 · Steve
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
A shopify/collection-hero-fix/PUSH-LIVE-CONSOLIDATED.sh
Diff
commit 9ae1ee0e210e0dc3435badc7349628f342f52306
Author: Steve <steve@designerwallcoverings.com>
Date: Tue Jun 23 16:22:20 2026 -0700
Add consolidated single-pass LIVE push for all 5 collection memos (gated on Steve's dev-Preview verify)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
.../collection-hero-fix/PUSH-LIVE-CONSOLIDATED.sh | 131 +++++++++++++++++++++
1 file changed, 131 insertions(+)
diff --git a/shopify/collection-hero-fix/PUSH-LIVE-CONSOLIDATED.sh b/shopify/collection-hero-fix/PUSH-LIVE-CONSOLIDATED.sh
new file mode 100755
index 00000000..ce1149b4
--- /dev/null
+++ b/shopify/collection-hero-fix/PUSH-LIVE-CONSOLIDATED.sh
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+# ============================================================================
+# CONSOLIDATED Steve-gated LIVE push — all 5 collection-page memos in ONE pass.
+# Reconciles memos A (toolbar consolidation) + B (grid-image CSS) + D (rotating
+# hero, supersedes C) + E (grid.js init-abort) into a single coherent push so
+# the two scripts that each PUT sections/collection.liquid can NEVER clobber
+# each other. DTD Option-A (2026-06-23): merge the colliding file, stage all on
+# ONE dev theme (143947038771), verify, push once.
+#
+# DO NOT RUN until Steve has opened the dev Preview of 143947038771 and confirmed:
+# - 1 sort dropdown + 1 density slider + filter chips (no dup controls)
+# - hero band crossfades through newest products; single clean title
+# - homepage carousels render (Flickity engages); NO blown full-width cards
+# - mobile header gap closed
+#
+# Additive + reversible. Every overwritten asset GET-backed-up to *.pushbak
+# BEFORE the PUT. Live theme resolved dynamically as role==main. ≥2s between PUTs.
+# bash PUSH-LIVE-CONSOLIDATED.sh
+# ============================================================================
+set -euo pipefail
+cd "$(cd "$(dirname "$0")/../.." && pwd)" # -> ~/Projects/Designer-Wallcoverings
+ROOT="$(pwd)"
+TOK=$(grep -m1 '^SHOPIFY_THEME_TOKEN=' ~/Projects/secrets-manager/.env | cut -d= -f2- | tr -d '"' | tr -d "'")
+[ -z "$TOK" ] && { echo "No SHOPIFY_THEME_TOKEN"; exit 1; }
+STORE="designer-laboratory-sandbox.myshopify.com"
+LIVE=$(curl -sS -H "X-Shopify-Access-Token: $TOK" "https://$STORE/admin/api/2024-10/themes.json" \
+ | python3 -c 'import sys,json;print(next((str(t["id"]) for t in json.load(sys.stdin)["themes"] if t["role"]=="main"),""))')
+[ -z "$LIVE" ] && { echo "could not resolve role==main"; exit 1; }
+echo "LIVE (role=main) = $LIVE"
+BK="shopify/collection-hero-fix/backups/live-push-$(date +%Y%m%d-%H%M%S)"
+mkdir -p "$BK"
+echo "backups -> $BK"
+
+python3 - "$TOK" "$LIVE" "$STORE" "$BK" "$ROOT" <<'PY'
+import sys,json,urllib.request,urllib.parse,re,time,os
+tok,LIVE,STORE,BK,ROOT=sys.argv[1:6]
+def get(k):
+ q=urllib.parse.urlencode({'asset[key]':k})
+ return json.load(urllib.request.urlopen(urllib.request.Request(
+ f"https://{STORE}/admin/api/2024-10/themes/{LIVE}/assets.json?{q}",
+ headers={'X-Shopify-Access-Token':tok})))['asset']['value']
+def put(k,v):
+ body=json.dumps({'asset':{'key':k,'value':v}}).encode()
+ s=json.load(urllib.request.urlopen(urllib.request.Request(
+ f"https://{STORE}/admin/api/2024-10/themes/{LIVE}/assets.json",
+ data=body,method='PUT',headers={'X-Shopify-Access-Token':tok,'Content-Type':'application/json'})))['asset']['size']
+ print(' PUT',k,'->',s,'bytes'); time.sleep(2)
+def backup(k):
+ try:
+ cur=get(k); open(os.path.join(BK,k.replace('/','_')+'.pushbak'),'w').write(cur); print(' backup',k,f'({len(cur)}b)')
+ except Exception as e:
+ print(' backup',k,'(absent/new file)')
+
+R=lambda p: open(os.path.join(ROOT,p)).read()
+
+# ---- 1. straight asset replacements (back up each first) ----
+# Memo E (grid.js init-abort)
+backup('assets/grid.js')
+put('assets/grid.js', R('shopify/grid-js-fix/grid.js.production-554k.from-theme-141318651955'))
+backup('snippets/product-list-item.liquid')
+put('snippets/product-list-item.liquid', R('shopify/grid-js-fix/patched/product-list-item.liquid'))
+backup('sections/header.liquid')
+put('sections/header.liquid', R('shopify/grid-js-fix/patched/header.liquid'))
+# Memo A (toolbar consolidation)
+backup('snippets/collection-toolbar.liquid')
+put('snippets/collection-toolbar.liquid', R('pending-approval/toolbar-consolidation-assets/snippets__collection-toolbar.liquid'))
+backup('layout/theme.liquid')
+put('layout/theme.liquid', R('pending-approval/toolbar-consolidation-assets/layout__theme.liquid'))
+# Merged A+D collection.liquid
+backup('sections/collection.liquid')
+put('sections/collection.liquid', R('shopify/collection-hero-fix/patched/sections_collection.MERGED.liquid'))
+# Memo D new files
+backup('snippets/dw-collection-hero-bg.liquid')
+put('snippets/dw-collection-hero-bg.liquid', R('shopify/collection-hero-fix/snippets_dw-collection-hero-bg.liquid'))
+backup('assets/dw-hero-rotator.js')
+put('assets/dw-hero-rotator.js', R('shopify/collection-hero-fix/dw-hero-rotator.js'))
+
+# ---- 2. settings_schema: add Collection-hero group (existence-guarded) ----
+backup('config/settings_schema.json')
+live_ss=json.loads(get('config/settings_schema.json'))
+have_grp=any(isinstance(g,dict) and any(s.get('id')=='collection_default_hero' for s in g.get('settings',[])) for g in live_ss)
+have_tog=any(isinstance(g,dict) and any(s.get('id')=='collection_hero_rotate' for s in g.get('settings',[])) for g in live_ss)
+if not have_grp or not have_tog:
+ live_ss=[g for g in live_ss if not (isinstance(g,dict) and g.get('name')=='Collection hero')]
+ live_ss.insert(1,{"name":"Collection hero","settings":[
+ {"type":"paragraph","content":"Collection-page hero band. Per-collection Collection images always take priority (frame 1). When 'Rotate newest arrivals' is on, the newest store-wide products follow as a crossfade slideshow."},
+ {"type":"image_picker","id":"collection_default_hero","label":"Default collection hero image","info":"Used only when a collection has no image of its own. Recommended 2000x600."},
+ {"type":"checkbox","id":"collection_hero_rotate","label":"Rotate newest arrivals in the hero","default":True,"info":"Crossfades through the newest store-wide products (from the New Arrivals collection). Off = show only the curated/default image."}]})
+ put('config/settings_schema.json', json.dumps(live_ss,indent=2,ensure_ascii=False))
+else: print(' settings_schema already has hero group + rotate toggle, skipped')
+
+# ---- 3. custom.css: BOTH marked blocks (grid-fix B + hero D), idempotent ----
+backup('assets/custom.css')
+css=get('assets/custom.css')
+def upsert(css, start, end, body):
+ css=re.sub(re.escape(start)+r'.*?'+re.escape(end),'',css,flags=re.S).rstrip()+'\n'
+ return css+'\n'+start+'\n'+body+'\n'+end+'\n'
+GS='/* >>> dw-collection-grid-fix START >>> */'; GE='/* <<< dw-collection-grid-fix END <<< */'
+HS='/* >>> dw-collection-hero-fix START >>> */'; HE='/* <<< dw-collection-hero-fix END <<< */'
+css=upsert(css, GS, GE, R('shopify/grid-js-fix/dw-collection-grid-fix.css'))
+css=upsert(css, HS, HE, R('shopify/collection-hero-fix/dw-collection-hero.css'))
+put('assets/custom.css', css)
+
+# ---- 4. verify ----
+coll=get('sections/collection.liquid'); css=get('assets/custom.css')
+theme=get('layout/theme.liquid'); tool=get('snippets/collection-toolbar.liquid'); grid=get('assets/grid.js')
+checks=[
+ ('collection.liquid hero render', "dw-collection-hero-bg" in coll),
+ ('collection.liquid native sort-by removed', 'select id="sort-by"' not in coll),
+ ('collection.liquid density.js removed', "src=\"{{ 'collection-grid-density.js'" not in coll),
+ ('collection.liquid toolbar include', "include 'collection-toolbar'" in coll),
+ ('toolbar null-guard', '!sortSelect' in tool or '!densitySlider' in tool),
+ ('theme.liquid dw-grid-control removed', 'dw-grid-control.js include removed' in theme),
+ ('theme.liquid infinite scoped', 'newwall-infinite.js scoped' in theme),
+ ('css grid-fix block', GS in css),
+ ('css hero block', HS in css),
+ ('grid.js production', 'ATTENTION' not in grid[:2000] and len(grid)<700000),
+]
+ok=all(v for _,v in checks)
+for n,v in checks: print((' OK ' if v else ' !! '),n)
+print('LIVE consolidated push', 'VERIFIED' if ok else 'HAS GAPS', f'(backups in {BK})')
+PY
+
+echo "=== verify LIVE collection pages return no Liquid error ==="
+sleep 3
+for c in all new-arrivals grasscloth 1838-wallcoverings; do
+ err=$(curl -sS -A "Mozilla/5.0" "https://www.designerwallcoverings.com/collections/$c?_cb=$(date +%s)" | grep -oE "Liquid error[^<]*" | head -1)
+ printf " %-22s %s\n" "$c" "${err:-OK}"
+done
+echo ""
+echo "Rollback: re-PUT every *.pushbak in $BK to its original asset key."
← f9adefec Reconcile 5 collection memos: merge sections/collection.liqu
·
back to Designer Wallcoverings
·
auto-save: 2026-06-23T16:22:58 (13 files) — audits/designtex 11c5de3a →