ScottSpence.com

Scott's Thoughts Pamphlet!

Sitemap Generation for Dynamic Routes In NextJS with the Sanity Client

A sitemap is an important for Search Engine Optimisation (SEO) because it makes it easier for Google and other search engines to find your site’s pages.

Google ranks web pages not just websites. There is no downside of having an XML Sitemap and having one can improve your SEO.

At the beginning of January I asked a question in the Sanity.io Slack.

slack message asking about site map

The Lee Robinson solution didn’t work for me so I reached out on the Sanity slack channel and Knut being the legend he is offered up how they have done it:

knut slack reply

1const client = require('../../client')
2const sm = require('sitemap')
3const defaultUrls = [
4 { url: '/', changefreq: 'daily', priority: 1 },
5 { url: '/pricing', priority: 0.5 },
6 { url: '/pricing/compare', priority: 0.5 },
7 { url: '/docs', priority: 0.7 },
8 { url: '/community', priority: 0.7 },
9 { url: '/blog/', changefreq: 'weekly', priority: 0.7 },
10]
11async function getSitemap() {
12 const { routes, blogposts } = await client.fetch(`
13 {
14 "routes": *[_type == "route" && includeInSitemap],
15 "blogposts": *[_type == 'post' && includeInSitemap == true && publishedAt < $now] | order(publishedAt desc) {
16 slug
17 }
18 }
19 `)
20 const urls = routes
21 .filter(({ slug = {} }) => slug.current)
22 .reduce(
23 (acc, route) => [
24 ...acc,
25 {
26 url: route.slug.current,
27 priority: route.sitemapPriority || 0.5,
28 },
29 ],
30 defaultUrls
31 )
32 const blogUrls = blogposts
33 .filter(({ slug = {} }) => slug.current)
34 .map(post => {
35 return {
36 url: `/blog/${post.slug.current}`,
37 priority: 0.5,
38 }
39 })
40 return sm.createSitemap({
41 hostname: 'https://www.sanity.io',
42 cacheTime: 600000,
43 urls: urls.concat(blogUrls),
44 })
45}
46module.exports = function sitemapXML(req, res, next) {
47 res.setHeader('Content-Type', 'application/xml')
48 getSitemap()
49 .then(result => {
50 res.send(result.toString())
51 })
52 .catch(next)
53}

I was just about to start getting my head around how that was done then James Weis came in with setting the headers to text/xml

james weis reply headers to text/xml

This made a lot more sense to me so I implemented this straight away.

Create the file as pages/sitemap.xml.js then the following:

1import groq from 'groq'
2import sanityClient from '../sanity-client'
3
4export default function SiteMap() {
5 return <div>loading</div>
6}
7
8export async function getServerSideProps({ res }) {
9 const baseUrl = `https://myawesomesite.com`
10 const query = groq`{
11 "countries": *[_type == 'country']{slug},
12 }`
13 const urls = await sanityClient.fetch(query)
14 const countries = urls.countries.map(page => {
15 const slug =
16 page.slug.current === '/' ? '/' : `/${page.slug.current}`
17 return `
18 <loc>${baseUrl}${slug}</loc>
19 <changefreq>daily</changefreq>
20 <priority>0.7</priority>
21 `
22 })
23
24 const locations = [...countries]
25 const createSitemap = () => `<?xml version="1.0" encoding="UTF-8"?>
26 <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
27 ${locations
28 .map(location => {
29 return `<url>
30 ${location}
31 </url>
32 `
33 })
34 .join('')}
35 </urlset>
36 `
37 res.setHeader('Content-Type', 'text/xml')
38 res.write(createSitemap())
39 res.end()
40 return {
41 props: {},
42 }
43}

This is genius!

So what the code block there is doing is saving the file as the sitemap and it’s located with the rest of the pages as sitemap.xml, this can them be added to the Google search console as the sitemap and located as https://myawesomesite.com/sitemap.xml.

I asked for permission to document this from James and he was happy with being mentioned, thanks James. 🙏

asking for permission to add this content to my blog

Back to Top


Scott Spence

Built with Gatsby · Hosted on Vercel · 2021