Mostrar todas las entradas en un tipo de contenido personalizado, agrupadas por una taxonomía personalizada
Estoy trabajando en una página de miembros donde uso un tipo de contenido personalizado con una taxonomía personalizada. Mi tipo de contenido personalizado se llama member
y mi taxonomía personalizada se llama member_groups
.
Quiero listar todos los miembros pero agruparlos en sus respectivos grupos.
Para ser claro, tengo 35 miembros divididos en 9 grupos – así que en lugar de hacer la misma consulta nueve veces, quiero hacerla una vez pero agruparlos juntos, de modo que Miembro1, Miembro4 y Miembro11 estén agrupados juntos en un grupo llamado "Marketing".
Estoy usando WP_Query
para obtener todas las entradas bajo el tipo de contenido member. He intentado diferentes aproximaciones pero sin resultados exitosos.
¿Cómo puedo lograr esto?
Por lo tanto, podrías considerar automatizar las múltiples consultas.
Primero, obtén la lista de términos en tu taxonomía personalizada, usando get_terms()
:
<?php
$member_group_terms = get_terms( 'member_group' );
?>
Luego, recorre cada uno, ejecutando una nueva consulta cada vez:
<?php
foreach ( $member_group_terms as $member_group_term ) {
$member_group_query = new WP_Query( array(
'post_type' => 'member',
'tax_query' => array(
array(
'taxonomy' => 'member_group',
'field' => 'slug',
'terms' => array( $member_group_term->slug ),
'operator' => 'IN'
)
)
) );
?>
<h2><?php echo $member_group_term->name; ?></h2>
<ul>
<?php
if ( $member_group_query->have_posts() ) : while ( $member_group_query->have_posts() ) : $member_group_query->the_post(); ?>
<li><?php echo the_title(); ?></li>
<?php endwhile; endif; ?>
</ul>
<?php
// Restablecer cosas, por si acaso
$member_group_query = null;
wp_reset_postdata();
}
?>
No veo nada particularmente incorrecto con este enfoque, aunque puede tener una capacidad limitada para escalar (es decir, si tienes cientos o miles de miembros, o términos de member_group, podrías experimentar problemas de rendimiento).

Sí, funciona perfectamente. Solo tengo un problema. Quiero mostrar campos personalizados así <?php get_post_meta($member_group_term->ID, 'job_title', true);?> pero no funcionó. También intenté con $post->ID pero tampoco funcionó, ¿podrías ayudarme @Chip Bennett por favor?

Me doy cuenta de que ha pasado más de una década, pero hay algo seriamente incorrecto con este enfoque, ya que estás creando una consulta separada para cada término. Cuando hablamos de un pequeño número de términos, no vamos a ver mucho impacto en el rendimiento. Pero una vez que empezamos a superar los 20-30 términos, este tipo de bucle afectará seriamente los tiempos de carga y el tiempo de respuesta del servidor. Mi sugerencia aquí es realmente obtener todas las publicaciones y luego ejecutar un usort
después. De esta manera, no estás saturando la base de datos con un montón de consultas, y obtienes tus resultados en dos pasos.

Encontré una solución utilizando una consulta personalizada y luego agrupándola con el nombre del término:
SELECT *
FROM wp_term_taxonomy AS cat_term_taxonomy
INNER JOIN wp_terms AS cat_terms ON cat_term_taxonomy.term_id = cat_terms.term_id
INNER JOIN wp_term_relationships AS cat_term_relationships ON cat_term_taxonomy.term_taxonomy_id = cat_term_relationships.term_taxonomy_id
INNER JOIN wp_posts AS cat_posts ON cat_term_relationships.object_id = cat_posts.ID
INNER JOIN wp_postmeta AS meta ON cat_posts.ID = meta.post_id
WHERE cat_posts.post_status = 'publish'
AND meta.meta_key = 'active'
AND meta.meta_value = 'active'
AND cat_posts.post_type = 'member'
AND cat_term_taxonomy.taxonomy = 'member_groups'
Luego, simplemente usando un bucle foreach regular puedo extraer la información que deseo.
Pero todavía estoy interesado en otra forma si existe, tal vez utilizando las propias funciones de WordPress.

Acabo de agregar un método alternativo. Tiendo a evitar cualquier cosa que requiera consultas SQL directas.

Me alegra ver esto marcado como la respuesta correcta, incluso si la consulta deja de funcionar en WordPress si el esquema cambia en algún momento... El concepto de recopilarlos todos en una sola consulta es la respuesta correcta. La iteración para agrupar las taxonomías en PHP no escalará tan bien como esto.

