GNU/Linux, Open Source, Cloud Computing, DevOps and more...

Google XML Sitemaps v3 for qTranslate doesn’t work with Qtranslate Slug


One of the most widespread options to create a multi-language site with WordPress is to use the qTranslate plugin, wich works pretty well and it’s free. Perhaps the most sensitive aspect of multilingual sites ​​is URL translation, since it affects website’s information architecture and search engine optimization (SEO).

Precisely qTranslate does not support URL’s translation, so we must choose to install an additional plugin: qTranslate Slug. At first all works well with these two plugins installed, but problems arise when we need an XML sitemap to upload to Google.

That’s when we realize, perhaps too late, that many of the URLs within the XML sitemap are incorrect. And I say too late because if we don’t detect the problem quickly, Google will get plenty of links that end in a 404 page not found error, and the number of indexing errors in Google Webmaster Tools will dramatically increase, which in turn may have side effects on SEO if we don’t fix it soon.

The problem’s root

Qtranslate logo

The cause of this problem is that Google XML Sitemaps v3 for qTranslate plugin doesn’t translate the slug part of URLs. Thus, a link that should be /es/google-xml-sitemaps-v3-for-qtranslate-no-funciona-con-qtranslate-slug/ appears as /es/google-xml-sitemaps-v3-for-qtranslate-doesnt-work-with-qtranslate-slug, ie, in English rather than Spanish, although the conversion of /en/ by /es/ is done properly.

This malfunction also affects categories and tags. In that case we won’t get 404 not found errors because for some reason the qTranslate Slug plugin does accept URLs in website’s default language and displays the content in the correct language, but URLs have a the wrong structure and they don’t appear on the sitemap in the desired language.

Where is the error?

Doing some reverse engineering I found out that there is a failure inside sitemap-qtranslate.php file located at plugins/google-xml-sitemaps-v3-for-qtranslate/ directory, which makes a call from qt_permalink() function to qtrans_convertURL() when it comes to a URL in site’s non default language. However, qtrans_convertURL() function doesn’t perform the translation of the URL’s slug part, causing the entire problem. This qtrans_convertURL() method doesn’t belong to Google XML Sitemaps plugin, or even the qTranslate Slug plugin, but the qTranslate main plugin (wp-content/plugins/qtranslate/qtranslate_core.php), which as said earlier doesn’t support URL translation. Thus, it seems that this is a bad implementation of qt_permalink() method that hopefully will be fixed in future versions by plugin developers.

How to fix it?

Until that time comes, here I offer a temporary workaround that will allow you to continue using the plugin and have a valid and error free XML sitemap. Two files are involved that we must modify: sitemap-qtranslate.php and sitemap-core.php, both located in the wp-content/plugins/google-xml-sitemaps-v3-for-qtranslate/ directory.


Replace all this excerpt:

50    // Add an extra permalink url for every non-default qTranslate language
51    foreach ($languages as $language) {
52          if ($qt["hide_default_language"] == 1 && $qt["default_language"] == $language) {
53              $sitemap->AddUrl($permalink, $modified_time, $change_freq, $priority);
54          } else {
55              $sitemap->AddUrl(qtrans_convertURL($permalink, $language, true), $modified_time, $change_freq, $priority);
56          }
57    }

With this one:

