WP desde cero (10): modificar el loop I

En esta entrada aprenderemos a modificar el loop principal de WordPress mediante la función query_post() y el gancho pre_get_posts

Roy Lichtenstein

archivado en: WordPress / 14 diciembre, 2012 / taller:

Ya sabemos cómo trabajar con el loop de WordPress con sus valores por defecto, pero hay muchas ocasiones en las que se necesita modificar algún parámetro, como excluir una categoría o mostrar menos post que los indicados en los ajustes generales.

En esta entrada y la siguiente conoceremos las cuatro maneras principales de modificar el loop, que por orden creciente de complejidad son:

  1. cambiar la query con query_post()
  2. usar un hook (gancho),
  3. usar la clase WP_Query,
  4. trabajar directamente contra la base de datos.
En la primera parte veremos cómo se trabaja con query_post() y el hook y en la segunda las otras dos.

1. query_post()

Cuando se hace una consulta a la base de datos, por ejemplo para recuperar los post de un blog, se envía una instrucción que traducida tiene este aspecto: «Selecciona de la tabla post las últimas 10 entradas publicadas ordenándolas por fecha». Esta instrucción se denomina query.

WordPress usa una query por defecto en el loop que podemos modificar usando la función query_post() justo antes de que comience el bucle while. La sintaxis básica es:

  1. <?php
  2. query_posts( $args );
  3. while ( have_posts() ) : the_post();
  4. the_title();
  5. // más cosas del loop...
  6. endwhile;
  7. wp_reset_query();
  8. ?>

La expresión $args es habitual en el mundo WP y significa «argumentos», que en este caso son los parámetros de la query. Estos se pueden definir de dos maneras, una es indicándolos directamente entre comillas simples en los paréntesis de la función. Por ejemplo, así se indica que solo deben recuperarse los últimos 5 post:

  • query_posts(  'posts_per_page=5' );

Para modificar más de un parámetro, se concatenan con &, que significa «y» en inglés. Así, por ejemplo, recuperamos los primeros 5 post de la categoría 3.

  • query_posts(  'posts_per_page=5&cat=3' );

Y con el signo negativo, indicamos que queremos los primeros 5 post que no sean de la categoría 3.

  • query_posts(  'posts_per_page=5&cat=-3' );

La query original, sin alterar, tiene una serie de parámetros definidos desde el back-end, como el número de post a mostrar. Cuando usamos esta manera de alterar el loop, podemos recuperarlos y cambiar solo los que se necesiten mediante la variable global $query_string, que se puede concatenar al fragmento de la query personalizada con un punto (.), al igual que se concatena cualquier cadena de texto de PHP con variables.

  • global $query_string;
  • query_posts( $query_string . '&cat=3' );

La segunda manera de enviar argumentos a query_post  es usando un array, que ya sabemos qué es. Lo más limpio es definirlo primero y luego incluirlo en la función, aunque se puede hacer directamente.

  • $args = array(
  • 'cat' => 22,
  • 'year' => $current_year,
  • 'monthnum' => $current_month,
  • 'order' => 'ASC' );
  • query_posts( $args );

De todas maneras, si los cambios van más allá de introducir un matiz aprovechando la variable $query_string, es mejor usar la clase WP_Query que veremos más adelante.

Un detalle más antes de terminar este apartado. Como veremos, WordPress incluye un sistema de paginación automática, el cual se descabala cuando alteramos el loop de esta manera. Para recuperarlo hay que hacer un apaño que ya analizaré en detalle en otra entrada:

  • <?php
  • $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
  • query_posts('posts_per_page=12&paged='.$paged);
  • ?>

Muy importante: cuando se usa query_post() se modifican los parámetros de todas las querys que siguen a esta. Por ejemplo, imaginemos que la portada de una web tiene esta estructura:

  • Loop normal
  • Plugin 1 normal
  • Plugin 2 con query_post
  • plugin 3 normal

Al llegar al plugin 2, se modifica la query normal, lo cual afectaría al plugin 3, que no se comportaría de forma correcta. Para evitar esto es muy importante resetear la query al final cuando se use query_post() mediante la función wp_reset_query().

2. pre_get_posts

Por razones imposibles de explicar de forma sencilla (ver explicación de Andrew Nacin), es mucho más eficiente si en vez de usar query_post() se utiliza un hook llamado pre_get_post.

Los hook o ganchos son instrucciones que se ejecutan durante algún momento del proceso que va desde que un dispositivo se conecta a la web hasta que el server le envía la información. Explicado de otra manera...

Cuando un dispositivo cliente se conecta a un sitio realizado en WordPress (1), el motor del CMS comienza a ejecutar una serie de instrucciones internas (2); luego busca si hay hooks, que son más instrucciones que pueden modificar el comportamiento natural de las primeras (3); a continuación realiza la consulta, la query, a la base de datos (4); a ese resultado opcionalmente puede hacerle algunos cambios, como aplicarle más hooks (5); envía toda esa información al dispositivo cliente, que es el que se encarga de procesar el HTML, las CSS y el JavaScript (6) para mostrar finalmente la página por pantalla.

[singlepic id=47 w=600 h=247 float=center]

Entonces, query_post() funciona tras la fase 4, por lo que WP debe lanzar una segunda query ajustada a los nuevos parámetros; por el contrario, con el hook pre_get_post, la query se ejecuta ya modificada desde un principio. Esto es porque, como decía, los hooks pueden «engancharse» en cualquier momento del proceso. Por ejemplo, con init se ejecutan en cuanto WP ha terminado de cargarse y con pre_get_post justo antes de que se ejecute la query.

