email telefono contacto

WP_Query de WordPress

En este post te voy contar todo lo referente a la clase WP_Query. No solo te mostraré su funcionamiento con ejemplos, sino que haremos un recorrido por su código y su ciclo de vida.

El objetivo es que, cuando termines el post, tengas unos conocimientos más profundos y técnicos sobre WP_Query.

Como te comento, este artículo es algo técnico, por lo que tómate tu tiempo para leerlo. No tengas prisa.

Sin más dilación, ¡comenzamos!

WP_Query de WordPress 1
¡Suscríbete al boletín!

No te enviaremos spam, lo prometemos. Enviamos a nuestros suscriptores contenido sobre WordPress, hosting, marketing digital y programación.

+ Información básica sobre protección de datos

Conocimientos básicos: Antes de empezar a trabajar con WP_Query

Antes de que sigas leyendo, te aconsejo que pares un momento a leer este apartado, pues a lo largo del post encontrarás ciertos tecnicismos y conceptos de un nivel intermedio.

Para que puedas comprender la totalidad del post, necesitas tener algunos conocimientos previos que te enumero a continuación:

  • Entender los conceptos básicos de PHP: Deberás estar familiarizado con términos como clase, métodos, atributos… ya que vas a encontrar toda esta terminología a lo largo del post. No necesitas ser un programador experto, pero sí tener asentadas las bases.
  • Disponer de conocimientos intermedios sobre WordPress: Para comprender mejor este artículo, es aconsejable que ya estés familiarizado con la estructura de WordPress y que, al hablarte del término post, no solo se te venga a la cabeza una entrada de un blog, sino que además sepas que un post es también un tipo de dato que usa WordPress de forma interna.
  • Conocer lo esencial sobre MySQL: Como el tema que vamos a tratar a lo largo de este artículo está estrechamente ligado con el acceso a base de datos, es aconsejable que tengas conocimientos básicos al respecto.

¿Qué es WP_Query?

WP_Query es una de las clases más importantes definidas en el core de WordPress. Se utiliza para facilitar el acceso a nuestra base de datos.

Esta clase no solo nos simplifica el trabajo al realizar nuestras consultas, sino que proporciona una forma segura y simple de hacerlo.

Seguridad

Uno de los puntos importantes que realiza WP_Query tiene que ver con la seguridad. Vamos a decir que «sanea» los datos que recibe, además de hacer diferentes comprobaciones para validar los tipos de datos recibidos a través de diferentes métodos.

Estas acciones permiten dotar a las consultas de un nivel de seguridad y prevenir problemas como, por ejemplo, una inyección por SQL, que es uno de los ataques más comunes.

Aunque la comprobación y el «saneamiento» de los datos que se realiza internamente son imprescindibles siempre que trabajamos con nuestra base de datos, te recomiendo encarecidamente que sigas una guía de seguridad para WordPress para proteger tu sitio web de otras posibles vulnerabilidades.

Simplicidad

WP_Query simplifica de forma significativa el trabajo al realizar nuestras consultas hacia la base de datos.

Si alguna vez has hecho una consulta en SQL un poco difícil, habrás sufrido en tus propias carnes lo complicado y engorroso que puede ser. Especialmente, si hablamos del uso de la instrucción JOIN.

Gracias al uso de WP_Query nos olvidamos de todos estos problemas y utilizamos únicamente una matriz o array que pasaremos por parámetro, donde le indicaremos las acciones que debe realizar de forma mucho más simple y legible.

El ciclo de vida de WP_Query

Aunque no necesitas saber cómo es el ciclo de vida de WP_Query para poder utilizarlo, creo que es interesante comentarte por encima cómo funciona internamente esta clase. Esto te permitirá tener unos conocimientos más profundos y comprender mejor su funcionamiento y, por ende, también te facilitará su uso.

