51

If I have a for loop in Liquid (using Jekyll), how can I target even (or odd) items only? I have tried:

{% for item in site.posts %}
    {% if forloop.index % 2 == 1 %}

but that doesn't seem to work. I have also tried:

(forloop.index % 2) == 1

and:

forloop.index - (forloop.index / 2 * 2) == 1
approxiblue
  • 6,982
  • 16
  • 51
  • 59
Adam Kiss
  • 11,811
  • 9
  • 48
  • 81

2 Answers2

90

I think you'll want to use the cycle tag for this. For example:

{% for post in site.categories.articles %}
   <article class="{% cycle 'odd', 'even' %}"></article>
{% endfor %}

If you want different HTML markup for each cycle:

{% for item in site.posts %}
  {% capture thecycle %}{% cycle 'odd', 'even' %}{% endcapture %}
  {% if thecycle == 'odd' %}
    <div>echo something</div>
  {% endif %}
{% endfor %}

You can find more information on it at Liquid for Designers, although the example there isn't particularly helpful. This Shopify support thread should also help.

approxiblue
  • 6,982
  • 16
  • 51
  • 59
Alex Lande
  • 1,280
  • 11
  • 11
  • 2
    It wasn't exactly what I was looking for, but the link you found got me the real answer. I edited your answer to include my solution. Thanks! – Adam Kiss Jan 24 '12 at 09:24
  • Also, your solution would work if I wanted to use CSS only, but I wanted to split `site.posts` into two columns, so only class switching wasn't enough for me. – Adam Kiss Jan 24 '12 at 09:27
  • Yeah, I wasn't sure if you were looking to use CSS or not. Glad to help though! – Alex Lande Jan 24 '12 at 20:40
  • Your example works great, although I needed to add an offset to one of my loops to get it to work for me. – jnthnclrk Jan 20 '13 at 15:54
  • I got the answer, but how come the modulo version doesn't work? – Augustin Riedinger May 27 '15 at 16:27
  • Sometimes you'll need to mention the collection explicitly (in this case `site.posts`): `{% cycle site.posts: 'odd', 'even' %}` if you reuse the code on multiple pages, for example. – Felix Zumstein Feb 04 '20 at 16:42
37

In contrast to what the Shopify support thread in Ales Lande's answer says, there is a modulo function in Liquid - in form of the modulo filter.

With it, you can do this:

{% for item in site.posts %}
    {% assign mod = forloop.index | modulo: 2 %}
    {% if mod == 0 %}
        <!-- even -->
    {% else %}
        <!-- odd -->
    {% endif %}
{% endfor %}
Community
  • 1
  • 1
Christian Specht
  • 35,843
  • 15
  • 128
  • 182
  • 5
    I like this solution better than the one using `cycle`; solving a mathematical problem using a string seems... odd! – Rick Davies Feb 10 '18 at 00:27
  • 1
    This solution will not work if you conditionally skip anything within the loop, such as looping through site.collections but trying to leave 'posts' (standard collection) out. – Erwin Lengkeek Sep 25 '18 at 12:27