Welcome to Theme Log!
Theme Log is a series where we share weekly theme customizations, patterns, and cool Liquid tricks.
The plan is to post a new topic each week around Midnight on Sunday (ET) and have us all share various things we did with themes and the online store during that week. A sort of community showcase of having had the opportunity to make a positive impact on merchants and their customers!
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:
# 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!
3 Likes
Add multiple products to cart on form submission
Objective:
The client wanted to be able to add a trial upsell product with the purchase of another product.
Affected Files:
Modified:
snippets/buy-buttons.liquid
assets/product-info.js
assets/product-form.js
config/settings_schema.json
layout/theme.liquid
Added:
snippets/trial-product-upsell.liquid
Snippet/Explanation:
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).
Note, if you are including selling plans or properties for only specific products I believe you may need to include them as blank value inputs for each of the products listed. Also, if you do not want certain products included you can simply disable
their associated inputs.
Code Snippet
<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 %}
Notes/Tips:
- With the theme I was working in, I needed to adjust the add to cart functionality to work with a third-party app-based cart drawer.
- The Shop Pay accelerated checkout button also did not seem to like the use of
name="items[][id]"
instead of name="id"
so I also recreated it.
- I also worked on a solution to ensure the trial upsell product was not in the cart if the primary product was removed.
- A few years back I would use this approach as a non-JS solution and then of course the Cart AJAX API when necessary as well.
- Back then I also noticed that trying to submit the same form submission with multiple variants of the same product would provide unexpected results, such as increased quantities you did not submit.
- I am currently unsure if that ever got fixed but I did contact Support about it at the time.
Screenshots / Before & After:
Preview Experience
1 Like
Great initiative @RobDukarski! Love it.
I have a funny one, not particular advanced, but a nifty trick I occasionally use. So sorry for already deviating from the format.
Generally save serverside-accessible data to be used inbetween pages
Objective:
Usescases could be to
- conditionally render a banner based off specific URL parameters
- render different menus based off a user pick on index page (imagine Men vs Women).
- save states like grid view (2 cols, 3cols, list view) or light/dark theme (example below)
Snippet/Explanation:
/* On a button click/event/page load with URL param */
fetch(theme.routes.cartUpdate, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
attributes: { view: 'list' } // 'list' as example
})
})
.catch((error) => console.error('Error updating collection view:', error.message));
{%- comment -%} Accessing the data with liquid {%- endcomment -%}
{%- assign default_view = cart.attributes.view | default: section.settings.default_view -%}
Notes/Tips:
The example I’ve used is for a button that changes the layout of collection pages. They can switch between grid and list view. I want the picked option to be remembered while browsing, without having to wait for javascript to update it.
On change (setting a new view
) we need a page reload, or a Section Rendering API call to update the view.
I think the usual way to handle it, is sessionStorage
. Then it’ll have to run and change on every load.
Screenshots / Before & After:
Preview Experience
/cart.json
Thanks, things have just been busy over here for months and I have been wanting to break back into the community involvement, I figured putting together some series like this would be a great way to start!
Also, I love to use cart attributes all of the time for updating things throughout the storefront, like they are even perfect for “password-protected” content!
We’re in the same boat, then.
Yeah, it has plenty usecases.
Love this new series @RobDukarski - this will be super helpful for any dev working on themes!
1 Like