Reputation: 421
What I'm trying to do is display a menu in my Woocommerce shop's sidebar with the current product category name and current categories children. If the product category has no children, then it should display the parent category and parent category children.
This is how the hierarchy looks: SHOP > PREPARED FOODS > FOODSTUFF
When you are on the PREPARED FOODS page you should see.
Prepared Foods
When you are on the FOODSTUFF page you should see
Prepared Foods
Right now I've gotten it to display the parent category links when you are in the top level category, but I haven't gotten it to display the parent category name when you are in the top level. Here is the code I have so far:
<?php
$queried_object = get_queried_object();
if ( is_product_category() && is_a($queried_object, 'WP_Term') ) {
$taxonomy = $queried_object->taxonomy;
echo '<h2 class="shop__sidebar-heading">
<a href="' . get_term_link( $queried_object ) . '">' . $queried_object->name . '</a>
</h2>';
}
?>
<?php
$term = get_queried_object()->term_id;
$termid = get_term($term, 'product_cat' );
if($termid->parent > 0)
{
$args = array(
'orderby' => 'name',
'order' => 'ASC',
'hide_empty' => false,
'child_of' => $termid->parent,
);
$siblingproducts = get_terms( 'product_cat', $args);
foreach ($siblingproducts as $siblingproduct) {
if ($siblingproduct->term_id == $term ) { ?>
<li>
<?php } else { ?>
<li>
<?php } ?>
<a href="<?php
echo get_term_link( $siblingproduct ); ?>"><?php echo $siblingproduct->name; ?><?php
echo "<span class='count'>" . $siblingproduct->count . "</span>"; ?></a></li>
<?php }
} else {
$args = array(
'orderby' => 'name',
'order' => 'ASC',
'hide_empty' => false,
'child_of' => $term
);
$subproducts = get_terms( 'product_cat', $args);
foreach ($subproducts as $subproduct) { ?>
<li> <a href="<?php echo get_term_link( $subproduct ); ?>"><?php echo $subproduct->name; ?><?php echo "<span class='count'>" . "</span>"; ?></a></li>
<?php }
}
?>
An example of what I'm trying to achieve can be see on the Food52 website sidebar https://food52.com/shop/pantry
Upvotes: 1
Views: 1541
Reputation: 893
You can get category and child category using following code. You need to call the following functions according to your needs and pass parameters.
/**
* Get Category
* @param $taxonomy
* @param string $order
* @return array
*/
function getPostTermCategory($taxonomy, $order = 'asc')
{
$term_query = new WP_Term_Query([
'taxonomy' => $taxonomy,
'order' => $order,
'hide_empty' => false,
'parent' => 0
]);
$categories = [];
foreach ($term_query->terms as $term) {
$categories[] = $term;
}
return $categories;
}
/**
* Get Child Categories of Parent
* @param $taxonomy
* @param $parentId
* @param string $order
* @return array
*/
function getPostTermChildCategory($taxonomy, $parentId, $order = 'asc')
{
$term_query = new WP_Term_Query([
'taxonomy' => $taxonomy,
'order' => $order,
'hide_empty' => false,
'parent' => $parentId
]);
$categories = [];
foreach ($term_query->terms as $term) {
$categories[] = $term;
}
return $categories;
}
Upvotes: 0
Reputation: 13840
I've taken the liberty to clean up a few things along the way (such as removing some unnecessary open/closing PHP tags) and some clarifying things - I hope you don't mind! Going through your existing code:
You shouldn't need to check is_a()
on the queried object (also, consider using instanceof
instead, as it has lower overhead since it's a language construct and not a function: if($queried_object instanceof WP_Term){}
. Still, you shouldn't need to check it because is_product_category()
runs the is_tax()
function which should handle that for you.
You seem to have an unused $taxonomy
declaration
It's less important on WordPress supplied functions, but it's good to get into the habit of using esc_url
and esc_attr
on attribute fields.
You've got some redundancy issues with getting the $term
set. It also seems like you could/should move these up into your outer if
statement since you're already checking to see if it's a WP_Term
object, so you shouldn't have to worry about things not being set or redefining values from it. Also your $term
and $termid
declarations are a bit mixed, it seems like they are flipped ($term
is the ID and $termid
is the actual object)
You seem to be creating two separate loop argument arrays (and subsequent loops) for no real reason, other than changing variable names - based just on if it's a toplevel term or not (parent_id > 0)
You add have a conditional <li>
that doesn't take advantage of the conditional check if it's the current WP_Term
being queried; Did you mean to add an active
class or something in there?
You don't appear to have a <ul>
to contain the <li>
elements. I've added that in conditionally based on the results of get_terms
for the child/sibling terms loop.
I'm familiar with WooCommerce, but don't currently have it installed on my dumping ground site, but I've recreated the category (product_cat
) structure from it and used this code (just with the taxonomy changed) and it appears to do what you've asked:
<?php
if( is_product_category() ){
$queried_object = get_queried_object();
$child_terms = get_term_children( $queried_object->term_id, 'product_cat' );
$based_term = (is_wp_error($child_terms) || empty($child_terms)) ? get_term( $queried_object->parent, 'product_cat' ) : $queried_object;
printf( '<h2 class="shop__sidebar-heading">
<a href="%s?so64231449=true">%s</a>
</h2>', esc_url(get_term_link($based_term->term_id)), $based_term->name );
$display_terms = get_terms( 'product_cat', array(
'orderby' => 'name',
'order' => 'ASC',
'hide_empty' => false,
'parent' => $based_term->term_id,
) );
if( !empty($display_terms) && !is_wp_error($display_terms) ){
echo '<ul>';
foreach( $display_terms as $display_term ){
printf(
'<li%s><a href="%s">%s <span class="count">%s</span></a></li>',
($display_term->term_id == $queried_object->term_id) ? ' class="active"' : '',
esc_url(get_term_link($display_term->term_id)),
$display_term->name,
number_format($display_term->count)
);
}
echo '</ul>';
}
}
?>
A few notes:
I've replaced a lot of the echo
s with printf()
. It may look a little daunting, but it removes the need for the mix of PHP Escapes and string concatenation that you have. It also makes it easier to pass functions and Ternary Operators to it.
%s
, in order, with that value.Ternary Operators are basically a succinct, one line, "if/else" statement. This lets you check for the active
WP_Term in the same declaration as the other terms really easily.
Here are a few links to show you it's working (scroll to the bottom of the page):
Upvotes: 1