If you benefit from web2py hope you feel encouraged to pay it forward by contributing back to society in whatever form you choose!

I wanted a way to make a full control sitemap (editable changefreq, priority etc) and that can be auto generated with all my public views. I want a way to get a sitemap for any public controller and get urls with args as unique urls.

Well, to do this little job I figure a simple solution:

 

In the Models:

db.define_table(
    'seo_sitemap',
    Field('loc', 'string', requires=IS_NOT_EMPTY()),
    Field('lastmod', 'datetime', ),
    Field('changefreq', 'string', default='none',
          requires=IS_IN_SET(('none', 'always', 'hourly', 'daily', 'weekly', 'monthly', 'anual', 'never'))),
    Field('priority', 'string', default='none',
          requires=IS_IN_SET(('none', '0.0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1.0'))),
    Field('translated', 'boolean', default=True),
    Field('active', 'boolean', default=True),
)

if request.extension.lower() == 'html' and not (request.ajax or auth.user) :
    db.seo_sitemap.update_or_insert(loc=request.env.path_info)

work done! all my requests are take by path_info, now I just need to navigate in application without any user and do customizations at appadmin.

 

Lets write the controller (default.py) I use:

def sitemap():
    # Get urls
    urls = db(db.seo_sitemap.active == True).select()
    languages = sorted([(c, i[1]) for c, i in T.get_possible_languages_info().iteritems() if c != 'default'])
    if len(languages) <= 1: languages = []
    return dict(urls=urls, languages=languages)

And the view (default/sitemap.xml)

{{
loc = lambda l: XML("%s://%s%s" % (request.env.wsgi_url_scheme, request.env.http_host, l))
urlset = ['xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"']
if languages: urlset += ['xmlns:xhtml="http://www.w3.org/1999/xhtml"']
}}<?xml version="1.0" encoding="UTF-8"?>
<urlset {{=XML(" ".join(urlset))}}>
  {{for url in urls:}}
    <url>
      <loc>{{=loc(url.loc)}}</loc>
      {{if url.lastmod:}}<lastmod>{{=url.lastmod}}</lastmod>{{pass}}
      {{if url.changefreq != 'none':}}<changefreq>{{=url.changefreq}}</changefreq>{{pass}}
      {{if url.priority != 'none':}}<priority>{{=url.priority}}</priority>{{pass}}
      {{if url.translated:}}
        {{for ref, name in languages:}}
          <xhtml:link rel="alternate" href="{{=alternate(url.loc, ref)}}" hreflang="{{=ref.replace("-", "_")}}"/>
        {{pass}}
      {{pass}}
    </url>
  {{pass}}
</urlset>

That is it. Now whe I request /appname/default/sitemap.xml  Will return a complete sitemap with translated versions. Hum.. well the ?locale= thing is the way I use to change language, but figure out your own way.

That's all folks..

Related slices

Comments (1)

  • Login to post



  • 0
    blackthorne 1 year ago

    Pedro,

    thank you for your slice.

    Just a couple of questions:

    1) given that your source of locations seems to be the request object, doesn't that require your visitors to open every page so it shows up in your "auto-generated" sitemap? If they can't find, it won't be in your sitemap and if it's not on the sitemap, they may not be able to find it in the first place..

    2) that check implies a DB update or insert for every single request (beyond the ones that are already needed for the project) which seems to be a bit heavy-weight. Couldn't you do that by looking into the logs, maybe with some crontask in the background?

    Kind regards,

    Francisco 


Hosting graciously provided by:
Python Anywhere