Shopify tablerow loop exiting early - html

I'm looping through my collection of frontpage products and generating a table. In the last row, I need to put some static content in the first table cell. I've been able to do that, but for some reason, the loop stops after it does that. Does anyone know why?
{% tablerow product in collections.frontpage.products cols: 2 %}
{% if tablerowloop.col_first and tablerowloop.last %}
<img src="{{'box.png' | asset_url}}">
{% else %}
<div class='featured-product'>
<img src="{{ product.images[1] | product_img_url: 'medium' }}">
<p>{{ product.title }}</p>
</div>
{% endif %}
{% endtablerow %}
Here's the site: https://hodkiewicz-zieme-and-hirthe180.myshopify.com/

tablerowloop.last only returns true for the last cell of the table (i.e. last product of the collection), not for the last row. Instead you need to check if the index within cols of the end of the collection, such that it must be the last row if it is the first column.
{% tablerow product in collections.frontpage.products cols: 2 %}
{% assign x = tablerowloop.length | minus:2 %}
{% if tablerowloop.col_first and tablerowloop.index > x %}
<img src="{{'box.png' | asset_url}}">
{% else %}
<div class='featured-product'>
<img src="{{ product.images[1] | product_img_url: 'medium' }}">
<p>{{ product.title }}</p>
</div>
{% endif %}
{% endtablerow %}

Related

How to create 2 columns using the batch filter in twig

Im trying to put Pictures into a gallery using the batch filter with twig. I want there to be 2 columns next to eachother, but the code seems not to create the second column. Everything goes into a single column.
{% extends "_bildlayout" %}
{% block content %}
{% for entry in craft.entries.section('bilder').limit(16)|batch(8) %}
<div class="column">
{% for value in entry %}
{% set bild = value.bild.one() %}
<img src="{{ bild.url }}" alt="{{ value.title }}">
{% endfor %}
</div>
{% endfor %}
{% endblock %}

Shopify After 4 Products add a Horizontal Break

I'm trying to figure out how to add a horizontal break after 4 products within the Shopify product loop. Is this possible at all? I've looked through their documentation but it doesn't show the possibility of counting or iterating over the loop.
Currently my loop looks as follows:
{% if collection.all_products_count > 0 %}
<div class="w-col w-col-12">
<div class="product-feed w-clearfix">
{% for product in collection.products %}
<a class="product product-collection w-inline-block" href="{{ product.url | within:collection }}">
<div class="reveal">
<img src="{{ product.featured_image | product_img_url: 'original' }}" alt="{{ product.title | escape }}" class="product-photo">
<img src="{{ product.images.last | product_img_url: 'original' }}" alt="{{ product.title | escape }}" class="hidden">
</div>
<h3 class="product-title">{{ product.title }}</h3>
<div class="product-price">{{ product.price | money }}</div>
<span class="shopify-product-reviews-badge" data-id="{{ product.id }}"></span>
</a>
{% endfor %}
</div>
{% assign count = paginate.pages %}
{% for part in (1..count) %}
<li {% if paginate.current_page == part %}class="active"{% endif %}>{{ forloop.index }}</li>
{% endfor %}
{% else %}
<p>Sorry, there are no products in this collection</p>
{% endif %}
It's fair explanation that you have not gone through the documentation properly. Refer this: - https://help.shopify.com/themes/liquid/objects/for-loops
Straight forward way to get this to work is add the following line before {% endfor %}
{% cycle '','','','<hr>' %} // or <br> if you prefer
<hr> gets added every time the forloop is iterating the 4th time. More on this - https://help.shopify.com/themes/liquid/tags/iteration-tags#cycle

display data in liquid

