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.
Error: Your Requested widget " ai_widget-6" is not in the widget list.
- [do_widget_area above-nav-left]
- [do_widget_area above-nav-right]
- [do_widget_area footer-1]
- [do_widget id="wpp-4"]
- [do_widget_area footer-2]
- [do_widget id="recent-posts-4"]
- [do_widget_area footer-3]
- [do_widget id="recent-comments-3"]
- [do_widget_area footer-4]
- [do_widget id="archives-4"]
- [do_widget_area logo-bar]
- [do_widget id="oxywidgetwpml-3"]
- [do_widget_area menu-bar]
- [do_widget id="search-3"]
- [do_widget_area sidebar]
- [do_widget id="search-4"]
- [do_widget id="ai_widget-2"]
- [do_widget id="categories-5"]
- [do_widget id="ai_widget-3"]
- [do_widget id="ai_widget-4"]
- [do_widget id="ai_widget-5"]
- [do_widget_area sub-footer-1]
- [do_widget id="text-4"]
- [do_widget_area sub-footer-2]
- [do_widget_area sub-footer-3]
- [do_widget_area sub-footer-4]
- [do_widget_area upper-footer-1]
- [do_widget id="search-2"]
- [do_widget id="recent-posts-2"]
- [do_widget id="recent-comments-2"]
- [do_widget id="archives-2"]
- [do_widget id="categories-2"]
- [do_widget id="meta-2"]
- [do_widget_area upper-footer-2]
- [do_widget_area upper-footer-3]
- [do_widget_area upper-footer-4]
- [do_widget_area widgets_for_shortcodes]
- [do_widget id="search-5"]
- [do_widget id="ai_widget-6"]
- [do_widget_area wp_inactive_widgets]
- [do_widget id="wpp-2"]
- [do_widget id="text-1"]
- [do_widget id="recent-posts-3"]
- [do_widget id="categories-3"]
- [do_widget id="archives-3"]
- [do_widget id="icl_lang_sel_widget-3"]
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
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.
Error: Your Requested widget " ai_widget-6" is not in the widget list.
- [do_widget_area above-nav-left]
- [do_widget_area above-nav-right]
- [do_widget_area footer-1]
- [do_widget id="wpp-4"]
- [do_widget_area footer-2]
- [do_widget id="recent-posts-4"]
- [do_widget_area footer-3]
- [do_widget id="recent-comments-3"]
- [do_widget_area footer-4]
- [do_widget id="archives-4"]
- [do_widget_area logo-bar]
- [do_widget id="oxywidgetwpml-3"]
- [do_widget_area menu-bar]
- [do_widget id="search-3"]
- [do_widget_area sidebar]
- [do_widget id="search-4"]
- [do_widget id="ai_widget-2"]
- [do_widget id="categories-5"]
- [do_widget id="ai_widget-3"]
- [do_widget id="ai_widget-4"]
- [do_widget id="ai_widget-5"]
- [do_widget_area sub-footer-1]
- [do_widget id="text-4"]
- [do_widget_area sub-footer-2]
- [do_widget_area sub-footer-3]
- [do_widget_area sub-footer-4]
- [do_widget_area upper-footer-1]
- [do_widget id="search-2"]
- [do_widget id="recent-posts-2"]
- [do_widget id="recent-comments-2"]
- [do_widget id="archives-2"]
- [do_widget id="categories-2"]
- [do_widget id="meta-2"]
- [do_widget_area upper-footer-2]
- [do_widget_area upper-footer-3]
- [do_widget_area upper-footer-4]
- [do_widget_area widgets_for_shortcodes]
- [do_widget id="search-5"]
- [do_widget id="ai_widget-6"]
- [do_widget_area wp_inactive_widgets]
- [do_widget id="wpp-2"]
- [do_widget id="text-1"]
- [do_widget id="recent-posts-3"]
- [do_widget id="categories-3"]
- [do_widget id="archives-3"]
- [do_widget id="icl_lang_sel_widget-3"]
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, $bean) {
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?
8 comments
Join the conversationEdgars Ritmanis - 18/10/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 - 21/04/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 - 18/02/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 - 25/06/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 - 25/06/2016
Ok, I found the problem. Need to check the “Allow manual sitemap creatin by GET queries”
Cristian Gologan - 24/08/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 - 26/08/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 - 26/08/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?