Shopify (Liquid): Syntax error expected close_square but found comma - shopify

I am creating an array in Shopify (Liquid) and I get an error,
{% assign numbers = [
"One",
"TWo",
"three",
"bla"
]
%}
Line 126 — Liquid syntax error: Expected close_square but found comma
in "{{[ "One","TWo", "three","bla" ] }}"

There is no way to create an array like this in liquid.
Instead, you can use the split filter to create an array from a string.
{% assign numbers = "one,two,three,four" | split: "," %}
<pre>{{ numbers | inspect }}</pre>
You can also create an empty array and feed it with the push filter
{% comment %} +++ Creates an empty array +++ {% endcomment %}
{% assign numbers = "" | split: "" %}
<pre>{{ numbers | inspect }}</pre>
{% comment %} +++ Feed the beast +++ {% endcomment %}
{% assign numbers = numbers | push: "one" %}
<pre>{{ numbers | inspect }}</pre>
{% assign numbers = numbers | push: "two" %}
<pre>{{ numbers | inspect }}</pre>

Related

How to append tags in a forlop to an array in shopify liquid

I am trying to make an array which already has some tags.. I want to loop through each product in cart and add the tags to the array. The {{tag }} part is working but its not getting assigned to the array..
{% assign finalTaglist = "apples, oranges, peaches" | split: ", " %}
{% for item in cart.items %}
<p>
{% for tag in item.product.tags %}
{{tag}}
{% assign finalTaglist = finalTaglist | concat: tag %}
{% endfor%}
</p>
{% endfor%}
<p>Final Tag List : {{finalTaglist}}</p>`
`
concat is used for joining arrays, but your code is trying to add a string to an array, hence why it doesn't work.
Start with an empty string, and use append to add on to the string, not forgetting your separator. Once built, use split to create the array, then you can append to another array if required.
Something along these lines (not tested, just winging it, but you get the idea..)
{% assign finalTaglist = 'apples,oranges,peaches' | split: ',' %}
{% assign newTagList = '' %}
{% for item in cart.items %}
{% for tag in item.product.tags %}
{% assign newTagList = newTagList | append: ',' | append: tag %}
{% endfor%}
{% endfor%}
{% assign newTagList = newTagList | remove_first: ',' | split: ',' %}
{% assign joinedTagLists = finalTaglist | concat: newTagList %}

How to turn a string in to an array of objects with keys and values in Liquid

I'm looking to turn a string that you can be edited in Shopify theme settings into an array of object key values in my Liquid file.
For example:
var text = 'key1:value1,key2:value2,anotherKey:anotherValue'
in to:
var array = [{key1: value1}, {key2: value2}, {anotherKey: anotherValue}]
Each object will be separated by a ',' in the string and the key will be to the left of a ':' with the value to the right.
I need to write this inside a theme.liquid file but unsure how to achieve this. Any help would be most appreciated.
I've so far only got as far as:
{% assign text = 'key1:value1,key2:value2,anotherKey:anotherValue' %}
{% assign splitText = text | split: ',' %}
{% assign array = '' | split: '' %}
{% for data in splitText %}
{% assign key = data | split: ':' | first %}
{% assign value = data | split: ':' | last %}
{% assign array = array | concat: key | append: ':' | concat: value %}
{% endfor %}
{{ array }}
Creating associative arrays or arrays with named indexes is not possible in Liquid. However, as a work around, you can create 2 arrays. Treat the same indexes of one array as key while other as value.
A sample implementation would look like
{% assign text = 'key1:value1,key2:value2,anotherKey:anotherValue' %}
{% assign objArr = text | split: ',' %}
{% assign keyArr = ''%}
{% assign valArr = ''%}
{% for obj in objArr %}
{% assign key = obj | split: ':' | first %}
{% assign value = obj | split: ':' | last %}
{% assign keyArr = keyArr| append: ',' | append: key %}
{% assign valArr = valArr| append: ',' | append: value %}
{% endfor %}
{% assign keyArr = keyArr | remove_first: ',' | split: ',' %}
{% assign valArr = valArr | remove_first: ',' | split: ',' %}
{% for obj in objArr %}
{{keyArr[forloop.index0]}} : {{valArr[forloop.index0]}}
<br/>
{% endfor %}
The above code does a basic job. Do not forget to compare both array lengths to identify if all key value pairs were created perfectly as per logic.

Assign a value to array by index in Liquid

I am inside of a bit complex loops and I need to assign a value to an array by index, so that if the value is already there it will replace it, if not it will create it.
So I need to do something like this:
{% assign arr = '' | split: '' %}
{% assign arr[index] = value %}
which is not working, the array is still empty.
Is there any workaround to do this?
There is no direct workaround.
You can always re-create the array with a default value though that would only give you a single value.
One potential work around would be to re-create the source and fill in any missing defaults then re-split into an array
{% assign arr = someValue | split: '' %} <!-- splitting to single chars ? -->
{% assign withDefaults = '' %}
{% for ...%}
{% unless arr[loop.index0] == true %}
{% withDefaults = withDefaults | append : 'defaultValue,' %}
{% else %}
{% withDefaults = withDefaults | append : arr[loop.index0] | append : ',' %}
{% endfor %}
{% assign arr = withDefaults | split: ',' %} <!-- you'll have an extra blank element but that may not matter -->