Hay dos tipos de hooks, las acciones (actions) y los filtros (filter), cuyas peculiaridades y diferencias estudiaremos más adelante. De momento, nos basta con saber que la sintaxis básica de las acciones es:

  • <?php add_action( 'momento en que debe engancharse el hook', 'nombre de la función' , [prioridad], [argumentos]); ?>

Es decir, en el primer parámetro indicamos en qué fase del proceso hay que ejecutar el hook y en el segundo, separado del primero por una coma, la función que debe cargarse en ese momento. De los dos parámetros opcionales, prioridad y argumentos, solo nos interesa ahora el primero, que permite establecer en una escala del 1 al 10 el orden en que deben ejecutarse los hooks y en nuestro caso debe ser lo más alto posible, un 1.

Por lo tanto, en el archivo functions.php, que recordemos es donde se incluyen todos los códigos que alteran el comportamiento natural de WP, hay que añadir un hook de este tipo:

  • <?php add_action( 'pre_get_posts', 'cambia_queries' , 1); ?>

Pero, antes, hay que definir la función que estamos enganchando:

  • <?php
  • function cambia_queries ( $query  ) {
  • // Aquí el código para cambiar la query
  • }
  • add_action( 'pre_get_posts', 'cambia_queries' , 1);
  • ?>

Para entender lo que sigue, sería recomendable saber algo sobre programación orientada a objetos. De todas maneras trataré de explicarlo de la forma más sencilla que pueda. En la función podemos recuperar varias propiedades de la clase  WP_Query, que veremos con más detalle en la próxima entrada, como $query o $post_count entre otras. La que nos interesa es $query.

Una vez accedido a la propiedad $query, podemos trabajar con varios métodos, pero de momento solo necesitamos el método set, que en inglés significa cambio.

  • set( 'parámetro a cambiar', 'valor' )

Se pueden cambiar muchos parámetros. Algunos habituales son:

  • set( 'cat', 1): selecciona solo los post de la categoría 1.
  • set( 'cat', -1): selecciona todos los post menos los de la categoría 1.
  • set( 'tag', 'etiqueta1, etiqueta1'): selecciona solo los post con el tag «etiqueta1» y «etiqueta2».
  • set( 'author', 'asdrubal'): selecciona solo los post escritos por «asdrubal»
  • ...

En fin, hay un montón que se pueden consultar en la documentación de WordPress, por lo que no vale la pena repetirlos aquí.

Ya solo nos falta un detalle para terminar de preparar el hook. Por lo general, no se necesita aplicar para las consultas de todo el sitio web, sino solo para las que se realizan en algunos sitios concretos. Para acotarlo, podemos usar unas estructuras condicionales de WP que identifican dónde se encuentra el usuario, como veremos en detalle más adelante. Por ejemplo, con is_home() se puede acotar el hook para que solo funcione en la página principal, en la home.

Pero, además, mediante la función is_main_query() podemos acotar aún más el gancho para indicar que solo debe funcionar en la home y solo en la consulta principal.

Por último, indicamos que solo debe funcionar en el front-end mediante la función is_admin(), que si va precedida de una exclamación significa que no debe ser el back-end.

Así, por ejemplo, quitaríamos la categoría 44 del loop principal, en el cual solo se recuperan 12 post, estén definidos más o menos en los Ajustes.

  • function cambia_queries ( $query ) {
  • if ( ! is_admin()&& is_home() && $query->is_main_query() ) {
  • $query->set( 'posts_per_page', 12 );
  • $query->set( 'cat', -44);
  • return;
  • }
  • }
  • add_action( 'pre_get_posts', 'cambia_queries' , 1);

Bueno, soy consciente de que esta entrada ha sido más compleja que las anteriores, las siguientes serán en general más sencillas, pero al menos ya sabemos cómo cambiar el loop de forma correcta si alguna vez necesitamos hacerlo.

Abrazos++;

Más información en:

|| Tags: , , , ,

valoración de los lectores sobre WP desde cero (10): modificar el loop I

  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración negativa
  • 4.2 sobre 5 (11 votos)

¿Te ha parecido útil o interesante esta entrada?
dormido, valoración 1 nadapensativo, valoración 2 un poco sonrisa, valoración 3 a medias guiño, valoración 4 bastante aplauso, valoración 5 mucho

Tú opinión es muy importante, gracias por compartirla!

5 respuestas a “WP desde cero (10): modificar el loop I

  1. La verdad que para los que recien empezamos con WordPress estas series de Tutoriales tan didácticos nos vienen geniales, y sobre todo en Español [que escasean en la web]…Gracias y saludos

  2. Pero qué cariño te he cogido en dos días XD
    Ojalá el codex estuviera en español y así de bien explicadito for Dummies.

    Lo que llevo días tratando de entender (ya que no se muy bien cómo se estructura internamente WordPress), lo he aprendido contigo en cuatro ratos.

    Muchas gracias y, por favor, sigue así.

  3. Hola, a ver si me puedes ayudar que llevo tras ello varios meses y no lo consigo. Quiero que en distintas páginas de mi blog se muestren categorías determinadas. No sé dónde tengo que modificar el loop ni de qué manera ya que cada vez que lo intento me sale error 500. Gracias….