aún más simple:
$terms = get_terms('tax_name');
$posts = array();
foreach ( $terms as $term ) {
$posts[$term->name] = get_posts(array( 'posts_per_page' => -1, 'post_type' => 'post_type', 'tax_name' => $term->name ));
}
Dentro del array resultante $posts, cada término de taxonomía es la clave para un array anidado que contiene sus posts.

Tuve exactamente esta necesidad, y la solución de Chip funcionó, excepto por una cosa: se requiere 'field' => 'slug'
.
foreach ( $service_categories as $category ) {
$services = new WP_Query(
array(
'post_type' => 'service',
'tax_query' => array(
array(
'taxonomy' => 'service_category',
'terms' => array( $category->slug ),
'operator' => 'IN',
'get' => 'all',
'field' => 'slug'
)
)
)
); ?>
<h2><?php echo $category->slug; ?></h2>
<?php if ( $services->have_posts() ) { // aquí va el bucle ?>
También necesitaba que el resultado se mostrara plano, por eso aquí se establece 'get' => 'all'
.
Espero que esto ayude a alguien más.

Tuve que hacer esto en un proyecto hace años. Respuesta similar a djb, pero con un poco más de detalles. Esto generará todos los nombres de tus taxonomías como un h3, con una lista de viñetas de cada título de publicación enlazado a su página de detalle.
<?php // Mostrar todos los nombres de Taxonomías con sus respectivos elementos
$terms = get_terms('member_groups');
foreach( $terms as $term ):
?>
<h3><?php echo $term->name; // Imprimir el nombre del término ?></h3>
<ul>
<?php
$posts = get_posts(array(
'post_type' => 'member',
'taxonomy' => $term->taxonomy,
'term' => $term->slug,
'nopaging' => true, // para mostrar todas las publicaciones en esta taxonomía, también se podría usar 'numberposts' => -1
));
foreach($posts as $post): // comenzar ciclo a través de las publicaciones de esta taxonomía
setup_postdata($post); //configurar datos de la publicación para usar en el bucle (permite usar the_title(), etc sin especificar un ID de publicación)
?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endforeach; ?>
</ul>
<?php endforeach; ?>

$query = new WP_Query(
array (
'post_type' => 'miembro',
'orderby' => 'meta_value',
'meta_key' => 'grupo_miembro'
)
);
Luego, cuando iteres a través de esta consulta, podrías usar un condicional similar a este (en pseudocódigo PHP):
$nombreGrupo = "";
$contador = 0;
if havePosts: while havePosts: thePost
if( $nombreGrupo != post->meta_value )
{
if ($contador > 0)
{
</ul>
}
<h1>Nombre de un grupo</h1>
<ul>
<li>nombre del miembro</li>
}
else
{
<li>nombre del miembro</li>
}
endwhile;endif
</ul>
Espero que esto ayude. Creo que lo estabas haciendo mucho más complicado de lo necesario.
Más información: http://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters

Bueno, es un hilo antiguo, pero si alguien pasa por aquí como yo lo hice, esto podría ayudar. La idea es modificar la consulta principal para que no necesitemos ir a las plantillas y generar nuevas consultas y bucles...
PD: Aún no se ha probado en bases de datos grandes. Fue satisfactorio en mi caso.
function grouped_by_taxonomy_main_query( $query ) {
if ( $query->is_home() && $query->is_main_query() ) { // Ejecutar solo en la página de inicio
$post_ids = array();
$terms = get_terms('my_custom_taxonomy');
foreach ( $terms as $term ) {
$post_ids = array_merge( $post_ids, get_posts( array(
'posts_per_page' => 4, // como desees...
'post_type' => 'my_custom_post_type', // Si es necesario... Por defecto son posts
'fields' => 'ids', // solo queremos los IDs para usar luego en 'post__in'
'tax_query' => array( array( 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id, )))) // obteniendo posts en el término actual
);
}
$query->query_vars['post_type'] = 'my_custom_post_type'; // Nuevamente, si es necesario... Por defecto son posts
$query->query_vars['posts_per_page'] = 16; // Si es necesario...
$query->query_vars['post__in'] = $post_ids; // Filtrando con los IDs de posts que obtuvimos arriba
$query->query_vars['orderby'] = 'post__in'; // Aquí mantenemos el orden que generamos en el bucle de términos
$query->query_vars['ignore_sticky_posts'] = 1; // Si no quieres que tus posts fijos cambien el orden
}
}
// Enganchar mi función anterior a la acción pre_get_posts
add_action( 'pre_get_posts', 'grouped_by_taxonomy_main_query' );
