Taxonomy menu with post count and multiple parents

I’m using WordPress 3.1.3 and trying to make a “product” menu with post count in each category. Like this:

  • New Cars (4)
    • BMW (2)
    • Ford (1)
    • Nissan (1)
  • Used Cars (10)
    • BMW (3)
    • Ford (1)
    • Nissan (6)

For this, I’ve created custom post type Cars and taxonomies Type and Brand. Not sure if it the best way to do this, but here’s my code:

Read More
<?php $auto_types = get_terms('type', 'hide_empty=1'); ?>
<ul>
<?php foreach( $auto_types as $auto_type ) : ?>
  <li>
    <a href="<?php echo get_term_link( $auto_type->slug, 'type' ); ?>">
      <?php echo $auto_type->name; ?> (<?php echo $auto_type->count; ?>)
    </a>
                <?php
                $terms = get_terms('brand');
                $count = count($terms);
                if($count > 0) :
                    ?>
                     <ul>
                        <?php foreach ($terms as $term) : ?> 

                        <li>
                            <a href="/?type=<?php echo $auto_type->slug ?>&brand=<?php echo $term->slug ?>">
                                    - - <?php echo $term->name; ?> (<?php echo $term->count; ?>)
                            </a>
                        </li>
                        <?php endforeach ?>
                    </ul>
                    <?php endif ?>

    </li>           
<?php endforeach ?>
</ul>

So my questions are:

  • is this is a good way to do it?
  • how do I filter post counts?

Edit – I’ve managed to solve my second problem, but i’m still not sure if it’s a good way to do it. Here’s new code:

<?php $auto_types = get_terms('type', 'hide_empty=1'); ?>
    <ul>
    <?php foreach( $auto_types as $auto_type ) : ?>
        <li>
        <a href="<?php echo get_term_link( $auto_type->slug, 'type' ); ?>"> 
            <?php echo $auto_type->name; ?>
        </a>
        <?php $auto_brands = get_terms('brand', 'parent=0' ); ?>
            <ul>
                <?php foreach ($auto_brands as $auto_brand) : ?>
                    <?php $brand_filter['tax_query'] = array(
                            'relation' => 'AND',
                            array(
                                'taxonomy' => 'type',
                                'terms' => array($auto_type->slug),
                                'field' => 'slug',
                            ),
                            array(
                                'taxonomy' => 'brand',
                                'terms' => array($auto_brand->slug),
                                'field' => 'slug',
                            ),
                        );
                    $tax_query = new WP_Query($brand_filter);
                        $count = 0;
                    if ( $tax_query->have_posts() ) : while ( $tax_query->have_posts() ) : $tax_query->the_post();
                        $count++;
                    endwhile; endif; wp_reset_postdata();
                        if ( $count > 0 ) : ?>
                            <li>
                                <a href="/?type=<?php echo $auto_type->slug ?>&brand=<?php echo $auto_brand->slug ?>">
                                    - - <?php echo $auto_brand->name; ?> (<?php echo $count; ?>)
                                </a>
                            </li>
                <?php endif; endforeach ?>
            </ul>                 
        </li>           
    <?php endforeach ?>
    </ul>

Edit 2 – Changed query_posts() method to wp_query() (thanks to VicePrez), but is it efficient to use query to only get correct post count or there’s a better way to make this menu?

Related posts

Leave a Reply

1 comment

  1. I adjusted your code a little bit to integrate the wp_query() class instead of query posts(), which is only meant for altering the main loop. You should always opt to use wp_query() when trying to create secondary loops.

    Since we’re using wp_query(), we’re also going to have to use wp_reset_postdata() instead of wp_reset_query. Im not sure if this is going to fix your problem, but adjust your code to this, and we’ll tackle the rest of your problems step by step.

    <?php $auto_types = get_terms('type', 'hide_empty=1'); ?>
    <ul>
    <?php foreach( $auto_types as $auto_type ) : ?>
        <li>
        <a href="<?php echo get_term_link( $auto_type->slug, 'type' ); ?>"> 
            <?php echo $auto_type->name; ?>
        </a>
        <?php $auto_brands = get_terms('brand', 'parent=0' ); ?>
            <ul>
                <?php foreach ($auto_brands as $auto_brand) : ?>
                    <?php $brand_filter['tax_query'] = array(
                            'relation' => 'AND',
                            array(
                                'taxonomy' => 'type',
                                'terms' => array($auto_type->slug),
                                'field' => 'slug',
                            ),
                            array(
                                'taxonomy' => 'brand',
                                'terms' => array($auto_brand->slug),
                                'field' => 'slug',
                            ),
                        );
                        $tax_query = new WP_Query($brand_filter);
                        if ( $tax_query->have_posts() ) :
    
                            $count = 1;
                            while ( $tax_query->have_posts() ) : 
                            $tax_query->the_post();
    
                            if ( $count >= 1 ) { ?>
                               <li>
                                   <a href="/?type=<?php echo $auto_type->slug ?>&brand=<?php echo $auto_brand->slug ?>">
                                       - - <?php echo $auto_brand->name; ?> (<?php echo $count; ?>)
                                   </a>
                               </li>
                            <? }
    
                            $count++;
    
                            endwhile; 
                            wp_reset_postdata();
    
                        endif; 
                    endforeach 
                ?>
            </ul>                 
        </li>           
    <?php endforeach ?>
    </ul>
    

    UPDATE: I added the posts_per_page parameter and set it to -1 to show all posts. I tested it on my side. It should give you the results you were looking for.

    <?php $auto_types = get_terms('type', 'hide_empty=1'); ?>
    <ul>
    <?php foreach( $auto_types as $auto_type ) : ?>
        <li>
        <a href="<?php echo get_term_link( $auto_type->slug, 'type' ); ?>"> 
            <?php echo $auto_type->name; ?>
        </a>
        <?php $auto_brands = get_terms('brand', 'parent=0' ); ?>
            <ul>
                <?php foreach ($auto_brands as $auto_brand) : ?>
                    <?php $brand_filter = array(
                        'posts_per_page' => '-1',
                        'tax_query' => array(
                            'relation' => 'AND',
                            array(
                                'taxonomy' => 'type',
                                'field' => 'slug',
                                'terms' => array($auto_type->slug),
                            ),
                            array(
                                'taxonomy' => 'brand',
                                'field' => 'slug',
                                'terms' => array($auto_brand->slug),
                            )
                        )
                    );
                    $tax_query = new WP_Query($brand_filter);
                        $count = 0;
                    if ( $tax_query->have_posts() ) : while ( $tax_query->have_posts() ) : $tax_query->the_post();
                        $count++;
                    endwhile; endif; wp_reset_postdata();
                        if ( $count > 0 ) : ?>
                            <li>
                                <a href="/?type=<?php echo $auto_type->slug ?>&brand=<?php echo $auto_brand->slug ?>">
                                    - - <?php echo $auto_brand->name; ?> (<?php echo $count; ?>)
                                </a>
                            </li>
                <?php endif; endforeach ?>
            </ul>                 
        </li>           
    <?php endforeach ?>
    </ul>