Shopify Line item variants in separate lines - shopify

Currently in my shopify code I can use a line item input like so:
line_item.variant.title
This will output the following:
Snapback / One Size Fits All / Camo
What I'm trying to do is to break up each one into it's own line. So I can get this back:
Snapback
One Size Fits All
Camo
The challenge is that there are several products with different variants. Some contain the string "7/9" so I wouldn't be able to use "/" as a delimiter. Any suggestions?

The variant title is generated based on the variant options.
So if you like to show the different options you just call the options instead of the title.
Example:
{{ variant.option1 }}<br/>
{{ variant.option2 }}<br/>
{{ variant.option3 }}
Refer to the docs here: https://help.shopify.com/en/themes/liquid/objects/variant#variant-option1

I found this one is a better solution to set this dynamically:
{% if line.variant.title != 'Default Title' %}
<span class="order-list__item-variant variant-title">
{% assign variantOptions = line.variant.title | split: ' / ' %}
{% assign count = 0 %}
{% for option in line.product.options_with_values %}
<span><b>{{ option.name }} :</b> {{variantOptions[count]}}</span>
<br />
{% assign count = count | plus: 1 %}
{% endfor %}
<br />
</span>
{% endif %}
As by default, we are getting / in the value of line.variant.title. So we need to split this first So that we can get individual option values. and because there is no feasible object to get option label so we need to use the
line.product.options_with_values in a loop and iterate and set label with value as in the above code.
So, just use this code in your order confirmation email and you will get the format in the email as follow. Here Embroidery as yes and no. and Border as Zigzag and Simple are the options for product variants.

Related

Shopify: How to check if there is > 1 collection in a cart

I am trying to prevent orders with more than one collection from being checked out. If there's more than one collection, i just want to disable the checkout button. I know the syntax is bad, but i want to do something like this.
{% for item in cart.collections %}
{% if item.collection.length > 1 %}
<button disabled>Cant checkout</button>
{% else %}
<button disabled>Can checkout</button>
{% endif %}
This is the current code for the button
<div class="cart__checkout-wrapper">
<button disabled id="button" type="submit" name="checkout" data-terms-required="{{ settings.cart_terms_conditions_enable }}" class="btn cart__checkout">
{{ 'cart.general.checkout' | t }}
</button>
{% if additional_checkout_buttons and settings.cart_additional_buttons %}
<div class="additional-checkout-buttons additional-checkout-buttons--vertical">{{ content_for_additional_checkout_buttons }}</div>
{% endif %}
</div>
{% endfor %}
Method 1
This simple check might work for what you need:
{% liquid
assign all_collections_in_cart = cart.items | map: 'product' | map: 'collections' | map: 'title' | uniq
assign collection_count = all_collections_in_cart.size
if collection_count > 1
assign can_checkout = false
else
assign can_checkout = true
endif
%}
What it does
First, we use a sequence of map filters to 'drill down' through the object structure. Items in the cart do not themselves belong to any specific collection(s), but each item is associated with both a variant and a product. From the product, we can then get all of the collections that it belongs to, which will be an array of collection objects. We can't do much with the objects themselves, so we drill down one layer further to get something that can be compared, such as title handle or id. At this point we now have an array of text entries (or numbers, if you swap to IDs), so we can apply the uniq filter to remove any duplicates.
Now that we have an array with no duplicates, we can check the size of the array to see if it is greater than one and set a variable appropriately.
Note that this will always return false if a single product belongs to more than one collection!
Method 2:
If instead you need to test that all products share a collection because products can belong to more than one at a time, we won't be able to take as many shortcuts. Instead, our code might look something like this:
{% liquid
assign can_checkout = true
if cart.items.size > 1
assign shared_collections = cart.items.first.product.collections | map: 'title'
for item in cart.items
if forloop.first
continue
endif
assign item_collections = item.product.collections | map: title
assign placeholder_array = ''
for coll in shared_collections
if item_collections contains coll
if placeholder_array.size > 0
assign placeholder_array = placeholder_array | append: ','
endif
assign placeholder_array = placeholder_array | append: coll
endif
endfor
assign shared_collections = placeholder_array | split: ','
if shared_collections.size == 0
assign can_checkout = false
break
endif
endfor
endif
%}
What it does
This second version will trigger if there are 2 or more items in the cart. If there are, we get all of the collection titles from the first item in the cart, then loop through all of the remaining items in the cart. At each step, we go through our list of shared collections to see how many are shared with the current item in the cart to make a new array. (Liquid does not let us make an array directly, so we have to build out a delimited string and then use the split filter afterwards)
If at any time we have an array with 0 shared entries, we set our can_checkout variable to false and use the break command to stop searching.
Addendum
For both of the above methods, things might get a little bit trickier if you have certain collections that don't count towards your collection rules. For example, if you have 'featured' or 'summer sale' collections, you will want to make sure that you aren't counting those in the collection comparisons (for example, by having an array of exceptions and removing those items from the array of collections that the item belongs to).

working with 'strings' as 'arrays' in shopify liquid