En este apartado te voy a hablar con algunos términos avanzados como objetos, clases, métodos o instancias. Soy consciente de que estas explicaciones se pueden hacer algo pesadas. Por eso, si te resulta difícil de entender no te preocupes, puedes saltarte este punto.

Ciclo de vida de WP_Query

Inicialización de WP_Query

El primer paso de todos sería inicializar el objeto. Esta acción la realizamos cuando creamos una nueva instancia.

 new WP_Query($args);

Al inicializarla se hará uso de su método query que, a su vez, llamará a una serie de métodos, entre los que se encuentra el principal, denominado init.

Esta función hará que comience su ciclo de vida. Dicho método llamará a init_query_flags, que establecerá a false las flags usadas en la construcción de la query.

Función llamada al inicializar un objeto de WP_Query

Extrayendo los argumentos

En este paso se extraen los argumentos que le hemos pasado por parámetro. La forma más conocida es a través de un array o matriz, aunque también acepta los argumentos en formato de url.

Si le pasamos nuestros argumentos en formato string o de url, convertirá estos en una matriz o array a través de la función wp_parse_args.

En ambos casos, estos argumentos serán utilizados para construir la consulta, siendo almacenados en las variables de query y query_vars que están definidas como propiedades o atributos de la clase.

En general no hay muchas diferencias entre ellas. query_vars contiene la información almacenada en query y alguna extra, como los argumentos por defecto que no hayamos especificado.

Además, me parece importante comentar un detalle: el método wp_parse_args no es propio de la clase WP_Query, sino que se encuentra dentro de functions.php en la carpeta wp-includes. En este fichero se ubican múltiples funciones que son utilizadas a través de todo el core de WordPress.

Función wp_parse_args utilizada por todo el core de WordPress

Estableciendo los flags para la consulta

Una vez que se han asignado los argumentos a las propiedades que te he mencionado antes, comenzamos una nueva etapa donde se asignarán los valores correspondientes a las flags que WP_Query tiene como parámetros.

Este proceso se realiza a través de la función parse_query donde no solo se asignan las propiedades de las flags, sino que también realiza acciones de seguridad, como comprobaciones de tipo y saneamiento.

Todas estas acciones las realiza a través de un extenso fragmento de código que, básicamente, contiene una consecución de estructuras de control como if, elseif y else.

Cuando hablamos de flags en programación nos referimos a variables donde se almacenan los estados de nuestra aplicación o software. Estas variables suelen ser de tipo booleano (true o false). Por ejemplo, si estamos recorriendo un bucle podríamos utilizar una variable con el nombre is_loop y, dentro del bucle, asignarle un valor true. Una vez que salgamos del mismo, podremos actualizar nuestra flag o variable y asignarle un valor false.

Convirtiendo los argumentos en una sentencia SQL

Una vez finalizado el método parse_query ya se han establecido todas las propiedades necesarias para poder empezar construir la consulta, pero todavía no tenemos una sentencia SQL que nuestra base de datos pueda entender.

Se construye en el método get_posts (un método muy similar a parse_query). Esta función o método contiene un gran bloque de código con declaraciones condicionales que irán construyendo nuestra consulta.

Exactamente, tiene algo más de 1500 líneas de código, en las cuales el método get_post hace acopio de otras clases importantes como WP_Meta_Query, WP_Date_Query y WP_Tax_Query, todas ellas pertenecientes al código interno de WordPress.

Además del uso de diferentes clases, también nos define dos hooks que podemos usar: pre_get_posts y posts_selection. De estos dos ganchos, pre_get_posts nos permite realizar acciones muy interesantes al trabajar con la consulta.

Por el contrario, el hook posts_selection no tiene mucha funcionalidad «práctica» y está enfocado a ser trabajado con motivos de cacheo.

Generando objetos WP_Post

El último proceso del ciclo de vida de WP_Query es convertir los resultados obtenidos a objetos de WP_Post.

Esta conversión sucede cuando el método get_posts es llamado. Una vez se han convertido los resultados a objetos de WP_Post, podemos acceder a través de ellos con la variables posts contenida en la clase de WP_Query.

