Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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:

<?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?

share|improve this question
    
1: your code seems clean. 2: what do you mean by filter? are you trying to remove post counts? –  VicePrez May 27 '11 at 22:50
    
As it is now, post count displays number of all posts with that term (I would get BWM (5) in both parent terms), but I need to filter it by it's parrent term too. I managed to do it via query_posts, but not sure if it's a good way :) Updated my original question with a new code. –  Kovas May 28 '11 at 11:51

1 Answer 1

up vote 1 down vote accepted

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>
share|improve this answer
    
@VicePrez Well, I've changed query_posts() method to wp_query(), but other changes are not good for this :) Your query would print term link for each post: BMW (1) BMW (2) BMW (3). And I need to print it only once for each term. So query should end before <li> (foreach will handle it). Also $auto_brand->count will return post count of all posts in that term, not only New+BWM, but Used+BMW too and that was my problem in the first place :) I've edited my question again, to reflect this suggested wp_query change. –  Kovas May 28 '11 at 15:50
    
@sinshade alright, let me try to recreate this on my dev site, so i can see whats going on, its an easy fix. –  VicePrez May 28 '11 at 16:12
    
@sinshade updated the code. –  VicePrez May 28 '11 at 17:27
    
@VicePrez Yes, it works, but I was asking if it's a good way to achieve all this. I mean, if I would need 3rd level for that menu (ex. car models: Ford Focus, Ford Mondeo, Ford Mustang etc.), I would need to duplicate some code to get it right. So maybe there's a better way to do it? :) –  Kovas May 28 '11 at 18:03
    
@sinshade Of-course, its possible. I believe your going to have to build a query around the custom post type Cars, and get all the taxonomies under that post type. Its going to be hefty, but its doable, but that's beyond the scope of this question. Try asking a new question, and paste your working code so people can have a look at it. Here are a few sources to get you started here and here –  VicePrez May 28 '11 at 18:23

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.