I am trying to display color boxes next to items based on item varients. However, it has been giving me weird results in my array. Yes I know there are no real arrays in liquid. I have two options below. The first one doesnt work. It gives me things like "background-color: [''''''' ". Along with all the correct ones too.
So the second option i just hard coded all the colors and checked against that. This works as long as the colors are in order... but if the colors are not in order than it will display duplicates.
New to liquid but this seems super ugly and probably means i am doing it wrong.
<div class="color-box-wrapper">
{% assign values = '' %}
{% for variant in product.variants %}
{% assign value = variant.option2%}
{% unless values contains value %}
{% assign values = values | append: ',' | append: value %}
{% assign values = values | split: ',' %}
{% for color in values %}
{% if color.size > 0%}
<div class="product-color-box" style="background-color:{{color}}"></div>
{% endif %}
{% endfor %}
{% endunless %}
{% endfor %}
</div>
THIS WAY KINDA WORKS BUT SEEMS HACKY.
<div class="color-box-wrapper">
{% assign realColors = 'yellow, blue, white, burgandy, black, red, green, purple, beige, light_brown' | split: ", "%}
{% assign values = '' %}
{% for variant in product.variants %}
{% assign value = variant.option2 | downcase%}
{% unless values contains value %}
{% assign values = values | append: ',' | append: value %}
{% assign values = values | split: ',' %}
{% for color in values %}
{% if realColors contains color %}
<div class="product-color-box" style="background-color:{{color}}"></div>
{% endif %}
{% endfor %}
{% endunless %}
{% endfor %}
</div>
It might work better to use the product.options_with_values field, something like this:
{% assign color_option = product.options_with_values | where: 'name', 'color' | first %}
<h1>Color option is in position {{ color_option.position }}!</h1>
<h2>Array of all values is: {{ color_option.values | json }}</h2>
{% for value in color_option %}
<h3>Gimmie a {{ value }}!! {% if value == color_option.selected_value %}(Selected){% endif %}</h3>
{% endfor %}
It's a bit trickier if your colours are not CSS-recognized colour names, but there are certainly a number of things you can do for that. I typically prefer adding a CSS layer that can translate colour values into the appropriate display values (either background images or colour hex-codes). Some ideas are:
Add a data attribute or a class to your element (usually using the | handle filter to standardize the output) and use a CSS sheet to assign background images or colours appropriately
Create a section with blocks that allows you to map colour values to hex codes. If you are creating this for someone other than yourself, it would allow the merchant to set up the colours themselves and fine-tune all the shades.
Use metafields on your product that can generate the correct colour code using the options as the lookup. (Eg: If you create a metafield namespace on your products of product.metafields.colors and use the colour names as the keys and hex codes as the values, you can output {{ product.metafields.colors[value] }} to get the right computer colour. (This generally requires installing an app to manage - though metafields themselves are native Shopify functionality, Shopify doesn't have any native way to set them in the admin)
Hope this helps!
References:
Shopify Liquid Reference - Product objects: https://help.shopify.com/en/themes/liquid/objects/product#product-options_with_values
Shopify Liquid Reference - Product Option objects (from options_with_values): https://help.shopify.com/en/themes/liquid/objects/product_option

Using a string to create a Liquid variable

In my shopify store, I am using SuperFields in order to customize my site, though my question isn't about the app. On one of my pages, I need the value for the following:
variant.metafields.sf_{{ collection.title | downcase }}[meta_tag_key]
The value should be 0 or 1. If I evaluate the statement directly, such as:
{if variant.metafields.sf_{{ collection.title | downcase }}[meta_tag_key] =1%}
It throws an error when I render the page: Unexpected character '{'
I've also tried the following:
{% capture defaultImage %}variant.metafields.sf_{{ collection.title | downcase }}[meta_tag_key]{% endcapture %}
{% assign test = defaultImage %}
But 'test' is considered nil and doesn't return any value. I have tried to search for answers here and on the shopify forum, but, as my clumsy post title suggests, I'm having a hard time concisely searching for a solution to this problem. Any help is greatly appreciated.
You can try :
{% assign metafield-key = collection.title | downcase | prepend: "sf_" %}
{% assign key = variant.metafields[metafield-key][meta_tag_key] %}
{% if key == 1 %}
Do the twist !
{% endif %}
You are missing a % sign in your code. Hence the error message. Your if statement started with {% and not just {
If you working in liquid then you have to use {% %} for defining any variable & also for condition in shopify. You can't use { this.

how to split the string in django template?

i am trying to split the string in template using custom template filter. But i got an error
TemplateSyntaxError at /job/16/
'for' statements should use the format 'for x in y': for skill in form.instance.skills | split : ","
Here it is my filter
#register.filter(name='split')
def split(value, key):
"""
Returns the value turned into a list.
"""
return value.split(key)
this is my template
<h4>Skills</h4>
{% for skill in form.instance.skills | split : "," %}
{{ skill }}
{% endfor %}
Thanks
Split is a custom filter, don't forget to create your filter, and to load it in your HTML page.
Documentation for Django 4.0: https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/
<h4>Skills</h4>
{% with form.instance.skills|split:"," as skills %}
{% for skill in skills %}
{{ skill }}<br>
{% endfor %}
{% endwith %}
For extract character string, use filter cut:
Phone
this removes the scripts from the string.
The direct for loop works too, you just have to remove the spaces in the syntax:
<h4>Skills</h4>
{% for skill in form.instance.skills|split:"," %}
{{ skill }}
{% endfor %}

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.