Shopify: how to add a class depending on collection - collections

On a clients homepage they want 'all the products' listed with a load more button at the bottom.
There are four categories and each has a different color associated. I want to pull in all the products by date listed order and apply a class to the product depending on the category.
Currently I have
{% assign collection = collections.all %}
{% for product in collection.products %}
{% if collection.handle == 'clothing' %}
<div class="theme-red overview-item">
{% elsif collection.handle == 'pictures' %}
<div class="theme-green overview-item">
{% elsif collection.handle == 'posters' %}
<div class="theme-blue overview-item">
{% elsif collection.handle == 'other' %}
<div class="theme-beige overview-item">
{% else %}
<div class="theme-none overview-item">
{% endif %}
...
</div>
{% endfor %}
This is currently picking up as theme-none and that's because I'm calling collections.all?
How do I get all the products shown regardless of a collection and then apply do something as per the if/else statements like above.
Any ideas, I've tried to see if product.collections, collection.all_types with no happiness.

The reason you're getting theme-none is because your if statement checks if the collection's handle is 'clothing', 'pictures', etc. but you've set the collection to collections.all so it's never going to match any of those conditions.
What you want to do instead is check if the current product is within one of those collections. For example:
{% assign collection = collections.all %}
{% for product in collection.products %}
{% for c in product.collections %}
{% if c.handle == 'clothing' %}
{% assign theme = "red" %}
{% elsif c.handle == 'pictures' %}
{% assign theme = "green" %}
{% elsif c.handle == 'posters' %}
{% assign theme = "blue" %}
{% elsif c.handle == 'other' %}
{% assign theme = "beige" %}
{% else %}
{% assign theme = "none" %}
{% endif %}
{% endfor %}
<div class="theme-{{ theme }} overview-item">
...
</div>
{% endfor %}

Related

How to change "if" condition related to a page

I would like to include tab_system.twig file in two differents files : archive.twig and blog_list.twig to have the same html in those two files.
{% include "tab_system.twig" %}
In this tab_system.twig file I have a condition to add the active class :
{% if XXX %}active{% endif %}
But this condition must be different depending on which page the user is.
For blog_list.twig :
{% if loop.first %}active{% endif %}
For archive.twig :
{% if item.term_id == term_page.term_id %}active{% endif %}
I wrote this without success :
{% set addclass = '' %}
{% if is_blog_list %}
{% set addclass = '{% if loop.first %}active{% endif %}' %}
{% elseif is_archive %}
{% set addclass = '{% if item.term_id == term_page.term_id %}active{% endif %}' %}
{% endif %}
In tab_system.twig I have a tab system with menu from a part and content to the other part. I wrote a js loop to display the corresponding content. I need to add active class on the first link and first content tab in blog_list.twig file and to add active class to the link and content tab depending on which category the user is.
<div class="tab-menu-list">
{% for item in all_posts %}
<a href="#" class="tab-menu {{ addclass }}"</a>
{% endfor %}
</div>
<div class="tab-content-list">
{% for item in all_posts %}
<div href="#" class="tab-content {{ addclass }}"</div>
{% endfor %}
</div>
is_archive and is_blog_list are variables defined elsewhere. They work
How can I create a condition ? Thank you in advance.
As I'm assuming you are looping the records, I'd say don't overcomplicate things,
single.twig
{% for i in 1..5 %}
{% include 'article.twig' with { 'active' : loop.first, } %}
{% endfor %}
template_blog.twig
{% for item in items %}
{% include 'article.twig' with { 'active' : item.term_id == term_page.term_id, } %}
{% endfor %}
article.twig
<div class="articles__list tab-content{{ active ? ' active'}}">
foo
</div>
demo - just change the main template
If you really wanted to keep that for inside the article template, which I think is not a great idea, you could still use the variables is_archive and is_blog_list inside article, e.g.
article.twig
{% for item in items %}
{% if is_archive %}
{% set active = loop.first %}
{% elseif is_blog_list %}
{% set active = item.term_id == term_page.term_id %}
{% endif %}
<div class="articles__list tab-content{{ active ? ' active'}}">
{% endfor %}

Is it possible to override default # products in a row in custom Shopify collections template?

