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

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.

Related

HuBL: Using for loop variable outside for loop

I have created a template partial file where I'm defining all variables in that file. I then want to reference a variable in custom modules. However, the for loop loop closes in the partial file, so when I reference it in the HTML of a custom module, it'll be out of scope.
Is there any way to use for loop variables outside the loop?
Demo:
Here is my template partial file:
<!--
templateType: "global_partial"
isAvailableForNewContent: false
-->
{% set table = hubdb_table_rows(table_id_here) %}
{% for row in table %}
{% set firstname = row.first_name %}
{% endfor %}
And here is how I'm calling the variable in my markup:
<div class="hero">
{% include "/template_partial_file.html" %}
<h1>{{ firstname }}</h1>
</div>
You can't access a variable set inside a for loop outside of said loop.
You can set up an array outside of a loop and push information from within the loop to it, e.g.
{% set names = [] %}
{% for row in table %}
{% do names.append(row.first_name) %}
{% endfor %}

Use variable and filter within tag in nunjucks + eleventy

I am a nunjucks newbie - trying it out along with eleventy.
Short version: can I use variables and filters within tags in nunjucks? For example:
{% set myVar = {{ title | lower }} %}
(assume the {{ title }} variable is set correctly)
Longer version / my specific use case:
I am trying to create a layout file called section.njk and use it for several pages (basically the section frontpages of each section of my site - similar idea to a section.html layout file in Hugo) I have a data file for each section, containing the menu for that section.
Given the following files:
guides.json
index.md with frontmatter including title: "Guides"
This does not work:
{% for item in {{ title | lower }} %}
<div>{{ item.title }}</div>
{% endfor %}
This works:
{% for item in guides %}
<div>{{ item.title }}</div>
{% endfor %}
So I'm wondering if the problem is using variables within tags in Nunjucks, and if so, if there's a way round it?
Entire project source is here: https://github.com/StarfallProjects/tech-writer-toolkit/tree/11ty (the 11ty stuff is in src)
Thanks for any help.
Yes, you can.
{% set myVar = title | lower %}
{% set myVar = title | lower + var2 | upper %}
{% set myVar = (title | lower + var2) | trim %}
...
{% for item in items | sort(false, true) %}
<div>{{ item.title | lower}}</div>
{% endfor %}
The lower, upper and trim filters are applyed to number/string vars. They can't be applyed for some array (or object).
On the another side, the sort-filter expects an array as input.
The filter "type" is obvious by its description in docs.

Liquid - if contains statement not working in 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 !!

How can I use Jinja2 to generate an index-like list?

In an index, references are listed alphabetically and grouped by letter. Also, instead of a simple alphabetical sort, leading articles and punctuation are removed before sorting. The result would look like this:
A
Abba
The Archer
Away From Here
B
"Bangkok" Mike
Bullets
I'm using the Pelican static site generator, which uses Jinja2 in its templates, and I'd like to create an index like this of TV shows that I've blogged about on my site.
TV show names are listed in a metadata field {{ article.showname }} (only one show per post, so only one show in the metadata field) and so are easily retrieved. But stripping the leading article/punctuation, grouping by first letter and inserting the correct letter of the alphabet is more than I know how to do.
Possible steps I could take
I could strip the leading article/punctuation and create another metadata field with the show name that's ready to be sorted, called, say, {{ article.shownamesort }}. For that matter, if there's not an easy way to group the names by their first letter, I could create a metadata field with the show's first (sortable) letter, {{ article.shownameletter }}.
For each letter, I could create a loop that begins by grabbing that letter's posts:
{% if article.shownameletter == "A" %}
Once that's done, I don't know how to sort the text from one metadata field based on the text of a different metadata field. That is, I don't know how to print the {{ article.showname }} list that's sorted by the {{ article.shownamesort }} list. Can this be done in Jinja2? For the record, if there's a solution that takes a completely different approach, I'd be very happy with it, including if it required different/more metadata fields.
I did something like that on the tags and categories pages. It iterates over all the characters and then prints the results
Iterate over the letters:
{% for char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"|list %}
...
{% endfor %}
Comparison for show or not show the tag:
{% if char == tag|upper|truncate(1, True, end='') %}
...
{% endif %}
Full example:
{% for char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"|list %}
<h2>{{char}}</h2>
{% for tag, articles in tags|sort %}
{% if char == tag|upper|truncate(1, True, end='') %}
<dt>{{ tag }}</dt>
{% for article in articles|sort %}
<dd>{{ article.title }}</dd>
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}

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