Son las 8 de la mañana. Acabo de llegar al trabajo después de un rato de bici y metro. El olor a café que emana mi taza de Son Goku está despertando mis neuronas y las ganas de comerme el mundo aumentan. Abro el navegador y mi editor de código favorito (que, por supuesto, es Vim y no ese engendro devora-recursos llamado Atom que usa Toni).
Mientras tomo el primer sorbo de café leo el único ticket de soporte que tengo en mi bandeja de entrada: un cliente al que no le funciona bien Nelio Content cuando toca compartir una entrada. ¡Qué raro! Solo le pasa a él, así que estoy seguro de que debe ser un problema con su instalación. Probablemente algún plugin.
No es la mejor forma de empezar una mañana, pero como mínimo sé que será un día entretenido. Ahora toca investigar qué está pasando… y es que el mundo del desarrollo en WordPress es un camino tortuoso y difícil. En un par de horitas junto a Toni hemos sido capaces de detectar cuál es la causa del problema: el loop de WordPress. En concreto, la forma en que WordPress gestiona los loops anidados.
Como es un tema un poco complejo y explicarlo de esta forma lo hace aún más confuso, mejor pasamos a un ejemplo sencillo y concreto con el que pueda explicarte qué pasó exactamente y qué hicimos para solucionarlo, ¿te parece? Así que, venga, ¡vamos a hablar del loop de WordPress!
Recordemos qué era el Loop de WordPress
Hace un par de años ya, Toni escribió una serie de entradas donde explicaba qué es y cómo funciona el loop de WordPress, cómo puedes modificarlo y algunos trucos avanzados. Si te las perdiste, te recomiendo que las leas detenidamente hoy; son muy amenas y aprenderás todo lo que necesitas saber para entender la entrada de hoy. De todas formas, y para ponerte en contexto, recordemos la definición que nos daba Toni entonces:
El Loop de WordPress determina qué contenido (entradas, páginas o contenido personalizado) se va a mostrar cuando navegas a una página de tu web. (…)
Simplificando al máximo, WordPress funciona del siguiente modo: el Loop hace una consulta a la base de datos de WordPress para obtener una serie de entradas (o páginas, ya me entiendes) teniendo en cuenta ciertos parámetros.
Es decir, el loop no es más que la forma que tiene WordPress de recuperar un conjunto de entradas y «manipularlas» (normalmente para mostrarlas en pantalla). Veamos un ejemplo muy sencillo de dicho loop:
¿Eres capaz de identificar todas las partes del loop? Es muy sencillo, fíjate: en las líneas 3-6 establecemos los parámetros de nuestra búsqueda (en este caso, queremos 5 contenidos de tipo post), en las líneas 9 y 10 vamos iterando por todas las entradas que ha encontrado, pintando el título de cada entrada en una lista, y finalmente en la línea 15 deshacemos este bucle que hemos montado y volvemos a lo que sea que estuviera haciendo WordPress.
Pues bien, ahora que ya has entendido cómo funciona el loop, veamos qué nos pasó en Nelio.
Ejecutando múltiples Loops a la vez… ¡esto es un cacao!
En nuestro plugin definimos una función más o menos sencilla que, dado el identificador de una entrada, nos devolvía un array con datos sobre esa entrada. Algo tal que así, vaya:
Como puedes ver, nada nuevo bajo el sol. En esta función, sencillamente construimos el loop en las líneas 5-7, comprobamos que la entrada existe y si no existe nos vamos cancelando este loop que acabamos de empezar en las líneas 9-12, y luego ya pasamos a lo de siempre: cargamos la entrada (línea 14), montamos el array que queremos devolver y acabamos. Sin problemas, ¿no?
Supongamos, por ejemplo, que llamamos a esta función con el identificador de entrada 1
y que el resultado que esperamos es el siguiente:
Pues bien, aunque parezca mentira, el resultado que obteníamos era este:
Tal y como puedes ver, el título ya no es My First Post, sino que nuestra función nos devuelve un título totalmente diferente (Some Randome Title), el cual corresponde a otra entrada de nuestro blog. ¿Qué narices está pasando aquí? ¿Por qué nuestra función, aparentemente sencilla, está fallando de forma tan estrepitosa?

