Assign a value to array by index in Liquid - shopify

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 -->

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.

Is there any alternative of PHP In_array() in Shopify?

I tried lots of things but didn't get what exactly I am looking for.
Below is the example of what type of array I am looking for in Shopify,
$array['bag'] = 2; $array['shoes'] = 3; $array['xyz'] = 6;
Here is the sample of what and how I am looking for my array variable in shopify.
Where
bag, shoes, xyz
are product type
and 2,3,6
are number of products added for specific product type.
I know it's easy in PHP, but don't know how to do in Shopify liquid code.
As per Shopify documentation, you cannot initialize arrays. However, you can use split filter to create one dimensional array. You cannot create associative arrays using this. However, as a workaround, use 2 arrays of same length where same index in both arrays point to related key and value as of associated array. Example code
{% assign product_type = "type-1|type-2|type-3" | split: '|' %}
{% assign product_count = "1|2|3" | split: '|' %}
{% for p_type in product_type %}
{{ p_type }}
{{ product_count[forloop.index0] }}
{% endfor %}
Expected output
Product Type Count
type-1 1
type-2 2
type-3 3
For your particular scenario explained in comments, have a look at below code and code comments. I have used checkout object for sample code. You may adjust according to your need.
// declare 2 vars to create strings - that will be converted to arrays later
{% assign product_type = "" %}
{% assign product_count = "" %}
// iterate over line_items in checkout to build product_type string
{% for line_tem in checkout.line_items %}
// if product_type exists , then skip -- unique product types
{% if product_type contains line_tem.product.type%}
{% else %}
{% assign product_type = product_type | append: '#' | append: line_tem.product.type %}
{% endif %}
{% endfor %}
// remove first extra hash and convert to array
{% assign product_type = product_type | remove_first: "#" | split: '#' %}
// iterate over unique product type array generated earlier
{% for product_type_item in product_type %}
// set product count for this product type to zero initially
{% assign total_count = 0 %}
// iterate over all lin items and +1 if same product type
{% for line_tem in checkout.line_items %}
{% if product_type_item == line_tem.product.type%}
{% assign total_count = total_count | plus: 1 %}
{% endif %}
{% endfor %}
// append count to product count string
{% assign product_count = product_count | append: '#' | append: total_count %}
{% endfor %}
// remove first extra hash and convert to array
{% assign product_count = product_count | remove_first: "#" | split: '#'%}
{{-product_type-}}
{{-product_count-}}

Shopify - Increment or Counter

I'm trying to set up a simple way to increment within for loops in my themes and can't figure out how to get it to work. I'm familiar with two ways to increment:
{% assign variable = 0 %}
{% for .....
{% assign variable = variable | plus: 1 %}
.... endfor %}
and
{% assign variable = 0 %}
{% increment variable %}
However neither of these work. Update: Currently the following block of code will output "0" when it should be "1"
{% assign variable = 0 %}
{% assign variable = variable | plus: 1 %}
{{ variable }}
What am I doing wrong?
What you are doing with the assign should work however there is an easier way:
{{forloop.index0}}
See the docs for the loop object

Liquid - Convert Array to Lowercase

I'm using Shopify and want to hook into customer tags, however they are case sensitive. So {% if customer.tags contains "wholesale" %} is not the same as {% if customer.tags contains "Wholesale" %}. My client may or may not stick to one case when applying tags so I want to guard against that in the future.
I would like to take an array, customer.tags, and convert all of the values to lowercase. I'm trying to work out the logic but am having trouble.
I want to put customer.tags into a new array which isn't working.
{% assign newArray = customer.tags %}
{{ newArray }}
What am I doing wrong?
You could use the downcase filter for this:
{% assign contains_wholesale = false %}
{% for tag in customer.tags %}
{% assign lowercase_tag = tag | downcase %}
{% if lowercase_tag == 'wholesale' %}
{% assign contains_wholesale = true %}
{% endif %}
{% endfor %}
Note: downcase just works for ASCII characters. If you need to search for strings with accented letters or other Unicode characters then this won't be enough.
if you would like to keep customer.tags as an array so you can keep using contains in a simple if statement (like your example). You could also chain a couple of liquid filters together to turn all of the strings within the array to lowercase.
Example:
{% assign lowercaseTags = customer.tags | join: ',' | downcase | split: ',' %}
{% assign randomString = 'WholeSale' | downcase %}
{% if lowerCaseTags contains randomString %}
{% comment %}
Will now match regardless of case sensitivity
{% endcomment %}
{% endif %
Explanation:
Join filter: Turn the array into a string seperated by ,
Downcase filter: make the whole string lowercase
Split filter: opposite of join, recreates the array from the string based on the character used in join ,
Another solution as you use the "contains" operator would be to skip the "w".
Something like {% if customer.tags contains 'holesale' %} should work.