Set limit of posts to display in jekyll - jekyll

I need to limit the number of posts that show in a list from a collection of many posts. I am currently checking each post with a category of a specific name and then breaking the loop after the first 4 posts have been found.
{% assign count = 0 %}
{% for post in site.faqs %}
{% if post.faq_category contains "category-name" %}
{% assign count = count | plus:1}
{% if count == 4 %}
{% break %}
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
However, this is not returning any results. I'm not sure if I just have the count in the wrong place or what.

I figured out that I had to set the count below the li element:
{% assign count = 0 %}
{% for post in site.faqs %}
{% if post.faq_category contains "category-name" %}
{% assign count = count | plus:1 %}
<li>{{ post.title }}</li>
{% if count == 4 %}{% break %}
{% endif %}
{% endif %}
{% endfor %}

Using the counter you can filter posts and just display when the counter is less than 4, otherwise use break as you did:
{% assign count = 0 %}
{% for post in site.faqs %}
{% if post.faq_category contains "category-name" %}
{% assign count = count | plus:1}
{% if count < 4 %}
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
A cleaner version can be done creating the array of faqs items of the desired category and then limiting the for loop to 4:
{% assign faqs = site.faqs | where_exp:"item",
"item.faq_category contains 'category-name'" %}
<ul>
{% for post in faqs limit:4 %}
<li>{{post.title}}</li>
{% endfor %}
</ul>

Related

jekyll: combine limit and where and reverse

Using Jekyll i'd like to:
iterate through all the pages
where the page.path is not the current path
where the page.categories contains "featured"
reverse them(most recent first)
limit 3
i'm having problems when getting all those filters together
{% assign posts = site.posts | reverse %}
{% for post in posts limit:3 %}
{% if post.categories contains 'featured' and post.path != page.path %}
{% include card.html post=post %}
{% endif %}
{% endfor %}
right now the limit is not working properly because the inner if will prevent a few items from being rendered.
Assign 0 to a counter variable before entering your loop. Don't set a limit on the loop, but instead set another condition on your counter being below your limit, and increment the counter using Liquid's plus filter every time you meet your criteria and output the card.
{% assign posts = site.posts | reverse %}
{% assign counter = 0 %}
{% for post in posts %}
{% if counter < 3 and post.categories contains 'featured' and post.path != page.path %}
{% include card.html post=post %}
{% assign counter = counter | plus: 1 %}
{% endif %}
{% endfor %}
A more complex example
I'm basing all of this on the looping I use myself. My condition is a little more complex: I check for any shared tag with the current page. I've included this as a further example below.
{% assign counter = 0 %}
{% for post in site.posts %}
{% if counter < 4 %}
{% if post.url != page.url %}
{% assign isValid = false %}
{% for page_tag in page.tags %}
{% for post_tag in post.tags %}
{% if post_tag == page_tag %}
{% assign isValid = true %}
{% endif %}
{% endfor %}
{% endfor %}
{% if isValid %}
{% include article_card.html %}
{% assign counter = counter | plus: 1 %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
Why where fails
Although Liquid has a where filter, it can only do exact comparisons, so you have to reinvent the wheel like this in order to achieve the where-like scenario for more complex conditions. This does make for a lot of looping through site.posts, but Jekyll being a preprocessor means the penalty of using a somewhat inefficient improvised where-type looping is only a compile-time concern, not a runtime one. Even so, to mitigate this cost as much as possible, I opt for having the counter condition be the first that Jekyll calculates.

Liquid markup sorting the output

I am trying to display a list of all articles using liquid markup. I've got this code which displays them properly, however I want to be able to sort by the modified date descending (most recent article on top). How can this be accomplished?
I was thinking that perhaps I need to create a new array with all articles in it and then sort that, but I am not sure how to do that. Also note that I want to sort ALL of my articles by date, not just within each folder.
{% for category in portal.solution_categories %}
{% if category.folders_count > 0 %}
{% for folder in category.folders %}
{% for article in folder.articles %}
{{ article.title }} - {{ article.modified_on | short_day_with_time }} <br>
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
Thanks!
You can use a variable to sort the list of articles and then iterate that variable.
{% for category in portal.solution_categories %}
{% if category.folders_count > 0 %}
{% for folder in category.folders %}
{% assign sorted = (folder.articles | sort:date) %}
{% for article in sorted %}
{{ article.title }} - {{ article.modified_on | short_day_with_time }} <br>
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}

