GNU/Linux, Open Source, Cloud Computing, DevOps y más...

Google XML Sitemaps v3 for qTranslate no funciona con Qtranslate Slug

3 comentarios

Una de las opciones más extendida para crear un sitio multi-idioma con WordPress es utilizar el plugin Qtranslate, que además de ser gratuito funciona bastante bien. Quizás el aspecto más delicado de los sitios en diferentes idiomas sea el de la traducción de las URL’s, ya que afecta a la propia arquitectura de la información de esa web y a su posicionamiento en buscadores (SEO).

Precisamente Qtranslate no ofrece soporte para la traducción de URL’s, por lo que debemos optar por la instalación de un plugin adicional, Qtranslate Slug para lograrlo. En principio todo funciona bien con estos dos plugins instalados, hasta que tenemos la necesidad de contar con un mapa de nuestro sitio en XML para subirlo a 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"]

                  Ahí es cuando nos damos cuenta, quizás demasiado tarde, de que muchas de las URL’s que aparecen en el sitemap XML son incorrectas. Y digo demasiado tarde, porque si no detectamos el problema rápidamente, Google recibirá un montón de enlaces que acaban en un error 404 de página no encontrada, y el número de errores de indexación en las Herramientas para Webmasters de Google aumentará de forma vertiginosa, lo cual podrá tener efectos negativos en el SEO de nuestra web si no lo remediamos pronto.

                  Naturaleza del problema

                  Qtranslate logo

                  El origen de este problema está en que el plugin Google XML Sitemaps v3 for qTranslate no traduce la parte de la URL que muestra los nombres de los artículos (slug). Así, un enlace que debería ser /es/google-xml-sitemaps-v3-for-qtranslate-no-funciona-con-qtranslate-slug/ aparece como /es/google-xml-sitemaps-v3-for-qtranslate-doesnt-work-with-qtranslate-slug, es decir, en inglés en lugar de en español, a pesar de que la conversión de /en/ por /es/ sí se hace correctamente.

                  Este mal funcionamiento afecta también a categorías y etiquetas. En este caso no obtendremos errores 404 de páginas no encontradas, pues por alguna razón el plugin Qtranslate Slug sí acepta las URL’s en el idioma por defecto del sitio web y muestra el contenido en el idioma correcto, pero las URL’s tendrán una estructura errónea y no aparecerán en el idioma deseado.

                  ¿Dónde está el error?

                  Haciendo un poco de ingeniería inversa he descubierto que se trata de un fallo en el fichero sitemap-qtranslate.php ubicado en plugins/google-xml-sitemaps-v3-for-qtranslate/, el cual hace una llamada desde la función qt_permalink() a la función qtrans_convertURL() cuando se trata de una URL en otro idioma distinto del que tiene configurado nuestro sitio web por defecto. Sin embargo, la función qtrans_convertURL() no realiza la traducción de la parte del slug de la URL, lo que provoca todo el problema. Esta función qtrans_convertURL() no pertenece al plugin Google XML Sitemaps, ni tan siquiera al plugin Qtranslate Slug, sino al propio plugin Qtranslate (wp-content/plugins/qtranslate/qtranslate_core.php), que como decía al principio no tiene soporte para la traducción de URL’s. Por tanto, todo indica que se trata de una mala implementación del método qt_permalink() que esperemos sea solucionado en futuras versiones por los desarrolladores del plugin.


                  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"]

                                  ¿Cómo solucionarlo?

                                  Hasta que ese momento llegue, aquí os ofrezco una solución temporal que os permitirá seguir usando el plugin y tener un sitemap XML válido y libre de errores. Los ficheros implicados que deberemos modificar son 2: sitemap-qtranslate.php y sitemap-core.php, ambos ubicados en el directorio wp-content/plugins/google-xml-sitemaps-v3-for-qtranslate/.

                                  sitemap-qtranslate.php

                                  Sustituir todo este fragmento:

                                  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    }
                                  

                                  Por este otro:

                                  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);
                                                                  }
                                                          }
                                                  }
                                  

                                  Y no olvidemos añadir un nuevo parámetro $bean a la definición de la función qt_permalink() en el mismo fichero:

                                   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

                                  Añadir un último parámetro a todas las llamadas a la función qt_permalink() que se hagan en este fichero. Este parámetro será el objeto al que haga referencia la propia URL que estamos tratando de añadir a nuestro sitemap, como un post, una categoría o una etiqueta. Las líneas entre las etiquetas y son las que he modificado en este fichero:

                                  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>
                                  
                                  
                                  Categorías
                                  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>
                                  
                                  
                                  Etiquetas
                                  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>
                                  
                                  

                                  Por último, recuerda que es muy importante hacer una copia de seguridad de los ficheros modificados para que si actualizamos el plugin con una nueva versión que aún no aporta una solución a este problema y nuestros cambios son machacados podamos recuperarlos aunque sea de forma manual.

                                  ¿Te ha servido esta solución?

                                   

                                  Sobre el autor

                                  Daniel López Azaña
                                  Arquitecto de soluciones Cloud AWS & Linux Sysadmin Freelance

                                  Emprendedor, generador de ideas y mente inquieta. Apasionado de las nuevas tecnologías, especialmente de los sistemas Linux y del software libre. Me gusta escribir además sobre actualidad tecnológica, Cloud Computing, AWSi, DevOps, DevSecOps, seguridad, desarrollo web y programación, SEO, ciencia, innovación, emprendimiento, etc.

                                  DanielGoogle XML Sitemaps v3 for qTranslate no funciona con Qtranslate Slug

                                  Artículos relacionados

                                  3 comentarios

                                  Unirte a la conversación
                                  • Xavier Prunés - 18/09/2014 responder

                                    Perfecto, sólo te faltaría indicar la modificación de la función qt_permalink añadiendo el parámetro $bean:
                                    //function qt_permalink($qt, $permalink, $post_content, $modified_time, $change_freq, $priority, &$sitemap) {
                                    function qt_permalink($qt, $permalink, $post_content, $modified_time, $change_freq, $priority, &$sitemap, $bean) {

                                    Muchas gracias

                                    Daniel - 23/09/2014 responder

                                    Es cierto Xavier, olvidé ponerlo. Ya está rectificado. ¡Gracias a ti!

                                  • Marc - 28/01/2015 responder

                                    Hola, pues amí no me funcionado me sigue generando url’s erróneas :S

                                  Deja una respuesta

                                  Tu dirección de correo electrónico no será publicada.