Update for using custom taxonomies:
/**
* Tests if any of a post's assigned categories are descendants of target categories
*
* @param int|array $cats The target categories. Integer ID or array of integer IDs
* @param int|object $_post The post. Omit to test the current post in the Loop or main query
* @param string $target_cat The taxonomy name to query for. Omit to use the default 'category' taxonomy used for posts
* @return bool True if at least 1 of the post's categories is a descendant of any of the target categories
* @see get_term_by() You can get a category by name or slug, then pass ID to this function
* @uses get_term_children() Passes $cats
* @uses in_category() Passes $_post (can be empty)
* @version 2.7
* @link https://developer.wordpress.org/reference/functions/in_category/#comment-4999
*/
if(!function_exists('post_is_in_descendant_category')) {
function post_is_in_descendant_category($cats, $_post = null, $target_cat = 'category') {
foreach((array) $cats as $cat) {
// get_term_children() accepts integer ID only
$descendants = get_term_children((int) $cat, $target_cat);
if($descendants && has_term($descendants, $target_cat, $_post)) {
return true;
}
}
return false;
}
}
Some context
in_category
uses has_category
which in turn calls has_term( $category, 'category', $post )
with the hard-coded 'category' being set as taxonomy.
Using has_term()
directly allows us to check for a custom taxonomy like product_cat (WooCommerce) or any other taxonomy.
The function uses category as default so this can be used as a drop-in replacement.
Usage
Call the function like this:
if(post_is_in_descendant_category($category_to_check->term_id, $post, 'product_cat')) {
// do something
}