How to generate sitemap.xml with Bridgetown

bridgetown, sitemap

28 Mar 2021

During playing with Bridgetown (that I am using on this site), I needed to add a sitemap.xml file for search engines.

As Bridgetown does not have any official solution, Konnor recommended me a solution from _wout_ (thank you!). The solution described in this post is based on it heavily.

Preparing data for sitemap

I wanted to extend the sitemap.xml file to include the lastmod (and changefreq) for each item. Firstly, I needed to have the ability to ignore some of the pages defined in my menu. I added sitemap.ignore attribute for it:

- title: Home
  href: "/"
  content: '<i class="fas fa-user-circle"></i>'
  sitemap:
    changefreq: weekly
    ignore: false
- title: Blog
  href: "/blog/"
  content: '<span>Blog</span>'
  sitemap:
    changefreq: daily
    ignore: false
- title: Resume on LinkedIn
  href: "https://www.linkedin.com/in/petr-hlavicka/"
  content: '<span>Resume</span> <i class="fas fa-external-link-square-alt text-xs ml-1"></i>'
  sitemap:
    ignore: true

I also added changefreq, but I am not sure, how much the attribute is valid for Google. In the worst case, it will be ignored.

The lastmod attribute was a little bit more tricky for me, as I am not much experienced with Liquid. As the easiest way, with my knowledge, I choose to have a new post attribute that I called published_at. I wanted to have the date as the initial published date and the last updated date at the same time, to be able to sort posts by only one date.

In terms of a template, I ended up with this code:

<p class="text-indigo-gray-600 dark:text-white mb-2 font-medium">
  {% if post.published_at %}
    {{ post.published_at | date: "%e %b %Y" }}
    <em>・ Updated on {{ post.date | date: "%e %b %Y" }}</em>
  {% else %}
    {{ post.date | date: "%e %b %Y" }}
  {% endif %}
</p>

Whenever I want to have the “updated on” for my post, I simply set the published_at for the initial publishing date and change date to the date I updated the post.

Sitemap generation

---
layout: false
permalink: "/sitemap.xml"
---

<?xml version="1.0" encoding="UTF-8"?>
<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">

  {%- assign newest_post = site.posts | sort: "date" | last -%}

  {%- for item in site.data.menu %}
    {%- if item.sitemap.ignore -%}
      {%- continue -%}
    {%- endif -%}
    <url>
      <loc>{{ site.url }}{{ item.href }}</loc>
      <lastmod>{{ newest_post.date | date_to_xmlschema }}</lastmod>
      <changefreq>{{ item.sitemap.changefreq }}</changefreq>
    </url>
  {%- endfor %}
  {%- for post in site.posts -%}
    <url>
      <loc>{{ site.url }}{{ post.url }}</loc>
      <lastmod>{{ post.date | date_to_xmlschema }}</lastmod>
      <changefreq>weekly</changefreq>
    </url>
  {%- endfor -%}
</urlset>

Line #12 will select the lastly updated post so I can set this date as lastmod to all pages in the menu. This is, in my case, useful now only for the blog index page, but I would like to have the last post also on the homepage in the future.

Line #15 skips menu items with external links.

Having the post.date with the newest date also simplify the generation for posts (line #27).

You can see generated sitemap.xml of this site here.

If you know about a better way or you have any comments, don’t hesitate to contact me on Twitter. Thanks!


Do you like it? You can subscribe to RSS (you know how), or follow me on Dev.to or Twitter.