13 oct 2012

Cómo crear correctamente bucles o loops personalizados en WordPress

Cómo crear correctamente bucles o loops personalizados en WordPress:
En WordPress existen varias formas de realizar consultas personalizadas a la base de datos para traer algunos contenidos específicos y mostrarlos en las plantillas de tu theme o plugin:

  • pre_get_posts(): es un filtro, no una función de consulta a la BD. Para alterar el bucle principal.
  • query_posts(): ¿¿??
  • WP_Query(): para crear bucles alternativos o secundarios.
  • get_posts(): para crear bucles alternativos o secundarios.

Estos son los recursos principales que propone WordPress para modificar los bucles o crear bucles alternativos a los principales, para mostrar nuestros contenidos de diferentes formas en las plantillas. Y lógicamente, esto es algo que hay que hacer con cuidado y de la forma correcta para evitar errores y problemas de eficiencia.

Y ahora los explico un poco, :)

El bucle principal de WordPress


Antes de nada hay que explicar qué es el main loop o bucle principal de WordPress: es la forma que tiene el CMS para mostrar los posts que deben aparecer en esa página, procesarlos y disponerlos en la pantalla de la forma que se defina a través los diferentes Template Tags. La consulta principal a la base de datos y el procesado de la misma tiene lugar antes de la carga de la plantilla, basándose en la URL que se está visualizando.

En un theme de WordPress, cada plantilla tendrá probablemente un bucle principal. En el código, comienza de esta forma:


<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>


Y acaba normalmente así:

<?php endwhile; else: ?>
    <p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>


Los template tags que se incluyan en el código dentro de ese bucle, harán referencia a la consulta principal de WordPress.

pre_get_posts()


Si lo que se quiere es modificar directamente la consulta del bucle principal, pero no crear una nueva, entonces la recomendación es utilizar el filtro pre_get_posts(). Esta función nos permite alterar fácilmente los parámetros de la main query.

Por ejemplo: queremos modificar el número de posts mostrados en la portada de la página a sólo 4 y, además, que no aparezcan los posts de la categoría “7″. Lo haríamos fácilmente con las siguientes líneas de código:


function hmuda_modificar_main_query($query){
    //Primero asegurar que es la consulta principal y que es la home
    if( is_home() && $query->is_main_query() ){
        //Hacer la modificación que sea
        $query->set( 'posts_per_page', '4' );
        $query->set( 'cat', '-7' );
    }
}
add_action('pre_get_posts', 'hmuda_modificar_main_query');


Utilizando el método set() podemos pasarle todos los parámetros que deseemos a la main query para modificarla a nuestro gusto.

query_posts()


La función query_posts(), como bien explican en la primera frase del Codex, es la forma más sencilla de alterar la consulta principal de WordPress, pero no es la preferida ni la más eficiente. De hecho, algunos desarrolladores de renombre como Konstantin Kovshenin no dudan en afirmar que debería declararse como obsoleta.

Esta función “destruye” la consulta principal de WordPress sobreescribiendo la variable global que la contiene. Sí, la consulta que ya tenía cargada, procesada, limpita y maquillada para salir a la calle.

Se recomienda no utilizar esta función. Siempre que se quiera usar para modificar la consulta principal, probablemente sea una mejor idea utilizar pre_get_posts().

En cualquier caso, si por alguna extraña razón se usa, la forma recomendada para restaurar el bucle principal después de usar query_posts() es utilizar la función wp_reset_query().

WP_Query()


En caso de querer crear bucles alternativos en una plantilla de WordPress, esta es la forma recomendada. Con este método se crea una nueva instancia del objeto WP_Query sin alterar ni afectar a la consulta principal del gestor.

Ejemplo: un bucle alternativo para mostrar los títulos de los últimos 3 posts de la categoría “8″ pero saltándonos el primero:


//Definir los parámetros de la consulta a la base de datos
$args = array(
    'posts_per_page' => 3,
    'cat'  => 8,
    'offset' => 1
);
$loop_alternativo = new WP_Query($args);
if( $loop_alternativo->have_posts() ):
    while( $loop_alternativo->have_posts() ): $loop_alternativo->the_post();
       //Ya estamos en el bucle alternativo
       the_title();
    endwhile;
endif;
wp_reset_postdata(); 


Hay que acordarse de que este loop alternativo sobreescribirá la variable global $post (que es la que buscan las template tags), por lo que una vez terminado deberemos siempre restaurar su estado al de la consulta principal. En caso contrario, WP creerá que el post actual del bucle principal es el último post del bucle alternativo, lo que es incorrecto y dará lugar a errores. Puede resetearse fácilmente utilizando la función wp_reset_postdata().

get_posts()


Es una especie de envoltorio para WP_Query(), para crear nuevas instancias del objeto WP_Query. No es en realidad un bucle, sino que la función acaba devolviendo un array de objetos de tipo post. Por tanto, podemos guardar ese array en una variable e iterar sobre ella para crear nuestro propio bucle personalizado.

Ejemplo (el mismo de antes): un bucle alternativo para mostrar los títulos de los últimos 3 posts de la categoría “8″ pero saltándonos el primero:


//Definir los parámetros de la consulta a la base de datos
$args = array(
    'posts_per_page' => 3,
    'cat'  => 8,
    'offset' => 1
);
global $post;
$myposts = get_posts( $args );
foreach( $myposts as $post ) : 
    //Ya estamos en el bucle alternativo
    setup_postdata($post); 
    the_title();
endforeach;
wp_reset_postdata(); 


La función setup_postdata() es una función que prepara el objeto global $post para su utilización con los template tags dentro del bucle.

La forma recomendada para reiniciar el bucle principal después de usar get_posts() es utilizar la función wp_reset_postdata().

Más información


Para más información sobre este tema, recomiendo ver y tomar nota de esta conferencia de Andrew Nacin en la que explica el sistema de queries de WordPress:


Enlaces de interés: