Daniel López Azaña

Tema

Social Media

Blog

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

Google XML Sitemaps v3 for qTranslate no funciona con Qtranslate Slug

Wordpress multilanguage icon

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.

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

Logo de Qtranslate

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.

¿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, <b>$bean</b>) {
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?

Multiidioma qTranslate qTranslate Slug Wordpress
Daniel López Azaña

Sobre el autor

Daniel López Azaña

Emprendedor tecnológico y arquitecto cloud con más de 20 años de experiencia transformando infraestructuras y automatizando procesos.

Especialista en integración de IA/LLM, desarrollo con Rust y Python, y arquitectura AWS & GCP. Mente inquieta, generador de ideas y apasionado por la innovación tecnológica y la IA.

Artículos relacionados

Wordpress multilingual site

Solucionando problemas de Qtranslate con la traducción del slug

A la hora de crear un sitio web multi-idioma basado en WordPress son básicamente dos las opciones que tenemos. Una implica crear páginas y artículos distintos, cada uno en su idioma, usando plugins del tipo de WPML, Polylang o xili-language. Otra introduce el contenido traducido en todos los idiomas que manejemos en el mismo post, separado por unas meta-etiquetas dentro del propio contenido, y es el propio plugin el que los separa en pestañas distintas dentro del editor de un único post existente.

16 de septiembre de 2014
Xorg icon

Cómo evitar que el fichero .xsession-errors alcance un tamaño enorme

El fichero .xsession-errors es un fichero de log que utiliza el sistema de ventanas X para registrar todos los errores que se producen en el entorno gráfico de Linux. Dado que todos los entornos de escritorio, ya sea Gnome, KDE, Cinnamon, XFCE, LXDE, etc., y todos los gestores de ventanas más livianos que no llegan a constituir un entorno de escritorio como FVWM, IceWM o Window Maker utilizan el sistema de ventanas X, al final cualquier aplicación gráfica que ejecutemos en nuestro ordenador puede provocar que se escriban mensajes de error en el fichero .xsession-errors, por lo que éste puede crecer de forma descontrolada hasta alcanzar fácilmente un tamaño muy grande de decenas de GB o incluso cientos si la capacidad de nuestro disco lo permite.

25 de junio de 2017
Ctrl+S

Desbloquear la línea de comandos de Linux tras pulsar Ctrl+s en Bash

Dado que la combinación de teclas Control+s es muy utilizada como atajo para la opción de Guardar ficheros en aplicaciones gráficas como editores de texto, editores de imágenes, navegadores web, etc. a veces nos traiciona el subconsciente cuando estamos trabajando desde la línea de comandos de Linux y utilizamos esa misma combinación de teclas cuando estamos por ejemplo editando un documento con Vim con la intención de guardarlo. A partir de ese momento observamos que ninguna tecla responde, la shell se ha bloqueado y ya no podemos hacer nada más en ella y nos entra un sudor frío porque no podemos acceder al documento que estábamos editando y no podemos salvar los cambios.

27 de abril de 2017

Comentarios

Xavier Prunés 18 de septiembre de 2014
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 de septiembre de 2014
Es cierto Xavier, olvidé ponerlo. Ya está rectificado. ¡Gracias a ti!
Marc 28 de enero de 2015
Hola, pues amí no me funcionado me sigue generando url's erróneas :S

Enviar comentario