I have created an alternate collection.liquid template for a shopify site I'm working on. My struggle is with not being able to control the number of products that appear in a row in the grid. I developed the custom template so that I wouldn't affect the number of products/row that appear on the other collections.
The code that displays the grid in my liquid template is this:
<div class="four columns section_select {% unless settings.collection_sort %}offset-by-four omega{% endunless %}">
{% for tag in collection.all_tags %}
{% if forloop.first %}
<label for="tag_filter" class="inline">
{{ 'collections.sorting.filter' | t }}: </label>
<select name="tag_filter" id="tag_filter">
<option {% unless current_tags %}selected="selected"{% endunless %} value="{% if collection.handle == "all" %}/collections/all{% else %}{{ collection.url }}{% endif %}">{{ 'collections.general.all_collection_title' | t: title: collection.title }}</option>
{% endif %}
{% unless tag contains 'meta-related-collection-' %}
<option {% if current_tags contains tag %}selected="selected"{% endif %} value="/collections/{% if collection.handle != blank %}{{ collection.handle }}{% else %}all{% endif %}/{{ tag | handleize }}">{{ tag }}</option>
{% endunless %}
{% if forloop.last %}
</select>
{% endif %}
{% endfor %}
</div>
Even when I change the class class="four columns" to something else, it is not reflected on my collection.
The problem could be in my code that assigns how many products are pulled in this collection but I can't seem to make a difference.
{% case products_per_row %}
{% when '1' %}
{% assign grid_item_width = 'medium--one-third large--one-whole' %}
{% when '2' %}
{% assign grid_item_width = 'medium-down--one-half large--one-half' %}
{% when '3' %}
{% assign grid_item_width = 'medium--one-third large--one-third' %}
{% when '4' %}
{% assign grid_item_width = 'medium-down--one-half large--one-quarter' %}
{% when '5' %}
{% assign grid_item_width = 'medium-down--one-half large--one-fifth' %}
{% endcase %}
Any help would be great!
It looks like your theme is using Timber grid.
You will find grid structure and classes to use in documentation here: https://shopify.github.io/Timber/
HTH

Twig compare two values in different arrays

