Site Map for plone.app.multilingual on Plone 5 Using Rapido

How to write a Rapido element that will generate a multi-language XML site map (on the fly) if you have plone.app.multilingual installed.

As of the date this was written (27-10-2016) there is an issue with plone.app.multilingual in which once installed on a Plone 5.x site, the site maps are not rendered properly (your sitemap.xml.gz file is empty).

Here is the issue that was logged on the Plone Community page that helped me with the below information: https://community.plone.org/t/capture-xml-output-from-rapido-function/2946

You can get around this by generating a sitemap that will render on the fly (once the URL is called) using Rapido.

Rapido

First you should install Rapido.

Once you have activated the Rapido add-on, go to Theming in Plone Control Panel and modify your theme.

Create a folder structure as per the Rapido tutorial. It should be structured the same as below:

++theme++yourtheme
|-rapido
|-sitemap
|-blocks
|-sitemap.yaml
|-sitemap.py

For this particular situation we do not need the .html file.

Rapido Files

Copy and paste the following into the sitemap.yaml file:

elements:
sitemap:
type: BASIC

Copy and paste the following into the sitemap.py file (please see below the code as there are some important things you will need to change):

# The URL structure of our dev server is http://server.domain.co.uk/plonesite 
# Thus every sub language is on URLs such as: http://server.domain.co.uk/plonesite/fr,
# http://server.domain.co.uk/plonesite/de etc.

def sitemap(context):
    language = str(context.content.language)
    results = context.api.content.find(Language=language)
    languages = {
        'en-gb' : '.co.uk',
        'fr'    : '.fr',
        'de'    : '.de',
        'it'    : '.it',
        'cz'    : '.cz'
    }
    language_tlds = languages.copy()
    del languages[language]
    html = '''<?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">
    '''
    
    purl = str(context.portal.absolute_url())
    
    url_structure = 1 # default inc .co.uk/language for TLD set to 2
    
    for r in results:
        
        html += '<url>'
        html += '<loc>%s</loc>' %r.getObject().absolute_url()
        
        for l in languages:
            url = r.getObject().absolute_url()

            if url_structure == 1:
                url = url.replace(language+'/', '')
                url = purl + '/' + l + str(url.replace(purl, ''))
                
                if url.endswith('/' + language):
                    url = purl + '/' + l
                
            if url_structure == 2:
                for tld in language_tlds:
                    url = url.replace( language_tlds[tld], languages[l] )
                    
            html += '''<xhtml:link
                    rel="alternate"
                    hreflang="%s"
                    href="%s" />
            ''' % (l, url)
    
        html += '</url>'

    html += '</urlset>'

    context.request.response.setHeader('content-type', 'application/xml')

    return html

Modifications necessary to sitemap.py

You will need to update the languages dictionary variable to a list of the language codes that you have enabled on your site, first put in the language code, followed by the domain suffix.

If you are using URLs structured as follows: http://server.domain.co.uk/plonesite/language or http://www.domain.co.uk/language leave the url_structure variable set to 1. If you are using top level domains, such as http://www.server.co.uk/ or http://www.server.de etc then set this variable to 2.

View the site map

To view the outputted XML just go to http://server.domain.co.uk/plonesite/<language>/@@rapido/sitemap/blocks/sitemap/sitemap.

NOTE: For Plone < 5.0.5 users you'll need to go to the singular 'block' not 'blocks' (a bug that was fixed in later Rapido releases) so if you're on any version of Plone less than version 5.0.5 you'll need to go to: http://server.domain.co.uk/plonesite/<language>/@@rapido/sitemap/block/sitemap/sitemap instead.

Summary

Obviously this is a little ugly but it'll do the trick for anyone in a bind. The good news is a proper fix is being worked on by the community so make sure to keep an eye on Rapido / plone.app.multilingual for updates.

Disclaimer

The script is still to be fully tested so it may misbehave, I will be testing it fully over the next few days.