Displaying Multiple Post types in Taxonomy

I have the following Custom Post Types which are all linked to the destination taxonomy.

  • Deals
  • Accommodation
  • Attractions
  • Articles

How would I change the taxonomy-destination.php file to show matching posts from all 4 post types.

Read More

For instance, when currently viewing the destination "los angeles", it shows all this content together by date rather than separating in sepearte sections.

I would prefer to have them split, deals at the top, followed by the other content not all mixed together.

How would be best to achieve this?

Related posts

Leave a Reply

1 comment

  1. Hook into pre_get_posts, check for the taxonomy, and set all four post types as the post_type parameter of the query object. Check out the Type Parameters section on the WP_Query docs for more information.

    <?php
    add_action('pre_get_posts', 'wpse87225_set_post_types');
    function wpse87225_set_post_types($query)
    {
        if (is_admin() || !$query->is_main_query() || !is_tax('destination')) {
            return; // bail, not where we want to be
        }
    
        $query->set('post_type', array(
            'Deals', 'Accommodation', 'Attractions', 'Articles'));
    }
    

    The above could go in your functions.php file, or, more appropriately, a plugin.

    Edit to address the group by requirement:

    That’s not going to split them up, however. There a few options to do that. First, you could just leave the main query alone (don’t do the above), and create multiple instances of WP_Query and do multiple loops. Not bad.

    You could also hook into posts_orderby and alter the SQL to order the posts by post type as well as whatever else is there:

    <?php
    add_filter('posts_orderby', 'wpse87225_posts_orderby', 10, 2);
    function wpse87225_posts_orderby($orderby, $query)
    {
        global $wpdb;
    
        if (is_admin() || !$query->is_main_query() || !is_tax('destination')) {
            return $orderby;
        }
    
        $new = "{$wpdb->posts}.post_type ASC";
    
        if ($orderby) {
            $orderby = $new . ', ' . $orderby;
        } else {
            $orderby = $new;
        }
    
        return $orderby;
    }
    

    You could even be very granular and order by specific post type with the help of the FIELD function.

    <?php
    add_filter('posts_orderby', 'wpse87225_posts_orderby', 10, 2);
    function wpse87225_posts_orderby($orderby, $query)
    {
        global $wpdb;
    
        if (is_admin() || !$query->is_main_query() || !is_tax('destination')) {
            return $orderby;
        }
    
        $new = "FIELD({$wpdb->posts}.post_type, 'Deals', 'Accommodation', 'Attractions', 'Articles') ASC";
    
        if ($orderby) {
            $orderby = $new . ', ' . $orderby;
        } else {
            $orderby = $new;
        }
    
        return $orderby;
    }
    

    Then just check when the post type changes, and display whatever header you like:

    <?php
    $post_type = '';
    while (has_posts()): the_post;
    
    if (get_post_type() !== $post_type) {
        // print the header for the post type
        // maybe something like this...
        echo '<h2>', esc_html(get_post_type_object(get_post_type())->label)), '</h2>';
    }
    
    // do stuff with the current post
    
    $post_type = get_post_type();
    
    endwhile;