67

My blog is built with Jekyll on Github. In the navigation bar, the default order is Pages, Messages, About, Archives. I want to change the list to Pages, Archives, About, Messages. What should I do?

I think it is related to the code below

{% assign pages_list = site.pages %}

I think site.pages is what I should change, but I don't know how.

halfer
  • 19,824
  • 17
  • 99
  • 186
Ever
  • 1,164
  • 1
  • 9
  • 13
  • Some functionality related to ordering has been added to Jekyll : https://github.com/plusjade/jekyll-bootstrap/commit/4eebb4462c24de612612d6f4794b1aaaa08dfad4 – Wojtek Kruszewski Mar 16 '15 at 12:54

10 Answers10

147

You can create custom order of your menu items like this:

  1. In your pages front matter add the order field (you can name it as you prefer)
    ---
    layout: default
    published: true
    title: Page title
    order: 1
    ---
    
  2. When getting pages, apply the 'sort' filter
    {% assign sorted_pages = site.pages | sort:"order" %}
    {% for node in sorted_pages %}
      <li><a href="{{node.url}}">{{node.title}}</a></li>
    {% endfor %}
    

You'll end up with an ordered (ASC) list of pages, based on the 'order' field value you add to each page.

vvvvv
  • 25,404
  • 19
  • 49
  • 81
