display data in liquid - jekyll

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'" %}

Related

Loop trough collections of products

I'm trying to loop through all the collections that a set of products is part of. This is my code:
<div class="container model-collection">
<h1>{{ collection.title }}</h1>
{% paginate collection.products by 12 %}
<div class="grid collection-products-container">
<ul>
{% for product in collection.products %}
{% for collection in product.collections %}
<li>{{ collection.title }}</li>
{% endfor %}
{% endfor %}
</ul>
</div>
{% if paginate.pages > 1 %}
{% include 'pagination' %}
{% endif %}
{% endpaginate %}
</div>
This works fine, however if two products are part of the same collection it lists that collection twice. So I need to limit the loop that it only shows each collection once.
I've tried to do it like this:
<div class="container model-collection">
<h1>{{ collection.title }}</h1>
{% assign model = collection.title %}
<div class="grid collection-products-container">
<ul>
{% for product in collection.products %}
{% assign seen_collections = "" %}
{% for collection in product.collections %}
{% unless seen_collections contains collection %}
{% assign seen_collections = seen_collections | append: "," | append: collection %}
<li>{{ collection.title }}</li>
{% endunless %}
{% endfor %}
{% endfor %}
</ul>
</div>
</div>
But this only returns one of the collections twice and none of the others. Any ideas how to do this?
You can get an aggregate list of nested properties by using the map filter in your Liquid code, and the map filter lets you drill into nested objects quite efficiently.
So to get an array of all the unique collection handles used by all the products in your collection, we can quickly get the info we want as:
{% assign collection_handles = collection.products | map: 'collections' | map: 'handle' | uniq %}
This creates an array of all the collection handles of all the products inside the collection, then reduces them to just the unique ones (using the uniq filter). Note: uniq needs to work with a number, string, or other simple field - which is why we needed an array of collection handles, not an array of collection objects.
So now you can do your loop as:
{% for handle in collection_handles %}
{% assign collection = collections[handle] %}
<!-- All your awesome stuff here -->
{% endfor %}
Hope this helps!

Twig set reusable piece of html

