Grouping collection by category - jekyll

I have the following collection in my jekyll project:
portfolio
|- portrait
|-- daniel.md
|-- george.md
|- nature
|-- national-park.md
|- food
|-- lasagna.md
|-- buritto.md
|-- pizza.md
What I want is to render a portfolio page grouping my portfolio by categories [ such as: portrait, nature and food ].
I've only managed to render my portfolio in one flat level like this:
<ul>
{% assign portfolio = site.portfolio %}
{% for entry in portfolio %}
<li class="item">
<h4 class="post-title">{{ entry.title }}</h4>
</li>
{% endfor %}
</ul>

I've found a solution. I've added the category name in front matter for each of the markdown files:
---
category: portrait
---
Then, I've changed my liquid to this:
{% assign category = site.portfolio | group_by: 'category' %}
{% for item in category %}
<!-- This is the category name -->
<h2>{{item.name}}</h2>
<ul>
<!-- filter the categories, selecting only the current category in the loop -->
{% assign portfolio = site.portfolio | where: 'category', item.name %}
{% for entry in portfolio %}
<li class="item">
<h4 class="post-title">{{ entry.title }}</h4>
</li>
{% endfor %}
</ul>
{% endfor %}
Is there any other way not to use front matter but the name of the folders inside my collection?

Related

Generate headings from a Jekyll Collection item's front-matter

As you see below, this is a fairly simple collection setup with an unordered lists of events that live in the _events folder at the root level (output is set to false). Instead of using {{ page.title }} in the layout, I want the heading(s) to read as months.
For example, if I add a new item into the _events collection and include month: January in the front-matter, I want that to generate a “January” heading, and place that unordered list underneath the heading. Likewise, if I add a new collection item and include month: February in the front-matter, I want to generate a “February” heading with a new unordered list below that heading.
I know I need a bit of re-arranging of where the heading lives, and I'm thinking I need some type of if statement, but I’m at a roadblock. I can’t figure this one out.
Is this possible with Jekyll Collections?
Layout
{% include root.html %}
<div class="flex-main">
{% include header.html %}
<main class="o-main" role="main">
<div class="o-grid-six">
<h1 class="f1 o-grid-six__child c-headline">{{ page.title }}</h1>
</div>
{{ content }}
</main>
</div>
<div class="flex-footer">
{% include footer.html %}
</div>
View (Events)
---
layout: events
title: Events
order: 2
---
<ul class="c-event-list">
{% for events in site.events %}
<li class="c-event-list__flag">
<div class="c-event-list__flag--left">
<div class="c-event-list__calendar">
<span class="c-event-list__day">{{ events.weekday }}</span>
<span class="f2 c-event-list__date">{{ events.date-number }}</span>
</div>
<img class="c-event-list__image" src="{{ p.url | prepend: site.baseurl }}{{ events.thumb }}" alt="">
</div>
<div class="c-event-list__flag--body">
<div class="c-event-list__content">
<h3 class="f2 c-event-list__title">{{ events.title }}</h3>
<p>{{ events.description }}</p>
<a class="c-button u-mt-2" href="{{ events.link }}">Sign Up</a>
</div>
</div>
</li>
{% endfor %}
</ul>
Collection item (an event)
---
layout: default
thumb: /images/event__screen-printing-basics.jpg
link: https://www.eventbrite.com/e/screen-printing-basics-tickets-41882948025
title: Screen Printing Basics
weekday: Wednesday
month: January
date-number: '10'
description: Join us for an after hours session to learn everything you need to know about screen printing in the Make Lab. We will be coating screens with emulsion, printing artwork onto transparencies, burning the image into the screen, washing out the stencil, mixing ink, prepping our work station, registering the paper, and finally pulling prints. The artwork always varies, so you’ll leave with a one-of-a-kind screen printed poster that you made yourself!
---
Interface
The best way to accomplish this is to use real dateTime and group_by_exp filter.
DateTime
---
layout: default
thumb: /images/event__screen-printing-basics.jpg
link: ...
title: Screen Printing Basics
description: ...
date: 2018-03-21 20:00
---
Note that for some reason date: 2018-03-21 doesn't work.
group_by_exp filter
Simplified print logic can be :
{% assign eventsByYear = site.events | group_by_exp:"event", "event.date | date: '%Y'" %}
{% for year in eventsByYear %}
<h1>{{ year.name }}</h1>
{% assign eventsByMonth = year.items | group_by_exp:"event", "event.date | date: '%B'" %}
{% for month in eventsByMonth %}
<h2>{{ month.name }}</h2>
<ul>
{% for event in month.items %}
<li>{{ event.title }}-{{ event.date | date: "%A, %B %d, %Y"}}</li>
{% endfor %}
</ul>
{% endfor %}
{% endfor %}