First of all I'm learning Twig.
I was wondering if it is possible wit Twig to compare two different values from different arrays/lists?!
I have two list of items I call them like so:
{% if page.cart %}
{% for product in page.cart.products %}
{{ product.id }}
{% endfor %}
{% endif %}
And:
{% if products %}
{% for product in products %}
{{ product.id }}
{% endfor %}
{% endif %}
I want to compare both product.id's so I can create a new statement. Is there any way to compare both values? The idea is to check if an id is present in page.cart.products and if so then do something.
I want to create a new statement to display some info. Something like so:
{% if page.cart %}
{% for product in page.cart.products %}
{% set cartId %}{{ product.id }}{% endset %}
{% endfor %}
{% endif %}
{% if products %}
{% for product in products %}
{% set listId %}{{ product.id }}{% endset %}
{% endfor %}
{% endif %}
{% if cartId == listId %}
.... do this ....
{% endif %}
Any help greatly appreciated!
You can loop over one array and check if the id is present in the second one. If it's there, you can do something.
{# In case you want to store them, you can do so in an array #}
{% set repeatedIds = [] %}
{% for productCart in page.cart.products if page.cart %}
{% for product in products if products %}
{% if productCart.id == product.id %}
<p>This id -> {{ product.id }} is already in page.cart.products</p>
{% set repeatedIds = repeatedIds|merge([product.id]) %}
{% endif %}
{% endfor %}
{% endfor %}
{{ dump(repeatedIds) }}
It's a very basic search algorithm and the cost is quadratic. Obviously, there are more efficient ways to look for an element in an array (though more complicated to implement).
If the amount of products you have to deal with is not very big, you could use this solution. However, if you have, let's say, more than one hundred products in each array (or you feel that the algorithm is slowing down your loading time), you could do this process in the controller using more sophisticated methods and PHP and just pass the result to the template.
Hope it helps.

For every 10 records print something using Symfony2 and Twig

I'm building a page where member addresses are printed to a sheet of labels, and once a sheet is full with 14 addresses on a page, I then want to put a page break after it so that the addresses can be printed on multiple sheets of paper.
How can I achieve this using Twig?
This is my current Twig code:
{% for row in data %}
<div class="label-page">
<div class="label-section L7163">
<p>{{row.FirstName}} {{row.Surname}}</p>
<p>{{row.AddressLine1}}</p>
{% if row.AddressLine2 != NULL or row.AddressLine2 != '' %}
<p>{{row.AddressLine2}}</p>
{% endif %}
{% if row.Town != NULL or row.Town != '' %}
<p>{{row.Town}}</p>
{% endif %}
{% if row.County != NULL or row.County != '' %}
<p>{{row.County}}</p>
{% endif %}
{% if row.Postcode != NULL or row.Postcode != '' %}
<p>{{row.Postcode}}</p>
{% endif %}
</div>
</div>
{% endfor %}
You can use loop.index in your twig loop which returns the current iteration of the loop and divisible by(num)
{% for row in data %}
{% if loop.index is divisible by(10) %}
/*your page break*/
{% endif %}
{% endfor %}

Twig equality if..else in symfony 2 gives both results

I'm using Symfony2 with Twig and when trying to determine the class that should be a div Twig says that all 4 classes are active even beeing in an if..else clause.
Redirect has only 1 value. I checked the syntax and I think it's correct so maybe I'm missing something.
It's correct my code or is something wrong in the Twig comparision (equality or if..else clause)?
Here is the Twig code:
{% if redirect == 'a' %}
{% block classA 'active' %}
{% elseif redirect == 'b' %}
{% block classB 'active' %}
{% elseif redirect == 'c' %}
{% block classC 'active' %}
{% else %}
{% block classD 'active' %}
{% endif %}
And the controller code:
[...]
$redirect = "a";
return $this->render('FrontendBundle:Default:delete.html.twig', array(
'id' => $id,
'redirect' => $redirect,
'text' => $text)
);
Edited.
Solution
I found that it's not possible to use if clauses out of a block, so the solution goes ahead using one block for each class.
I've also thought that a better solution would be to use a dynamic name block, but i read that's not possible.
Finally I found this that solve my problem in a different way: http://peter-hoffmann.com/2012/highlight-active-menu-item-with-twig-and-silex.html
Kind regards.
Even though this question is old, I want to clarify a few things, since there is no real answer provided.
The underlying problem here is that block is evaluated during compile time, while if is evaluated during run-time. This means that blocks are always defined, one cannot define blocks conditionally. That is also the reason why blocks cannot have dynamic names.
With the template from the question, this is not a problem:
classes.html.twig:
{% if redirect == 'a' %}
{% block classA %}active{% endblock %}
{% elseif redirect == 'b' %}
{% block classB %}active{% endblock %}
{% elseif redirect == 'c' %}
{% block classC %}active{% endblock %}
{% else %}
{% block classD %}active{% endblock %}
{% endif %}
If we render this, we get 'active', i.e. the expected output. While each block is defined, only one of them is rendered, because of the if. The problem is only revealed if we have inheritance. So let's say we have the following parent template (I assume something like that was used by the poster):
parent.html.twig:
{% block classA %}{% endblock %}
{% block classB %}{% endblock %}
{% block classC %}{% endblock %}
{% block classD %}{% endblock %}
And change our extending template to extend this (also added classE for demonstration purposes):
classes.html.twig:
{% extends "parent.html.twig" %}
{% if redirect == 'a' %}
{% block classA %}active{% endblock %}
{% elseif redirect == 'b' %}
{% block classB %}active{% endblock %}
{% elseif redirect == 'c' %}
{% block classC %}active{% endblock %}
{% else %}
{% block classD %}active{% endblock %}
{% endif %}
{% block classE %}undefined{% endblock %}
Now, if we render classes.html.twig, we get 'activeactiveactiveactive'. As before, the blocks are all defined with 'active', but the parent template has no conditional rendering, so all of them are shown. Block 'classE' is not rendered, because it is not defined in the parent template.
To fix this, one needs to essentially swap the if and block statements.
{% extends "parent.html.twig" %}
{% block classA %}
{% if redirect == 'a' %}
active
{% endif %}
{% endblock %}
{% block classB %}
{% if redirect != 'a' and redirect == 'b' %}
active
{% endif %}
{% endblock %}
{% block classC %}
{% if redirect != 'a' and redirect != 'b' and redirect == 'c' %}
active
{% endif %}
{% endblock %}
{% block classD %}
{% if redirect != 'a' and redirect != 'b' and redirect != 'c' %}
active
{% endif %}
{% endblock %}
Sadly, we lose the if/else structure when we do this, so we have to write more conditions. To fix this, we can add an intermediate step using a variable.
{% extends "classes.html.twig" %}
{% if redirect == 'a' %}
{% set render = 'a' %}
{% elseif redirect == 'b' %}
{% set render = 'b' %}
{% elseif redirect == 'c' %}
{% set render = 'c' %}
{% else %}
{% set render = 'd' %}
{% endif %}
{% block classA %}
{% if render == 'a' %}
active
{% endif %}
{% endblock %}
{% block classB %}
{% if render == 'b' %}
active
{% endif %}
{% endblock %}
{% block classC %}
{% if render == 'c' %}
active
{% endif %}
{% endblock %}
{% block classD %}
{% if render == 'd' %}
active
{% endif %}
{% endblock %}
I'm not sure if you're taking the most efficient approach for this kind of behavior, but regardless, shouldn't your blocks be defined like this?
{% block classA %}active{% endblock %}

Resources