Correct way to set up multi-language sitemap?

I’ve been fiddling around with this as well and i got it working, but the issue here is, that it’s really painfully slow. For 288 URLs in total it takes ~40s to generate the sitemap.xml here localy :snail:

Features

  • Works for both single and multi -language
  • Generates alternate hreflang entries for multi-language
  • Exclude by template
  • Mark certain pages (contact) important for higher priority
  • Style it with a assets/css/sitemap.xsl if present
<?php

// Based on https://github.com/thgh/kirby-plugins/tree/master/sitemap

kirby()->routes(array(
    array(
        'pattern' => 'sitemap.xml',
        'action'  => function() {

            $sitemap = '<?xml version="1.0" encoding="UTF-8"?>';
            if( file_exists(kirby()->roots()->assets() . DS . "css" . DS . "sitemap.xsl") ) {
                $sitemap .= '<?xml-stylesheet type="text/xsl" href="' . kirby()->urls()->assets() . DS . "css" . DS . "sitemap.xsl" . '"?>';
            }
            $sitemap .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';

            if(!empty(site()->languages())) {
                foreach(site()->languages() as $language) {
                    foreach(site()->pages()->index() as $page){
                        $sitemap .= add_sitemap_url($page, $language);
                    }
                }
            } else {
                foreach(site()->pages()->index() as $page){
                    $sitemap .= add_sitemap_url($page);
                }
            }
            $sitemap .= '</urlset>';

            return new Response($sitemap, 'xml');

        }
    )
));

function add_sitemap_url($page, $language = null){

    $exclude = c::get('sitemap.exclude', array('error'));
    $excludeTemplates = c::get('sitemap.exclude.templates');
    $important = c::get('sitemap.important', array('contact'));


    if($page->isHomePage() or !in_array($page->uri(), $exclude) and !in_array($page->template(), $excludeTemplates)){
        $url  = '<url>';
        $url .=     '<loc>' . ($language ? html($page->url($language->code())) : html($page->url())) . '</loc>';
        $url .=     '<lastmod>' . $page->modified('c') . '</lastmod>';
        $url .=     '<priority>' . (($page->isHomePage()||in_array($page->uri(), $important)) ? 1 : 0.95/$page->depth()) . '</priority>';

        if($language){
            foreach (site()->languages()->keys() as $lang => $code){
                $url .=     '<xhtml:link rel="alternate" hreflang="' . $code . '" href="' . html($page->url($code)) . '"/>';
            }
        }

        $url .= '</url>';
        return $url;
    }
}

But as I mentioned above, it’s so slow that’s it’s unusable.