In a site that I am building I am trying to create a template which will display all my "product" custom post types along with their parent and child taxonomies in some hierarchical structure which is very simple:
Parent taxonomy -> Child taxonomy (if exists) -> posts
I was looking all over the web and surprisingly could not fund an answer..anywhere.
I ended up creating the following code:
<?php
// List posts by the terms for a custom taxonomy of any post type
$post_type = 'product';
$tax = 'products';
$tax_args = array(
'order' => 'DESC'
);
$tax_terms = get_terms( $tax, $tax_args );
if ($tax_terms) {
foreach ($tax_terms as $tax_term) {
$args = array(
'post_type' => $post_type,
"$tax" => $tax_term->slug,
'post_status' => 'publish',
'posts_per_page' => -1,
'order' => 'ASC',
'caller_get_posts'=> 1
);
$my_query = null;
$my_query = new WP_Query($args);
if( $my_query->have_posts() ) : ?>
<h4><?php echo $tax_term->name; ?></h4>
<ul>
<?php
$my_query->query(array( 'post_type'=>'product', 'showposts'=>'6'));
?>
<?php while ( $my_query->have_posts() ) : $my_query->the_post(); ?>
<li><a href="<?php the_permalink() ?>">
<?php the_title(); ?>
</a>
</li>
<?php endwhile; // end of loop ?>
</ul>
<?php else : ?>
<?php endif; // if have_posts()
wp_reset_query();
} // end foreach #tax_terms
}
?>
This is almost what I need. I am getting this structure:
Parent Taxonomy Term
- Post Type
- Post Type
- Post Type
Child Taxonomy Term
- Post Type
- Post Type
- Post Type
Where what I need is this:
Parent Taxonomy Term
-- Child Taxonomy Term
--- Post Type
--- Post Type
--- Post Type
Parent Taxonomy Term
-- Child Taxonomy Term
--- Post Type
--- Post Type
--- Post Type
So I understand I need to add something for the child terms but I can't figure out how to do it. thought it is simple but couldn't find any answer
would love to get a help here thanks
Andrea P answers:
hello!
this should work as you whish
<?php
// List posts by the terms for a custom taxonomy of any post type
$post_type = 'product';
$tax = 'products';
$tax_args = array(
'order' => 'DESC',
'parent' => 0
);
// get all the first level terms only
$tax_terms = get_terms( $tax, $tax_args );
if ($tax_terms) {
foreach ($tax_terms as $tax_term) { // foreach first level term
// print the parent heading
?>
<h4 class="parent-term"><?php echo $tax_term->name; ?></h4>
<?php
// get all its children
$child_terms = ""; // first ensure this var is empty
$child_terms = get_terms ( $tax, array('order' => 'DESC', 'parent' => $tax_term->term_id) );
// store an array of child terms slug
$child_terms_array = array();
foreach ($child_terms as $child_term){
$child_terms_array[] = $child_term->slug;
}
// first of all, print the posts of the parent, but excluding the one which are also into a child term
$parent_args="";
$parent_args = array(
'post_type' => $post_type,
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => $tax,
'field' => 'slug',
'terms' => $tax_term->slug,
'include_children' => false,
'operator' => 'IN'
),
array(
'taxonomy' => $tax,
'field' => 'slug',
'terms' => $child_terms_array,
'include_children' => false,
'operator' => 'NOT IN'
)
),
'post_status' => 'publish',
'posts_per_page' => 6,
'order' => 'ASC',
);
// query the posts
$parent_query = null;
$parent_query = new WP_Query($parent_args);
if( $parent_query->have_posts() ) : ?>
<ul>
<?php while ( $parent_query->have_posts() ) : $parent_query->the_post(); ?>
<li><a href="<?php the_permalink() ?>">
<?php the_title(); ?>
</a>
</li>
<?php endwhile; // end of loop ?>
</ul>
<?php endif; // if have_posts()
wp_reset_query();
// if any, foreach child term, query the posts
if ( !empty($child_terms) ){
foreach ($child_terms as $child_term){
$child_args="";
$child_args = array(
'post_type' => $post_type,
'tax_query' => array(
array(
'taxonomy' => $tax,
'field' => 'slug',
'terms' => $child_term->slug,
'include_children' => false,
'operator' => 'IN'
)
),
'post_status' => 'publish',
'posts_per_page' => 6,
'order' => 'ASC',
);
// query the posts
$child_query = null;
$child_query = new WP_Query($child_args);
if( $child_query->have_posts() ) : ?>
<h4 class="child-term"><?php echo $child_term->name; ?></h4>
<ul>
<?php while ( $child_query->have_posts() ) : $child_query->the_post(); ?>
<li><a href="<?php the_permalink() ?>">
<?php the_title(); ?>
</a>
</li>
<?php endwhile; // end of loop ?>
</ul>
<?php endif; // if have_posts()
wp_reset_query();
} // end foreach #child_terms
}
} // end foreach #parent_term
}
?>
I have added 2 different classes to the h4 for parent and child terms, so you can easily style them differently (i.e. add a margin left to the child).
cheers!
***** UPDATE ****
I have tweaked the code so that it runs a secondary tax query when pulling the parent's posts, and it gets only the posts which are NOT also in the children terms
cheers!
hamergil comments:
OK
First of all it works great!
Thanks a lot. another question:
what if there is a product assign to a single category (without child category)
it seems like it won't work. can you check?
thanks
Andrea P comments:
Hello,
I was thinking the same and so I've tweaked the code in the answer.
let me know if everything works ok now
cheers!
hamergil comments:
Well. it works but it duplicates the products..
meaning that it shows something like that:
Main Category
-- Product 1
-- Product 2
Sub Category
-- Product 1
Another Sub Category
-- Product 2
I meant that if there are child categories than do not duplicate the products
but if there is a new category without a child it will show the products beneath it..
I hope I am not confusing you
if you have a solution to that I would love to hear
for now I'm going to use your first code.
Thanks