Jekyll group collections with the same frontmatter property - jekyll

I have a collection of markdown files in an _mycollection folder, each with a frontmatter value like category: category1, category: category2, etc. Currently I am using the following code to print out the content of each item.
{% for c in site.mycollection %}
<p>{{ c.content }}</p>
{% endfor %}}
What I need is to list all of these items under their categories, where items that share a category name go under the same category, like so:
category1
content from collection item 1 with "category1" in its frontmatter
content from collection item 4 with "category1" in its frontmatter
content from collection item 5 with "category1" in its frontmatter
category2
content from collection item 2 with "category2" in its frontmatter
content from collection item 3 with "category2" in its frontmatter
I am looking for how I can modify the code I mentioned above so that it includes a single heading for each category name and then places each collection item with that category under its respective category heading.

Try sorting output using Liquid's group_by filter.
{% for c in site.mycollection %}
<p>{{ c.content | group_by: "category" }}</p>
{% endfor %}}

Related

Get all categories belonging to one collection

Using jekyll, I would like to get all categories that belong to exactly one of my collections. Currently, I have two collections defined in my _config.yaml:
collections:
posts:
output: true
permalink: /blog/:title/
press_releases:
output: true
permalink: /press/:title/
I learned that by using site.categories I can access all categories that are currently mentioned in my posts. The problem is that I would like to get only those categories related to either one of these two collections. Meaning only categories from press_releases OR categories from posts. Is there something like site.posts.categories or site.press_releases.categories?
At the moment, it seems that by calling site.categories I only get those categories from my collection posts.
I searched for other similar cases but haven't found a single one so far. Does jekyll not support separating categories according to collections or am I having a wrong idea of how to use collections and categories?
No, Jekyll does not provide an attribute to access the categories for just one collection. However, this can be done with some liquid code.
{% for my_doc in site.press_releases %}
{% for category in my_doc.categories %}
{% capture my_categories %}
{% if my_categories %}
{{ my_categories | join: "," }},{{ category }}
{% else %}
{{ category }}
{% endif %}
{% endcapture %}
{% endfor %}
{% endfor %}
{% assign my_categories = my_categories | split: "," | uniq %}
{% for cat in my_categories %}
{{cat }}
{% endfor %}
Basically what we do here is, get all documents of the desired collection, cycle through all documents and get the categories as stored in frontmatter (or defaults) and collect them in an array. Note, array operations in liquid are a bit clumsy, why we need to convert an array to a string back and forth. In the above code, the final for-loop should give you all categories of your collection 'press_releases'.

How to group Jekyll pages by the first letter of the title?

I'm building a Jekyll site that has a page for each topic. I want to create an alphabetically grouped list of links to each page.
For example, if my topic titles are:
Aardvark
Beatle
Catfish
Cattle
I want to end up with a list of links organised as:
A
Aardvark
B
Beatle
C
Catfish
Cattle
So far, I have gotten code that looks like this:
{% assign topics_by_letter =
site.topics | group_by_expr: "topic", "topic.title | slice: 0, 1" %}
{% for letter in topics_by_letter %}
<div>
{{ letter.name }}
</div>
{% endfor %}
site.topics is the correct name of the page collection and evaluates as expected.
All topics have a valid title label.
Where I am stuck is that letter.name evaluates to empty and I just have a list of empty divs. The snippet {{ page.title | slice: 0, 1 }} works and gives you back the first letter of the topic title.
What am I missing?
Was a typo, group_by_expr should be group_by_exp.

Jekyll: Generator to link to all subpages in a static hierarchy

