Jekyll - Wrap variables - jekyll

Working with Jekyll, I have the following variable : {{ page.categories | category_links }}
I would like each result (each categories) to be wrapped in a li tag.
How could I do that ?

This is a way to show the categories as an unordered list:
<ul>
{% for category in page.categories %}
<li>{{ category }}</li>
{% endfor %}
</ul>

Related

How to list tags from both posts and collections

I have a tags.md which contain the code below, It list the tags from my _site/post.md
---
layout: default
title: Tags
---
{% for tag in site.tags %}
<h2>{{ tag[0] }}</h2>
<ul>
{% for post in tag[1] %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
{% endfor %}
And I also have a Collections for work stuff, like work.md in the jekyll root directory and the post in there is inside _work/
How can I make the tags.md list the tags from both _posts/*.md and _work/*.md?
I realize I can't do something like this
{% for tag in site.tags %}
{% for tag in work.tags %}
<h2>{{ tag[0] }}</h2>
<ul>
{% for post in tag[1] %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
{% endfor %}
{% endfor %}
Using site.documents should be your way to go, see https://jekyllrb.com/docs/variables/
site.documents
A list of all the documents in every collection.
Internally, posts are also treated as a collection here.
The first line below groups all documents by tag:
{% assign docs_by_tags = site.documents | group_by: 'tags' %}
{% for tag in docs_by_tags %}
<h2>{{ tag.name }}</h2>
<ul>
{% for item in tag.items %}
<li>{{ item.title }}</li>
{% endfor %}
</ul>
{% endfor %}
BUT the result shows quoted tag names, which is not what we want.
A better solution to group arrays
Someone else already found a good way to group arrays in posts and collections back in 2015, see https://github.com/mushishi78/jekyll-group-by-array/blob/master/group-by-array.html - the project's readme has some sample code using the include file.
The code "extracts" tags or other attributes and pushes data to arrays before data is returned to be displayed.
The solution with both post and collection tag
Just use site.documents in the include as first parameter
{% comment %}based on https://github.com/mushishi78/jekyll-group-by-array{% endcomment %}
{% include group-by-array.html collection=site.documents field='tags' %}
<ul>
{% for tag in group_names %}
{% assign posts = group_items[forloop.index0] %}
<li>
<h2>{{ tag }}</h2>
<ul>
{% for post in posts %}
<li>
<a href='{{ site.baseurl }}{{ post.url }}'>{{ post.title }}</a>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Reversing the posts order in the list
To reverse the post order under the tag, you can add a reversed to the for loop above:
{% for post in posts reversed %}

Display language filtered posts by category in Jekyll

I run a Jekyll blog in multiple languages using the setup making Jekyll multilingual by Sylvain Durand without use of any plugin.
All posts have the following markup:
---
title: Hello world!
lang: en
ref: hello
---
The posts are using the normal folder structure:
jekyll
|
-- posts
|
--name-of-post
--name-of-post-2
--name-of-post-3
I have a page named en.md which have layout: home and lang: en markup, which displays English posts correctly with the following code in home.html
{% assign posts=site.posts | where:"lang", page.lang %}
<ul>
{% for post in posts %}
<li>
{{ post.title }}
</li>
{% endfor %}
</ul>
But I would like instead to display posts by category, filtered on the language.
Tried to achieve this with the following:
{% assign posts=site.categories | where:"lang", page.lang %}
<div class="categories">
{% for category in site.categories %}
<li><a name="{{ category | first }}">{{ category | first }}</a>
<ul>
{% for posts in category %}
{% for post in posts %}
<li>{{ post.title }}</li>
{% endfor %}
{% endfor %}
</ul>
</li>
{% endfor %}
</div>
When I build, the following message is displayed
Liquid Exception: no implicit conversion of String into Integer in /_layouts/home.html
Tried many variants, but none seems to work.
This does the trick :
---
Title: English posts
lang: en
---
<ul>
{% for category in site.categories %}
{% comment %}
Here we have something like this
category = Array[
"category1",
[doc1, doc2]
]
{% endcomment %}
{% assign name = category[0] %}
{% assign posts = category[1] %}
{% comment %}
>> This also works
{% assign name = category.first %}
{% assign posts = category.last %}
{% endcomment %}
{% comment %}
>> Filtering posts based on their `lang` variable
>> and on the current `page.lang`
{% endcomment %}
{% assign selectedPosts = posts | where:"lang", page.lang %}
{% comment %}
>> Let's make sure that we need to print something
{% endcomment %}
{% if selectedPosts.size > 0 %}
<li>
Category {{ name }} :
<ul>
{% for post in selectedPosts %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
</li>
{% endif %}
{% endfor %}
</ul>
Short version :
<ul class="post-list">
{% for c in site.categories %}
{% assign selectedPosts = c.last | where:"lang", page.lang %}
{% if selectedPosts.size > 0 %}
<li>Category {{ c.first }} :
<ul>
{% for post in selectedPosts %}
<li>{{ post.title }} - {{ post.lang }}</li>
{% endfor %}
</ul>
</li>
{% endif %}
{% endfor %}
</ul>
WITH the built-in category solution of Jekyll
I found this partial solution, just like you did...:
{% for category in site.categories %}
<li><a name="{{ category | first }}">{{ category | first }}</a>
<ul>
{% for posts in category %}
{% for post in posts %}
<li>{{ post.title }}</li>
{% endfor %}
{% endfor %}
</ul>
</li>
{% endfor %}
What you want to do/did is filter the 'posts' variable with the page language. This can indeed be done with assign using a where filter, but should look like this (as 'lang' is a attribute of the individual post and not of the category):
{% assign lang_posts = posts | where:"lang", page.lang %}
This leads to the following code:
{% for category in site.categories %}
<li><a name="{{ category | first }}">{{ category | first }}</a>
<ul>
{% for posts in category %}
{% assign lang_posts = posts | where:"lang", page.lang %}
{% for post in lang_posts %}
<li>{{ post.title }}</li>
{% endfor %}
{% endfor %}
</ul>
</li>
{% endfor %}
WITHOUT the built-in category solution of Jekyll
If you have a random list of categories in your front matter, like this:
- categories:
- web
- css
- internet
... and your sites _config.yml contains a similar (but more complete) list, like this:
- categories:
- web
- css
- internet
- html5
- jekyll
You have a whole other problem. In that case you are NOT using the built-in category solution of Jekyll and this solution does not apply. A lot of the statements mean different things in that case, like this:
{% for category in site.categories %}
{{ category | first }}
It means you loop over all existing categories from the _config.yml, and category | first should then be category. In this situation you probably want something like this:
<ul class="categories">
{% for category in site.categories %}
<li><a name="{{ category }}">{{ category }}</a>
<ul>
{% assign posts=site.posts | where:"lang", page.lang %}
{% for post in posts %}
{% if post.categories contains category %}
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Note that this is just simple Jekyll/liquid array logic that overwrites the Jekyll category variables.

Having Jekyll categories count and linked to a list of posts related to it

I am working on a Jekyll project. This is a blog with posts which have categories.
I would like to succeed in having a sidebar on the right side listing the categories and the count of posts related to this category AND when clicking on the category itself, having the list of the posts related to this category.
For now, I succeeded in having the list of categories with their counts but not the display of the posts. Here is the code :
<ul class="tag-box inline">
{% assign tags_list = site.categories %}
{% if tags_list.first[0] == null %}
{% for tag in tags_list %}
{{ tag | capitalize }} <span>{{ site.tags[tag].size }}</span>
{% endfor %}
{% else %}
{% for tag in tags_list %}
<div>{{ tag[0] | capitalize }} <span> ({{ tag[1].size }}) </span></div>
{% endfor %}
{% endif %}
{% assign tags_list = nil %}
</ul>
I was looking for some solutions on Internet and some of them were explaining that I should create a folder category and under this folder as many folder as categories I have with an index.html to display the categories. However, this is a lot of duplicated content and I don't know if it is the best way to do.
Thank you for your help!
As you cannot use plugins, you will have to create one page for each category.
In order to avoid repeating content, you can factorize with help of layout chaining. Your category pages will use category_index.html as layout, that will itself use default.html.
Sidebar
<ul class="tag-box inline">
{% for category in site.categories %}
<div>{{ category[0] | capitalize }} <span> ({{ category[1].size }}) </span></div>
{% endfor %}
</ul>
If you want urls like category/toto/ you have to set permalink: pretty in _config.yml.
A category page : category/toto.html
---
layout: category_index
category: toto
---
That's all.
_layouts/category_index.html
---
layout: default
---
<div class="home">
<h1 class="page-heading">Posts in category : {{ page.category }}</h1>
<ul class="post-list">
{% for p in site.categories[page.category] %}
<li>
<h2>{{ p.title }}</h2>
</li>
{% endfor %}
</ul>
</div>

Jekyll, Liquid - Get all pages from category from page

I have a question in Jekyll Liquid.
I have layout, where I want to show pages from category. To show category I use page.categories variable. When I show in bracket {{page.categories}} is correct.
but I don't know, how to pass to loop?
{% for post in site.categories[page.categories] %}
<li>{{ post.title }}</li>
{% endfor %}
{% for post in site.categories[{{page.categories}}] %}
<li>{{ post.title }}</li>
{% endfor %}
Don't work.
If I passed explicite:
{% for post in site.categories['cat1'] %}
<li>{{ post.title }}</li>
{% endfor %}
It works.
I found another topic:
Jekyll site.categories.{{variable}}?
But it doesn't work.
page.categories is a list (see Page Variables), so you need to loop through it first and pass each category to the loop from your question:
{% for cat in page.categories %}
<h1>{{ cat }}</h1>
<ul>
{% for post in site.categories[cat] %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
{% endfor %}
This will first display all posts for the page's first category in descending order, then all posts for the page's second category in descending order, and so on.
Thank you. It's work.
Also I can use this code (use first on element of array, because in my case I have only one category per page):
{% assign pcat = page.categories %}
<ul>
{% for post in site.categories[pcat.first] %}
<li {% if post.url == page.url %}class="active"{% endif %}>{{ post.title }}</li>
{% endfor %}
</ul>

List tags within a specific category in Jekyll

I am migrating my Wordpress blog to Jekyll, which I like a lot so far. The current setup in the new site is like this:
use category to distinguish two types of posts (e.g., blog and portfolio)
use tag as normal
The challenge right now is to display all tags within a category because I want to create two separate tag clouds for two types of posts.
As far as I know, Liquid supports looping over all tags in a site like this:
{% for tag in site.tags %}
{{ tag | first }}
{% endfor %}
But I want to limit the scope to a specific category and am wishing to do something like this:
{% for tag in site['category'].tags %}
{{ tag | first }}
{% endfor %}
Any advice will be appreciated.
This seems to work for all kinds of filters like category or other front matter variables - like "type" so I can have type: article or type: video and this seems to get tags from just one of them if I put that in the 'where' part.
{% assign sorted_tags = site.tags | sort %}
{% for tag in sorted_tags %}
{% assign zz = tag[1] | where: "category", "Photoshop" | sort %}
{% if zz != empty %}
<li><span class="tag">{{ tag[0] }}</span>
<ul>
{% for p in zz %}
<li>{{ p.title }}</li>
{% endfor %}
</ul>
</li>
{% endif %}
{% endfor %}
zz is just something to use to filter above the first tag[0] since all it seems to have is the tag itself, so you can filter anything else with it. tag[1] has all of the other stuff.
Initially I was using if zz != null or if zz != "" but neither of them worked.
This will work, it will list only the tags on post of category 'X'. Replace X with the name of the category.
{% for post in site.categories['X'] %}
{% for tag in post.tags %}
{{ tag }}
{% endfor %}
{% endfor %}