[object Object]

← back to Designer Wallcoverings

Diagnose + stage revert of broken Approach-B section-inside-section on LIVE collection page

de52ba2c94fb9cd40e6fe91c3325cc48a1d4200a · 2026-06-23 07:32:01 -0700 · Steve Abrams

Live main theme 142250278963 (Steves Version 5.0) sections/collection.liquid L85
had {%- section 'collection-filters-horizontal' -%} inside the collection section
-> 'Cannot render sections inside sections' on every collection page. Prior fix
commits targeted the wrong (now-unpublished) theme 143739584563. Adds race-safe
push-revert-collection-fix.sh (Steve-gated live push) + original backup + fixed file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit de52ba2c94fb9cd40e6fe91c3325cc48a1d4200a
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jun 23 07:32:01 2026 -0700

    Diagnose + stage revert of broken Approach-B section-inside-section on LIVE collection page
    
    Live main theme 142250278963 (Steves Version 5.0) sections/collection.liquid L85
    had {%- section 'collection-filters-horizontal' -%} inside the collection section
    -> 'Cannot render sections inside sections' on every collection page. Prior fix
    commits targeted the wrong (now-unpublished) theme 143739584563. Adds race-safe
    push-revert-collection-fix.sh (Steve-gated live push) + original backup + fixed file.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 ...ollection.liquid.MAIN-142250278963.FIXED.liquid | 256 +++++++++++++++++++++
 shopify/push-revert-collection-fix.sh              |  74 ++++++
 2 files changed, 330 insertions(+)

