Skip to content

Kirby 3.9.8

Sitemap for search engines

For basic search engine optimization it's good to have a sitemap.xml file, which contains machine-readable information about all the pages and the structure of your site.

The syntax for such a sitemap.xml file is fairly simple. You can find all about it on http://www.sitemaps.org/.

Because you probably don't want to generate that file by hand, you can create a snippet that indexes your entire site and generates a sitemap.xml for you in a few steps:

Create the snippet with your XML

Create a new snippet with the following content in /site/snippets:

/site/snippets/sitemap.php
<?= '<?xml version="1.0" encoding="utf-8"?>'; ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <?php foreach ($pages as $p): ?>
        <?php if (in_array($p->uri(), $ignore)) continue ?>
        <url>
            <loc><?= html($p->url()) ?></loc>
            <lastmod><?= $p->modified('c', 'date') ?></lastmod>
            <priority><?= ($p->isHomePage()) ? 1 : number_format(0.5 / $p->depth(), 1) ?></priority>
        </url>
    <?php endforeach ?>
</urlset>

The variables in this snippet are defined and passed to the snippet() helper in the route below.

Create new routes

In your config.php, create these two new routes:

/site/config/config.php
<?php

return [
  'routes' => [
    [
      'pattern' => 'sitemap.xml',
      'action'  => function() {
          $pages = site()->pages()->index();

          // fetch the pages to ignore from the config settings,
          // if nothing is set, we ignore the error page
          $ignore = kirby()->option('sitemap.ignore', ['error']);

          $content = snippet('sitemap', compact('pages', 'ignore'), true);

          // return response with correct header type
          return new Kirby\Cms\Response($content, 'application/xml');
      }
    ],
    [
      'pattern' => 'sitemap',
      'action'  => function() {
        return go('sitemap.xml', 301);
      }
    ]
  ]
];

You can now test the sitemap of your Kirby site by visiting http://yourdomain.com/sitemap.xml or http://yourdomain.com/sitemap. The second route redirects to the first.

Excluding pages from your sitemap

You can do that in your config. Here we call the option sitemap.ignore.

/site/config/config.php
return [
  'sitemap.ignore' => ['error'],
];

Automatic Priorities

The sitemap template will automatically try to create priorites for each page, by using the ->depth() attribute. The depth attribute is a simple number, which indicates how deep the page is nested. Main pages have a depth of 1, subpages of main pages have a depth of 2, etc.

The home page will automatically get a priority of 1. You can easily change priorities or remove them entirely if you prefer.

Submitting your sitemap to a search engine

To let your favorite search engines know about your brand-new sitemap, please read the instructions on sitemap.org.

Extending the basic example

This is a very basic example. If you need something more complex, you can either use one of the plugins provided by the community, or extend it yourself, for example, by fine-tuning the options for pages you want to ignore (e.g. filter by template), or adding images.

Final config

Make sure that your config file only has one return array with all your options:

/site/config/config.php
<?php

return [
  // … your other settings
   'routes' => [
    [
      'pattern' => 'sitemap.xml',
      'action'  => function() {
          $pages = site()->pages()->index();

          // fetch the pages to ignore from the config settings,
          // if nothing is set, we ignore the error page
          $ignore = kirby()->option('sitemap.ignore', ['error']);

          $content = snippet('sitemap', compact('pages', 'ignore'), true);

          // return response with correct header type
          return new Kirby\Cms\Response($content, 'application/xml');
      }
    ],
    [
      'pattern' => 'sitemap',
      'action'  => function() {
        return go('sitemap.xml', 301);
      }
    ]
  ],
  'sitemap.ignore' => ['error'],
];