Update: Read this tutorial on how to get this setup in Ghost 0.5+, which also includes a change that adds the base url to the sitemap.

My friend Timothy Strimple posted a great tutorial for adding a dynamic sitemap to your Ghost blog. Ghost serves its purpose of strictly blogging well, but it's young and lacks a lot of features, one of them being sitemap support. With Tim's tutorial, a temporary, yet viable, solution can be had today.

I wanted to expand on Tim's tutorial by including more blog posts and static pages, and specify different priority levels for the content type. Also, I am going to assume you followed the tutorial and have a fully functional sitemap running. If not, take the few minutes needed to do so now.

One last note: all changes occur in /core/server/controllers/frontend.js

To change the priority for a static page and a blog post, modify the buildSitemap() method to check the value of post.page. Static pages have a value of 1, while blog posts have 0. For my purposes, I have given static pages a higher priority than blog posts. These changes occur in the buildSitemap() method:

if (posts.length > 0) {
    var post = posts.shift();
    sitemap.add({
        url: '/' + post.slug + '/',
        priority: post.page == 0 ? 0.5 : 0.8
    });
    process.nextTick(buildSitemap.bind(this, posts, done, sitemap));
}

The changefreq and lastmod fields could also be added to sitemap.add().

sitemap.add({
    url: '/' + post.slug + '/',
    priority: post.page == 0 ? 0.5 : 0.8,
    changefreq: post.page == 0 ? 'weekly' : 'monthly',
    lastmod: post.updated_at
});

Next, I wanted to have more than 15 posts in the sitemap, and for it to include all of my static pages. All that's needed is to update the object passed to the api.posts.browse() call:

'sitemap': function(req, res, next) {
    api.posts.browse({ staticPages: 'all', limit: 1000 }).then(function(result) {
        ...
    });
},

The staticPages field accepts several values, all, true, false, and string and numerical equivalents of a boolean. Passing false, the default value, will return only blog posts, while passing true will return only static pages. Using all will return both blog posts and static pages.

Ghost's API also supports other parameters: status, where and withRelated. For the purposes of a sitemap, leave status to the default published since unpublished content can't be accessed anyway. If you want to play around with the values on your site, go to /ghost/api/v0.1/posts/?staticPages=all&limit=1000 and change the parameters at will.

I think Ghost has a ton of potential and what little exposure I have had with it gets my creative juices flowing. I hope this tutorial helps! And remember, upgrading Ghost will clobber the above changes. If upgrading to 0.6, the planned release to include sitemaps, then that won't matter.