Jekyll - Get all posts that are in multiple categories - jekyll

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.

Related

How to check if a value is present in a list?

I would like to get the list of posts having a specific tag in their front matter (*)
I tried the code below, which iterates over all the tags of the current post pages (the current tag is t), then iterates over all the posts (p) to check if they have this tag (and just outputs the title, for debugging reasons):
{% for t in page.tags %}
{% for p in site.posts %}
{% if t in p.tags %}
{{ p.title }}
{% endif %}
{% endfor %}
{% endfor %}
The line {% if t in p.tags %} seems to fail (I come form a Python background so I gave it a try) and I cannot find the in operator in liquid. Does it exits?
(*) I am mentioning what I want to achieve in case there is a more straightforward way to do that but I am still interested in the general question.
Following your example it can be done with the contains tag:
contains can also check for the presence of a string in an array of
strings.
{% if product.tags contains "outdoor" %}
This product is great for
using outdoors!
{% endif %}
So to get the list of posts having a specific tag in their front matter (in this case the posts with the tag mytag):
{% assign posts_with_mytag = site.posts | where_exp:"item",
"item.tags contains 'mytag'" %}
{% for post in posts_with_mytag %}
{{post.title}}
{% endfor %}
Following-up on #maracuny's answer, the corrected code from my question for completeness:
{% for t in page.tags %}
{% for p in site.posts %}
{% if p.tags contains t %}
{{ p.title }}
{% endif %}
{% endfor %}
{% 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

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

Getting the related posts from specific category (category/_posts)

I am doing the following
{% for post in site.related_posts limit:3 %}
// My stuff
{% endfor %}
and it keeps returning the posts from each of my categories i.e. blog/_posts/ as well as projects/_posts/ what I want is only blog posts. So I tried to do the following
{% for post in site.categories.blog.related_posts limit:3 %}
// My stuff
{% endfor %}
But it doesn't seem to return anything at all. Can any one please tell me what am I doing wrong here?
I never use related_posts, but this fairly ugly bit might work for you:
capture the category
{% capture related_posts %}{{ page.categories }}{% endcapture %}
Use that category to create your related posts
{% assign collection = site.categories[related_posts] %}
Return the related posts in a loop, pulling out the current page's post
{% for article in collection %}
{% unless page.url == article.url %}
{{ article.title }} - {{ category | capitalize }}<br />
{% endunless %}
{% endfor %}
Both this and related posts are processor intensive if you have a lot of posts.

Unable to find current post's category jekyll

I want to display keywords and description automatically according to the category of the current post. I've used the following code, but it doesn't worked.
{% if page.categories = "category" %}
{% else %}
{% endif %}
But while using {% page.categories %} it is echoing out the category name correctly. Here are my two doubts:
How can I compare the current post's category?
Are {{ }} and {% %} are same here?
It should look like the following:
{% if page.categories == 'some-name' %}
Hei I am in some-name category
{% else %}
No I am not in some-name category
{% endif %}
2.
No, {{ }} and {% %} are not the same. {{ }} is used for echoing stuff, while {% %} is used for logic expressions and arguments.