Nelio Content
Estoy tan contento con Nelio Content que parece que me hayan pagado para hablar bién de él… pero es que también a ti te encantará: funciona como prometen, la programación automática de mensajes es increíble, la calidad/precio no tiene parangón y su equipo de soporte se siente como si fueran parte del tuyo.

Panozk
¡Yo os maldigo, loops anidados!
Pues la explicación es sencilla y desafortunada…
Nuestro cliente tenía un plugin instalado que añadía una lista de entradas relacionadas al contenido de la entrada. Como puedes imaginar no era un plugin sencillo, pero la esencia de lo que hacía era lo siguiente:
Básicamente, este otro plugin lanzaba un nuevo loop para buscar entradas relacionadas al contenido actual (en el ejemplo hemos puesto a saco el identificador 25
), recuperaba las entradas relacionadas para añadirlas en el contenido, reseteaba la «query original» con wp_reset_postdata()
y tan a gusto. Hasta aquí, todo normal y ejecutado perfectamente.
Ahora bien, ¿has visto en qué momento se ejecuta este fragmento de código? Efectivamente, en el momento en que se ejecuta el the_content
. ¡Anda, mira, pero si la llamada de nuestro plugin ejecutaba este filtro precisamente en la línea 18! ? ¿Cuál es el título de la entrada 25
?
¡La madre que me…! Resulta que el título incorrecto que estoy poniendo en la entrada 1
es el de la entrada 25
y, ¡oh, qué casualidad!, es precisamente la entrada que se ha cargado en un loop anidado. Es decir, que mientras yo estoy montando el array para la entrada 1
, otro plugin ha lanzado un segundo array para la entrada 25
y, a partir de ese momento, WordPress se ha hecho la picha un lío y ya todo lo mío sale mal. ??
Cómo solucionar el problema de múltiples Loops anidados pisándose las mangueras
Bueno, parece que una vez encontrado el problema la solución debería ser super sencilla, ¿no? Esto debería ser el abecé del mundillo WordPress, ¿no? ¡¿No?! Pues eso pensaba yo y por eso posteé mi duda en los foros de WordPress…
…y al rato ya tenía una respuesta de Pascal Birchler (¡cómo mola la comunidad!). Por desgracia, la respuesta no fue demasiado reconfortante, puesto que la podemos resumir en dos puntos:
wp_reset_postdata
no sirve para recuperar la entrada del loop que se estaba ejecutando justo antes de mí… sirve para recuperar la entrada del loop principal (tal y como indica la documentación). Por lo tanto, esta llamada, puesta de tan buena fe por el plugin de entradas relacionadas y por nosotros mismos, no sirve para lo que yo pensaba ?- La forma de solucionar este problema es… no haciéndolo así. Es decir, no uses llamadas que puedan tener filtros (accediendo, por ejemplo, a
$post->post_content
directamente) o incluso usando la API REST (?).
Aunque agradezco muchísimo el soporte gratuito y desinteresado que recibí, la verdad es que no quedé muy satisfecho con la solución. Así que opté por algo diferente y radical: cada vez que ejecuto un template tag, reseteo manualmente mi loop cada vez (con $query->reset_postdata()
) para garantizar que la siguiente llamada se ejecutará sobre la entrada que toca:
La verdad es que no estoy muy orgulloso de esta solución ?, puesto que parece un poco ñapa ?… pero, oye tú, funciona ?
¡Y eso es todo por hoy! Ya sólo me queda lanzarte una preguntilla: ¿te ha pasado algo a ti parecido? ¿Cómo lo has solucionado? En serio, si tienes una solución mejor a este problema, dímela porque me encantaría conocerla ?
Deja una respuesta