Si buscamos en el fichero, podemos observar que la conversión se produce exactamente en esta línea:

$this->posts = array_map( 'get_post', $this->posts );

Esta línea hace uso de unos de los múltiples métodos que PHP nos proporciona para el manejo de arrays. Concretamente, hace uso de array_map.

Una vez finalizada la ejecución de array_map, se asigna el valor de la propiedad posts y ya estaremos listos para trabajar con ellos.

¿Cómo funciona WP_Query?

En este apartado te voy hablar de cómo funciona WP_Query y de cómo trabaja a través de The Loop o El bucle.

«The Loop» en WordPress

Para comprender mejor el uso de WP_Query te podría poner múltiples ejemplos de cómo sacar entradas, pero la finalidad de este artículo es que tengas un conocimiento profundo de la clase WP_Query y, para ello, tengo que hablarte del «The Loop».

Básicamente, «The Loop» es un fragmento de código utilizado por WordPress para procesar y mostrar posts.

Antes de que apareciera la clase WP_Query, WordPress ejecutaba una query en el fichero wp-blog-header.php.

El “Loop” no era más que una iteración a través de un foreach que guardaba los resultados en la variable global de posts. Por aquel entonces, no se podía volver a ejecutar la consulta y simplemente se ejecutaba al cargar una página.

Con la llegada de la clase WP_Query la metodología cambió, guardando los resultados como propiedades de dicha clase y permitiendo crear diferentes bucles y ejecuciones.

El loop y WP_Query

Ahora que sabes un poco la historia del loop de WordPress, te voy a contar cómo interactúa la clase de WP_Query con el loop.

A grandes rasgos, la interacción entre WP_Query y el loop se resume en el uso de una serie de variables internas que administra a medida que son ejecutadas por el bucle.

Las variables que administra internamente son 4 y, a continuación, te explico un poco de cada una:

  • current_post: Almacena el valor del índice de la publicación actual en el array de publicaciones.
  • in_the_loop: Consiste en un flag o bandera que indica si está dentro del loop o no.
  • post: Es un objeto de WP_Post correspondiente al índice current_post.
  • post_count: Rastrea el número total de publicaciones en el array de publicaciones.

Comprobando que existen posts en el bucle

WP_Query realiza una comprobación antes de ejecutar el bucle. Esta comprobación se realiza a través del método have_posts, el cual nos retornará true o false dependiendo de si existen registros post o no.

Para cerciorase de que existen posts, el método have_posts realiza una comparación de las propiedades current_post y post_count que vimos en el punto anterior.

Una vez finalizado el bucle, have_posts llama al método rewind_posts, el cual restablece el índice de current_post a -1 y cambia otras variables internas que manejan el bucle.

Función have_post que comprueba si existen resultados que podamos iterar

Iterando sobre los posts

Como te contaba, antiguamente «The loop» consistía en un simple foreach, pero este fue reemplazado por el método the_post.

Cada vez que se llame a este método, se configurará el indicador in_the_loop a verdadero. Después de comprobar que current_post posee el value de -1, llamará a loop_start, que iniciará el bucle.

Se comenzará a llamar al método next_post que incrementará el índice en uno, obteniendo el post actual y retornando sus datos para que puedas trabajar con su contenido.

¿Cómo utilizar WP_Query?

Hasta este punto nos hemos centrado en aprender el funcionamiento interno de WP_Query: su ciclo de vida, algunas propiedades, métodos… Ahora nos vamos a ensuciar las manos y vamos a ver cómo utilizarlo a través de ejemplos.

Ten en cuenta que al ejecutar querys en WordPress estas tendrán un impacto en el rendimiento de tu sitio web, por lo que es importante trabajarlas de forma correcta.

Puedes comprobar el rendimiento a través del plugin de Query Monitor y revisar el tiempo de carga o el número de consultas que tu WordPress está ejecutando.

