0

I'm beginning in PHP and I'm building a little shop with WooCommerce. I'm trying to display the top level parent category of a product in the body class.

This code works well :

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' );

But it just gets the parent category. In a tree like this :

"Toplevel cat > Parent cat > Category > My product"

It will just get the parent one. However, I'd like to get the top level category.

Do you have a solution ? Thank's a lot in advance!

2 Answers 2

0

If you want this to work for woocommerce categories you can start by limiting the logic to only woocommerce categories with is_product_category, that will help with preventing the code running when you don't need it to.

Using WordPress get_ansestors you can get the top lvl category (taxonomy) of the current category no matter how deep it is.

function woo_custom_taxonomy_in_body_class ($classes) {
    if (is_product_category()) {
        // get the current category (product_cat taxonomy)
        $cat = get_queried_object();

        if ($cat->parent == 0) { // if parent add it to body classes
            $classes[] = 'product_cat_' . urldecode($cat->slug);
        } else { // if not parent, find the top leven parent and add it
            // get the category parents
            $get_ancestors = get_ancestors($cat->term_id, 'product_cat');
            
            // get top level parent id, because ancestors from lowest to highest
            // we use PHPs end to get the last element of the array
            $top_parent_cat_id = end($get_ancestors);

            // using the parent id get the parent object
            $top_parent_cat = get_term_by('id', $top_parent_cat_id, 'product_cat');

            // get slug using the parent object
            $classes[] = 'product_parent_cat_' . urldecode($top_parent_cat->slug);
        }
    } else if (is_product()) {
        global $product;
        
        // get the product categories and check if not empty
        if (!empty($product_categories = get_the_terms($product->get_id(), 'product_cat'))) {
            // this is a bit more complicated
            // because product can have multiple categories we cannot always get the correct one
            // for this example ill take the firdt category I find and work with it
            // if you only have one category per product then this will work fine
            
            // get the first category (product_cat taxonomy) that we find
            $cat = $product_categories[0];

            if ($cat->parent == 0) { // if parent add it to body classes
                $classes[] = 'product_cat_' . urldecode($cat->slug);
            } else { // if not parent, find the top leven parent and add it
                // get the category parents
                $get_ancestors = get_ancestors($cat->term_id, 'product_cat');

                // get top level parent id, because ancestors from lowest to highest
                // we use PHPs end to get the last element of the array
                $top_parent_cat_id = end($get_ancestors);

                // using the parent id get the parent object
                $top_parent_cat = get_term_by('id', $top_parent_cat_id, 'product_cat');

                // get slug using the parent object
                $classes[] = 'product_parent_cat_' . urldecode($top_parent_cat->slug);
            }
        }
    }

    return $classes;
}
add_filter('body_class', 'woo_custom_taxonomy_in_body_class');
5
  • It works perfectly for archive pages ! Maybe my question wasn't clear, but I want this to be on single product page. You helped me a lot tho, thank you. Still looking for the solution
    – gCoffy
    Sep 14, 2021 at 14:21
  • @gCoffy No problem, updated my code for working with product as well. Notice, this code will work correctly if you have one product category per product, it take the first connect category of the product and works with it, if you want it to work with all categories let me know. Sep 14, 2021 at 14:56
  • Thanks so much, we are almost there ! When I go on a product page, I got a critical error : Fatal error: Uncaught Error: Call to a member function get_id() on string in {functions.php page}. It seems to be this line : if (!empty($product_categories = get_the_terms($product->get_id(), 'product_cat'))) {
    – gCoffy
    Sep 14, 2021 at 16:26
  • @gCoffy Strange, on my env it works fine, did you copy my code as is or made some changes? Sep 14, 2021 at 16:35
  • I published an answer, according to you, the code can works ? Is it clean ? Thank you
    – gCoffy
    Sep 16, 2021 at 12:43
0

EDIT : I maybe found a solution (which displays the class in body and product box (I need the class to be in product boxes, shop body and product page body), based on @Buttered_Toast answer) :

function woo_custom_taxonomy_in_body_class ($classes) {
    if (is_woocommerce()) {
    // get the product categories and check if not empty
    if (!empty($product_categories = get_the_terms(0, 'product_cat'))) {
        // this is a bit more complicated
        // because product can have multiple categories we cannot always get the correct one
        // for this example ill take the firdt category I find and work with it
        // if you only have one category per product then this will work fine
        
        // get the first category (product_cat taxonomy) that we find
        $cat = $product_categories[0];

        if ($cat->parent == 0) { // if parent add it to body classes
            $classes[] = 'product_cat_' . urldecode($cat->slug);
        } else { // if not parent, find the top leven parent and add it
            // get the category parents
            $get_ancestors = get_ancestors($cat->term_id, 'product_cat');

            // get top level parent id, because ancestors from lowest to highest
            // we use PHPs end to get the last element of the array
            $top_parent_cat_id = end($get_ancestors);

            // using the parent id get the parent object
            $top_parent_cat = get_term_by('id', $top_parent_cat_id, 'product_cat');

            // get slug using the parent object
            $classes[] = 'product_parent_cat_' . urldecode($top_parent_cat->slug);
        }
        }
    }
return $classes;
}
add_filter( 'post_class', 'woo_custom_taxonomy_in_body_class' );
add_filter('body_class', 'woo_custom_taxonomy_in_body_class');

Can it be correct ? Personally, I tested and it works. Regards,

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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