Adding an Auto-Generated Sitemap to Your Jigsaw-based Static Site

Posted on May 18, 2018 | By Matt Stauffer

I love Tighten's static site generator, Jigsaw. I've tried a few other static site generators, and (of course, I'm biased) I think Jigsaw has the best combination of power and simplicity. Plus, it feels like I'm writing Laravel code—because, essentially, I am.

There are a few tasks that are still pretty tough with static sites—for example, search, and submitting forms (which we're trying to fix with FieldGoal). But there are other tasks that are tough-but-possible, and key among them are RSS and sitemaps.

Let's start with sitemaps. Our lead developer on Jigsaw, Keith Damiani, added a feature recently that allows you to add lifecycle hooks to your Jigsaw sites, and he even wrote up how to use those hooks to generate a sitemap. I wanted to try it out, so I did, and I extracted his instructions to this very simple post.

The simple steps

For such a powerful concept, I expected this to be a lot of work. Turns out it took less than fifteen minutes. Let's walk through it step by step:

1. Require the sitemap package

First, we're going to require on an external package for actually generating the sitemap. Let's pull in samdark/sitemap:

composer require samdark/sitemap

1b. A brief interlude: introduction to Jigsaw's event listeners

Next, we're going to take advantage of the hooks Keith introduced. The new hook system has three events you can listen for: beforeBuild, afterCollections, and afterBuild. Hopefully I can get him to write them up in more detail in a blog post, but for now if you're interested in learning more you can take a look at the pull request.

We'll be using afterBuild, which allows our system to have access to the full list of the output files when it goes to generate the sitemap. Since the listener we're building is a bit complex, we'll pull this functionality out to a class in a dedicated Listeners directory.

2. Create the GenerateSitemap class

Let's start by creating our listener. Make a new directory called Listeners, and create a new file in it named GenerateSitemap.php. Paste in the following:

<?php namespace App\Listeners;

use TightenCo\Jigsaw\Jigsaw;
use samdark\sitemap\Sitemap;

class GenerateSitemap
{
    public function handle(Jigsaw $jigsaw)
    {
        $baseUrl = $jigsaw->getConfig('baseUrl');
        $sitemap = new Sitemap($jigsaw->getDestinationPath() . '/sitemap.xml');

        collect($jigsaw->getOutputPaths())->each(function ($path) use ($baseUrl, $sitemap) {
            if (! $this->isAsset($path)) {
                $sitemap->addItem($baseUrl . $path, time(), Sitemap::DAILY);
            }
        });

        $sitemap->write();
    }

    public function isAsset($path)
    {
        return starts_with($path, '/assets');
    }
}

Let's read through this file. First, we're using the $jigsaw object to pull information out of Jigsaw, including our baseUrl from the config.

Next, we're creating an instance of our Sitemap dependency. Its constructor wants us to pass the path the file should be built to, so we're just putting it in build_{environment}/sitemap.xml.

Next, we work through all the files that are being output (which we get from $jigsaw's getOutputPaths()) and adding every file to the sitemap unless it lives in the assets directory.

Finally, we rely on the Sitemap package to write the file. Done! ... almost.

3. PSR-4 load the Listeners directory

Let's get this new directory into our actual app using PSR-4 autoloading. Modify your composer.json to add a PSR-4 autoloader; it'll look something like this when you're done:

{
    "require": {
        "tightenco/jigsaw": "^1.2",
        "samdark/sitemap": "^2.2"
    },
    "autoload": {
        "psr-4": {
            "App\\Listeners\\": "Listeners"
        }
    }
}

Now just run composer dump-autoload on the command line, and it's loaded up.

4. Register the GenerateSitemap class in bootstrap.php

Finally, let's register the afterBuild event listener in bootstrap.php:

$events->afterBuild(App\Listeners\GenerateSitemap::class);

Now, as the last step of every Jigsaw build, our GenerateSitemap class will be invoked and it'll generate our new sitemap.

5. Celebrate!

That's it! On your next build, you'll see sitemap.xml sitting in your build directory. Boom. Just that easy.

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
    <url>
        <loc>
            https://mattstauffer.com/why-i-love-jigsaw
        </loc>
        <lastmod>2017-05-23T00:00:00+00:00</lastmod>
        <changefreq>weekly</changefreq>
        <priority>0.6</priority>
    </url>
</urlset>

Comments? I'm @stauffermatt on Twitter


Tags: jigsaw