Daniel López Azaña

Theme

Social Media

Blog

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

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

Wordpress multilanguage icon

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.

sitemap-qtranslate.php

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);
                                        }
                                }
                                else
                                {
                                        $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, <b>$bean</b>) {
sitemap-core.php

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.

Posts
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>
Categories
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>
Tags
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?

Multi-language Multilingual qTranslate qTranslate Slug Wordpress
Daniel López Azaña

About the author

Daniel López Azaña

Tech entrepreneur and cloud architect with over 20 years of experience transforming infrastructures and automating processes.

Specialist in AI/LLM integration, Rust and Python development, and AWS & GCP architecture. Restless mind, idea generator, and passionate about technological innovation and AI.

Related articles

Wordpress multilingual site

Fixing Qtranslate slug problems

There are basically two options when creating a multi-language website based on WordPress. One involves duplicating posts and pages by creating one different post for each language, wich is the approach followed by some plugins like WPML, Polylang or xili-language. Another approach is to introduce all the translations into the same post, separated by meta-tags within the content itself.Each translation is displayed in different tabs within the HTML editor of a single post. This is the case of Qtranslate, which happens to be the simplest solution from my point of view, as it is not necessary to modify the WordPress database in order to create relationships between a post or page and their translations, as well as among other WordPress objects like categories, tags, widgets, menus, etc. Therefore Qtranslate is my favorite choice when it comes to creating a multilingual website based on WordPress.

September 16, 2014
Xorg icon

How to prevent the .xsession-errors file from growing to a huge size

The .xsession-errors file is where the X Window system logs all errors that occur within the Linux graphical environment. All desktop environments, whether Gnome, KDE, Cinnamon, XFCE, LXDE, etc., and all lighter window managers like FVWM, IceWM or Window Maker make use of the X Window system. Therefore any graphical application running on your computer can cause that error messages are written to the .xsession-errors file, reason why it can grow wildly until reaching very big sizes of tens of GB or even hundreds if your disk capacity allows it.

June 25, 2017
Ctrl+S

Unlock Linux command line after pressing Ctrl+s in Bash

Since the key combination Control+s is widely used as a shortcut to save files in GUI applications such as text editors, image editors, web browsers, etc. sometimes you are betrayed by your subconscious when you are working from the Linux command line and you use that same key combination when you are for example editing a Vim document when trying to save it. Then you notice that no key answers, the shell is locked and you can no longer do anything else in it.  Even worse, you get a cold sweat because you can’t continue editing your document and you can’t save the changes.

April 27, 2017

Comments

Edgars Ritmanis October 18, 2014
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 April 21, 2015
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 February 18, 2016
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 June 25, 2016
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 - http://example.com/de/p=123 http://example.com/en/p=123 instead of : http://example.com/ru/hardware/apple-ipad-air-review http://example.com/de/hardware/apple-ipad-air-bewertung
Arthur June 25, 2016
Ok, I found the problem. Need to check the "Allow manual sitemap creatin by GET queries"
Cristian Gologan August 24, 2017
interesting but does not seem to work for me please have a look: http://water-ionizers.info/sitemap.xml I can send you the modified files to have a look as well
Cristian Gologan August 26, 2017
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 August 26, 2017
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?

Submit comment