jekyllliquid

Excluding page from Jekyll navigation bar


I am setting up a basic Github-hosted Jekyll website (so minimal, I am not even bothering to change the default theme). I have a nested site with a small number of first-tier pages that I would like to appear in the navigation bar (i.e. the default mode of operation). I also have some second-tier pages that I would like to NOT junk up the navigation bar.

While a multi-level navigation system would be nice, I'm trying to avoid using plugins. Therefore, I believe the simplest solution is to just exclude tier two pages from the navigation system entirely.

Here's a hypothetical page structure (minus the other Jekyll files):

jekyllsite
jekyllsite/bar
jekyllsite/bar/alice
jekyllsite/bar/alice/index.md
jekyllsite/bar/bob
jekyllsite/bar/bob/index.md
jekyllsite/bar/index.md
jekyllsite/baz
jekyllsite/baz/index.md
jekyllsite/foo
jekyllsite/foo/eggs
jekyllsite/foo/eggs/index.md
jekyllsite/foo/index.md
jekyllsite/foo/spam
jekyllsite/foo/spam/index.md
jekyllsite/index.md

In descending order of awesome, this is how I'd like this to go down:

  1. Best case, context sensitive navigation (don't think possible without plugins): When visiting jekyllsite/index.md, I would get a single layer navigation bar offering me links to foo, bar, and baz. When visiting jekyllsite/bar/index.md, I would see a two-tiered navigation bar containing foo, bar, and baz at the top level, and with alice and bob in the second tier.

  2. The next best option would be for me to change something globally, such that only top-level directories (foo, bar, baz) got added to the nav bar. Subdirectories such as alice, bob, spam, and eggs would be automatically excluded from the nav bar.

  3. Finally (and I think this might be the easiest) would be for a YAML frontmatter flag to exclude a page. Something like nonav: true in the frontmatter of the page to be excluded.

This seems like it would have to be a fairly common use case, though I haven't been able to find anything that looks like a short path to either of these three options. I'm hoping someone more familiar with Jekyll has a "path of least resistance" answer.


Solution

  • It is possible to create a multi-level, context-sensitive navigation like you described without plugins, I have done it.

    The only caveat is that you need to maintain a YAML data file with your menu hierarchy - with my approach, it's not possible to generate this automatically from your directory structure.

    I'll show the short version here, but I have a way more detailed explanation on my blog:


    1. Create a YAML data file (/_data/menu.yml) which contains your menu hierarchy:

    - text: Home
      url: /
    - text: First menu
      url: /first-menu/
      subitems:
        - text: First menu (sub)
          url: /first-menu/first-menu-sub/
          subitems:
            - text: First menu (sub-sub)
              url: /first-menu/first-menu-sub/first-menu-sub-sub/
    - text: Second menu
      url: /second-menu/
      subitems:
        - text: Second menu (sub)
          url: /second-menu/second-menu-sub/
    

    2. Create an include file (/_includes/nav.html) with the following content:

    {% assign navurl = page.url | remove: 'index.html' %}
    <ul>
    {% for item in include.nav %}
        <li>
            <a href="{{ item.url }}">
                {% if item.url == navurl %}
                    <b>{{ item.text }}</b>
                {% else %}
                    {{ item.text }}
                {% endif %}
            </a>
        </li>
        {% if item.subitems and navurl contains item.url %}
            {% include nav.html nav=item.subitems %}
        {% endif %}
    {% endfor %}
    </ul>
    

    This include file will take care of showing the correct navigation for each page:

    If you don't understand what exactly the include file is doing under the covers, read my blog post - I explained it there, in great detail (in the section "The recursive include file").


    3. In your main layout file, embed the include file:

    {% include nav.html nav=site.data.menu %}
    

    This will display the navigation there.
    Note that I'm passing the complete data file from step 1 to the include.


    That's all!

    As I said in the beginning:

    The only disadvantage of this approach is that each time you create a new page, you also need to insert the page's title and URL into the data file.

    But on the other hand, this makes it very easy to exclude some pages from the navigation: you just don't add them to the data file.