How can I split a string by newline in Shopify?

I have a field in my settings.html where I am expecting the user to input multiple paragraphs separated by two newline characters. I would like to split this string of input into an array of strings, each representing a paragraph.
I would like to do something like this:
{% assign paragraphs = settings.intro | split: '\n' %}
{% for paragraph in paragraphs %}
<p>
{{ paragraph }}
</p>
{% endfor %}
I can't seem to figure out how to refer to the newline character in Liquid. How can I go about doing this? Is there some kind of work around?
Try this:
{% assign paragraphs = settings.intro | newline_to_br | split: '<br />' %}
{% for paragraph in paragraphs %}<p>{{ paragraph }}</p>{% endfor %}
#josh-browns answer got me pretty much there and might be enough for most instances. However, I had some blank paragraphs coming through from user generated double lines.
Denilson Sá Maia comment of strip_newlines did not help with my markdown processor so I checked if each line was empty manually before outputting the paragraph.
{% for paragraph in paragraphs %}
{% assign paragraph-length = paragraph | number_of_words %}
{% if paragraph-length > 0 %}
<p>{{ paragraph }}</p>
IMAGE HERE
{% endif %}
{% endfor %}
This doesn't solve the blanks in the array, for that I iterated over the array to create a new one, with only valid content. It would be really nice if there was a filter that worked on arrays, not just hashes.
{% assign all-paragraphs = content | strip | newline_to_br | strip_newlines | split: "<br />" %}
{% assign paragraphs = site.emptyArray %}
{% for paragraph in all-paragraphs %}
{% if paragraph and paragraph != "" and paragraph != site.emptyArray %}
{% assign paragraphs = paragraphs | push: paragraph %}
{% endif %}
{% endfor %}
If you do, in fact, need Shopify to split by newlines for any reason where you don't iterate with a for loop afterwards, it is indeed possible:
{% assign paragraphs = settings.intro | split: '
' %}
{% for paragraph in paragraphs %}
<p>
{{ paragraph }}
</p>
{% endfor %}
ie. you need to type an explicit newline into your source code.
This is due to the way Liquid works, quoting from the documentation about Types:
Liquid does not convert escape sequences into special characters.

creating and accessing arrays in liquid templates

Was first looking for a means to select certain existing products in order to place title, image, description on another page (or even within another product page - as some products are combined to make other products) within Shopify.
The method below was the only one I seem to come across for creating an array within Shopify. (the split method).
The next part of the equation, is to use the values from {{ myArray }}, to select the matching var, and to then spit out the different values stored within that array.
However, my attempt does not work. Is there a way to add keys to the other arrays (i.e, p1, p2, p3 arrays), in order to make the selecting of them easier during the for loop?
{% assign myArray = "p1|p3" | split: "|" %}
{% assign p1 = "Product One|product-one|This is my description of product one, and it must be a single paragraphy without any html formatting. The length is not an issue.|product_one_image.jpg" | split:"|" %}
{% assign p2 = "Product Two|product-two|This is my description of product two, and it must be a single paragraphy without any html formatting.|product_two_image.jpg" | split:"|" %}
{% assign p3 = "Product Three|product-three|This is my description of product three, and it must be a single paragraphy without any html formatting.|product_three_image.jpg" | split:"|" %}
{% for item in myArray %}
<h4>{{ item[0] }}</h4>
<p>{{ item[2] }}</p>
{% endfor %}
Continuity flow is wrong in your code.
Here's what you need to do
Load product elements for each product into an array
{% capture list %}
{% for product in products %}
{{ product.title }}|{{ product.handle }}|{{ product.description}}|{{ product.featured_image }}{% if forloop.last %}^{% endif %}
{% endfor %}
{% endcapture %}
{% assign p_list = list | split: "^" %}
Now p_list contains all the products as each element in the array. It is time to get the output.
{% for p_item in p_list %}
{% assign item = p_item | split: "|" %}
<h4>{{ item[0] }}</h4>
<p>{{ item[2] }}<p>
{% endfor %}
Once you start the for loop it will iterate through each value in your array, so indexing (using []) won't work since the array is already being iterated.
In the example above, you began iterating through the list and then attempted to index item, which will not work. If you wanted to index the array then do not make a for loop, in the list above the array only has 2 items but you selected an index outside of the available indexes, this is because the array position starts at 0. so that <p> tag should've been item[1] and outside of the for loop.
To do a for loop. do this:
{% for item in array %}
<h4>{{ item }}</h4>
{{ continue }}
<p>{{ item }}</p>
{% endfor %}
The continue tag will cause it to iterate to the next item on the for loop.