I'm looking to display information from a csv file on a jekyll-generated site. I need to search for the appropriate category in the csv file, then display four of them on the page. Filtering to the selected category is no problem, but I'm having difficulty limiting the output to four.
Is there a way to apply a limit to an if statement? Or is there any other way to write this? I'm not that savvy in Liquid, so it's extremely likely that I'm missing an obvious solution.
Basic code to make all the applicable data show up on the screen:
{% for study in site.data.studies %}
{% if study.category contains "foo" %}
<div class="col-sm-3">
<h3>{{ study.title }}</h3>
<div class="list-of-attributes">
<h6>Attributes: </h6>
{{ study.attributes }}
</div>
</div>
{% else %}
{% continue %}
{% endif %}
{% endfor %}
I've also tried unless and tablerow, neither of which worked at all. Am I at least on the right track? How can I limit this forloop to stop at four items?
Thank you!
Ideally data should be filtered before rendering however you can also create a variable in liquid to hold the number of stuff rendered
{% assign rendered = 0 %}
{% for study in site.data.studies %}
{% if study.category contains "foo" %}
<div class="col-sm-3">
<h3>{{ study.title }}</h3>
<div class="list-of-attributes">
<h6>attributes: </h6>
{{ study.attributes }}
</div>
</div>
{% assign rendered = rendered | plus: 1 %}
{% if rendered == 4 %}
{% break %}
{% endif %}
{% endif %}
{% endfor %}
The ideal solution as I said would be to create your own filter which does all the work (filter by category and limit the number of results)
{% assign filtered = site.data.studies | my_custom_filter %}
{% for study in filtered %}
<div class="col-sm-3">
<h3>{{ study.title }}</h3>
<div class="list-of-attributes">
<h6>attributes: </h6>
{{ study.attributes }}
</div>
</div>
{% endfor %}
Presuming that your category is a string, not an array, you can do :
{% assign selected = site.data.studies | where: 'category','foo' %}
{% for study in selected limit:4 %}
<div class="col-sm-3">
<h3>{{ study.title }}</h3>
<div class="list-of-attributes">
<h6>Attributes: </h6>
{{ study.attributes }}
</div>
</div>
{% endfor %}
And if your category is a string like "foo, bar, baz" or and array of strings you can use the jekyll 3.2 where_exp filter like this :
{% assign selected = site.data.studies | where_exp:"item", "item.category contains 'foo'" %}

Liquid template: Get first 5 posts that match criterion

I want to display the 5 most recent posts which have a thumbnail on the main page of my jekyll-blog. How to achieve this?
I set the thumnail as an attribut in the header of the post:
---
layout: post
title: Lorem Ipsum
thumb: images/thumb.jpg
---
I tried
{% for post in site.posts | sort:"date" | reverse | limit: 5 %}
{% if post.thumb %}
<img src= ... />
{% endif %}
{% endfor %}
but of course, if one of the five happens not to have a picture, only four will be displayed. Is there a smooth way around this?
Try:
{% assign maxPost = 5 %}
{% assign counter = 0 %}
{% for post in site.posts | sort:"date" | reverse %}
{% if post.thumb %}
<img src= ... />
{% assign counter = counter | plus: 1 %}
{% if counter == maxPost %}
{% break %} {% comment %}exit the for loop{% endcomment %}
{% endif %}
{% endif %}
{% endfor %}

How to set up related collection items rather than related posts in Jekyll?

