Filter paginator.posts - jekyll

I run a vanilla Jekyll (4.1.1) system. It displays the posts on the index page paginated and within two columns with this code:
<div class="row">
<div class="col-md-6">
{%- for post in paginator.posts -%}
{% assign mod3 = forloop.index | modulo: 2 %}
{% if mod3 != 0 %}
{% include card_post.html post=post %}
{%- endif -%}
{%- endfor -%}
</div>
<div class="col-md-6">
{%- for post in paginator.posts -%}
{% assign mod3 = forloop.index | modulo: 2 %}
{% if mod3 == 0 %}
{% include card_post.html post=post %}
{%- endif -%}
{%- endfor -%}
</div>
</div>
Each post has this header:
---
layout: blogpost
title: "foobar"
publication_date: 2020-12-11
categories:
- car
- whatever
---
On the index page I only want to display posts which do not include the categories with the value of bike. It seems to be such an easy thing to do but I can't find a negative filter which works with the pagination.
How can I solve this?

hidden: true tells pagination not to use it. It is not perfect but solves this specific problem.
https://jekyllrb.com/docs/pagination/
Pagination does not support tags or categories. Pagination pages
through every post in the posts variable unless a post has hidden:
true in its front matter. It does not currently allow paging over
groups of posts linked by a common tag or category. It cannot include
any collection of documents because it is restricted to posts.

Related

How to stop a for loop that has "include tags" in certain item in Nunjucks?

