Twig merge multiple things in an array - arrays

I'm trying to create an array with dates in it for an order system. Those dates corresponds with days that the shop can't deliver.
I'm having trouble to create that array since values are strings and that keeps getting producing an error with the merge filter.
I have only access to the frontend of the shop so I can't create custom functions whatsover.
The end result need to be an array with all dates in it so I can use that as javascript array, like so:
var closed = [
{{ closedDates }} // ["01-01-2018", "02-01-2018", etc...]
];
So what I have is this:
1) Webshop fills in the single days they are closed and perhaps a range of days.
That are three variables like:
{{ closedDays }} {# produces eg 01-01-2018, 02-01-2018, 03-01-2018 { it's dd-mm-yy #}
{{ date_range_start }} {# produces eg. 10-01-2018 #}
{{ date_range_end }} {# produces eg. 20-01-2018 #}
2) So what I did is this:
{% set closedDates = [] %}
{% if theme.closedDays %}
{% set foo = theme.closedDays %}
{% for i in foo | slice(0, 5) %}
{% set closedDates = closedDates | merge(i) %}
{% endfor %}
{% endif %}
{% if theme.date_range_start and theme.date_range_end %}
{% set start_date = theme.date_range_start %}
{% set end_date = theme.date_range_end %}
{# below function lists all days between start and end date #}
{% for weekRange in range(start_date|date('U'), end_date|date('U'), 86400 ) %}
{% set closedDates = closedDates | merge(weekRange | date('d-m-Y')) %}
{% endfor %}
{% endif %}
When I do it like above I get an error saying The merge filter only works with arrays or hashes;. But how do you create an array then with those values? That's only done with merge right?!
Any help greatly appreciated.

In Twig you can't just push elements to an array. Instead, you have to merge array with another array.
Given one array:
{% set firstArray = ['a', 'b'] %}
if you want to add element 'c', you have to merge it providing an array, even if you want to add single string element.
{% set firstArray = firstArray | merge(['c']) %}
If you work with associative arrays, it's analogical:
{% set secondArray = {'a': 'string a', 'b': 'string b' } %}
{% set secondArray = secondArray | merge({'b': 'overwritten!', 'c': 'string c' }) %}
The only diference is that element b will be overwritten with the value from the secondArray, so you'll get:
{
'a': 'string a',
'b': 'overwritten!',
'c': 'string c'
}

Related

Using Liquid, is there a way to filter an array and ignore non matching items

Using Liquid for a store.
I want to look through an array of values and check to see if any of those values match another list of values. If they match i want to display them. if they do not match i want to ignore them.
I'm currently able to do it in reverse by looking at all the values then 'remove' the ones i don't want individually but that is a terrible way to do this.
{% for 'field' in [metafield.key.value] | split: ", " %}
{% if field == 'value 1' or field == 'value 2' or field == 'value 3'%}
<div>
field
</div>
{% else %}
{% continue %}
{% endif %}
for future weary travelers:
this works you may need to adjust where you're splitting the string:
{% assign metafield_str = product.metafields.yada.yada | split: "," %}
{% assign control_str = 'value, something, test, test2' | split: "," %}
{%- capture variable -%}
{% for c_str in control_str %}
{% for m_str in metafield_str %}
{% if c_str == m_str %}
{{m_str}}
{% endif %}
{% endfor %}
{% endfor %}
{%- endcapture -%}

Loop through products in collection and find lowest price (excluding $0 prices)

I have a Shopify site with multiple categories. Some products do not have a price (Shopify interests this as $0). All collections are displayed on the front page. I want to loop through all products in each collection and output the minimum price (excluding $0 values).
The current array I'm using is:
{% assign startingFrom = collection.products | sort: 'price' %}
{{ startingFrom[0].price_min | money_without_currency }}
Unfortunately, this captures and outputs $0 values.
What is the best way to loop through values that are higher than $0 and output the lowest price?
I have tried to exclucde zero values:
{% assign startingFrom = collection.products | sort: 'price' %}
{% if 'price' != 0.00 %}
{{ startingFrom[0].price_min | money_without_currency }}
{% endif %}
This outputs $0.00.
{% for product in collection.products %}
{% if forloop.first %}
{% assign lowest_price = product.price %}
{% endif %}
{% assign new_price = product.price %}
{% if new_price < lowest_price and new_price != 0 %}
{% assign lowest_price = new_price %}
{% endif %}
{% endfor %}
it is not tested but it should work.
You can't rely on that way unless you have fewer than the pagesize limit of products in your collection.
See the discussion and solution under Shopify: Getting highest price item from collection

Jekyll - syntax for a for loop in range given by two integer variables

In Python, what I would like to achieve is:
count = 0
for i in range(count, count+5):
count
What is the syntax for this with Jekyll, if it is possible?
{% assign count = 0 %}
{% for i in (...) %}
{{ i }}
{% endfor %}
You can define range with integers {% for i in (1..10) %} or with variables {% for i in (myVar..myOtherVar) %}

How do I create an array from a forloop?

I have a folder of images that I'd like to render on a page. I'd like these images to be ordered/filtered a particular way. To do that, I understand that the images need to first be together in an array.
I therefore start with an empty array:
{% assign my_array = "" %}
I then loop through the image folder, and attempt different ways of pushing each image into my_array. Example:
{% for image in site.static_files %}
{% if image.path contains "assets/images/target-folder" %}
<!-- Push image into array -->
{{ my_array | push: image }}
{% endif %}
{% endfor %}
Ideally, I can then use this array as intended:
{% for image in my_array | sort:"date" | reverse %}
<!-- show image -->
{% endfor %}
I'm aware that I could make a data file with the images, but I'd like to avoid needing to take that extra step. Thanks for reading.
You are almost there, the way of how you are creating the array it is the only thing to fix.
This {% assign my_array = "" %} creates an empty string. One easy way to create an array in Liquid is to split the above:
{% assign my_array = "" | split: ',' %}
Now you can push items into the array inside a for loop in the following way:
{% for image in site.static_files %}
{% if image.path contains "assets/images/target-folder" %}
<!-- Push image into array -->
{% assign my_array = my_array | push: image %}
{% endif %}
{% endfor %}
Also note that you can do this without a loop using where/where_exp filters:
{% assign my_array = site.static_files |
where_exp: "item", "item.path contains 'assets/images/target-folder'" %}
or:
{% assign target_folder = "assets/images/target-folder" %}
{% assign my_array = site.static_files |
where_exp: "item", "item.path contains target_foler" %}
(Although, unlike the accepted answer, this doesn't precisely correspond to the question's title, it's still a useful option in the described example.)
This solution worked for me:
{% assign namesArr = '' %}
{% for animal in animals %}
{% assign namesArr = namesArr | append: animal.name %}
{% if forloop.last == false %}
{% assign namesArr = namesArr | append: "," %}
{% endif %}
{% endfor %}
{% assign namesArr = namesArr | split: "," %}
Now namesArr is array, we can check array contains some value: https://stackoverflow.com/a/30823063/5638975

How to add a new index to an existing array on Volt?

So I have an existing array, I want to run a for loop through it and recreate new arrays. I am trying to figure out how to create my own array directly on volt. Here is my code:
{% set oNomesAgendaAmigos = [], oNomesAgendaRecomendado = [], oNomesAgendaAmigosRecomendado = [] %}
{% for oNomeAgenda in oNomesAgenda %}
{% set oNomesAgendasTotal = oNomeAgenda.cliente_nome %}
{% if oNomeAgenda.ind_amigo == 1 %}
{% set oNomesAgendaAmigos = oNomeAgenda %}
{% endif %}
{% if oNomeAgenda.ind_recomendado == 1 %}
{% set oNomesAgendaRecomendado = oNomeAgenda.cliente_nome %}
{% endif %}
{% if oNomeAgenda.ind_recomendado == 1 AND oNomeAgenda.ind_amigo == 1 %}
{% set oNomesAgendaAmigosRecomendado = oNomeAgenda.cliente_nome %}
{% endif %}
{% endfor %}
Last time i have checked there were no mechanism for setting table bit by bit in Volt. The walk-around would be to use array_merge() or implement own filter/method into Volt engine.
Anyway it's a bit against MVC principles. You should set all tables you need over your PHP part of code.
To loop ever array with indexes inside loop you use that trick:
{% for index, value in numbers %}
{{ index }}: {{ value }}
{% endfor %}
I also really appreciate this part of Volt Documentation.

Resources