I'm using Jekyll on GitHub pages, and I want to have hierarchical categories like this:
I'd like users to be able to visit /animals
and see a listing of every post from every category. But if they go to /animals/mammals
, they'd only see mammals. If they go to /animals/mammals/cats
, then they only see cats.
I know I can do this manually by putting an index.html
file in every single directory and then looping through site.categories.mammals
or site.categories.cats
, for example.
But that seems a little bit too brute force, and I'm hoping there's a better way. If I want to change how I'm showing the listings, I'll have to change that in every single subcategory. I'll also have problems when subcategories share a name, like /ABC/XYZ/_posts/one.md
and /DEF/XYZ/_posts/two.md
.
I've tried to follow this article, which uses one main category.html
page that loops through page.category
:
{% for post in site.categories.[page.category] %}
<h2><a href=""></a></h2>
<p></p>
{% endfor %}
Then every index.html
file uses this as its layout. That almost works, but it seems limited to one category, not multiple hierarchical categories.
Is there a less brute-force approach to creating listings for hierarchical categories?
page.categories is a list
https://stackoverflow.com/a/23927986
{% for cat in page.categories %}
<h1>{{ cat }}</h1>
<ul>
{% for post in site.categories[cat] %}
<li><a href="{{ post.url }}">{{ post.title }}</a></li>
{% endfor %}
</ul>
{% endfor %}
From jekyll's documentation about page.category http://jekyllrb.com/docs/variables/#page-variables
The list of categories to which this post belongs. Categories are derived from the directory structure above the _posts directory. For example, a post at /work/code/_posts/2008-12-24-closures.md would have this field set to ['work', 'code']. These can also be specified in the YAML Front Matter.
You should be easily able to add a simple dynamic index.html to every folder and the categories should be hierarchical automatically.
The above does NOT work. You need to treat the combination of categories of each hierarchy as a unique item. Concat the index page's categories, and compare that against all the posts in the site.
/foo/bar/_posts/2016-08-01-foo-bar-test.html
---
categories:
- foo
- bar
title: test foo bar
---
<h2>Foo Bar</h2>
/var/bar/_posts/2016-08-01-test-var-bar.html
---
categories:
- var
- bar
title: test var bar
---
<h2>Var Bar</h2>
/foo/bar/index.html
---
categories:
- foo
- bar
---
{% assign pagecat = page.categories | join ' ' | append: ' '%}
{% assign pagecatlen = page.categories.size %}
<h1>{{ cat }}</h1>
<ul>
{% for post in site.posts %}
{% assign postcat = '' %}
{% for thispostcat in post.categories limit: pagecatlen %}
{% assign postcat = postcat | append: thispostcat %}
{% assign postcat = postcat | append: ' ' %}
{% endfor %}
{% if (postcat == pagecat) %}
<li><a href="{{ post.url }}">{{ post.title }}</a></li>
{% endif %}
{% endfor %}
</ul>
The categories are optional for the files in _posts, but they are required for the front matter of each index file.
Modify your _config.yml accordingly
collections:
animals:
output: true
mammals:
output: true
cats:
output: true
dogs:
output: true
reptiles:
output: true
lizards:
output: true
then created the structure:
mkdir -p _animals/reptiles/lizards
mkdir -p _animals/mammals/cats
mkdir _animals/mammals/dogs
add your md files and all index.html which will index items with filter. It should look like this (maybe with more indexes) :
_animals/
├── index.html
├── mammals
│ ├── cats
│ │ ├── housecat.md
│ │ └── tiger.md
│ ├── dogs
│ │ ├── doberman.md
│ │ └── poodle.md
│ └── index.html
└── reptiles
└── lizards
├── chameleon.md
└── iguana.md
then you create _includes/list_animals.html
{% assign animals = site.animals| sort:'title' %}
{% for animal in animals %}
{% if page.url != animal.url and include.taxonomy == nil or animal.url contains include.taxonomy %}
<a href={{ animal.url | prepend: site.baseurl }}>{{animal.title}}</a>
{% endif %}
{% endfor %}
to list all animals in animals/index.html
:
---
title: animals
---
{% include list_animals.html %}
For example, to list all mammals in animals/mammals/index.html
:
---
title: animals
---
{% include list_animals.html taxonomy="mammals" %}
Finally the generated structure should look like this (with some more index.html):
_site
└── animals
├── index.html
├── mammals
│ ├── cats
│ │ ├── housecat.html
│ │ └── tiger.html
│ ├── dogs
│ │ ├── doberman.html
│ │ └── poodle.html
│ └── index.html
└── reptiles
└── lizards
├── chameleon.html
└── iguana.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With