Creando un loop básico con WP_Query

A través del siguiente ejemplo te voy a desglosar lo que necesitas saber para construir un bucle con WP_Query.

Voy a abarcar los puntos más importantes que necesitas para construir tus consultas y personalizar su contenido.

Te recomiendo que no implementes ningún código directamente en tu hosting de producción y que lo hagas en un servidor que tengas dedicado para hacer pruebas o desarrollar. Si no posees ninguno, puedes echarle un vistazo a nuestro hosting de WordPress que está pensado específicamente para trabajar con este CMS.

$args = array (
    // Argumentos que serán utilizados para construir la query.
    // En este caso, se devolverán todos los posts sin paginación
    'pagination' => false,
    'posts_per_page' => '-1',
);
// Instancia del objeto pasando por parámetro los argumentos.
$the_query = new WP_Query( $args );
// Comprobamos que existen resultados.
if ( $the_query->have_posts() ) {
	// Comenzamos el bucle sobre los resultados.
	while ( $the_query->have_posts() ) : $the_query->the_post(); 
		// Código para trabajar con el post
		echo '<h2>' . the_title() . '</h2>';
	endwhile;
} else {
	// Código en caso de que no existan resultados
}
// Restablecemos los datos de $post
wp_reset_postdata();

$args: matriz o array donde definiremos los datos que nos interesen para construir nuestra consulta. WP_Query admite un gran número de valores para configurar en nuestro array. Te voy a indicar brevemente algunas de las más usadas:

  • author (int | string): El id del author o lista de autores separados por coma. Es posible excluir algún id específico utilizando el caracter «-«.
    'author' => '1,2,3,'
  • author_name (string): Utiliza el campo ‘user_nicename’. Es importante no confundirlo con el campo name.
    'author_name' => 'raiolanetworks',
  • cat (int): Desplegará los post asociados a la categoría indicada, así como sus categorías hijas, todo ello utilizando el id de categoría.
    'cat' => 5,
  • tag (string): Utiliza el tag de categoría para desplegar los post asociados.
    'tag' => 'tutorial',
  • tax_query (array): matriz o array utilizado para construir consultas complejas. Podemos indicar relaciones con otras tablas, operaciones, exclusiones…  Quizás sea el argumento más complejo de manejar.
    'tax_query' => array(
    	array(
                'taxonomy' => 'my-taxonomy',
                'terms' => array(
                    '11',
                    '12'
                ),
                'operator' => 'NOT IN'
    	)
    )
  • post_type (string / array): Permite retornar los post por su tipo. Por defecto, su value es ‘post’. Se puede usar para retornar CPT o Custom Post Type.

Estos son algunos de los valores que se pueden establecer en args, pero existen muchos otros que no he mencionado, por lo que te puedes hacer una idea de la flexibilidad y facilidad con la que podemos construir querys.

Si te interesa, te facilito una lista completa de los argumentos de WP_Query que puedes utilizar al definir tu array para construir la consulta que desees.

Quiero mencionar también que existen varios argumentos con valores por defecto y que, por lo tanto, si no son especificados en nuestro array, se tomarán esos valores. Estos argumentos son los siguientes:

  • posts_per_page: Este valor se almacena en base de datos en el option ‘posts_per_page’.
  • post_type: Por defecto, tomará el valor ‘post’.
  • post_status: Por defecto, tomará el valor ‘publish’.

Inicialización: Como ya sabes, la instancia de un objeto de WP_Query la realizamos con la siguiente línea:

$the_query = new WP_Query( $args );

No hay mucho que explicar sobre esto. Simplemente crea un nuevo objeto donde le pasaremos los argumentos por parámetro y construirá la query en base a ellos.

Método have_posts(): Como he mencionado antes, este método simplemente se encarga de comprobar que tenemos resultados que podamos recorrer.

Bucle while: Recorrerá todos los resultados hasta el último mientras haya resultados. Al llamar al método the_post() podremos disponer de los métodos propios de un Post como the_title() o the_content(), entre otros.

