Ask your WordPress questions! Pay money and get answers fast! (more info)

Display taxonomy terms, child terms and posts in a template WordPress

  • SOLVED

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

Answers (1)

2015-04-30

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