Filter site.related_posts in Jekyll - ruby

I am very new to Jekyll and Ruby (yet, very excited).
Without using a plugin, I am trying to find a way to filter the site.related_posts.
For example, I am reading the post with title Foo and categories A, B.
The site contains in total 3 posts:
Foo (Categories: A, B)
Bar (Categories: A, C, D)
Zoo (Categories: B, F)
By the default, in Jekyll we do this:
{% for post in site.related_posts limit:5 %}
{% endfor %}
However, the above code returns all the (3) posts.
A post contains many categories, so categories should be an array.
How can I modify the code and return only those whose categories intersect with the current post's categories?
(In this example, I would like the code to return only Foo and Zoo.)

I don't have the ability to test this right now, but something like this will work given Liquid's limited syntax:
{% for post in site.related_posts limit:5 %}
{% assign match = false %}
{% for category in post.categories %}
{% if page.categories contains category %}
{% assign match = true %}
{% endif %}
{% endfor %}
{% if match %}
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}

Make sure each post has a category in the YAML front matter, then add this to where you would like to show the post relating CATEGORY_NAME:
{% for post in site.categories.CATEGORY_NAME %}
<li>
<a href="{{ post.url }}">
<img src="{{ post.thumbnail }}">
<p>{{ post.excerpt }}</p>
</a>
</li>
{% endfor %}

Related

How to pass a limit parameter to an include using Jekyll's Liquid

I have a collection of projects on my site that I iterate over using {% for project in site.projects %} and store in an include called projects-list.html.
I would like to include the latest project from this collection on the homepage as a ‘featured’ item – is it possible to include the projects-list but pass in a limit:1 parameter so that only the first project is shown? Based on the Jekyll docs found here, I have tried passing the parameter to the include like this:
{% for project in site.projects limit:{{ include.limit }} %}
and refercing the include like this:
{% include projects-list.html limit=1 %}
but this does not appear to work. Is this a syntax error or am I missing something?
You could try the first
{% assign projectFeatured = site.projects | first %}
{% for projects in site.projects %}
{% include projects-list.html %}
{% endfor %}
{% for projects in projectFeatured %}
{% include projects-list.html %}
{% endfor %}
Though I encourage you to add a featured: True in your post and do something like that:
{% if post.featured == true %}
{% include post.html %}
{% endif %}
https://shopify.github.io/liquid/filters/first/
Below is my current solution (with featured: true) added to post frontmatter. It's really nasty but appears to work for now:
<div class="project-list">
{% if page.layout == "home" %}
{% assign projects = site.projects | where: "featured", "true" %}
{% for project in projects %}
{% include project/project.html %}
{% endfor %}
{% else %}
{% assign projects = site.projects %}
{% for project in projects %}
{% include project/project.html %}
{% endfor %}
{% endif %}
</div>

How to filter Taxonomies using Rust-based Zola / Tera?

