Consulta WP_Query de Taxonomía Personalizada para Todos los Términos en una Taxonomía
¿Hay alguna manera fácil de consultar cualquier entrada que esté etiquetada con cualquier término de una taxonomía específica?
Conozco esta técnica:
$custom_taxonomy_query = new WP_Query(
array(
'taxonomy_name' => 'term_slug',
)
);
Pero me gustaría poder pasar un comodín en lugar de term_slug, o quizás simplemente una cadena vacía. Esto me daría todas las entradas que están etiquetadas por cualquier término en esa taxonomía, no solo un término específico.
Gracias por tu ayuda, Dave
Me encontré con una situación similar Dave. Este código solucionó el problema para mis necesidades. No es la opción más ligera del mundo, pero hace bien el trabajo:
// Obtener todos los IDs de términos en una taxonomía dada
$taxonomy = 'taxonomy_name';
$taxonomy_terms = get_terms( $taxonomy, array(
'hide_empty' => 0,
'fields' => 'ids'
) );
// Usar el nuevo argumento tax_query de WP_Query (desde la versión 3.1)
$taxonomy_query = new WP_Query( array(
'tax_query' => array(
array(
'taxonomy' => $taxonomy,
'field' => 'id',
'terms' => $taxonomy_terms,
),
),
) );
Espero que esto te ayude a ti o a cualquier otra persona que esté experimentando este problema.
Kevin

Algo como esto podría funcionar:
$args = array(
'post_type' => 'post',
'tax_query' => array(
array(
'taxonomy' => 'your_custom_taxonomy',
'operator' => 'EXISTS'
),
),
);
$query = new WP_Query( $args );
Básicamente estás solicitando cualquier publicación asignada a cualquier término dentro de tu taxonomía personalizada.

Hola @Dave Morris:
Tienes razón, WordPress decide que si no tienes un término, simplemente ignorará tu taxonomía.
Existen tres (3) enfoques principales que podrías probar:
Usar una consulta SQL completa con
$wpdb->get_results()
,Obtener una lista de
$post->ID
s para todas las publicaciones en tu taxonomía y luego pasarlos usando el argumento'post__id'
, oAnotar el SQL utilizado por
WP_Query
con uno de los hooks que te permiten agregar unINNER JOIN
de SQL haciendo referencia a las tablas de taxonomía.
Intento evitar SQL completo en WordPress hasta que no haya otra opción o simplemente se esté devolviendo una lista de IDs. Y en este caso evitaría extraer una lista de $post-ID
s para usar con el argumento 'post__id'
porque podría tener problemas de rendimiento e incluso de memoria si tienes muchas publicaciones. Así que nos queda la opción #3.
He creado una clase para extender WP_Query
llamada PostsByTaxonomy
que utiliza el hook 'posts_join'
. Puedes verla aquí:
class PostsByTaxonomy extends WP_Query {
var $posts_by_taxonomy;
var $taxonomy;
function __construct($args=array()) {
add_filter('posts_join',array(&$this,'posts_join'),10,2);
$this->posts_by_taxonomy = true;
$this->taxonomy = $args['taxonomy'];
unset($args['taxonomy']);
parent::query($args);
}
function posts_join($join,$query) {
if (isset($query->posts_by_taxonomy)) {
global $wpdb;
$join .=<<<SQL
INNER JOIN {$wpdb->term_relationships} ON {$wpdb->term_relationships}.object_id={$wpdb->posts}.ID
INNER JOIN {$wpdb->term_taxonomy} ON {$wpdb->term_taxonomy}.term_taxonomy_id={$wpdb->term_relationships}.term_taxonomy_id
AND {$wpdb->term_taxonomy}.taxonomy='{$this->taxonomy}'
SQL;
}
return $join;
}
}
Llamarías a esta clase como se muestra a continuación. El argumento 'taxonomy'
es obligatorio pero puedes pasar cualquier (¿o todos?) de los otros parámetros que WP_Query
espera, como 'posts_per_page'
:
$query = new PostsByTaxonomy(array(
'taxonomy' => 'category',
'posts_per_page' => 25,
));
foreach($query->posts as $post) {
echo " {$post->post_title}\n";
}
Puedes copiar la clase PostsByTaxonomy
al archivo functions.php
de tu tema, o puedes usarla dentro de un archivo .php
de un plugin que estés desarrollando.
Si deseas probarlo rápidamente, he publicado una versión autocontenida del código en Gist que puedes descargar y copiar en la raíz de tu servidor web como test.php
, modificar según tu caso de uso y luego solicitar desde tu navegador usando una URL como http://ejemplo.com/test.php
.
ACTUALIZACIÓN
Para omitir las Publicaciones Destacadas de las publicaciones incluidas en la consulta, prueba esto:
$query = new PostsByTaxonomy(array(
'taxonomy' => 'category',
'posts_per_page' => 25,
'caller_get_posts' => true,
));
O si es importante para ti que la clase PostsByTaxonomy
nunca incluya publicaciones destacadas, podrías agregarlo al constructor:
function __construct($args=array()) {
add_filter('posts_join',array(&$this,'posts_join'),10,2);
$this->posts_by_taxonomy = true;
$this->taxonomy = $args['taxonomy'];
$args['caller_get_posts'] = true; // Sin Publicaciones Destacadas
unset($args['taxonomy']);
parent::query($args);
}
ACTUALIZACIÓN 2
Después de publicar lo anterior, me enteré de que 'caller_get_posts'
quedará obsoleto y se usará 'ignore_sticky_posts'
en WordPress 3.1.