Reseteando los datos: Si estamos utilizando WP_Query dentro de un template o página deberíamos hacer un reseteo de los datos, ya que WordPress utiliza la variable $post de forma global. Esta variable contiene los datos del post actual, pero al hacer uso de WP_Query y llamar al método the_post la sobreescribimos.

Para realizar el reseteo solo debemos utilizar el método wp_reset_postdata(). Así nos aseguramos que, si posteriormente utilizamos métodos propios sobre la variable global $post, nos devuelva los datos de $post actual y no el valor asignado por WP_Query.

También existe una función similar denominada wp_reset_query(). Hace casi lo mismo. La diferencia es que deberíamos utilizar esta última si se han realizado modificaciones con query_posts().

Ejemplos de uso de WP_Query

Voy a mostrarte algunos ejemplos de WP_Query que te pueden ayudar a comprender mejor su uso y que abarcan diferentes consultas. Veremos diferentes valores que podemos establecer en nuestro array de argumentos y que nos proporcionarán diferentes consultas en base a ellos.

También veremos algún ejemplo de cómo trabajar con nuestros posts personalizados y no solo con los posts por defecto.

Quiero comentar que, dentro del bucle while, puedes trabajar con etiquetas HTML para construir las estructuras que creas convenientes. No obstante, en estos ejemplos me voy a centrar en cómo realizar diferentes consultas y no tanto en la parte visual, que podría variar dependiendo de los temas que uses en tus instalaciones con WordPress.

1 – Obtener las últimas entradas de una categoría excluyendo el post actual

Es habitual querer mostrar los últimos post de una entrada relacionados por la categoría a la que pertenezca pero, como es lógico, también deberíamos excluir la entrada actual, pues es posible que esta se haya publicado recientemente y no queramos que salga.

En este ejemplo, desplegaremos un enlace hacia el post cuyo texto será el título y, justo después, desplegaremos la imagen principal asignada al post.

// Recogemos la categoría actual del post (recogeremos la primera en caso de que tenga más de una categoría).
$current_post_cats = get_the_category();
$current_post_first_cat_id = $current_post_cats[ 0 ]->term_id;
 
// Preparamos los argumentos.
$args = array(
    // Especificamos el de la categoría que hemos asignado anteriormente.
    'cat' => $current_post_first_cat_id,
    // Excluimos el post actual a través de su id.
    'post__not_in' => array( $current_post_id )
);
 
// Instanciamos nuestro objeto WP_Query.
$the_query = new WP_Query( $args );
// Comprobamos que existen resultados.
if ( $the_query->have_posts() ) {
	// Comenzamos el bucle sobre los resultados.
	while ( $the_query->have_posts() ) : $the_query->the_post(); 
		// Enlace con el título del post
        echo '<h2><a href="' . get_permalink() . '">' . get_the_title() . '</a></h2>';
        // Imagen destacada
        echo get_the_post_thumbnail( get_the_ID(), 'full' );
	endwhile;
} else {
	// Código en caso de que no existan resultados
}
// Restablecemos los datos de $post
wp_reset_postdata();

2 – Mostrar los CPT de un author en concreto

En este ejemplo obtendremos nuestros Custom Post Types o CPT de un autor específico. El autor lo conseguimos pasándole como parámetro su id en author. Para este ejemplo, simplemente le pasamos que queremos los CPT del autor con el ID 1.

Debo aclarar que, por supuesto, el id del author se le podría pasar de forma dinámica, pero para este ejemplo he decidido pasarle directamente un ID específico para que veas su funcionamiento. De este modo, en el array de argumentos asignaríamos directamente el id del autor.

También quiero mencionar que nuestro CPT deberá soportar autores.

Además, vamos a ordenarlo de forma descendiente según su fecha y obteniendo 10 resultados por página.

