loop through filtered collection in jekyll - 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.

Related

How to list tags from both posts and collections

I have a tags.md which contain the code below, It list the tags from my _site/post.md
---
layout: default
title: Tags
---
{% for tag in site.tags %}
<h2>{{ tag[0] }}</h2>
<ul>
{% for post in tag[1] %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
{% endfor %}
And I also have a Collections for work stuff, like work.md in the jekyll root directory and the post in there is inside _work/
How can I make the tags.md list the tags from both _posts/*.md and _work/*.md?
I realize I can't do something like this
{% for tag in site.tags %}
{% for tag in work.tags %}
<h2>{{ tag[0] }}</h2>
<ul>
{% for post in tag[1] %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
{% endfor %}
{% endfor %}
Using site.documents should be your way to go, see https://jekyllrb.com/docs/variables/
site.documents
A list of all the documents in every collection.
Internally, posts are also treated as a collection here.
The first line below groups all documents by tag:
{% assign docs_by_tags = site.documents | group_by: 'tags' %}
{% for tag in docs_by_tags %}
<h2>{{ tag.name }}</h2>
<ul>
{% for item in tag.items %}
<li>{{ item.title }}</li>
{% endfor %}
</ul>
{% endfor %}
BUT the result shows quoted tag names, which is not what we want.
A better solution to group arrays
Someone else already found a good way to group arrays in posts and collections back in 2015, see https://github.com/mushishi78/jekyll-group-by-array/blob/master/group-by-array.html - the project's readme has some sample code using the include file.
The code "extracts" tags or other attributes and pushes data to arrays before data is returned to be displayed.
The solution with both post and collection tag
Just use site.documents in the include as first parameter
{% comment %}based on https://github.com/mushishi78/jekyll-group-by-array{% endcomment %}
{% include group-by-array.html collection=site.documents field='tags' %}
<ul>
{% for tag in group_names %}
{% assign posts = group_items[forloop.index0] %}
<li>
<h2>{{ tag }}</h2>
<ul>
{% for post in posts %}
<li>
<a href='{{ site.baseurl }}{{ post.url }}'>{{ post.title }}</a>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Reversing the posts order in the list
To reverse the post order under the tag, you can add a reversed to the for loop above:
{% for post in posts reversed %}

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

How get ints in Jekyll?

I am trying to make a blog and I want to make id tags that correspond with each time a for loop runs (e.g. #section_1, #section_2,#section_(insert variable) ).
Is there some way to do that in Jekyll?
This should produce what you're looking for:
{% assign indices = "1|2|3" | split: "|" %}
{% for index in indices %}
<div id="{{ index }}">This is div {{ index }}</div>
{% endfor %}
You'll have to know in advance how many sections that you want created, and add each ID to the 1|2|3 bit in the first line.
Use the forloop.index
The menu part :
<ul>
{% for posts in site.posts %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
Content part :
{% for posts in site.posts %}
<h2 id="section_{{ forloop.index }}">{{ post.title }}</h2>
{{ post.content }}
{% endfor %}

How to limit posts filtered by front matter?

I have Jekyll blog where some posts have "featured images," some posts don't.
Featured images are defined in the front matter of the post like so: featured-image: http://path/to/img
On the archive page, I'd like to grab the three most recent posts that have featured images and display them.
I imagine this would need an if statement, a counter, and a loop, but I can't get this one to work for me:
<ul id="archive-featured">
{% assign count = '0' %}
{% if count < '4' %}
{% for post in site.posts %}
{% if post.featured-image == true %}
{{ count | plus: '1' }}
<li><img src="{{post.featured-image}}" />{{ post.title }}</li>
{% endif %}
{% endfor %}
{% endif %}
</ul>
What am I missing?
Your YAML matter looks good, but I am not sure you need the count assignment to make this work. Try using limit instead to restrict the number of posts your assign on your archive page. You also do not need to assign a "true" value for the {% if %} statement to work:
<ul id="archive-featured">
{% for post in site.posts limit:3 %}
{% if post.featured-image %}
<li>
<a href="{{ post.url }}">
<img src="{{ post.featured-image }}" />
{{ post.title }}
</a>
</li>
{% endif %}
{% endfor %}
</ul>
I believe that the posts are automatically displayed by most recent post, so no extra work needs to be done there. Hope this helps!
A very late answer:
I think the problem is with {{count | plus: 1}}. Wouldn't this just ouput the count + 1, but not assign it?
You can solve this like by assign a new variable before the end of the forloop
<ul id="archive-featured">
{% assign count = 0 %}
{% if count < 4 %}
{% for post in site.posts %}
{% if post.featured-image == true %}
<li><img src="{{post.featured-image}}" />{{ post.title }}</li>
{% count | plus: 1 %}
{% endif %}
{% endfor %}
{% endif %}
</ul>
A workarounds that might be interesting:
If you add another simple statement to your front matter, like featured: true you can use the where filter to select only those posts. (The where filter sadly doesn't seem to work with comparisons)
<ul id="archive-featured">
{% assign posts=site.posts | where "featured", "true" %}
{% for post in posts | limit: 3%}
<li><img src="{{post.featured-image}}" />{{ post.title }}</li>
{% endfor %}
</ul>

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