Liquid - if contains statement not working in for loop - for-loop

I have a very basic conditional inside a loop that isn't working:
{% for tag in collections.all.tags %}
<li class="mb-1 ">
<a class="text-white" title="{{ tag }}" href="#">
{{ tag | handle }}
{% if canonical_url contains tag | handle %}
active
{% endif %}
</a>
</li>
{% endfor %}
Right now, my tag | handle is "dodge" and if I print my {{ canonical_url }} I get https://localhost:3000/collections/all/dodge so my conditional should evaluate to truthy and print the word 'active'.
If I modify my statement to {% if canonical_url contains 'dodge' %} it works fine but I need it to be dynamic. Any suggestions?

Set the handle into a variable and use the variable for the comparison instead of the handle.

First You have to assign value of tag handle to shopify liquid variable & then you will be able to use variable in condition And then every thing will be working fine & dynamic. Thanks !!

Related

How can i use string interpolation with Jekyll?

I have a Jekyll 3 project that allows language selection. We use the 'jekyll-multiple-languages-plugin' gem for internationalization.
We have a glossary that is supposed to display German terms or English terms according to the selected language. I get the selected language using the variable site.lang provided by the 'jekyll-multiple-languages-plugin' gem.
Right now glossary.html looks like this
<div id="glossary">
{% if site.lang == "de" %}
{% for term in site.data['terms_de'] %}
<!-- German glossary goes here -->
{% endfor %}
{% elsif site.lang == "en" %}
{% for term in site.data['terms_en'] %}
<!-- English glossary goes here -->
{% endfor %}
{% endif %}
</div>
However, i'd love to have something like this
<div id="glossary">
{% for term in site.data["terms_#{site.lang}"] %}
<!-- Glossary goes here -->
{% endfor %}
</div>
But for some reason, the string interpolation "terms_#{site.lang}" doesn't work. I also tried 'terms_'+site.lang
I think the interpolation is not working because, when i put {{ site.lang }} in the page, i see the selected language, but when i write {{ "terms_"+site.lang }} i don't see anything.
Thanks in advance.
You can make use of the capture tag, instead of displaying a value it sets to a variable:
{% capture term_lang %}{{ 'terms_' | append: site.lang }}{% endcapture%}
Then you can use that variable as the index of the array:
site.data[term_lang]
In your example:
{% capture term_lang %}{{ 'terms_' | append: site.lang }}{% endcapture%}
<div id="glossary">
{% for term in site.data[term_lang] %}
<!-- Glossary goes here -->
{% endfor %}
</div>

Shopify Liquid How do I use for-loop index variables in an assign or capture tag?

I am just getting into some liquid template coding on a Shopify site. How do I use the for-loop index/variable when defining variable names in assign or capture tags? ie: I'm trying to condense the code to create multiple link menus from sequentially numbered settings, where [i] would be a number between 2 and 4 in the settings key.
What is the proper syntax to insert that number into
a) a tag like an if statement or assign.
b) interpolated text like in the h3 element below.
c) a nested/bracketed key statement (sorry if that's not what its called, i'm still learning), like in the second for statement.
{% for i in (2..4) %}
{% if settings.footer_quicklinks_enable[i] %}
<div class="grid-item medium--one-half large--three-twelfths">
<h3>{{ 'layout.footer.quick_links{{i}}' | t }}</h3>
<ul>
{% for link in linklists[settings.footer_quicklinks_linklist[i]].links %}
<li>{{ link.title }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endfor %}
You need to use the square bracket notation instead of dot notation.
Create a string containing the variable name (with assign or capture), then use square bracket notation to access the setting with that name.
For example:
{% capture var %}footer_quicklinks_enable_{{i}}{% endcapture %}
{% if settings[var] %}
Also see this similar answer.

Selectively rendering Liquid templates?