Jekyll: Listing all categories but one with a limit breaks the limit

I am trying to output a list of post titles with the 5 latest posts in ALL categories BUT one. It works fine with the filtering, unfortunately it takes the posts that are being excluded in consideration for the limit. Is there any easy way to not count the excluded posts?
{% for post in site.posts limit: 5 %}
{% if post.category == "news" %}
//Do nothing
{% else if %}
{{ post.title }}
{% endif %}
{% endfor %}
To limit filtered posts you need to filter them first.
We create an array of posts that do not include the news category:
{% assign no_news = "" | split: "" %}
{% for post in site.posts %}
{% unless post.categories contains 'news' %}
{% assign no_news = no_news | push: post %}
{% endunless %}
{% endfor %}
Now we traverse this new array limiting iterations by 5:
{% for post in no_news limit: 5 %}
{{ post.title }} - {{post.categories}}
{% endfor %}
It will output 5 posts not containing the news category.
You should be able to assign the posts first, then call them:
{% assign relevant = site.posts | except:"category","news" %}
{% for posts in relevant limit:5 %}
{{ post.title }}
{% endfor %}
For more: https://github.com/jekyll/jekyll/issues/2018

Jekyll - Liquid Templating - Exclude a Category from Widget

I am attempting to rebuild a sidebar widget which shows my categories used in Jekyll. It works fine as it is now. I want to change the liquid templating to exclude one specific category link from being shown in this widget.
{% assign cat_list = site.categories %}
{% if cat_list.first[0] == null %}
{% for category in cat_list %}
<li>{{ category }} <span class="cat-count">{{ cat_list[category].size }}</span></li>
{% endfor %}
{% else %}
{% for category in cat_list %}
<li>{{ category[0] }} <span class="cat-count">{{ category[1].size }}</span></li>
{% endfor %}
{% endif %}
{% assign cat_list = nil %}
I think what I want is something like
{% for category in cat_list **UNLESS category = 'CATEGORY'** %}
But that did not work. I'm kinda stuck, is this possible?
Thank You.
Not displayed categories array :
{% assign noDisplay = "one,two,three" | split: "," %} => ["one", "two", "three"]
The test :
{% unless noDisplay contains category[0] %}
{{ category[0] }}...
{% endunless %}
Thank you, #David Jacquel
{% assign noDisplay = "CATEGORY" | split: "," %}
{% assign cat_list = site.categories %}
{% if cat_list.first[0] == null %}
{% for category in cat_list %}
<li>{{ category }} <span class="cat-count">{{ cat_list[category].size }}</span></li>
{% endfor %}
{% else %}
{% for category in cat_list %}
{% unless noDisplay contains category[0] %}
<li>{{ category[0] }} <span class="cat-count">{{ category[1].size }}</span></li>
{% endunless %}
{% endfor %}
{% endif %}
{% assign cat_list = nil %}

Looping through all list of posts not in some category in liquid

I want to loop through posts on a site except ones with the category unlisted. I'm able to do this by nesting an if statement inside the for loop, but this breaks down when I want to also specify a limit – the loop will run for 5 times only regardless of whether the post passes the check.
{% for post in site.posts limit: 5 %}
{% unless post.categories contains 'unlisted' %}
<!-- display post -->
{% endunless %}
{% endfor %}
I need to pass an already filtered list to the for loop, but I'm unable to do this mainly because I can't find a way to combine the where filter with contains and negation:
{% for post in site.posts | WHERE CATEGORIES NOT CONTAINS 'UNLISTED' | limit: 5 %}
<!-- display post -->
{% endfor %}
You can use a counter :
<ul>
{% assign postCounter = 0 %}
{% assign maxPost = 5 %}
{% for post in site.posts %}
{% unless post.categories contains 'unlisted' %}
<li>{{ post.title }}</li>
{% assign postCounter = postCounter | plus: 1 %}
{% if postCounter >= maxPost %}
{% break %}
{% endif %}
{% endunless %}
{% endfor %}
</ul>