I have this code on my blog site but I want the loop to stop in, for example, the second item/article or third
<div class="container mar2ritlft">
<div class="content3col">
{%- for article in collections.article | reverse -%}
{% include 'article-post.njk' %}
{%- endfor -%}
</div>
</div>
Ps: the "collections.article" is blogs that have "article" tag in the metaData
You may want to reconsider your approach on looping through multiple articles by allowing the index of your loop to have a relationship to the actual articles. If so, you should be able to pull off the following...
{%- for articleTitle in collections.article | reverse -%}
{% if loop.index > 2 %}
{{articleTitle}} {# a collection of blog titles???#}
{% include "articles/article-post" + loop.index + ".njk" %}
{% endif %}
{%- endfor -%}
In your articles/ directory, you would have something like...
article-post1.njk
article-post2.njk
article-post3.njk
article-post4.njk
...etc...

How to select specific items in Liquid

Assuming I have a list of tags: iFix_6.3, iFix_7.0, iFix_7.1, iFix_8.0, announcement, and so on... and I want to run an operation only on certain several tags. How can I check for these multiple values?
There is contains, but I'm looking for the opposite of it and for multiple values...
Here is an example where I actually filter out all posts that contain the iFix_6.3 tag, thus display all other posts. This actually does not work yet... plus needs to be extended to work for multiple tags.
// posts with iFix_xxx tag should be filtered from the main posts view.
{% assign postUpdates = site.posts | where_exp:"item", "item.tags != 'iFix_6.3'" %}
{% for post in postUpdates limit:10 %}
<div class="postItem inline">
<p class="postDate">{% if post.pinned %}<span class="glyphicon glyphicon-pushpin"></span>{% endif %}{{post.date | date: '%B %d, %Y'}}</p>
<p class="postTitle">{{post.title}}</p>
</div>
{% endfor %}
You can do this by building an array of excluded tags (excluded_tags) using split and a string of the comma-separated tags. Then for each post, you iterate on the post's tags. Check if the tag is in excluded_tags using contains, if it is then raise the flag filtered_out to not display the post, using the unless control flow tag.
{% assign excluded_tags = "iFix_6.2,iFix_6.3,announcement" | split : "," %}
{% for post in site.posts limit:10 %}
{% assign filtered_out = False %}
{% for tag in post.tags %}
{% if excluded_tags contains tag %}
{% assign filtered_out = True %}
{% break %}
{% endif %}
{% endfor %}
{% unless filtered_out %}
...
{% endunless %}
{% endfor %}
Seems unless would solve the case.
{% assign postUpdates = site.posts | where_exp:"item", "unless item.tags contains 'iFix_6.3'" %}

List non-posts pages in relevant category pages

I have a Jekyll blog up and running, but I'd like to do something that seems a bit unorthodox.
Essentially, I've got blog posts in /_posts, and a set of static pages in another folder at /projects.
The top of these projects page looks like this:
---
layout: project
title: My cool project
categories:
- Data Journalism
status: active
---
Now, the biggie: Each category (such as Data Journalism in the example above) has a page with a unique URL, where posts belonging to this category are aggregated.
I would like projects belonging to these categories to be aggregated on these same pages, eg the Data Journalism category page would have a list of projects and a list of posts, all of which are part of this category.
I managed to list all the projects on each category page with
<ul class="posts">
{% for page in site.pages %}
{% if page.layout == 'project' %}
{% if page.status == 'active' %}
<h2>{{ page.title }}</h2>
<div> {{ page.description }}</div>
{% endif %}
{% endif %}
{% endfor %}
</ul>
added in _layouts/category_index.html. But it shows all projects, not only the one belonging to the page category. In the example, My cool project should only be listed in the Data Journalism category page.
Can you help? I'd be most grateful!
EDIT: Thanks to Davic Jacquel for the solution. His answer's below, marked as solved, and here is the tweak I had to make:
<ul class="posts">
{% for p in site.pages %}
{% if p.layout == 'project' and p.status == 'active' %}
{% assign cat = p.categories | downcase %}
{% if cat contains page.category %}
<h2>{{ p.title }}</h2>
<div> {{ p.description }}</div>
{% endif %}
{% endif %}
{% endfor %}
</ul>
Edit : reading your plugin code makes me realize that you have a page.category variable in all your categories pages.
Note : current page's data are stored in the page variable. So, when you loop, try not use page as a storage variable to avoid collision.
In _layouts/category_index.html :
---
layout: default
---
<ul class="posts">
{% for p in site.pages %}
{% if p.layout == 'project' and p.status == 'active' %}
{% if p.categories contains page.category %}
<h2>{{ p.title }}</h2>
<div> {{ p.description }}</div>
{% endif %}
{% endif %}
{% endfor %}
</ul>

Jekyll - Get all posts that are in multiple categories

I want to loop over all posts that are assigned category "foo" and category "bar" ..
{% for post in site.categories.foo and in site.categories.bar %}
Is this possible?
In my case "foo" as a "parent" category to "bar" ... /foo/bar/_posts
Thanks
Instead of looking through every post and matching with an or, you can filter by the first tag and then look for the second (and third, fourth, fifth...) tags:
{% for post in site.categories.fizz%}
{% if post.categories contains "buzz" and post.categories contains "bang" %}
<!--post has categories fizz AND buzz AND bang-->
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
This is a little more efficient than iterating over every single post, and it sets up an and relationship instead of an or relationship.
It is fully possible: loop over all posts, and then select the wanted posts:
{% for post in site.posts %}
{% if post.categories contains "foo" or post.categories contains "bar" %}
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
Using the Where Expression filter in Jekyll.
Jekyll Liquid Filter Docs
Where Expression,
Select all the objects in an array where the expression is true.
3.2.0
{{ site.members | where_exp:"item", "item.projects contains 'foo'" }}
So on my site I did:
_includes/clippings.html
...
{% capture _filter %}item.tags contains '{{ include.tag }}'{% endcapture %}
{% for clip in site.clippings | where_exp: 'item', _filter %}
{{ clip.do_stuff }}
# more html and stuff
{ endfor }
{% include clippings.html tag='foo' %}
In this case I need to specify the filter tag dynamically. And clippings is just a collection like posts.
If you want to filter by multiple static tags you could do something like:
{% for post in site.posts | where_exp: 'item', "item.tags contains 'foo'" | where_exp: 'item', "item.tags contains 'bar'" %}
{{ post.do_stuff }}
{ endfor }
If you want to do multiple dynamic filter tags then you will need to do something similar to the capture stuff I did above.
I have not tested this, but it should filter posts by an arbitrary amount of filter tags.
{% assign posts = site.posts %}
{% filter_tags = 'foo, bar, buzz' | slipt: ', ' %}
{% for tag in filter_tags %}
{% capture _filter %}item.tags contains '{{ tag }}'{% endcapture %}
{% assign posts = posts | where_exp: 'items', _filter %}
{% endfor %}
{% for post in posts %}
{{ post.do_stuff }}
{% endfor %}
However looping over the whole thing once and checking each post might be more efficient at that point.

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