Add Woocommerce parent category to WP 'body' class - php

I am trying to add a product's parent category from Woocommerce as a class to wordpress' body tag.
Every time I go within a child category the parent category is no longer within the body class.
Could something like below be edited to find the parent category and add within the body tag?
Maybe a term like "product_parent_cat"? Tried this and searched their API but no success..
function woo_custom_taxonomy_in_body_class( $classes ){
$custom_terms = get_the_terms(0, 'product_cat');
if ($custom_terms) {
foreach ($custom_terms as $custom_term) {
$classes[] = 'product_cat_' . $custom_term->slug;
}
}
return $classes;
}
add_filter( 'body_class', 'woo_custom_taxonomy_in_body_class' );

You can try this modification (untested):
function woo_custom_taxonomy_in_body_class( $classes ){
$custom_terms = get_the_terms(0, 'product_cat');
if ($custom_terms) {
foreach ($custom_terms as $custom_term) {
// Check if the parent category exists:
if( $custom_term->parent > 0 ) {
// Get the parent product category:
$parent = get_term( $custom_term->parent, 'product_cat' );
// Append the parent class:
if ( ! is_wp_error( $parent ) )
$classes[] = 'product_parent_cat_' . $parent->slug;
}
$classes[] = 'product_cat_' . $custom_term->slug;
}
}
return $classes;
}
add_filter( 'body_class', 'woo_custom_taxonomy_in_body_class' );
to add the parent product category slugs to the body class.
Here we use the parent property of the term object returned by the get_term() function.

Related

Woocommerce: check if current product is in a child category of 'XXX'