I have recently discovered Zola and Tera (Rust frameworks for statically-generated websites) and found them amazing.
I'm trying to filter specific category pages to display in a section on the same page. To illustrate, I wrote some code like this:
<div class="content">
{% block content %}
<div class="list-posts">
{% for page in section.pages %}
{% for key, taxonomy in page.taxonomies %}
{% if key == "categories" %}
{% set categories = taxonomy %}
{% for category in categories %}
{% if category == "rust" %}
<article>
<h3 class="post__title">{{ page.title }}</h3>
</article>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}
</div>
{% endblock content %}
</div>
There should be MULTIPLE sections of the code above for different categories, e.g. "rust", "java", etc.
I wrote the code to explain my question, but it isn't the way I want it (and it doesn't work when the sections are duplicated).
How do I do the filtering of the particular category when the sections/pages are loaded?
The front-matter metadata in the content file is:
title = "A web page title"
[taxonomies]
categories = ["rust"]
If you see my example code above, I have to access it first via a hash map, then an array, in order to filter all pages which is "rust".
The filter below doesn't work:
for page in section.pages | filter(attribute="taxonomies.categories", value="rust"
I managed to resolve it. First, I did tests like this:
HTML test print output
{% set categories = get_taxonomy(kind="categories") %}
{% set rustItems = categories.items | filter(attribute="name", value="rust") %}
{% set javaItems = categories.items | filter(attribute="name", value="java") %}
{{ rustItems[0].pages | length }}
<br>
{{ rustItems[0].pages[0].title }}
<br>
{{ rustItems[0].pages[1].title }}
<br>
I was able to pick up the title as set in the .md file.
So I moved on further and I did:
{% set categories = get_taxonomy(kind="categories") %}
{% set category = categories.items | filter(attribute="name", value="business") | first %}
{% for page in category.pages %}
{{ page.title }}
... etc.
The above code will filter the pages for category taxonomy.

Jekyll array contains check

I've an array in my _config.yaml. Let's say
exclude_pages: [ "/404.html", "/search.html", "/atom.xml", "/rss.xml", "/index.html", "/sitemap.txt" ]
What I want to do is exclude these pages in the pages loop of site.pages. So following is the code that I'm trying.
{% for entry in site.pages %}
{% if site.exclude_pages contains entry.url %}
<!-- Do Nothing -->
{% else %}
<!-- Show Page -->
{% endif %}
{% endfor %}
But somehow it is not happening. All the pages are being ignored in this code.
Any idea what I'm missing here ?
Try :
exclude_pages: [ "index.html", "anyfolder/index.html" ]
Then loop with entry.path not entry.url:
{% for entry in site.pages %}
{% if site.exclude_pages contains entry.path %}
<!-- Do Nothing -->
{% else %}
<!-- Show Page -->
{% endif %}
{% endfor %}
According to template docs you my try to use Where Expression with contains and unless.
{{ assign entries = site.pages | where_exp:"item", "unless item.url contains site.exclude_pages" }}
{% for entry in entries %}
<!-- Show Page -->
{% endfor %}
See sample how a live code works to generate feed.json in my github site.

Why doesn't this Jekyll Liquid where filter filter?

I am trying to output a list of blog posts for a certain author. I tried this where Jekyll filter:
{% for post in (site.posts | where:"author", "mike") %}
{{ post.title }}
{% endfor %}
But it outputs every post. I'm not clear what I'm doing wrong.
Supposing that your post author is in your front matter, like this :
---
author: toto
...
---
If you want two last post by author == toto, just do :
{% assign counter = 0 %}
{% assign maxPostCount = 2 %}
<ul>
{% for post in site.posts %}
{% if post.author == 'toto' and counter < maxPostCount %}
{% assign counter=counter | plus:1 %}
<li>{{ counter }} - {{ post.title }}</li>
{% endif %}
{% endfor %}
</ul>
Et hop !
EDIT :
And another solution using the where filter instead of the if clause :
{% assign posts = site.posts | where: "author", "toto" %}
{% assign counter2 = 0 %}
{% assign maxPostCount2 = 3 %}
<ul>
{% for post in posts %}
{% if counter2 < maxPostCount2 %}
{% assign counter2=counter2 | plus:1 %}
<li>{{ counter2 }} - {{ post.title }}</li>
{% endif %}
{% endfor %}
</ul>
RE-EDIT: Justin is right I don't need my two vars (counter2 and maxPostCount2), I can use Liquid for loop limit:n option.
{% assign posts = site.posts | where: "author", "toto" %}
<ul>
{% for post in posts limit:3 %}
<Ol>{{ post.title }}</ol>
{% endfor %}
</ul>
Better !
You need to do an assign first for the filtered items
{% assign posts = site.posts | where:"author", "mike" %}
{% for post in posts %}
{{ post.title }}
{% endfor %}
It seems filters are to be used only inside output tags (those surrounded by {{ and }}. Which mean you could use something like :
{{ site.posts | where "author", "mike" }}
But you can't use it the way you're doing.
Source: liquid documentation on Filters

How do I add a link to an external site the main navbar in CKAN

I know that I can customize the set of navigation links at the top of the page in the standard template by overriding the header_site_navigation_tabs block e.g. as in the [datahub.io customization](https://github.com/okfn/ckanext-datahub/blob/3d64748fc1f3c4499780b199e971a5929ba69315/ckanext/datahub/templates/header.html#L9
)
{% block header_site_navigation_tabs %}
{{ h.build_nav_main(
('search', _('Datasets')),
('organizations_index', _('Organizations')),
('about', _('About'))
) }}
{% endblock %}
However, I want to add a link to this list to an external website? Can I just do (see extra entry at the end):
{% block header_site_navigation_tabs %}
{{ h.build_nav_main(
('search', _('Datasets')),
('organizations_index', _('Organizations')),
('about', _('About'))
('http://blog.datahub.io/', 'Blog')
) }}
{% endblock %}
No, you can't do that. The helper method looks for routes declared internally (config['routes.named_routes']). You can, however, simply add a li element, so the whole block would look like this
{% block header_site_navigation %}
<nav class="section navigation">
<ul class="nav nav-pills">
{% block header_site_navigation_tabs %}
{{ h.build_nav_main(
('search', _('Datasets')),
('organizations_index', _('Organizations')),
('about', _('About'))
) }}
<li>Blog</li>
{% endblock %}
</ul>
</nav>
{% endblock %}

Resources