TTWeb Basics 6. Site Menus

Defining Menus

In addition to Content Models and Pages, another type of Content is “Menus”. In the UI you can find this in the content area. The CMS allows users to specify any number of menus for the site, as long as the developer has them set up.

The menu content is stored in _data/_menus.yml and looks like this:

main:             # The menu ID used in layouts
  depth: 2        # How nested can the user make the menu
  name: Top Menu  # The label in the CMS
  items:          # List of menu items - these will change when the user edits it in the CMS
    - <menu item object - see below>
    - <menu item object - see below>


footer:
  depth: 1
  name: Footer links
  items:
    - <menu item object - see below>
    - <menu item object - see below>
    - <menu item object - see below>

Each menu item can be one of 3 types - an external URL link, a link to a page in the site, or a “folder”. Each type can have custom localized copy and URLs. Each type might have nested menu items specified by the “items” key, and both url and label can be localized (or not). Lastly, each type may have a target: attribute specified. See complete example below.

In it’s simplest form:

page_id: _pages/about.html

This will generate URLs and labels based on the page settings (front matter) for _pages/about.html. But the user can also specify explicit content, e.g.

page_id: _pages/about.html
url: https://some-other-site.com
label: About

In it’s simplest form:

url: https://google.com
label: Google

Folders

Folder only get a label, e.g.

label: Grouped Items

Complete Example

main:             # The menu ID used in layouts
  depth: 2        # How nested can the user make the menu
  name: Top Menu  # The label in the CMS
  items:          # List of menu items - these will change when the user edits it in the CMS
    - page_id: _pages/offers.html    # Page Menu Item that also has subnav
      items:
        - page_id: _pages/offer1.html
        - page_id: _pages/offer2.html
    - page_id: _pages/gallery.html   # Page Item
      url: /gallery/
      label_localized:
        en: Gallery
        es: Gallery (ES)
    - url_localized:                 # External Link Menu Item
       en: https://www.google.com
       es: https://www.google.es
     label_localized:
       en: Google US
       es: Google ES
     target: _NEW
    - label_localized:               # Group Menu Item (not clickable) with subnav
       en: Group
       es: Group (ES)
     folder: true
     items:
       - page_id: _pages/about.html
       - url: /test/
         label_localized:
           en: Test
           es: Prueba

Rendering Menus

Generally you should be able to use the bedrock menu include files to generate menus as you need them. An example is included below (simplified to just highlight the jekyll tags). Ultimately, the _menus.yml content is accessible just like any other Jekyll data. The nav-item-list file reflects the logic of when an item is a page vs external link vs group and how to handle nested items.

nav-main.html:


<nav>
  <ul class="nav greedy-nav__links align-items-center text-uppercase justify-content-end pr-2">
    {% assign items = site.data._menus.main.items %}
    {% include nav/nav-item-list.html items=items %}
  </ul>
</nav>

nav-item-list.html


{% assign items=include.items %}

{% for item in items %}
  {% if item.page_id %}
    {% for page in site.pages %}
      {% if page.path == item.page_id %}
        {% assign url = page | permalink %}
        {% assign text = item.label| default: page.title | default: page.name %}   
      {% endif %}
    {% endfor %}
  {% else %}
    {% assign url = item.url %}
    {% assign text = item.label %}
  {% endif %}   
  <li class="nav__item{% if item.items %} has-subnav{% endif %}">
    {% if item.folder %}
      <span class="nav__link--group nav__link{% if page.url == url %} active{% endif %}" >{{text}}</span>
    {% else %}
      <a class="nav__link{% if page.url == url %} active{% endif %}" href="{{url}}" {% if item.target %}target="{{ item.target }}"{% endif %}>{{text}}{% if page.url == url %}<span class="sr-only">(current)</span>{% endif %}</a>
    {% endif %}
    {% if item.items %}
      <ul class="subnav">
        {% include nav/nav-item-list.html items=item.items %}
      </ul>
    {% endif %}
  </li>                 
{% endfor %}