$args = array(
    'author' => 1,
    'post_type' => 'slug-cpt',
    'posts_per_page' => 10,
    'order' => 'DESC',
    'orderby' => 'date',
);
$author_posts = new WP_Query( $args );

if( $author_posts->have_posts() ) {
    // Comenzamos el bucle sobre los resultados.
    while ( $author_posts->have_posts() ) : $author_posts->the_post(); 
        // Titulo del cpt
        echo the_title();
        // Contenido del cpt
        echo the_content();
    endwhile;
}else{
   // Código en caso de que no existan resultados 
}
wp_reset_postdata();

3 – Mostrar los productos con un tag específico

Como has visto anteriormente, WP_Query puede trabajar con CPT sin ningún problema o, lo que es lo mismo, podremos trabajar con nuestros posts personalizados.

En este ejemplo, vamos a trabajar con los productos de tu tienda online montada en WordPress.

Con este código obtendremos los productos que tengan asignados un tag específico. También vamos a indicarle a través de order by que ordene nuestros productos por su id.

$args = array(
    'post_type' => 'product',
    'post_status' => 'publish',
    'tags' => 'hot',
    'orderby' => 'id',
    'order' => 'ASC'
);

$related_products = new WP_Query( $args );

if( $related_products->have_posts() ) {

     while ( $related_products->have_posts() ) {
    
        $related_products->the_post();
        echo '<h2><a href="' . get_permalink() . '">' . get_the_title() . '</a></h2>'; 
        if( has_post_thumbnail() ){
            echo the_post_thumbnail( 'full', array( 'class' => 'related-product-img', 'alt' => get_the_title() ) );
        }
    }

}else{
    // Código en caso de que no existan resultados 
}

wp_reset_postdata();

4 – Mostrar custom posts type con un valor específico creado con ACF

En este ejemplo mostraremos los CPT que contengan un valor específico creado a través de ACF.

Vamos a suponer que hemos creado un CPT denominado «proyectos» y le hemos asignado un field «terminado».

Como los custom fields no dejan de ser metas keys personalizadas, podemos obtener rápidamente los proyectos cuyo field «terminado» sea «si» a través de array de argumentos.

Bastará con indicarle en el array que pasaremos para generar nuestra query, el key del meta y el value que queremos que tenga.

$args = array(
    'post_type' => 'proyectos',
    'post_status' => 'publish',
    'meta_key'  => 'terminado',
    'meta_value' => 'si'
  );

   $the_query = new WP_Query( $args );

   var_dump($the_query->have_posts());

   if( $the_query->have_posts() ) {
        // Comenzamos el bucle sobre los resultados.
        while ( $the_query->have_posts() ) : $the_query->the_post(); 
            // Titulo del cpt
            echo '<h2><a href="' . get_permalink() . '">' . get_the_title() . '</a></h2>';
            // Field creado con ACF
            echo '<p>' . the_field('terminado') . '</p>'; 
        endwhile;
    }else{
        // Código en caso de que no existan resultados 
    }

wp_reset_postdata();

Conclusión

Espero que tras leer este artículo hayas comprendido mejor qué es WP_Query y cómo trabajar con él al construir tus consultas en tu página web.

También quiero felicitarte si te has tomado tu tiempo de leerlo, ya que soy consciente de que este artículo es algo técnico. Sin embargo, creo que es interesante profundizar no sólo en las funcionalidades, sino también en un estudio más profundo. Al fin y al cabo, una buena compresión del core de WordPress te ayudará a desarrollar mejores proyectos con este CMS.

Patricia Álvarez
Patricia Álvarez

Programadora y diseñadora. Disfruto picando código y haciendo que las cosas se vean bonitas.

Artículos relacionados

Si te ha gustado este post, aquí tienes otros que pueden ser de tu interés. ¡No dejes de aprender!

Tenemos 0 comentarios en "WP_Query de WordPress"
Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¿Vienes de otro proveedor?

¡Ningún problema! Te migramos gratis y sin cortes
cohete raiola