I've successfully implemented related posts in my site by using site.related_posts with the following Liquid templating:
The code bellow returns 4 posts related by tags on every post page, so far so good, but what's the best approach to achieve something like this for Jekyll collections?
{% assign hasSimilar = '' %}
{% for post in site.related_posts %}
{% assign postHasSimilar = false %}
{% for tag in post.tags %}
{% for thisTag in page.tags %}
{% if postHasSimilar == false and hasSimilar.size < 4 and post != page and tag == thisTag %}
{% if hasSimilar.size == 0 %}
{% endif %}
<a href="{{ site.baseurl }}{{ post.url }}" class="entry">
<div class="entry-media">
<img src="{{ post.thumbnail | prepend: site.baseurl }}" alt="">
<p class="post-cat">{% for category in post.categories.last %}{{ category }}{% endfor %}</p>
</div>
<h6 class="entry-title">{{ post.title | truncatewords: 70, '...' }}</h6>
<p class="post-date">{{ post.date | date: "%d/%m/%Y" }}</p>{% if post.series %}(Series: {{ post.series }}){% endif %}
</a>
{% capture hasSimilar %}{{ hasSimilar }}*{% endcapture %}
{% assign postHasSimilar = true %}{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% if hasSimilar.size > 0 %}
{% endif %}
As per Jekyll's documentation, when you create a collection it becomes available via the site Liquid variable, much like site.pages and site.posts, so in order to create a related collection items for my portfolio collection I replicated the Liquid logic above and assigned site.portfolio as posts, see:
{% assign posts = site.portfolio | sort: "tags" %}
So I set tags: [tag1, tag2, tag3] on every "project.md" document's front-matter within my _portfolio collectionas, as I'd normally do with posts and the liquid logic above returns the related portfolio collection items.
Anyway, although I'm not sure if this is the right path to achieve such functionality, it works as intended. I couldn't find any references/ usage for site.related_posts when it come to collections.
I'd really appreciate any thoughts regarding this issue. Thanks in advance.
site.related_posts are the ten most recent posts.
So, your code is only looking for related in ten posts not all posts.
The following code will looks for tags related items for site.posts or any site.collection
{% assign pageTagsNumber = page.tags | size %}
{% assign related = "" | split: "/" %}<!-- create empty array -->
{% assign relatedCount = 0 %}
{% assign maxRelated = 4 %}<!-- maximum number of related items -->
{% assign minTagMatch = 4 %}<!-- minimum number of tag match to be a related -->
{% if minTagMatch > pageTagsNumber %}
{% assign minTagMatch = pageTagsNumber %}
{% endif %}
{% assign matchedComplete = false %}<!-- flag -->
<!--
numberOfTag to match to be in the related list
Will try to match all page tags, then page tags size - 1, -2, until reaching minTagMatch
-->
{% for numberOfTag in (minTagMatch...pageTagsNumber) reversed %}
<!-- Looping over site.posts or any site.mycollection -->
<!-- here you can do {% for item in site.mycollection %} -->
{% for item in site.posts %}
<!-- !!! ITEM SPECIFIC -->
<!-- for a collection change item.title == page.title if needed-->
{% if related contains item or item.title == page.title %}
<!--
Don't scan an item that is already in related
Don't scan an item if we are on his page
-->
{% continue %}<!-- go to next item -->
{% endif %}
{% assign itemTagsNumber = item.tags | size %}
{% if itemTagsNumber < numberOfTag %}
<!-- Not enough tags {{ itemTagsNumber }} -->
{% continue %}<!-- go to next item -->
{% endif %}
{% assign matchingTags = 0 %}<!-- tag match counter -->
{% for tag in page.tags %}
<!-- Comparing page tag "{{ tag }}" to {{ item.tags | join: ", " }} -->
{% if item.tags contains tag %}
<!-- one matching tag increment matchingTags counter-->
{% assign matchingTags = matchingTags | plus: 1 %}
<!-- We have a match and {{ matchingTags }} matching tags total -->
{% if matchingTags >= numberOfTag %}
<!-- we have enough matching tag, this is a related item -->
{% capture html %}
<li><a href="{{ site.baseurl }}{{ item.url }}">
{{ item.title }}
{% assign pageTagsNumber = item.tags | size %}
- has {{ pageTagsNumber }} tags
- match on {{ matchingTags }} tags
</a></li>
{% endcapture %}
{% assign related = related | push: html %}
{% assign relatedCount = related | size %}
{% if relatedCount >= maxRelated %}
<!-- if we have all our related set the matchedComplete flag to true -->
{% assign matchedComplete = true %}
{% endif %}
{% break %}
{% endif %}
{% endif %}
{% endfor %}
{% if matchedComplete == true %}
<!-- matchedComplete breaking item loop! -->
{% break %}
{% endif %}
{% endfor %}
{% if matchedComplete == true %}
<!-- matchedComplete breaking numberOfTag loop! -->
{% break %}
{% endif %}
{% endfor %}
{% if relatedCount > 0 %}
<!-- print related items -->
<ul>
{% for item in related %}
{{ item }}
{% endfor %}
</ul>
{% endif %}