diff --git a/shopify/proposed-fixes/sections__collection.liquid.MAIN-142250278963.FIXED.liquid b/shopify/proposed-fixes/sections__collection.liquid.MAIN-142250278963.FIXED.liquid
new file mode 100644
index 00000000..323baf20
--- /dev/null
+++ b/shopify/proposed-fixes/sections__collection.liquid.MAIN-142250278963.FIXED.liquid
@@ -0,0 +1,256 @@
+<script
+  type="application/json"
+  data-section-id="{{ section.id }}"
+  data-section-type="static-collection"
+>
+</script>
+
+{% liquid
+  assign products_per_page = section.settings.products_per_row | times: section.settings.number_of_rows
+  assign use_masonry = false
+
+  if section.settings.layout == 'masonry'
+    assign use_masonry = true
+  endif
+
+  assign show_filters = false
+  if section.settings.show_filters
+    assign show_filters = true
+  endif
+
+  assign show_sorting = false
+  if section.settings.sorting
+    assign show_sorting = true
+  endif
+
+  assign show_collection_image = false
+  if collection.image and section.settings.show_collection_image
+    assign show_collection_image = true
+  endif
+%}
+
+<div>
+  {% unless use_masonry %}
+    <h1 class="page-title">{{ collection.title }}</h1>
+    {% render 'breadcrumbs' %}
+  {% endunless %}
+
+  {% paginate collection.products by products_per_page %}
+    <section
+      class="collection collection-image--{{ show_collection_image }}"
+      data-product-hover="{{ settings.product_hover }}"
+      {% if use_masonry %}data-collection-masonry{% endif %}
+      data-section-id="{{ section.id }}"
+      data-section-type="collection">
+
+      {% if use_masonry or show_collection_image or collection.description != blank or show_sorting or show_filters %}
+        <div
+          class="
+          collection-header
+          {% if use_masonry %}
+            collection-header-alternate
+          {% endif %}
+          {% if show_filters and show_sorting %}
+            collection-header--filters-sort-enabled
+          {% endif %}
+          "
+        >
+          {% if show_collection_image %}
+            <div class="collection-featured-image">
+              {%
+                render 'rimg',
+                img: collection.image,
+                size: '1024x1024',
+                lazy: true,
+              %}
+            </div>
+          {% endif %}
+
+          <div class="collection-header-content">
+            {% if use_masonry %}
+              {% render 'breadcrumbs' %}
+              <h1 class="page-title">{{ collection.title }}</h1>
+            {% endif %}
+
+            {% if collection.description != blank and section.settings.show_description %}
+              <div class="collection-description rte">
+                {{ collection.description }}
+              </div>
+            {% endif %}
+
+            {% if show_filters or show_sorting %}
+              <div class="collection-filters">
+                {% if show_filters and collection.filters.size > 0 %}
+                  <!-- Boost native filters (hidden by Approach B CSS, powers the filtering) -->
+                  <div class="faceted-filters" data-faceted-filter>
+                    {%
+                      render "faceted-filters",
+                      filters: collection.filters,
+                      class_prefix: 'collection',
+                    %}
+                  </div>
+                {% endif %}
+                {% if show_sorting %}
+                  <div class="collection-sorting__wrapper">
+                    <label class="collection-filters__title label" for="sort-by">
+                      {{- 'collections.collection.sort_title' | t -}}:
+                    </label>
+
+                    <div
+                      class="
+                        collection-dropdown
+                        collection-dropdown--sort
+                        select-wrapper
+                        {% if collection.current_vendor %}
+                          vendor-collection
+                        {% endif %}
+                      "
+                    >
+                      {% assign current_sort = collection.sort_by | default: collection.default_sort_by %}
+
+                      <span class="selected-text"></span>
+
+                      <select id="sort-by" class="select" data-collection-sorting>
+                        {%- for option in collection.sort_options -%}
+                          {% if current_sort == option.value %}
+                            <option value="{{ option.value }}" selected="selected">{{ option.name }}</option>
+                          {% else %}
+                            <option value="{{ option.value }}">{{ option.name }}</option>
+                          {% endif %}
+                        {% endfor %}
+                      </select>
+                    </div>
+                  </div>
+                {% endif %}
+              </div>
+            {% endif %}
+          </div>
+
+          {% if show_filters and collection.filters.size > 0 %}
+            {% for filter in collection.filters %}
+              {% if filter.active_values.size > 0 or filter.min_value.value or filter.max_value.value %}
+                  {%-
+                    render 'faceted-filters-active',
+                    show_sorting: show_sorting,
+                    filter: filter,
+                    filters: collection.filters,
+                    class_prefix: 'collection',
+                    clear_url: collection.url,
+                  %}
+                {% break %}
+              {% endif %}
+            {% endfor %}
+          {% endif %}
+        </div>
+      {% endif %}
+
+      <!-- Full Collection Toolbar: Sort + Grid Density Slider -->
+      {% include 'collection-toolbar' %}
+
+      <div
+        class="collection-products rows-of-{{ section.settings.products_per_row }} grid-cols-3"
+        data-collection-grid
+        {% if use_masonry %}data-masonry-grid{% endif %}
+      >
+        {%- if use_masonry -%}
+          <div class="product-grid-masonry-sizer" data-masonry-sizer></div>
+        {%- endif -%}
+
+        {%- if collection.handle == 'all' and collection.all_vendors.size == 0 and collection.all_types.size == 0 -%}
+          {%- for i in (1..section.settings.products_per_row) -%}
+            {%- capture productImage -%}
+              {%- cycle 'product-1', 'product-2', 'product-3' -%}
+            {%- endcapture -%}
+            {%- assign image = productImage | placeholder_svg_tag: 'placeholder-svg' -%}
+
+            {%- render 'home-onboard-product', image: image -%}
+          {%- endfor -%}
+        {%- else -%}
+          {% for product in collection.products %}
+            {%
+              render 'product-list-item',
+              product: product,
+            %}
+          {% else %}
+            {% capture continueLink %}
+              <a href="{{ routes.all_products_collection_url }}">{{ 'collections.collection.continue_link' | t }}</a>
+            {% endcapture %}
+             <p class="empty">{{ 'collections.collection.empty_html' | t: continue_link: continueLink }}</p>
+          {% endfor %}
+        {%- endif -%}
+      </div>
+    </section>
+
+    {%
+      render 'pagination',
+      paginate: paginate,
+    %}
+  {% endpaginate %}
+</div>
+
+<script src="{{ 'collection-grid-density.js' | asset_url }}" defer></script>
+
+{% schema %}
+{
+  "name": "Collection pages",
+  "settings": [
+    {
+      "type": "checkbox",
+      "id": "show_collection_image",
+      "label": "Show collection image"
+    },
+    {
+      "type": "checkbox",
+      "id": "show_description",
+      "label": "Show description"
+    },
+    {
+      "type": "checkbox",
+      "id": "sorting",
+      "label": "Enable sorting",
+      "info": "Parameters include: best selling, A-Z, newest to oldest, etc."
+    },
+    {
+      "type": "checkbox",
+      "id": "show_filters",
+      "label": "Enable filtering",
+      "default": true
+    },
+    {
+      "type": "select",
+      "id": "layout",
+      "label": "Layout",
+      "options": [
+        {
+          "value": "default",
+          "label": "Default"
+        },
+        {
+          "value": "masonry",
+          "label": "Masonry"
+        }
+      ],
+      "default": "default"
+    },
+    {
+      "type": "range",
+      "id": "products_per_row",
+      "label": "Products per row",
+      "min": 2,
+      "max": 4,
+      "step": 1,
+      "default": 3
+    },
+    {
+      "type": "range",
+      "id": "number_of_rows",
+      "label": "Rows",
+      "min": 1,
+      "max": 12,
+      "step": 1,
+      "default": 3
+    }
+  ]
+}
+
+{% endschema %}
diff --git a/shopify/push-revert-collection-fix.sh b/shopify/push-revert-collection-fix.sh
new file mode 100755
index 00000000..750798bf
--- /dev/null
+++ b/shopify/push-revert-collection-fix.sh
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+# REVERT the broken "Approach B" horizontal-filter element from the LIVE collection page.
+#
+# Bug: sections/collection.liquid had `{%- section 'collection-filters-horizontal' -%}`
+#      rendered INSIDE the collection section → Shopify error on every collection page:
+#      "Liquid error (sections/collection line 85): Cannot render sections inside sections"
+#
+# Why it slipped through: the other "Fix" commits pushed to theme 143739584563
+#      ("NewWall Template [Dev]", now UNPUBLISHED). The actual LIVE/main theme is
+#      142250278963 "Steves Version 5.0" — it never got the fix.
+#
+# This script is RACE-SAFE: it pulls the CURRENT live asset, surgically removes only
+# the offending block, backs up the original, PUTs, and verifies the error is gone.
+# It keeps the native Boost faceted-filters (the original working filter UI).
+#
+#   bash push-revert-collection-fix.sh
+set -euo pipefail
+cd "$(dirname "$0")"
+
+STORE="designer-laboratory-sandbox.myshopify.com"
+API="2024-10"
+MAIN="142250278963"   # role=main / published — "Steves Version 5.0"
+SECRETS="$HOME/Projects/secrets-manager/.env"
+TOK="${THEME_TOKEN:-$(grep -hE '^SHOPIFY_THEME_TOKEN=' "$SECRETS" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"'"'"' ')}"
+[ -z "$TOK" ] && { echo "No theme token. Run: THEME_TOKEN=shpat_xxx bash $0"; exit 1; }
+echo "token …${TOK: -4}  | LIVE main theme $MAIN"
+mkdir -p theme-backups
+
+python3 - "$STORE" "$API" "$TOK" "$MAIN" <<'PY'
+import sys, json, urllib.request, urllib.parse, datetime, re
+store, api, tok, tid = sys.argv[1:5]
+H = {"X-Shopify-Access-Token": tok, "Content-Type": "application/json"}
+key = "sections/collection.liquid"
+url = f"https://{store}/admin/api/{api}/themes/{tid}/assets.json?" + urllib.parse.urlencode({"asset[key]": key})
+
+a = json.load(urllib.request.urlopen(urllib.request.Request(url, headers=H)))["asset"]
+src = a["value"]
+print(f"pulled fresh: {len(src)} bytes, updated {a['updated_at']}")
+lines = src.split("\n")
+idx = [i for i,l in enumerate(lines) if re.search(r"{%-?\s*section\s+'collection-filters-horizontal'", l)]
+if not idx:
+    print("Already clean — no Approach-B section call. Nothing to do."); sys.exit(0)
+i = idx[0]
+drop = {i}
+if i-1>=0 and "Approach B" in lines[i-1]: drop.add(i-1)
+if i+1<len(lines) and lines[i+1].strip()=="": drop.add(i+1)
+new_lines = [l for j,l in enumerate(lines) if j not in drop]
+new = "\n".join(new_lines)
+remain = [n+1 for n,l in enumerate(new_lines) if re.search(r"{%-?\s*section\s", l)]
+if remain:
+    print(f"ABORT: other {{% section %}} calls remain at {remain} — manual review."); sys.exit(4)
+print("removing:")
+for j in sorted(drop): print(f"  -{j+1}| {lines[j]}")
+
+stamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
+bk = f"theme-backups/sections__collection.liquid.MAIN-{tid}.{stamp}.bak"; open(bk,"w").write(src)
+print("backup:", bk)
+
+body = json.dumps({"asset": {"key": key, "value": new}}).encode()
+r = urllib.request.urlopen(urllib.request.Request(
+    f"https://{store}/admin/api/{api}/themes/{tid}/assets.json", data=body, method="PUT", headers=H))
+print(f"PUT HTTP {r.status} OK -> {len(new)} bytes on LIVE main {tid}")
+
+chk = json.load(urllib.request.urlopen(urllib.request.Request(url, headers=H)))["asset"]["value"]
+print("verify asset clean:", not re.search(r"{%-?\s*section\s+'collection-filters-horizontal'", chk))
+PY
+
+echo "=== verify live page (fresh render) ==="
+sleep 3
+for c in phyllis-morris-classic-wallcovering animal-skin all; do
+  err=$(curl -sS -A "Mozilla/5.0" "https://www.designerwallcoverings.com/collections/$c?_cb=$(date +%s)" | grep -oE "Liquid error \(sections/collection line [0-9]+\)[^<]*" | head -1)
+  printf "  %-38s %s\n" "$c" "${err:-OK (no liquid error)}"
+done
+echo "Done. To roll back: PUT the newest theme-backups/sections__collection.liquid.MAIN-${MAIN}.*.bak back to theme ${MAIN}."

← bfe782d2 Upgrade all Gemini text calls from deprecated gemini-2.0-fla  ·  back to Designer Wallcoverings  ·  Deploy collection toolbar to live theme: sort dropdown + gri d3069393 →