I'm creating some templates with Twig and have an issue.
I'm trying to load a piece of html that is used several times troughout a webshop. So my idea is to create a reusable piece of code that I can load everytime when needed.
The problem I'm facing is that when I do a for loop and then include that piece of code I get an empty return. With other words my code doesn't recognize the data that need to be loaded for each product in the for loop. It returns empty info boxes.
To clarify:
I have a main template index.html which calls a snippet to include some products (don't look at rain extension!!):
{% if featured %}
{% include 'snippets/products.rain' with {'products': featured, 'type': 'grid'} %}
{% endif %}
My products.rain snippet looks like this:
{% if type %}
{% if type == 'grid' %}
{% for product in products %} {# Products in this case = feautured products #}
<li class="item clearfix">.... etc etc .... </li>
{% endfor %}
{% elseif type == 'other-layout' %}
<div class="item">.... etc etc .... </div>
{% endif %}
{% endif %}
In the for loop there's html that's for 95% the same as in each for loop. I want to place that code inside a block that can be included in the for loops.
So what I did was:
{% set product_html %}
.... a lot of html ....
<a href="{{ product.url | url }}" title="{{ product.fulltitle }}">
<img src="{{ product.image }}" width="100" height="100" alt="{{ product.fulltitle }}"/>
</a>
{% endset %}
And then included in the for loop, like so:
{% if type %}
{% if type == 'grid' %}
{% for product in products %} {# Products in this case = feautured products #}
<li class="item clearfix">{{ product_html | raw }}</li>
{% endfor %}
{% elseif type == 'other-layout' %}
<div class="item">{{ product_html | raw }}</div>
{% endif %}
{% endif %}
However this returns the html that is set however with empty product.image and empty product.fulltitle.
I tried the same with set block, but that has the same result.
Is there anything I'm doing wrong....??
When you are using {% set %}, content inside your variable is not dynamic, it will only use data in your current context, see it live.
You can achieve your goal using 2 ways: using include or using macros.
As your piece of code for a product is small and not reused somewhere else, I suggest you to use macros:
{% macro product_html(product) %}
Current product is: {{ product }}
{% endmacro %}
{% import _self as macros %}
{% for product in products %}
{{ macros.product_html(product) }}
{% endfor %}
See it live

loop through filtered collection in jekyll

I try to do things like this in my post:
<ul class="articles-list">
{% for post in site.posts | where:'group', post.group %}
<div data-scroll-reveal="enter ease 0">
{% include article-snippet.html %}
</div>
{% endfor %}
</ul>
but it loops through all my collection instead the only loops posts with special group.
You cannot use where filter in a loop.
But you can do :
{% assign posts = site.posts | where:'group', post.group %}
<ul class="articles-list">
{% for post in posts %}
<div data-scroll-reveal="enter ease 0">
{% include article-snippet.html %}
</div>
{% endfor %}
</ul>
According to liquid documentation about filters they should be used inside output tags {{ and }}.
You can maybe try an if statement:
{% for post in site.posts %}
{% if post.group == 'group' %}
<div data-scroll-reveal="enter ease 0">
{% include article-snippet.html %}
</div>
{% endif %}
{% endfor %}
Also you should use the where filter a bit differently. Something like this:
{{ site.members | where:"graduation_year","2014" }}
This says select site members whose graduation_year is 2014. You don't need to specify that it should filter members, the first part implicitly states that.

Shopify Display If Blog.Handle is X for blog listing

I am attempting to edit blog.liquid so that on a particular blogs listing, there is a customize graphic above it.
Something similar to this:
<div id="page-header">
<h2 id="page-title">{{ blog.title }}</h2>
</div>
{% if blog.new-years-revolution %}
<p class="alignCenter">**[custom code here]**
</p>
{% endif %}
{% for article in blog.articles %}
<h3 class="blog">
{{ article.title | escape }}</h3>
{% if article.excerpt.size > 0 %}
{{ article.excerpt }}
{% else %}
<p>{{ article.content | strip_html | truncate: 800 }}</p>
{% endif %}
{% endfor %}
Essentially I don't want it to show up on any other blogs, just this particular one. So a basic if statement that says "if on this blog, show this". I'm not sure whether to use the blog.id or blog.handle, and depending on which one, how to reference that particular handle so that this image only shows up on that one.
Hopefully I'm explaining clearly enough. Been googling for a while and haven't found anything helpful yet.
That should be:
{% if blog.handle == 'new-years-revolution' %}
<p class="alignCenter">**[custom code here]**</p>
{% endif %}

Jekyll Loop breaks on second iteration

I'm looping through two products - on the post view page I pull in a secondary post (in the example, a related recipe) which parses just fine on the first product page - on the second product page just {{ post.content }} won't parse. I can hack it with {{ post.content | markdownify }} - but I'd like to know why it's breaking. Here's the relevant code:
{% for post in site.categories.recipe %}
{% if post.products contains page.title and post.featured %}
<div class="row">
<div class="four columns">
<h4>{{ post.title }}</h4>
<ul>
<li>Serves {{ post.serves }}</li>
<li>Prep: {{ post.time }}</li>
<li>Share</li>
</ul>
{{ post.content }}
...
<!-- All tags are closed, the rest just isn't relevant -->
{% endif %}
{% endfor %}
Please find my solution with counter
<pre>
{% assign counter=0 %}
{% for post in site.posts%}
{% if post.category == 'blog' and counter < 2 %}
{% assign counter=counter | plus:1 %}
{{post.content}}
{% endif %}
{% endfor %}
</pre>
The markdownify filter is probably making it work because there might be special characters that aren't encoded in the content you're pulling from. I always forget to make my & into &.
If you're using the default Markdown interpreter Maruku, here's a list of the entities that might be giving you problems and their encoded equivalent. http://maruku.rubyforge.org/entity_test.html and more info on Maruku. http://maruku.rubyforge.org/maruku.html