Filter posts by category in Jekyll - jekyll

I have a folder of markdown files each with a number of key/values. I need to filter all of the markdown files in the _faq folder by the key faq_category.
I have tried:
{% assign post = site.faqs | where: "faq_category", name-of-category %}
<ul>
<li>{{ post.title }}</li>
</ul>
However, this is showing nothing in the end.
The folder structure it should be looping through is:
jekyll
|
--faqs
|
--name-of-faq
--name-of-faq-2
Sample markdown file:
title: name of faq
faq_id: 2567
slug: title-of-faq
created: Mar 6, 2017
modified: Mar 6, 2017
faq_category: how to fly

Instead of site.faqs use site.posts to get an array of posts.
Then put the markdown files in the folder: /faqs/_posts/ for example: /faqs/_posts/faq1.md.
After that you should be able to browse them like:
{% for post in site.posts %}
{{post.title}}
{% endfor %}
To filter a specific category use: site.categories.CATEGORY or filter them like: (for example the category "mycategory")
<ul>
{% for post in site.faqs %}
{% if post.categories contains "mycategory" %}
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}

Related

Find post where key has specific value in Jekyll

I need to be able to compare a value in each of the markdown files in a folder called in_media to the user_id of the current page stored in a _users folder and only display the post title that have that value from the in_media folder.
User markdown file in _users folder
---
user_id: 123
title: bob
---
Post markdown from in_media folder
---
users: 123
---
I tried the following:
{% for this_user in site.in_media %}
{% for user in page.user %}
{% if this_user == user.user_id %}
<li><a href="{{ post.external_link }}">{{ post.title }}</a </li>
{% endif %}
{% endfor %}
{% endfor %}
However, this is not returning anything
Try this way:
{% for post in site.in_media %}
{% if post.value == page.title %}
<li>{{ post.title }}</li>
{% endfor %}
{% endfor %}
I'm not sure that you can use external_link, never heard of it. Maybe you'll need to build permalink manually - depending on your _config.xml.
Also note the collection should be properly set up to work with permalinks.

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>

Accessing posts via directory tree in Jekyll

Let's say I have a directory like the following:
|things
|---|animals
|---|---|dog
|---|---|cat
|---|---|other
|---|languages
|---|---|Afrikaans
|---|---|Latin
|---|---|Japanese
|---|---|other
and I want to access all of the posts under the "other" category that is under the "languages" category.
I want to be able to do
{% for post in site.categories.things.languages.other do %}
but that apparently doesn't work in Jekyll.
If I can avoid it, I'd like to not do
{% for post in site.categories.cobol do %}
{% if post.categories equals ["things", "languages", "other"] %}
but if I absolutely must, I will.
If you want to simply output a list of posts contained in a given path :
languages_other.html
---
path: "things/languages/other/"
---
{% include post_by_folder.html path=page.path %}
_includes/posts_by_folder.html
<h1>Posts in folder {{ include.path }}</h1>
<ul>
{% for post in site.posts %}
{% if post.path contains include.path %}
<li>
{{ post.title }}
</li>
{%endif %}
{% endfor %}
</ul>
Now any time you want to make a list of posts in a particular folder, you just have to create a page like languages_other.html.

Jekyll 2.0 listing all post from category breaks

I moved from Jekyll pre-1.0 to 2.0 recently.
In my original code, on each blog post it will list all the title of posts that belongs to the same category as the current post being viewed. Previously this code worked:
{% for post in site.categories.[page.category] %}
<li {% if page.title == post.title %} class="active" {% endif %}>
{{ post.title }}</li>
{% endfor %}
However in the new version this does not work and I have to specify the category individually like so:
{% for post in site.categories.['NAME_OF_CATEGORY'] %}
Why can't I dynamically check for the category as before? And is there a work around for this instead of using if statements?
I figured it out. I had, in each post, my YAML front-matter category variables in uppercase or Camel case. Example: category: ABC or category: Zyx.
Doing page.category will always return the the actual category as it was written in the front-matter, which is ABC or Zyx. However site.categories.[CAT] only accepts CAT in lower cases (down case in liquid language).
Hence this will work site.categories.['abc'] or site.categories.['xyz'].
But this will fail site.categories.['ABC'] or site.categories.['Xyz']. It is the same as doing site.categories.[page.category].
Solution. Assign the current page category in lower case like so:
{% assign cat = page.category | downcase %}
{% for post in site.categories.[cat] %}
<li {% if page.title == post.title %} class="active" {% endif %}>
{{ post.title }}</li>
{% endfor %}

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.