Managing Navigation Menus In Jigsaw cover image

Managing Navigation Menus In Jigsaw

Tutorial | May 13, 2019

Remember the old days when everything was hard-coded? Every. Single. Page. Those days are long gone, at least if you use a CMS. But what about static site generators like Jekyll or, in my case, Jigsaw? Isn't static the opposite of dynamic? How can we make a static site more dynamic? Let me show you how I manage navigation in Jigsaw in a dynamically-static way.

What is dynamically-static?

Technically, that's not a thing. You can't actually have both, but you can get close. Simply use your config as a database. I'll explain what I mean later.

The old way of managing menus

I'm sure you've been in this situation before. You have your main nav in your header. Maybe you even have it in a master layout.

// master.blade.php

<nav>
  <a href="/">Home</a>
  <a href="/about">About</a>
  <a href="/contact">Contact</a>
</nav>

But now you need the same nav in the footer. What now?

You could just duplicate the main nav and place it in your footer, changing styles as needed. But what if you need to change the title of a link? Or the link itself? What if you need to add a new item? Or remove one?

You would have to make the change twice! There has to be a better way.

Remember when I said you could use your config as a database? Bingo!

Using your config as a database

Your typical Jigsaw config looks something like this...

<?php

  return [
    'baseUrl' => 'http://sample.com',
    'production' => false,
    'siteName' => 'My Awesome Site',
    'siteDescription' => 'This site is the most awesome site on the whole internet!',
    'siteAuthor' => 'John McAwesome',
  ];

Because the config file is simply an array, we can add whatever key-value pairs we want to it. It's like a file based database.

So how can we manage menus with this?

Like I said, the config file is just an array. We can add whatever we need to it. For a menu, we could add this:

// The rest of the config goes here...

'siteMenu' => [
  [
    'link' => '/',
    'title' => 'Home',
  ],
  [
    'link' => '/about',
    'title' => 'About',
  ],
  [
    'link' => '/projects',
    'title' => 'Projects',
  ],
  [
    'link' => '/blog',
    'title' => 'Blog',
  ],
  [
    'link' => '/contact',
    'title' => 'Contact',
  ],
],

Now our menu lives in one place so we only have to make changes once. But we have a problem now.

How do I render the nav?

That's where the power of Laravel's Blade templating comes in handy. Let's look at the main menu on this site for an example.

<nav class="hidden md:flex items-center justify-end text-sm">
  @foreach ($page->siteMenu as $menuItem)
    <a title="{{ $page->siteName }}" href="{{ $menuItem->link }}"
      class="ml-6 font-normal text-grey-darker hover:text-blue hover:no-underline {{ $page->isActive($menuItem->link) ? 'active text-blue font-bold' : '' }}">
        {{ $menuItem->title }}
    </a>
  @endforeach
</nav>

Let's walk through this snippet bit by bit. Jigsaw gives us access to anything in our config via the $page variable. This allows us to access the site name as $page->siteName.

Since we called our menu array siteMenu, we loop through $page->siteMenu as $menuItem (you can call it whatever you want). That gives us access to each iterations key-value pairs, link and title in this case. That $page->isActive part? That comes straight from the Jigsaw docs. It's a function defined in our config that checks if the argument passed matches the URI of the current page. More on adding functions to your config at another time.

Is it really that simple?

Yes! It really is. Jigsaw may be a static site generator, but it is so powerful that you really don't need a full blown CMS like Wordpress if you don't mind getting your hands dirty with some code.