2
votes

Playing around with Shopify theme creation, I am facing an issue while creating a loop.

I am allowing the theme administrator to choose from 1 to 4 products to display in the store. He can choose them from the customize UI of his theme.

The schema is:

{
  "type": "product",
  "id": "popular_product_1",
  "label": "Product N°1"
},
{
  "type": "product",
  "id": "popular_product_2",
  "label": "Product N°2"
},
{
  "type": "product",
  "id": "popular_product_3",
  "label": "Product N°3"
},
{
  "type": "product",
  "id": "popular_product_4",
  "label": "Product N°4"
}

Back to my liquid file, as a test, if I want the URL to the product I can do:

{{ all_products[section.settings.popular_product_1].url }}

And it's going to work. But of course, I have to repeat the same code 4 times. So I wanted to create a loop that would go over each.

But how to get the incremental number to be inserted in the above? Of course

{{ all_products[section.settings.popular_product_i].url }}
{{ all_products[section.settings.popular_product_{{i}}].url }}

don't work.

I also tried

{% assign i = 1 %}
{% capture popular_product %}section.settings.popular_product_{{i}}{% endcapture %}
{{ all_products[popular_product].url }}

but it does not work either... as it seems that the variable popular_product is a string while it's not what it should be.

1

1 Answers

4
votes

Alternate approach: Use section blocks

Have you considered using a section with blocks rather than just numbered product fields in the base settings? If you create a 'Popular Products' section and define popular-product blocks, you can add an arbitrary number of products (or can specify a maximum), then loop over them all using

{% for block in section.blocks %} 
   {% assign popular_product = all_products[block.settings.product] %}
   <!-- Cool stuff with your popular product -->
{% endfor %}

You can read more about setting up sections & blocks in Shopify here: https://help.shopify.com/en/themes/development/sections


Now, the approach you used isn't wrong, but the code you have above has some errors in it. These can be corrected to get the right product handle to use for the all_products lookup. First:

{{ all_products[section.settings.popular_product_{{i}}].url }}

is incorrect: we never nest Liquid curly-braces inside of Liquid curly-braces. Instead, this should look something like:

{% for i in (1..4) %}
  {% assign setting_name = 'popular_product_' | append: i %}
  {% assign handle = section.settings[setting_name] %}
  {% assign popular_product = all_products[handle] %}
  <!-- Cool stuff with our popular_product object -->
{% endfor %}

Next, the capture variable will evaluate everything between the tags and store it in a string. When you use:

{% capture popular_product %}section.settings.popular_product_{{i}}{% endcapture %}

The contents of the capture is going to first substitute the value of i and then capture the resulting string, which is not a product handle! What you really want is a specific value in the section.settings object.

You should use capture to just get the popular_product_x variable you need and accessing that inside of the section.settings. For example:

{% capture field_name %}popular_product_{{i}}{% endcapture %}
{% assign popular_product = all_products[section.settings[field_name]] %}
<!-- Cool stuff with your popular product -->

Hope this helps!


Note: I personally prefer assign for simple variables like the above and use capture only for grabbing multiple lines (like a block of HTML), but either one works in this instance. A warning with capture though: remember that all whitespace is captured as well, which is often unintended with simple variables like product handles or setting names.

Hope this helps!