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.
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!
Related
I am passing a query to the context of a normal Django template. Within the template I want to do this:
{% for item in sample %}
{% if item.status != "Close" %}
Show something
{% endif %}
{% endfor %}
However, the if condition is never evaluated to True.
I can perfectly access the field for each item in the template like {{item.status}} but the if part is not working.
Is there a special way to write the if statement so the template expands item.status to its value before evaluating the comparison?
My website is made by shopify and I use the dawn theme.
I've been trying for a few days to translate the word "Color" from inside the product pages into my language "Culoare". I looked for a solution on the internet, but I didn't find it. I don't want to translate the whole website because it is translated, I'm interested in translating only the variant picker metafield, the "Color" and "Size" options.
Thank you in advance.
You can put this code inside your main-product.liquid so that you can use the t filter for translation:
{% if option.name == 'Colors' %}
{% assign color_label = 'products.product.colors' %}
<legend class="form__label">{{ color_label | t }}</legend>
{% else %}}
<legend class="form__label">{{ option.name }}</legend>
{% endif %}
Then in your ro-RO.json add the reference to the translation:
"products": {
"product": {
"add_to_cart": "Adăugați în coș",
"colors": "Culoare"
}
}
It's the solution I came up with. Maybe there is a better solution.
I would like to add a new function to the product details page that shows me the current quantity of the variant that is in stock.
I get this far with Liquid, only if another variant is selected, the display of the amount does not change,
Anyone of you have any ideas how I can do that?
This shows me the current variant, but does not change when I change the selection.
{% - for variant in product.variants -%}
{{current_variant.inventory_quantity}}
{% - endfor -%}
You can't use Liquid for this. Liquid is just Shopify's templating language and is only useful for the initial page render.
I know how to do this. You need to use vue so it‘s reactive on the front end, also each product with variants now has to be a collection. You will need to loop through the products in the collection and get the linked products with javascript.
So let‘s say you have a specific product and you have three versions of it, you would actually create three separate products.
The next thing to do is link them with liquid and javascript, so in your product.liquid file open a set of script tags and you would start it like this
{% assign current_product = product %}
const product = (function() {
const product = {{ product | json }};
return product
})();
const linked_products = (function() {
const linked_products = []
{% for collection in current_product.collections %}
{% for product in collection.products %}
{% if product.id != current_product.id and product.title == current_product.title %}
product = {{ product | json }}
linked_products.push(product);
{% endif %}
{% endfor %}
{% endfor %}
return linked_products;
})();
This is just to get the ball rolling but you will need to handle quite a bit of other things and this is quite a large project.
In Shopify I am declaring a variable like this:
{% assign favourites = hello %}
Instead of the variable being `hello, I want to use a metafield from my product. I can get the metafield like this:
{{ product.metafields.global["other_options"] }}
I can't, however, merge the two together like this
{% assign favourites = {{ product.metafields.global["other_options"] }} %}
I have tried wrapping the liquid object in single and double quotation marks but this doesn't work.
Is it possible to do this?
Remove the internal braces :)
{% assign favourites = product.metafields.global["other_options"] %}
I'm not able to access template variable in TWIG macro.
Here is a simplified example:
{% set myname = "Ligio" %}
{{ _self.pagedurl(1) }}
{% macro pagedurl(page) %}
Hi {{ _self.myname }}! This is Page Num {{ page }}
{% endmacro %}
How can I access the variable myname without passing it to the macro?
You can not.
As stated in the documentation:
As PHP functions, macros don't have access to the current template
variables.
Your only solution is to pass the parameter to the macro:
{% import _self as flow %}
{{ flow.pagedurl(1, "Ligio") }}
{% macro pagedurl(page, myname) %}
Hi {{ myname }}! This is Page Num {{ page }}
{% endmacro %}
IMPORTANT NOTE:
You may have noticed in my example, I call {% import _self as flow %}.
This is something you MUST do:
When you define a macro in the template where you are going to use it,
you might be tempted to call the macro directly via _self.input()
instead of importing it; even if seems to work, this is just a
side-effect of the current implementation and it won't work anymore in
Twig 2.x.
http://twig.sensiolabs.org/doc/tags/macro.html
If you need to pass more than one global variable into the macro, you might find the _context variable useful:
{% macro mymacro(globalvars) %}
Value of the global variable pi is {{ globalvars.pi }}
{% endmacro %}
{% set pi = 3.14159 %}
{{ _self.mymacro(_context) }}
Ref: this or this answer.
You can set a global variable and access it anywhere in the template
$loader = new \Twig_Loader_Filesystem('path/to/templates');
$twig = new \Twig_Environment($loader);
$twig->addGlobal('V_Name', 'V_Value');