Mike, gracias por tu ayuda. Por alguna razón no logro que funcione. No está devolviendo solo las publicaciones con términos asignados desde mi taxonomía personalizada. Siempre parece devolver otras publicaciones. Sin embargo, no devuelve todas las publicaciones, así que definitivamente está haciendo algo... ¿Puedo usar la función $query->have_posts() para iterar? Ninguno de los métodos parece funcionarme, de cualquier manera.

Ah, esto es interesante. Encontré la consulta en el registro de mysql que obtiene las dos publicaciones que espero, y funciona. Pero por alguna razón, cuando recorro $query->posts, me devuelve cinco publicaciones. Lo único adicional que noto es que justo después de ejecutarse la consulta de las publicaciones de la taxonomía personalizada, se ejecuta otra consulta que obtiene tres publicaciones más, por sus post_id's. Y luego supongo que las cinco publicaciones se colocan en un único array de resultados.

Creo que lo resolví. Esta consulta personalizada parece incluir publicaciones destacadas (sticky posts), aunque no estén en esa taxonomía personalizada. ¿Alguna idea sobre cómo manejar correctamente las publicaciones destacadas o al menos cómo sacarlas de esta consulta en particular? Gracias, Dave

Bueno, son "pegajosos", ¿verdad? :)
Es un comportamiento extraño, creo, pero si usas caller_get_posts=1
deberían desaparecer:
http://codex.wordpress.org/Function_Reference/query_posts#Sticky_Post_Parameters
Espero que esto ayude.

Ese if(isset($query->posts_by_taxonomy))
es un buen truco para combinar la metodología orientada a objetos con la metodología de hooks de WordPress.

@Jan Fabry - ¡Sí, gracias! Solo me tomó unos 2 años de prueba y error antes de que se me ocurriera. Claro que ahora parece obvio... :)

¡Eso funcionó! Muchas gracias por tu ayuda. Me gusta aprender nuevos trucos de WordPress, especialmente los de POO.

@Dave Morris - De nada. Por cierto, acabo de enterarme que se llamará 'ignore_sticky_posts'
en WP 3.1.

@MikeSchinkel ¿Qué pasa con la paginación? Esto funciona bien, pero la paginación para esta consulta no está funcionando como debería en mi caso... http://wordpress.stackexchange.com/q/57884/12261

Deberías poder simplemente establecer la taxonomía y negar para incluir un término...
Ejemplo:
<?php
$your_query = new WP_query;
$your_query->query( array( 'taxonomy' => 'nombre-de-tu-taxonomia' ) );
?>
Lo cual sería básicamente lo mismo que la consulta que realiza un archivo de taxonomía.

La línea 1432 de query.php verifica si la taxonomía O el término están vacíos, así que no puedes simplemente no pasar un slug... ¿Alguna otra idea?

@t31os - Esa fue también mi primera reacción; de hecho me ha causado problemas más de una vez porque sigo olvidándolo. Pero @Dave Morris tiene razón; si no es un par taxonomía/término entonces WP_Query
simplemente lo descarta.

Vaya, no sabía eso, es un poco tonto realmente... lección aprendida... :) Medio esperaba que funcionara como los parámetros meta_key / meta_value (no sé por qué)...

@t31os - Sí, WP_Query
lamentablemente no está implementado de una manera tan elegante. Son casi 1200 líneas de casos especiales codificados de forma rígida.

En retrospectiva, he hecho una mezcla de las sugerencias de MikeSchinkel y t31os. Es posible inyectar esto en consultas existentes sobre la marcha, pero se requiere WordPress 3.1:
Plugin para obtener un feed RSS de entradas que contengan cualquier término de una taxonomía