How to determine active post category?

I have a dropdown menu for categories and posts within them. Need to check if category is active - the opened post to use active class for menu category.
Posts can have new categories, they are not predefined.
Front matter is standard:
---
layout: post
title: "Some post title"
date: 2016-04-06 13:41:07 +0300
category: Events
---
In order to show class for open post in menu, I use a common technique
{% if page.url == post.url %}
<li class="active">{{post.title}}</li>
{% else %}
<li>{{post.title}}</li>
{% endif %}
How to apply class for a dropdown category in which open post is present?
Here's full code of categories with nested post titles for output, I currently have:
<ul class="nav navbar-nav">
Categories
<li class="dropdown active">
{% for category in site.categories %}
<li>{{ category | first }}
<ul class="dropdown-menu">
{% for posts in category %}
{% for post in posts %}
{% if page.url == post.url %}
<li class="active">{{post.title}}</li>
{% else %}
<li>{{post.title}}</li>
{% endif %}
{% endfor %}
{% endfor %}
</ul>
</li>
{% endfor %}
</li>
</ul>
You can try this :
{% for category in site.categories %}
{% assign categoryName = category | first %}
<li>
<a href="#"
class="dropdown-toggle {% if page.category == categoryName %} active{% endif %}"
data-toggle="dropdown"
name="{{ categoryName }}">{{ categoryName }}</a>
...

Jekyll, Liquid - get posts belonging to category1 and category2

I produced an overview page for all posts from the category "Tutorials" like this:
<ul class="post-list">
{% for post in site.categories.Tutorials %}
<li>
<span class="post-meta">{{ post.date | date: "%b %-d, %Y" }}</span>
<h2>
<a class="post-link" href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a>
</h2>
{{ post.excerpt }}
</li>
{% endfor %}
</ul>
But now I would like to produce an index page for posts with both category "Tutorials" and category "German". But how?
The post I would like to have in this overview page is this one:
---
layout: post
title: 'German tutorial'
categories: [Tutorials, German]
---
Posts I would not like to have in this overview page are posts with a header like this:
---
layout: "post"
title: "English totorial"
categories: [Tutorials, English]
---
I tried for example:
{% for post in site.categories.Tutorials & site.categories.German %}
but this doesn't work...
I easily would switch to tags instead of categories, if this makes it easier.
Get the first category array : site.categories.Tutorials then sort German category posts out of it :
{% assign tutorials = site.categories.Tutorials %}
{% comment %}Creates an empty array{% endcomment %}
{% assign germansTutos = "" | split: "/" %}
{% for p in tutorials %}
{% if p.categories contains "German" %}
{% assign germansTutos = germansTutos | push: p %}
{% endif %}
{% endfor %}
<ul>
{% for post in germansTutos %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
You can also simply assign a tutorial category and a lang variable to your posts and filter them by the power of the where filter.
eg:
---
layout: post
title: "Post 1"
date: 2016-01-27 00:29:55 +0100
categories: Tutorials
lang: ge
---
Post one
You can then sort your posts like this :
{% assign tutorials = site.categories.Tutorials %}
{% assign germanTutos = tutorials | where: 'lang', 'ge' %}
<ul>
{% for post in germanTutos %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>

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>

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>