Victor Stegaru
  • 1,471
  • 2
  • 9
  • 4
  • 1
    This is hands down the best solution. Straightforward and it works perfectly. – Jazzer Mar 02 '16 at 14:38
  • 2
    For step 2 where does one "get pages" to apply the sort filter? I.e. where can the file be found that we modify for step two? – kentkr Oct 09 '20 at 21:03
  • I use Minima theme. After doing step 1, for step 2, I simply modify in header.html under _include folder (copy it from minima if you don't have it) the line: {%- assign default_paths = site.pages | map: "path" -%} to {%- assign default_paths = site.pages | sort:"order" | map: "path" -%} – LXJ Oct 15 '22 at 12:01
31

Update: Some ordering functionality seems to have been added to Jekyll: https://github.com/plusjade/jekyll-bootstrap/commit/4eebb4462c24de612612d6f4794b1aaaa08dfad4

Update: check out comment by Andy Jackson below – "name" might need to be changed to "path".

This seems to work for me:

{% assign sorted_pages = site.pages | sort:"name" %}
{% for node in sorted_pages %}
  <li><a href="{{node.url}}">{{node.title}}</a></li>
{% endfor %}

name is file name. I renamed pages to 00-index.md, 01-about.md etc. Sorting worked, but pages were generated with those prefixes, which looked ugly especially for 00-index.html.

To fix that I override permalinks:

---
layout: default
title: News
permalink: "index.html"
---

Sadly, this won't work with custom attributes, because they are not accessible as methods on Page class:

{% assign sorted_pages = site.pages | sort:"weight" %} #bummer
Wojtek Kruszewski
  • 13,940
  • 6
  • 38
  • 38
21

The order of your navbar menu is determined by the HTML template in _layout (which may be pulling in HTML fragments from _includes.

It sounds like your navbar is being programatically generated from the list of pages provided in site.pages using the liquid code

{% assign pages_list = site.pages %}

If you have only a small number of pages, you may prefer to just write the list out manually. site.pages is Jekyll's alphabetical list of all pages. Nothing stops you from just hardcoding this instead:

 <div class="navbar" id="page-top">
      <div class="navbar-inner">
        <div class="container">
          <a class="brand" href="/">EverCoding.net</a>
          <ul class="nav">
            <li><a href="/pages.html">Pages</a></li>        
        <li><a href="/archive.html">Archive</a></li>
        <li><a href="/about.html">About</a></li>
        <li><a href="/messages.html">Messages</a></li>

Whereas I'm guessing at the moment you have that list generated programmatically, perhaps by following the way Jekyll-bootstrap does with liquid code:

<div class="navbar">
      <div class="navbar-inner">
        <div class="container">
          <a class="brand" href="{{ HOME_PATH }}">{{ site.title }}</a>
          <ul class="nav">
            {% assign pages_list = site.pages %}
            {% assign group = 'navigation' %}
            {% include JB/pages_list %}
          </ul>
        </div>
      </div>
    </div>

The liquid code in this second example is handy if you really want to determine the menu each time, but if you have a static menu in a static order you are probably best coding it by hand as in my first example, rather than modifying the liquid code to sort.

If you could link to the Jekyll source, rather than the published blog, we could be more specific.

cboettig
  • 12,377
  • 13
  • 70
  • 113
  • Thanks. Ni have looked at the [Jekyll source](https://github.com/mojombo/jekyll/blob/master/lib/jekyll/site.rb) aboue about site.pages. Looks it cannot deal the site.pages array – Ever Nov 09 '12 at 07:46
  • I am afraid I don't follow your comment. Are you using the jekyll-bootstrap template? It accesses site.pages just fine. As per my suggestion above, I don't see why you need access to site.pages if you intend to work with the four static page choices you specify. – cboettig Nov 09 '12 at 18:01
  • thanks. I have chanage my blog with your first method. I give the comment above for learning. I just wonder why i cannot deal with an array in the jekyll.. – Ever Nov 14 '12 at 05:18
  • 1
    @Ever You can indeed deal with an array in Jekyll, it's simply more complicated. For instance, you could use a liquid filter to sort the `pages_list` array (https://github.com/Shopify/liquid/wiki/Liquid-for-Designers), but you don't want an alphabetical sort. You could manually specify the order, `pages_list[3], pages_list[2]` etc, or write a custom liquid filter and manipulate the string in a ruby script. I just think the above answer is easier to use and understand than the things I just mentioned. – cboettig Nov 14 '12 at 19:17
  • Sorry - I am just getting used to this, but it is not clear where the code chunks you suggest go (which files). Using jekyllbootstrap, I have found `_assets/JB/pages_list`. Would I put the liquid code in that file? Or, where would the html code go? – David LeBauer Oct 28 '14 at 16:39
  • They'd go in an HTML template page in `_layouts`. Or You could put those chunks each in their own file with names like `navbar.html` in _includes and then reuse them into in multiple `_layouts` with `{{ include navbar.html }}` (effectively copy-pastes them in). – cboettig Oct 28 '14 at 17:10
  • Hi, Thank you for your answer. I employed the code to change the links in `_includes/default.html`, but I see that it changes the nav bar only on the home page, not on any other page. Any help regarding how to change them site-wide would be very helpful. Thanks! – Satya Jan 25 '16 at 16:37
12

I'm using Jekyll v2.5.3 and you can also number your actual markdown files (order them that way) and since you're using the Front Matter block you can still keep the titles and permalinks as you want them.

The parser will order your page links that way.
I.e.:

01_about.md
02_photos.md
03_projects.md
99_contact.md
Gerben Jacobs
  • 4,515
  • 3
  • 34
  • 56
8

I made pages.yml file in the _data directory it is look like similar:

- url: pages/test.html
  title: Pages
  group: navigation
- url: pages/front.html
  title: Front
  group: navigation

And I changed the default.html (from site.pages to site.data.pages):

<ul class="nav">
  {% assign pages_list = site.data.pages %}
  {% assign group = 'navigation' %}
  {% include JB/pages_list %}
</ul>

And now I can use this yml file for the menu.

Ámon Tamás
  • 141
  • 3
  • 8
8

You could see the documentation: http://jekyll.tips/jekyll-casts/navigation/

There are good examples and explanations with navigation_weight.

---
layout: page
title: About
permalink: /about/
navigation_weight: 10
---

For minima:

<div>
     {% assign navigation_pages = site.pages | sort: 'navigation_weight' %}
        {% for p in navigation_pages %}
          {% if p.navigation_weight %}
            {% if p.title %}
            <a class="page-link" href="{{ p.url | relative_url }}">{{ p.title | escape }}</a>
            {% endif %}
          {% endif %}
        {% endfor %}
      </div>
mariope
  • 91
  • 1
  • 2
  • 6
4

For minima theme

Put:

header_pages:
 - pages.md
 - archive.md
 - about.md
 - messages.md

in _config.yml to override default order. That's all.

Minima README:

Customize navigation links

This allows you to set which pages you want to appear in the navigation area and configure order of the links.

For instance, to only link to the about and the portfolio page, add the following to you _config.yml:

  - about.md
  - portfolio.md

You can see how it works in header.html file from minima _includes.

Radek Daniluk
  • 405
  • 6
  • 14
3

You were on the right path. You could sort by a custom variable named, say, 'order'.

In header.html insert and extra row:

{% assign pages_list = (site.pages | sort: 'order') %}

Then replace site.pages with pages_list in the for statement:

{% for my_page in pages_list %}
   {% if my_page.title %}
      <a class="page-link" href="{{ my_page.url | relative_url }}">{{ my_page.title | escape }}</a>
   {% endif %}
{% endfor %}

Then add 'order' into the YAML front matter for each page, and set it a suitable value:

---
layout: page
title: About
permalink: /about/
order: 0
---
Laszlo
  • 769
  • 9
  • 19
2

The Jekyll Bootstrap 3 template requires that you include group navigation in the Jekyll header. Building on @Wojtek's answer, you can modify JB3's pages_list to use this group field to both filter, and sort.

Before calling pages_list, sort by group:

{% assign sorted_pages = site.pages | sort:"group" %}

Then, simply change one line in pages_list:

{% if group == null or group == node.group %} -> {% if group == null or node.group contains group %}

Now you can specify the group to be navigation-00, navigation-01, without having to rename your files or set up any permalinks, and you get sorting for free.

Jeff Brateman
  • 3,229
  • 2
  • 20
  • 26
0

I made a simple plugin some time ago to sort pages according to a page_order array you can define your _config.yml:

pages_order: ['index', 'summary', 'overview', 'part1', 'part2', 'conclusion', 'notes']

It exposes page.prev and page.next in templates to allow navigation:

{% if page.prev %}
 <a id="previous-page" href="{{page.prev}}.html">Previous</a>
{% endif %}

{% if page.next %}
 <a id="next-page" href="{{page.next}}.html">Next</a>
{% endif %} 

Note: Does not work on Github Pages.

Marc
  • 609
  • 1
  • 5
  • 10