Group posts in a category based on tags in custom taxonomy

For the query_post function, it is recommended not to use according to official docs.

This function will completely override the main query and isn’t intended for use by plugins or themes……..This must not be used within the WordPress Loop.

You may read this post to grasp more ideas.

To query with multiple taxonomies, may use class WP_Query to create custom query.

<?php
$slug = the_slug();

// get all the tags from the database
$tags = get_tags();

// loop through the categories
foreach ($tags as $tag) {
    // setup the category ID
    $tag_id = $tag->term_id;

    // custom query with multiple taxonomy as parameter
    $args = array(
        'orderby' => 'title', 
        'order' => 'ASC', 
        'posts_per_page' => -1,
        'tax_query' => array(
            'relation' => 'AND', // at the same time meet both conditions
            array(
                'taxonomy' => 'towns', // custom tag taxonomy name
                'field'    => 'term_id',
                'terms'    => array( $tag_id ),
            ),
            array(
                'taxonomy' => 'category', // default taxonomy category name
                'field'    => 'slug',
                'terms'    => array( $slug ),
            ),
        ),
    );

    $query = new WP_Query( $args );

    // start the wordpress loop!
    if ($query->have_posts()) :

        // Make a header for the category, only if there are posts under it
        echo '<h2 class="group-title">'.$tag->name.'</h2>';

        while ($query->have_posts()) : $query->the_post(); 
            get_template_part('template-parts/place-listing', 'place');
        endwhile;

        // After looping through a nested query, this function restores the $post global to the current post in this query.
        // properly reset may avoid problem in most of the cases
        wp_reset_postdata(); 

    endif; // done our wordpress loop. Will start again for each category 
} // done the foreach statement 
?>

Hi Steve, I have also read your previous questions that @Pieter Goosen suggests to use default loop. Since you use query_post() with an argument. In this case, WP_Query is preferred instead for performance and stability because query_post modify the global $post object. I guess this portion is only part of the template and not the main loop. The suggestion is based on your original code and environment. You may adjust and test according to actual needs.

Troubleshooting and debugging suggestions

If there is no results, it is good by splitting the query into parts and test with finite values.

(The following are tested and worked by placing in init hook at functions.php with simulated taxonomy, slug and id, for testing purpose, I didn’t placed inside template)

  1. to test it with a slug value and with only 1 taxonomy
$args = array(
    // 'post_type' => 'post', // default post type is 'post', allow array of post types
    'orderby' => 'title', 
    'order' => 'ASC', 
    'posts_per_page' => -1,
    'tax_query' => array(
        array(
            'taxonomy' => 'category',
            'field'    => 'slug',
            'terms'    => array( 'arts' ), // place the slug here
        ),
    ),
);

$query = new WP_Query( $args );

if ($query->have_posts()) :

    while ($query->have_posts()) : $query->the_post(); 
        the_title();
        echo 'something';
    endwhile;

    wp_reset_postdata(); 

endif;

  1. to test it with a slug value and with 1 custom taxonomy
$args = array(
    'orderby' => 'title', 
    'order' => 'ASC', 
    'posts_per_page' => -1,
    'tax_query' => array(
        array(
            'taxonomy' => 'towns', // custom tag taxonomy name, please confirm the name
            'field'    => 'term_id',
            'terms'    => array( 43 ), // change to your tag ID
        ),
    ),
);

$query = new WP_Query( $args );

if ($query->have_posts()) :

    while ($query->have_posts()) : $query->the_post(); 
        the_title();
        echo 'something';
    endwhile;

    wp_reset_postdata(); 

endif;
  1. to test it with a slug value and with multiple taxonomies
$args = array(
    'orderby' => 'title', 
    'order' => 'ASC', 
    'posts_per_page' => -1,
    'tax_query' => array(
        'relation' => 'AND',
        array(
            'taxonomy' => 'category',
            'field'    => 'slug',
            'terms'    => array( 'arts' ),
        ),
        array(
            'taxonomy' => 'towns',
            'field'    => 'term_id',
            'terms'    => array( 43 ), // change to your tag ID
        ),
    ),
);

$query = new WP_Query( $args );

if ($query->have_posts()) :

    while ($query->have_posts()) : $query->the_post(); 
        the_title();
        echo 'something';
    endwhile;

    wp_reset_postdata(); 

endif;