Sitemap generator for multilanguage website

Is there a plugin to create automatically a sitemap for multilanguage website?

i am using the one from the kirby blog. its a template actually.
https://getkirby.com/blog/xmlsitemap

or if you want more control maybe this one
http://www.getkirby-plugins.com/enhanced-sitemap

Yeah, I also use the one from the blog with a multi-lang site.

To keep the site structure clean, I’ve put my sitemap in a route and mine doesn’t work with multi language out of the box - I’m curious to know how your sitemap working with multi language @texnixe ? :blush:

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

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

            $sitemap = '<?xml version="1.0" encoding="utf-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
            foreach(site()->pages()->index() as $p){
                if(!in_array($p->uri(), $exclude) and $p->isVisible()){
                    $sitemap .= '<url><loc>' . html($p->url());
                    $sitemap .= '</loc><lastmod>' . $p->modified('c') . '</lastmod><priority>';
                    $sitemap .= ($p->isHomePage()||in_array($p->uri(), $important)) ? 1 : 0.6/$p->depth();
                    $sitemap .= '</priority></url>';
                }
            }
            $sitemap .= '</urlset>';

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

        }
    )
));

On a multi language website you can use

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

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

            $sitemap = '<?xml version="1.0" encoding="utf-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
            foreach(site()->languages() as $l) {
              foreach(site()->pages()->index() as $p){
                  if(!in_array($p->uri(), $exclude) and $p->isVisible()){
                      $sitemap .= '<url><loc>' . html($p->url($l->code()));
                      $sitemap .= '</loc><lastmod>' . $p->modified('c') . '</lastmod><priority>';
                      $sitemap .= ($p->isHomePage()||in_array($p->uri(), $important)) ? 1 : 0.6/$p->depth();
                      $sitemap .= '</priority></url>';
                  }
              }
            }
            $sitemap .= '</urlset>';

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

        }
    )
));

Change the order of the two foreach lines if you want!

Your solution shows the pages only in the default language!

2 Likes

Thank you @anon77445132 :slight_smile:

I’ve now added support for both single and multi language situations

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

            $sitemap = '<?xml version="1.0" encoding="utf-8"?>';
            $sitemap .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
            if(!empty(site()->languages())) {
                foreach(site()->pages()->index() as $page){
                    foreach(site()->languages() as $language) {
                        $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'));
    $important = c::get('sitemap.important', array('contact'));

    if(!in_array($page->uri(), $exclude) and $page->isVisible()){
        $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.6/$page->depth()) . '</priority>';
        $url .= '</url>';
        return $url;
    }
}

You may want to look at Google . Search Console Help: Use a sitemap to indicate alternate language pages.

2 Likes

When I put it on test on a live server i have an error.
Fatal error: Can’t use method return value in write context in

How can I resolve it?

Thank you for your code! It looks it works for me! Just a stupid issue… $page->modified(‘c’) doesn’t render any date but it just print c …!!!

Do you know why?
Thanks!

Have you set the date handler to strftime? If so, you need to modify your date format: http://php.net/manual/de/function.strftime.php

Oh thank you! I just solved editing

c::set('date.handler','strftime');

to

c::set('date.handler','date');

in config.php

What a great community!!! :blush: :kissing_heart:

1 Like

My solution as a route according to @anon77445132’s link. Works with multilang and regular sites:

[
   'pattern' => 'sitemap.xml',
   'action' => function () {
      $ignore = ['error'];
      $pages = site()->pages()->index();
      $languages = site()->languages() ?: [];
      $sitemap = '<?xml version="1.0" encoding="utf-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">';
      foreach ($pages as $page) {
         if (in_array($page->uri(), $ignore)) continue;
         $sitemap .= '<url><loc>'.html($page->url()).'</loc>';

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

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

      $sitemap .= '</urlset>';

      return new Response($sitemap, 'text/xml');
   }
]