Theme Log Vol. 3 – Customization Round-Up (2025-07)

Welcome to Theme Log!

Theme Log is a series where we share theme customizations, patterns, and cool Liquid tricks.

If you missed the previous topic, feel free to check it out here.

There has been a bit of a delay with these round-up topics. I was initially skipping them because I moved my family into a new home and needed the time for unpacking. Then I wanted to let Shopify Editions Summer '25 and the Editions.dev event to take priority instead. The unpacking part has taken a bit longer than expected because I also decided to expand our front garden, helped my FIL move, and have been preparing to welcome our 3rd child to the family early next week!

I mentioned last time about figuring out a better format for these starter posts and I came to the conclusion that I should set them up as a monthly round-up where we can share things we had the opportunity to work on throughout the entire month.

That said, for the month of July 2025, let’s set this round-up for specific customizations where you utilized updates shared with the recent Shopify Editions Summer '25.

Did you work with Horizon? Generate blocks with AI? Maybe it was adding a discount code input to a cart drawer. Whatever it was, please share it with the community!

Note, I also have another endeavor for the community that I started working on while I was away and will be sharing more on that soon!

I am looking forward to seeing what everyone shares this month!

:card_file_box: Got a trick? Did you build something cool?

If you have done something cool with any Online Store 2.0 theme, reply below with a snippet or a screenshot. Bonus points for sharing reusable code blocks!


If you are sharing something please try to adhere to this format for easy consumption:

# Add multiple products to cart on form submission [Short Name or Goal]

---
## :straight_ruler: Objective:
Briefly describe what you were trying to do (e.g., Add a trial upsell product with the purchase of another product).

---
## :clipboard: Affected Files:
List any theme files affected (e.g., buy-buttons.liquid, theme.js)

Modified:
- `snippets/buy-buttons.liquid`

Added:
- `snippets/trial-product-upsell.liquid`

---
## :light_bulb: Snippet/Explanation:
Use a code block for Liquid/JS/CSS and a short paragraph on how it works.

---

You can include multiple products in one product form and generally have them all add on submit (if native or `FormData` via Cart AJAX API).

[details="Code Snippet"]
```liquid
<input
  type="hidden"
  name="items[][id]"
  value="{{ product.selected_or_first_available_variant.id }}"
>
<input
  type="hidden"
  name="items[][quantity]"
  value="1"
>
{% if product.requires_selling_plan %}
<input
  type="hidden"
  name="items[][selling_plan]"
  value="{{ product.selected_or_first_available_variant.selected_or_first_available_selling_plan_allocation.selling_plan.id }}"
>
{% endif %}```
[/details]

---
## :test_tube: Notes/Tips:
Any edge cases, mobile quirks, or performance tips.

---
## :camera_with_flash: Screenshots / Before & After:
Use image embeds to showcase your positive impact visually. Be sure to include them in a `details` to keep things organized!

[details="Preview Experience"]
[/details]

Otherwise feel free to reply to others and connect further about whatever they share!

2 Likes

Thanks for posting this Rob - lots of great tips here. Hope the house move is going well :slight_smile:

Tabbed Collections


Objective

Use visible_if in the theme Maker(v10) for a tabbed-ui customization to conditionally show spacing controls for tabbed collection section converting collection sections to blocks.


:clipboard: Affected Files:

Created

  • featured-collection-tabs.liquid
  • grid-with-overlay-tabs.liquid

:light_bulb: Snippet/Explanation:

Because in a tabbed UI there are tab controls and each panel may have it’s on heading ,or lack it, such a section needs to have it’s own spacing-above and spacing-below behaviors that can be disabled to let children blocks control spacing above and below.
So the entire section could have it’s own heading, or each collection block would bring it’s own heading.
Ontop of new CSS for the new space rules it also included changing spacing controls from checkboxes to selects in settings.

Code Snippet
    {
      "type": "header",
      "content": "Style and layout"
    },
    {
      "id": "no-padding",
      "label": "No padding",
      "type": "checkbox",
      "default": true,
      "info": "removes padding on ALL sides letting sections be bigger, disables spacing"
    },
    {
      "id": "spacing-above",
      "label": "Spacing above",
      "type": "select",
      "options": [
        {
          "label": "None",
          "value": "none"
        },
        {
          "label": "Half",
          "value": "half"
        },
        {
          "label": "Full",
          "value": "full"
        }
      ],
      "default": "half",
      "visible_if": "{{section.settings.no-padding == false}}"
    },
    {
      "id": "spacing-below",
      "label": "Spacing below",
      "type": "select",
      "options": [
        {
          "label": "None",
          "value": "none"
        },
        {
          "label": "Half",
          "value": "half"
        },
        {
          "label": "Full",
          "value": "full"
        }
      ],
      "default": "half",
      "visible_if": "{{section.settings.no-padding == false}}"
    },

:test_tube: Notes/Tips:

Any edge cases, mobile quirks, or performance tips?
Because the maker theme has a grid overlay section with it’s own blocks this meant a remix into a tabbed UI meant it had to use a static content_for to make tab controls(buttons)
Unlike the featured-collection-tabs.liquid because that sections blocks could be defined in the section settings blocks schema and from that can just use a separate loop over it’s blocks to render tab controls.

Like so

Code Snippet
      {%- for block in section.blocks -%}
      <button
        type="button"
        class="featured-tabs--button{% if forloop.first %} active {% endif %}"
        data-tab-id="tab-{{ block.id }}"
        data-item="{{- buttons_style -}}"
      >
        {%- if block.settings.button-label != blank -%}
          {{- block.settings.button-label | escape -}}
        {%- endif -%}
      </button>
    {%- endfor -%}

Since the tab-controls(button blocks) are static, in the grid-with-overlay-tabs section, this means the blocks are scoped.
So you still have to establish some sort of reference to the relevant blocks that are scoped separately.
e.g. <button type="button" data-tab-id="tab-{{ block_index }}" > {{- button_label | escape -}} </button>

So get an index into the static block by looping over a range up to the section.blocks.size:

Code Snippet
 {%- for index in (1..section.blocks.size) -%}
  {% assign block_index0 = index | minus: 1 %}
  {% if forloop.index0 == section.blocks.size %}{% break %}{% comment %}break if empty{% endcomment%}{% endif %}
  {% assign id = 'tab-controls-' | append: index %}
  {% content_for "block", type: "_tabs_buttons", id: "buttons", block_index: block_index0 , buttons_style: buttons_style %}
{%- endfor -%}

And to have control over button labels even with blackboxing, the tab-controls blocks in this case has to have it’s own setting to assign labels.
Using a CSV format to set the labels text since it cannot get such details from the other blocks.

Code Snippet
   "settings": [
    {
      "id": "button-labels",
      "type": "text",
      "label": "Button Labels(CSV)",
      "default": "Button Label1 , Button Label2, Button Label3",
      "info":"Names of buttons separated by commas(,). One name for each related grid-with-overlay tab block."
    }
  ],

With the CSV split into an array getting the correct index using the block index parameter(from the static block render)
{% assign button_label = button_labels[block_index] %}


:camera_with_flash: Screenshots / Before & After:

Preview Experience

2 Likes