I'm trying to write a static site with Jekyll that has a few layers to it. What's the best way to generate links to all subpages within a section?
For example, if I have a site structure like this:
landing
- Topic A
- Content 1
- Content 2
- Content 3
- Topic B
- Content 1
- Content 2
- Content 3
What would be the best way to create links to each of the Content pages from its Topic page? And, is there a simple way to link to all the Topic pages from the landing?
These are not posts, just static pages. It would be really great if I could just do {% for topic.each %} ...etc. and print the links out.
I would not use posts for this purpose (as yaitloutou suggests). I would read the hierarchy from the directory structure (solution 1) or create two seperate collections (solution 2). You can let the collections from solution 2 share the same layout if you want that.
1. Using pages
Create a directory structure with index.md pages and loop over the Jekyll veriable called 'site.pages' to create the menu.
index.md
topic-a/index.md
content-1/index.md
content-2/index.md
content-3/index.md
topic-b/index.md
content-1/index.md
content-2/index.md
content-3/index.md
And loop over all pages like this:
<ul>
{% assign sitepages = site.pages | sort: 'order' %}
{% for sitepage in sitepages %}
<li {% if page.url == sitepage.url %} class="active"{% endif %}>
{{ sitepage.title }}
</li>
{% endfor %}
</ul>
If you want the nested structure, you can do something like this. Or if you want only the results for Topic A, you can do this:
<ul>
{% assign sitepages = site.pages | sort: 'order' %}
{% for sitepage in sitepages %}
{% if sitepage.url contains 'topic-a' %}
<li {% if page.url == sitepage.url %} class="active"{% endif %}>
{{ sitepage.title }}
</li>
{% endif %}
{% endfor %}
</ul>
2. Using collections (simplest solution and quickest build)
Create a collection Topic A and create another collection Topic B. Your config file should look like this:
collections:
topic-a:
output: true
permalink: /topic-a/:path/
topic-b:
output: true
permalink: /topic-b/:path/
Outputting the items of one topic goes like this:
{% assign atopics = site.topic-a | sort: 'order' %}
{% for atopic in atopics %}
<li {% if page.url == atopic.url %} class="active"{% endif %}>
{{ atopic.title }}
</li>
{% endfor %}
</ul>
You should create a _topic-a and a _topic-b directory with your content-1.md, content-2.md, etc. files.
Note that both solutions have YML variables called 'order', to determine the order of appearance of the items/pages. This looks like this:
---
title: mytitle
layout: mylayout
order: 50
---
mycontent
I'll propose here 2 ways, you can determine the "best" according to your specific needs/situation, and which one sound more adapted to them.
first of all, "posts" and "pages" are basically just collections of md/html files. with some variables associated to each one.
to generate files with this structure, you can:
1. Using _posts and page.categories
put all the sub-files in _posts (the 2017-01-01- is just a place holder)
_posts/
- 2017-01-01-content-a-1.md
- 2017-01-01-content-a-2.md
- 2017-01-01-content-a-3.md
- 2017-01-01-content-b-1.md
- 2017-01-01-content-b-2.md
- 2017-01-01-content-b-3.md
add appropriate categories to each file:
2.1. for posts caontent-a-* add category: topic-a (in this order) by adding this line in the yaml front matter at top of each of them:
---
layout: page # or any appropriate layout
category: topic-a
---
2.2. for posts caontent-b-* add category: topic-b
set a premalink to ignore the date, and create the desired structure, by adding the following line to _config.yml:
defaults:
-
scope:
path: "_posts" # to all the file in posts
values:
permalink: /landing/:categories/:title.html # set this as default permalink value
you still can specify a permalinks per post in its front matter, or just add the permalink line to each md folder front matter.
the above will generate the desired structure.
loop through all the
{% for entry in site.posts %}
{% if entry.category == type-a %}
<!-- do A stuff -->
{% elsif entry.category == type-b %}
<!-- do B stuff -->
{% endif %}
{% endfor %}
2. Using collections:
it's similar to the above, but instead of using the already existent _postscollection you'll start by creating a new collection (one advantage is that you'll not need to add a date )
any of the approaches above will generate this structure inside _site
landing/
type-a/
content-a-1/
index.html
content-a-2/
index.html
...
type-b/
...

How to have different layouts per category?

How to have different layouts for post categories?
For example, if i have "toys" and "swords" as categories for my posts, i'd like the page listing "toys" to have a different layout than the page listing "swords". Even better would be to have a default "products" layout if the post is in a category that does not have its own layout. Any ideas on how to implement this using jekyll?
As the semantic of your documents will not change between categories I think you have to address that with CSS.
sword_list.html
---
category: sword
layout: product_listing
title: swords list
---
{% include product_listing_loop %}
_includes/product_listing_loop.html
<div class="{{page.category}}">
<ul>
{% for post in categories[page.category] %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
</div>
You can even use the page.category as a class on the body element in the main template.
Edit : If your really need to have a different markup you can try :
sword_list.html
---
category: sword
layout: product_listing
title: swords list
---
{% assign include_name = 'category_' | append: {{page.category}} %}
{% include {{include_name}} %}
This will call _includes/category_sword.html

In Jekyll, I want to loop through items in a list and set assign tags for each item

In Jekyll, I want to loop through items in a list and assign variables to each of them.
In a data file, my list looks like this:
entries:
- title: Sidebar
subcategories:
- title: Overview
items:
- title: Introduction
url: /introduction/
linkname: intro
- title: Release Notes
url: /release_notes/
linkname: relnote
My looping logic looks like this:
{% for entry in sidebar %}
{% for subcategory in entry.subcategories %}
{% for item in subcategory.items %}
{% assign item.linkname = "{{item.title}}" %}
{% endfor %}
{% endfor %}
{% endfor %}
Then I want to insert the variable using {{intro}} or {{relnote}} on a page. Using this method, I should be able to generate variables for all the items in my sidebar, making it easy to embed links in my content.
However, this method doesn't seem to work. Nothing appears for the variable when I insert it. What am I doing wrong?
With Jekyll/Liquid, you cannot create a variable name from a variable value.