I'm working on WP single.php (woocommerce installed).
I need to check if current page is a product page: if yes, also check if this product is in a child category of XXX.
I found this piece of code:
if ( ! function_exists( 'post_is_in_descendant_category' ) ) {
function post_is_in_descendant_category( $cats, $_post = null ) {
foreach ( (array) $cats as $cat ) {
// get_term_children() accepts integer ID only
$descendants = get_term_children( (int) $cat, 'category' );
if ( $descendants && in_category( $descendants, $_post ) )
return true;
}
return false;
}
}
This works perfectly fine on my regular pages, but not on my product pages.
Now I currently use this code:
if ( is_product() && has_term( 'XXX', 'product_cat' ) ) {
The problem is this doesn't check for child categories. Any help?
The function you are using only checks the category taxonomy. use this one on product pages. I've replace 'category' with 'product_cat' and replaced in_category with has_term since that only works on categories
<?php
if (!function_exists('product_is_in_descendant_category')) {
function product_is_in_descendant_category($cats, $_post = null)
{
foreach ((array)$cats as $cat) {
// get_term_children() accepts integer ID only
$descendants = get_term_children((int)$cat, 'product_cat');
if ($descendants && has_term($descendants, 'product_cat', $_post)) {
return true;
}
}
return false;
}
}
or add a third parameter to the original function that reads $tax = 'category' and replace 'category' with $tax on line 5. then when you call the function on product pages pass 'product_cat' as the third parameter. FYI doing it this way would also require you to replace in_category with has_term

Add a body class for product category archive page in Woocommerce

I want to add product category slug in the body class on product category archive pages.
Here is an example of what I would like (url of the product category page example):
https://example.com/product-category/canon/… So I would like "canon" in the body class.
Your example link doesn't seem to work; however, WooCommerce should already be adding a term-specific class to your category pages: something along the lines of archive tax-product_cat term-{slug} term-{id} to a product category page. Taking your example link, and assuming the term ID is 7 (for example), the body class would include:
tax-product_cat term-7 term-canon
So if you need to access it via CSS/jQuery/whatever, you can use the selector body.term-canon.
You can use page slug in body class, See this code
function add_slug_body_class( $classes ) {
global $post;
if ( isset( $post ) ) {
$classes[] = $post->post_type . '-' . $post->post_name;
}
return $classes;
}
add_filter( 'body_class', 'add_slug_body_class' );
for this you need to add the below code in your functions.php file in your activated theme.
add_filter( 'body_class', 'product_cats_css_body_class' );
function product_cats_css_body_class( $classes ){
if( is_archive( 'product-cat' ) )
{
$custom_terms = get_the_terms(0, 'product_cat');
if ($custom_terms) {
foreach ($custom_terms as $custom_term) {
$classes[] = $custom_term->slug;
}
}
}
return $classes;
}
this will add the category slug at the last of body class.
Even if Woocommerce embed as body class the product category term slug as term-canon, you can easily add just canon using the dedicated WordPress body_class action hook, with Woocommerce is_product_category() conditional function and WordPress get_queried_object() this way:
add_filter( 'body_class', 'product_category_slug_to_body_class', 99, 1 );
function product_category_slug_to_body_class( $classes ){
if( is_product_category() ){
$classes[] = get_queried_object()->slug;
}
return $classes;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Add the term slug as a class to the product category div tag in Woocommerce

In Woocommerce, I'm trying to filter the output of wc_get_product_cat_class() function located in wc-template-functions.php core code:
function wc_get_product_cat_class( $class = '', $category = null ) {
$classes = is_array( $class ) ? $class : array_map( 'trim', explode( ' ', $class ) );
$classes[] = 'product-category';
$classes[] = 'product';
$classes[] = wc_get_loop_class();
$classes = apply_filters( 'product_cat_class', $classes, $class, $category );
return array_unique( array_filter( $classes ) );
}
I need it to add the cat slug as a class to each li tag on the category page.
It works fine when i edit the file directly and add this to the function :
$classes[] = $category->slug;
I then have <li class="product-category whatever-cat-slug product">
But obviously i am trying to find a better way to add it to my themes function file.
I have tried this, without success :
add_filter( 'product_cat_class' , 'add_class_to_category_list_element');
function add_class_to_category_list_element($classes) {
$classes[] = $category->slug;
return $classes;
}
Because $category has no meaning here.
Any help is welcome.
The product_cat_class filter hook manage 3 arguments $classes, $class and $category, so your code is just a bit incomplete. Also you should be sure that $category is a defined object before trying to get the slug on it.
Try this instead:
add_filter( 'product_cat_class' , 'add_class_to_category_list_element', 10, 3 );
function add_class_to_category_list_element( $classes, $class, $category ) {
if( is_object( $category ) )
$classes[] = $category->slug;
return $classes;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Add a body class related to the product category in WooCommerce

How can I add a body class related to the product category slug?
Thank you!
Add this to your functions.php
add_filter( 'body_class', 'wc_cat_names' );
function wc_cat_names( $classes ) {
if(is_product()){
global $post;
$terms = get_the_terms( $post->ID, 'product_cat' );
foreach ($terms as $term) {
$classes[] = $term->slug;
}
}
return $classes;
}
This one will work only in woocommerce product page and Yes I tested this on my test site.
There is a pretty good guide for doing exactly this on the Wordpress support site: Modify body_class() output to show category-{slug} for single posts
I have altered the code from the post to suit your needs:
add_filter('body_class','add_category_to_single');
function add_category_to_single($classes, $class) {
if (is_single() ) {
global $post;
foreach((get_the_category($post->ID)) as $category) {
echo $category->cat_name . ' ';
// add category slug to the $classes array
$classes[] = $category->slug;
}
}
// return the $classes array
return $classes;
}

Wordpress - Maintain "active" class on parent menu item

I am implementing a theme in Wordpress. This theme has a top navigation menu with horizontal sub menus under each parent item. It puts an "active" class on current parent items currently been viewed (otherwise it won't show it's children sub menu items). I have somehow managed to maintain "active" class on current parent items by using these two function in functions.php.
/**
* Wp Nav Menu Customizer.
*/
function special_nav_class($classes, $item){
if( in_array('current-menu-item', $classes) ){
$classes[] = 'active ';
}
return $classes;
}
add_filter('nav_menu_css_class' , 'special_nav_class' , 10 , 2);
class SH_Last_Walker extends Walker_Nav_Menu{
function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
$id_field = $this->db_fields['id'];
//If the current element has children, add class 'sub-menu'
if( isset($children_elements[$element->$id_field]) ) {
$classes = empty( $element->classes ) ? array() : (array) $element->classes;
$classes[] = 'has-sub-menu';
$element->classes =$classes;
}
// We don't want to do anything at the 'top level'.
if( 0 == $depth )
return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
//Get the siblings of the current element
$parent_id_field = $this->db_fields['parent'];
$parent_id = $element->$parent_id_field;
$siblings = $children_elements[ $parent_id ] ;
//No Siblings??
if( ! is_array($siblings) )
return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
//Get the 'last' of the siblings.
$last_child = array_pop($siblings);
$id_field = $this->db_fields['id'];
//If current element is the last of the siblings, add class 'last'
if( $element->$id_field == $last_child->$id_field ){
$classes = empty( $element->classes ) ? array() : (array) $element->classes;
$classes[] = 'last';
$element->classes =$classes;
}
return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}
}
But now my problem is that when i click on sub menu or child of any parent menu item it successfully takes me to the child page but removes "active" class from parent and puts it on children (because it is the currently viewed page). I don't want it to put this class to children, i want it to be there (on parent item) whenever it's children are being viewed.
Any help would be much appreciated.
if you want to the dropdown grand-grand parent to be active when child menu item is active, then you can check for current-menu-ancestor or current-page-ancestor.. in your case, i think current-menu-ancestor check is most favorable.
function special_nav_class($classes, $item){
if( in_array('current-menu-item', $classes) || in_array('current-menu-ancestor', $classes) ){
$classes[] = 'active ';
}
return $classes;
}
I hope this would help, have a nice day :)
If all you want is to add some style or other properties by targeting the parent element then WordPress Provides you built-in classes for it for example:
when you are on a child page you can see classes like current-menu-parent current-page-parent current_page_parent current_page_ancestor these added to the parent page by WordPress you can choose any of these to target the parent element.
When you click on sub menu item WordPress will add .current-menu-item class to that sub menu item and .current-menu-parent class to the parent menu item of that sub menu item. You can style those specific classes according to your needs.

Categories