WordPress: Custom post type segregation on Category page

I’ve got two custom post types, for example ‘Cars’ and ‘Bikes’. I’ve used WordPress’s default category to categorise the posts from the two post types. Let’s say for example the categories are ‘Red’, ‘Blue’ and ‘Black’.

What I’m trying to achieve here is that when I go to the category page for ‘Red’, I want to see the ‘Cars’ and the ‘Bikes’ that are categorised under ‘Red’. I’m using the category.php and this is the query that I’m trying to run:

Read More
$car_args = array(
                    'posts_per_page'   => -1,
                    'orderby'          => 'date',
                    'order'            => 'DESC',
                    'post_type'        => 'cars',
                    'post_status'      => 'publish',
                    'cat'              => $cat
                );

                // The Query
                $car_query = new WP_Query( $car_args );

                // The Loop
                if ( $car_query ->have_posts() ) {
                echo "<h3>Cars</h3>";
                    while ( $car_query->have_posts() ) {
                        $car_query->the_post();
                        echo get_post_type() . '<a href="'. get_permalink() .'">' . get_the_title() . '</a><br />';
                    }
                } else {
                    // no posts found
                }

$bikes_args = array(
                    'posts_per_page'   => -1,
                    'orderby'          => 'date',
                    'order'            => 'DESC',
                    'post_type'        => 'bikes',
                    'post_status'      => 'publish',
                    'cat'              => $cat
                );

                // The Query
                $bikes_query = new WP_Query( $bikes_args );

                // The Loop
                if ( $bikes_query ->have_posts() ) {
                echo "<h3>Bikes</h3>";
                    while ( $bikes_query->have_posts() ) {
                        $bikes_query->the_post();
                        echo get_post_type() . '<a href="'. get_permalink() .'">' . get_the_title() . '</a><br />';
                    }
                } else {
                    // no posts found
                }

                /* Restore original Post Data */
                wp_reset_postdata();

The $cat in the query gets the category id of ‘Red’ category. Both these queries are correctly restricting the posts by the ‘Red’ category but posts from both the ‘Cars’ post type and ‘Bikes’ post type are showing up even though I’ve tried to restrict by post type. I’ve read in a few articles that WordPress ignores the post type args on the category page. Is this true and if it is, is there a workaround for this?

Related posts

1 comment

  1. What you are trying to do is possible with one query only, and only with the main query without any custom queries.

    First of all, lets first add your custom post types to your category page. By default, custom pist types are excluded from category pages. So we need to add this manually to the main query arguments via pre_get_posts. Add the following to your functions.php: (CAVEAT: Untested and also requires PHP 5.3+)

    add_action( 'pre_get_posts', function ( $q )
    {
        if ( !is_admin() && $q->is_main_query() && $q->is_category() ) {
            $q->set( 'post_type', array( 'post', 'cars', 'bikes' ) ); // Change this according to your post types
            $q->set( 'nopaging', true ); // This will get all posts, same as posts_per_page=-1
        }
    });
    

    You should now have all posts from a clicked category is your set post types on your category pages.

    Next, wee need to sort out your loops. Delete all your custom queries in category.php and replace it with the default loop. As you would want two block ordered by post type, we will use rewind_posts() so we can run the loop twice

    if ( have_posts() ) {
        while ( have_posts() ) {
        the_post();
    
            if ( $post->post_type == 'cars' ) { //Change accordingly to only show cars in this loop
    
                // Your loop
    
            }
        }
    
        rewind_posts();
    
        while ( have_posts() ) {
        the_post();
    
            if ( $post->post_type == 'bikes' ) { // Change accordingly to only show bikes
    
                // Your loop
    
            }
        }
    }
    

    This should now display your posts in two block sorted by post type

Comments are closed.