global $q_config;
                $qts_options = get_option('qts_options');
                $oslug = new QtranslateSlug();

                foreach($q_config['enabled_languages'] as $language) {
                        if ($qt["hide_default_language"] == 1 && $qt["default_language"] == $language) {
                                $sitemap->AddUrl($permalink, $modified_time, $change_freq, $priority);
                        } else {
                                // Posts
                                if (isset($bean->ID))
                                        $p = qtrans_convertURL($permalink, $language, true);
                                        if(!in_array($p, array('http://', 'http:/'))) {
                                                $def_slug = get_post_meta( $bean->ID, $oslug->get_meta_key($qt["default_language"]), true);
                                                $slug = get_post_meta( $bean->ID, $oslug->get_meta_key($language), true);
                                                $turl = str_replace($def_slug, $slug, $p);
                                                $sitemap->AddUrl($turl, $modified_time, $change_freq, $priority);
                                // categories
                                else if (isset($bean->taxonomy) && $bean->taxonomy == 'category')
                                        $def_taxonomy_category = $qts_options["_qts_taxonomy_category"][$qt["default_language"]];
                                        $taxonomy_category = $qts_options["_qts_taxonomy_category"][$language];
                                        $p = qtrans_convertURL($permalink, $language, true);
                                        if(!in_array($p, array('http://', 'http:/'))) {
                                                $def_slug = get_term_meta( $bean->term_id, $oslug->get_meta_key($qt["default_language"]), true);
                                                $slug = get_term_meta( $bean->term_id, $oslug->get_meta_key($language), true);
                                                $turl = str_replace($def_slug, $slug, $p);
                                                $turl = str_replace($def_taxonomy_category, $taxonomy_category, $turl);
                                                $sitemap->AddUrl($turl, $modified_time, $change_freq, $priority);
                                // tags
                                else if (isset($bean->taxonomy) && $bean->taxonomy == 'post_tag')
                                        $def_taxonomy_tag = $qts_options["_qts_taxonomy_post_tag"][$qt["default_language"]];
                                        $taxonomy_tag = $qts_options["_qts_taxonomy_post_tag"][$language];
                                        $p = qtrans_convertURL($permalink, $language, true);
                                        if(!in_array($p, array('http://', 'http:/'))) {
                                                $turl = str_replace('/'.$language.'/'.$def_taxonomy_tag.'/', '/'.$language.'/'.$taxonomy_tag.'/', $p);
                                                $sitemap->AddUrl($turl, $modified_time, $change_freq, $priority);
                                        $sitemap->AddUrl(qtrans_convertURL($permalink, $language, true), $modified_time, $change_freq, $priority);

And don’t forget to add a new $bean parameter to the qt_permalink() function definition found in the same file:

 34 // Add additional qTranslate language permalniks
 35 //function qt_permalink($qt, $permalink, $post_content, $modified_time, $change_freq, $priority, &$sitemap) {
 36 function qt_permalink($qt, $permalink, $post_content, $modified_time, $change_freq, $priority, &$sitemap, $bean) {

Add a last parameter to all qt_permalink() calls inside this file. This parameter will be the object instance referenced by the URL we are trying to add to our sitemap, as a post, category or tag. The lines between [dla] and [/dla] tags are the ones I have changed in this file.

1923  // <DLA>
1924  //else qt_permalink($qt, $permalink, $post->post_content, ($post->post_modified_gmt && $post->post_modified_gmt!='0000-00-00 00:00:00'?$post->post_modified_gm     t:$post->post_date_gmt), ($isPage?$cf_pages:$cf_posts), $prio, $this);
1925  else qt_permalink($qt, $permalink, $post->post_content, ($post->post_modified_gmt && $post->post_modified_gmt!='0000-00-00 00:00:00'?$post->post_modified_gmt:     $post->post_date_gmt), ($isPage?$cf_pages:$cf_posts), $prio, $this, $post);
1926  // </DLA>

2013  // <DLA>
2014  //else qt_permalink($qt, get_category_link($cat->ID), null, $cat->last_mod, $this->GetOption("cf_cats"), $this->GetOption("pr_cats"), $this);
2015  else qt_permalink($qt, get_category_link($cat->ID), null, $cat->last_mod, $this->GetOption("cf_cats"), $this->GetOption("pr_cats"), $this, $cat);
2016  //</DLA>


2027  // <DLA>
2028  //else qt_permalink($qt, get_category_link($cat->term_id), null, 0, $this->GetOption("cf_cats"), $this->GetOption("pr_cats"), $this);
2029  else qt_permalink($qt, get_category_link($cat->term_id), null, 0, $this->GetOption("cf_cats"), $this->GetOption("pr_cats"), $this, $cat);
2030  // </DLA>

2145  // <DLA>
2146  //else qt_permalink($qt, get_tag_link($tag->term_id), null, 0, $this->GetOption("cf_tags"), $this->GetOption("pr_tags"), $this);
2147  else qt_permalink($qt, get_tag_link($tag->term_id), null, 0, $this->GetOption("cf_tags"), $this->GetOption("pr_tags"), $this, $tag);
2148  // </DLA>

Finally, remember that it’s very important to backup changed files so that a plugin update wich still doesn’t provide a fix for this issue doesn’t crush our changes and we can recover them manually.

Was this solution helpful to you?


About the author

Daniel López Azaña
Freelance AWS Cloud Solution Architect & Linux Sysadmin

Entrepreneur, a generator of ideas and restless mind. Passionate about new technologies, especially Linux systems and Open Source Software. I also like to write about Technology News, Cloud Computing, AWS, DevOps, DevSecOps, System Security, Web Development and Programming, SEO, Science, Innovation, Entrepreneurship, etc.

DanielGoogle XML Sitemaps v3 for qTranslate doesn’t work with Qtranslate Slug

Related Posts


Join the conversation
  • Edgars Ritmanis - 18/10/2014 reply

    This is a great post. The fix works for pages and posts.
    However, custom post type slug translations that can be set through Settings>Slug options still don’t work.

  • gurumance - 21/04/2015 reply

    Hello Daniel, can you update your post as there is no qtranslate plugin anymore now it is qtranslate-x(and it is much better) can you check and share the way how to fix with latest plugins.

  • Lungile - 18/02/2016 reply

    Thank you!!! I have spent the better part of an afrtenoon looking for a simple solution to this.A quick clarification: Line 2 hooks the my_save_post’ function into the save_post action. But the function in line 3 is named simply save_post’. Is that a typo, or am I missing something else?

  • Arthur - 25/06/2016 reply

    Hello, can you please make an archieve with you patch? because tehre is something wrong on my side. I made all cahnges you made, but in my sitemap there is something like url –
    instead of :

  • Arthur - 25/06/2016 reply

    Ok, I found the problem. Need to check the “Allow manual sitemap creatin by GET queries”

  • Cristian Gologan - 24/08/2017 reply

    interesting but does not seem to work for me please have a look:
    I can send you the modified files to have a look as well

    Cristian Gologan - 26/08/2017 reply

    set default language to english and it works! but I have the same problem as Arthur above and “GET” option does not help-strange!

    Daniel - 26/08/2017 reply

    Cristian, I also have English as my default language in qTranslate, but if I change it to Spanish I get the same XML sitemap. I can’t reproduce neither Arthur’s problem nor yours, sorry…

    I have Version 3.4.1 of Google XML Sitemaps v3 for qTranslate, Version 1.1.7 of qTranslate slug and Version 2.5.39 of qTranslate. Which versions do you have?

Leave a Reply

Your email address will not be published.