I’m working on a member page where I use a custom post type with a custom taxonomy. My custom post type is called member and my custom taxonomy is called member_groups.
I want to list all the members but group them together into their respective groups.
So to be clear, I’ve 35 members divided into 9 groups – so instead of making the same query nine times I want to do it once but group them together, so that Member1, Member4 and Member 11 is grouped together in one group, called “Marketing”.
I’m using WP_Query to retrieve all posts under post type member. I’ve tried different attempts but with no successful result.
How can I achieve that?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
So, you might consider automating the multiple queries.
First, get the list of terms in your custom taxonomy, using get_terms():
<?php $member_group_terms = get_terms( 'member_group' ); ?>
Then, loop through each one, running a new query each time:
<?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
// Reset things, for good measure
$member_group_query = null;
wp_reset_postdata();
}
?>
I can’t see anything particularly wrong with this approach, though it may have a limited ability to scale (i.e. if you have hundreds or thousands of members, or member_group terms, you may see performance issues).
Method 2
I found a solution by using a custom query and then grouping it with the term name:
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'
Then by just using a regular foreach query I can just extract the information I want.
But I’m still interested in another way if there is, maybe by using WordPress’ own functions.
Method 3
even simpler:
$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 ));
}
Within the resultant $posts array, each tax term is the key to a nested array containing its posts.
Method 4
I had this exact need, and Chip’s solution worked, except for one thing: 'field' => 'slug' is required.
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() ) { // loop stuff goes here ?>
I also needed the resulting display to be flat, so 'get' => 'all' is set here.
Hopefully this helps somebody else out.
Method 5
I had to do this on a project years ago. Similar answer to djb, just with a bit more details. This will output all of your taxonomy names as an h3, with a bulleted list of each post title linked to their detail page.
<?php // Output all Taxonomies names with their respective items
$terms = get_terms('member_groups');
foreach( $terms as $term ):
?>
<h3><?php echo $term->name; // Print the term name ?></h3>
<ul>
<?php
$posts = get_posts(array(
'post_type' => 'member',
'taxonomy' => $term->taxonomy,
'term' => $term->slug,
'nopaging' => true, // to show all posts in this taxonomy, could also use 'numberposts' => -1 instead
));
foreach($posts as $post): // begin cycle through posts of this taxonmy
setup_postdata($post); //set up post data for use in the loop (enables the_title(), etc without specifying a post ID)
?>
<li><a href="<?php the_permalink(); ?>" rel="nofollow noreferrer noopener"><?php the_title(); ?></a></li>
<?php endforeach; ?>
</ul>
<?php endforeach; ?>
Method 6
$query = new WP_Query(
array (
'post_type' => 'member',
'orderby' => 'meta_value',
'meta_key' => 'member_group'
)
);
Then when you loop through this query you could just use an if along these lines
(in php pseudocode)
$groupName = "";
$counter = 0;
if havePosts: while havePosts: thePost
if( $groupName != post->meta_value )
{
if ($counter > 0)
{
</ul>
}
<h1>A group name</h1>
<ul>
<li>member name</li>
}
else
{
<li>member name</li>
}
endwhile;endif
</ul>
I hope that helps. I think you were making this far more complicated than it needed to be.
More information: http://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters
Method 7
Well, it’s an old thread, but if someone passes by as I did, this might help.
The idea is to modify the main query so we don’t need to go the templates and generate new queries and loops…
PS: Yet to be tested in large dbs. It was satisfactory in my case.
function grouped_by_taxonomy_main_query( $query ) {
if ( $query->is_home() && $query->is_main_query() ) { // Run only on the homepage
$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, // as you wish...
'post_type' => 'my_custom_post_type', // If needed... Default is posts
'fields' => 'ids', // we only want the ids to use later in 'post__in'
'tax_query' => array( array( 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id, )))) // getting posts in the current term
);
}
$query->query_vars['post_type'] = 'my_custom_post_type'; // Again, if needed... Default is posts
$query->query_vars['posts_per_page'] = 16; // If needed...
$query->query_vars['post__in'] = $post_ids; // Filtering with the post ids we've obtained above
$query->query_vars['orderby'] = 'post__in'; // Here we keep the order we generated in the terms loop
$query->query_vars['ignore_sticky_posts'] = 1; // If you dont want your sticky posts to change the order
}
}
// Hook my above function to the pre_get_posts action
add_action( 'pre_get_posts', 'grouped_by_taxonomy_main_query' );
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0