Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I create nested collections in Jekyll?

Tags:

jekyll

I would like to use Jekyll to create a manual that contains several chapters, each of which contains several sections, and store each section in a separate Markdown file. I want index.md to look something like this:

<ol>
{% for chapter in site.chapters %}
  <li>
    <a href="{{chapter.url}}">{{chapter.title}}</a>
    <ol>
    {% for section in chapter.sections %}
      <li><a href="{{section.url}}">{{section.title}}</a></li>
    {% endfor %}
    </ol>
  </li>
{% endfor %}
<ol>

If each chapter is a Markdown file in _chapters, and I add the right lines to _config.yml, I can iterate over the chapters, pull out the title field from the YAML header, etc. Is there a way to nest this? I've tried creating sub-directories under _chapters with various names, but (a) Jekyll doesn't pick them up as sub-collections and (b) there's no obvious place to store chapter-level information (like the chapter's overall title).

(Note: I think I can do this by explicitly enumerating chapters and sections in a block of YAML in _config.yml, or by creating a separate YAML file in _data, but I don't want to have to worry about keeping that enumeration in sync with the actual chapters and sections: I'd like Jekyll to pick up changes automatically.)

like image 743
Greg Wilson Avatar asked May 17 '16 13:05

Greg Wilson


1 Answers

So the best way I know how to do this is to invert your thinking.

You're not writing chapters, you're writing sections and organising them into chapters.

Assume you have a setup like this:

  • _sections
    • section01.md
    • section02.md
    • section03.md
    • section04.md

But you want it output like this:

  • _site
    • chapters
      • chapter1.html (contains section01.md followed by section03.md)
      • chapter2.html (contains section02.md followed by section04.md)

If that's the case, you can do so using collections. Set the chapter property in the frontmatter of section01.md and section03.md to 01 and the chapter property in the frontmatter of section02.md and section04.md to 02.

The problem is generating the pages for the chapters. You do need to make a page for each chapter, but it's not bad if you use a layout.

Here's the layout I used (in _layouts/chapter.html):

---
layout: default
---

<h1>Chapter {{ page.chapter }}</h1>

{% for section in site.sections %}
{% if section.chapter == page.chapter %}
{{ section.output }}
{% endif %}
{% endfor %}

Then in _chapters, I have chapter01.md, which looks like this:

---
chapter: 01
layout: chapter
---

Just copy that to chapter02.md and set the chapter property to 02, and now you have Chapter 2.

The only other thing required to make this work is updating your config:

collections:
        sections:
                output: false
        chapters:
                output: true

When you run jekyll build, you'll now have _site/chapters/chapter01.html and _site/chapters/chapter02.html. As new sections get created, they'll be added to whatever chapter is in their frontmatter.

This is all really confusing, so I set up a sample at http://paddycarver.github.io/jekyll-nested-collections-example/ with source code at https://github.com/paddycarver/jekyll-nested-collections-example.

like image 68
Paddy Avatar answered Nov 10 '22 08:11

Paddy