Is there a possibility to selectively render specific tags in a liquid template and leave the rest for a second render?
I have pages containing snippets(includes) and variables. The snippets are stored in the database and expensive to render. The variables are available only at runtime (via the URL request in the scenario of a landing page). I want to cache the page content with the snippets rendered but with all the rest of the liquid markup untouched.
So, If I have
{% snippet header %}
{% if vars.first_name %}
Welcome, {{ vars.first_name }}
{% endif %}
{% snippet footer %}
I would want the cached page content to be:
The header content
{% if vars.first_name %}
Welcome, {{ vars.first_name }}
{% endif %}
The footer content
At runtime this would be picked up from the memcached store and rendered:
The header content
Welcome, John
The footer content
Any idea on how to achieve this?
Update: Here's what I have in place already:
(It works, but I am looking for a cleaner, ideally liquid-only-based solution.)
A "vars" tag which produces a variable with the given name:
{% vars first_name %} #=> {{ vars.first_name }}
And, I use modified liquid markup for everything I don't want rendered the first time:
{* if vars.first_name *}
So, currently the initial page looks like this:
{% snippet header %}
{* if vars.first_name *}
Welcome, {% vars first_name %}
{* endif *}
{% snippet footer %}
Which gets rendered once and cached as:
The header content
{* if vars.first_name *}
Welcome, {{ vars.first_name }}
{* endif *}
The footer content
Then at runtime I retrieve the cached version and replace {* with {% etc. to get
The header content
{% if vars.first_name %}
Welcome, {{ vars.first_name }}
{% endif %}
The footer content
Which I render with liquid again to get to the desired outcome.
This does the job but is not pure liquid and I was wondering if there is a cleaner solution.
Is there?
{% snippet header %}
{% raw %}{% if vars.first_name %}
Welcome, {{ vars.first_name }}
{% endif %}{% endraw %}
{% snippet footer %}
This should get you the rendering that you want to cache, and then if you re-render it through Liquid I would think it would process the runtime variable.

If product tags contains - in shopify

So i'm basically trying to use the logic of shopify to show an image if the tags of the product contains the words "related"
(there is a json query that picks up the tags containing 'related-x' where x is the name of the product and it uses this to show the related products.)
Preceding the Json query is an image that says "related products" basically. what i would like to do is to only display this when there are "related" tags present.
I have tried this:
{% if product.tags contains 'related' %}
<img src="{{ 'complete-this-look.gif' | asset_url }}" alt="" align="left;" style="vertical-align:top; margin-right:8px; padding-top:0px;" width="130" height="175"/>
{% endif %}
Which doesnt display anything. I also tried:
{% for t in product.tags %}
{% if t contains 'related-' %}
<img src="{{ 'complete-this-look.gif' | asset_url }}" alt="" align="left;" style="vertical-align:top; margin-right:8px; padding-top:0px;" width="130" height="175"/>
{% endif %}
{% endfor %}
However this will display the image every time a related product is returned by the query.
What im after is for it to go (Image) (Query Results) - and if there is no query results then it displays nothing.
Any ideas?
The reason your first piece of code is not working is because contains is looking for a tag called 'related', not a tag containing the substring 'related'.
See the Shopify Wiki for contains where it states:
It can check for the presence of a string in another string, or it can check for the presence of a string in an array of simple strings.
In your instance, contains is checking for a string in an array of simple strings (and is looking for the whole string, not a string containing the specified string as a substring).
See also the Shopify wiki for product.tags:
Returns a list of the product's tags (represented by simple strings).
You can use the contains keyword with an array of simple strings, so
you can use this with a product's tags:
{% if product.tags contains 'custom to order' %}
<!-- Output custom to order form HTML here -->
{% endif %}
So, Gerard Westerhof's suggestion to use Join in the comment above is a good one. If you first join the product.tags array, then contains will search for the 'related' string inside the string of tags returned by join.
Try this:
{% if product.tags | join: ' ' contains 'related' %}
<img src="{{ 'complete-this-look.gif' | asset_url }}" alt="" align="left;" style="vertical-align:top; margin-right:8px; padding-top:0px;" width="130" height="175"/>
{% endif %}
EDIT:
Try this instead:
{% assign product_tags_string = product.tags | join: ' ' %}
{% if product_tags_string contains 'related' %}
<img src="{{ 'complete-this-look.gif' | asset_url }}" alt="" align="left;" style="vertical-align:top; margin-right:8px; padding-top:0px;" width="130" height="175"/>
{% endif %}

Translatable content and HTML tags

I use Twig and I want to make the following content translatable :
{% trans %}
You have actually <span class='messageNumber'>{{messageNumber}} message(s)</span> in your mailbox.
{% endtrans %}
But when this translatable content will be parsed by POEdit and sent to translators, they will see the <span> tags and attributes. What can I do to avoid this ?
I thought about doing this way :
{% messageNumberFormatted = "<span class='messageNumber'>"~messageNumber~"message(s)</span>" %}
{% trans %}
You have actually {{messageNumberFormatted}} in your mailbox.
{% endtrans %}
But isn't it a bit heavy or even bad practice for the translators ? In that case, they can't even see the word "message".
First, you should use transchoice with explicit interval pluralization, like this :
{% transchoice message_count %}
{0}You have {{no messages}} yet|{1}You have {{one message}}|]1,+Inf]You have {{%count% messages}}.
{% endtranschoice %}
Then maybe you could use replace to replace {{ with the opening tag, and }} with the closing tag. I don't know whether you can directly chain like this
{% transchoice message_count | replace('...') %}
Or if you must store in a variable by using set first.
You can use the trans twig filer with keys representing your sentences.
{{ you.have.actually|trans }} <span class='messageNumber'> {{ messageNumber message|trans }} </span> {{ in.your.mailbox|trans }}

Resources