Проверить, находится ли запись в любой дочерней категории родительской категории
На сайте, который я разрабатываю, есть следующая структура категорий:
* movies (родительская)
* thriller (дочерняя)
* comedy (дочерняя)
* drama (дочерняя)
Текущая запись находится в категории comedy. Функция has_term со следующими параметрами возвращает true:
has_term( 'comedy', 'category' )
Но та же функция со следующими параметрами возвращает false:
has_term( 'movies', 'category' )
Мой вопрос: есть ли в WordPress стандартная функция для проверки, находится ли текущая запись в любой дочерней категории указанной родительской категории? Если нет, как это можно проверить?
Заранее спасибо

Добавьте следующий код в файл functions.php вашей темы:
/**
* Проверяет, является ли любая из категорий поста дочерней по отношению к целевым категориям
*
* @param int|array $cats Целевые категории. ID в виде числа или массив ID
* @param int|object $_post Пост. Если не указан, проверяется текущий пост в цикле или основном запросе
* @return bool Возвращает true, если хотя бы одна категория поста является дочерней для любой из целевых категорий
* @see get_term_by() Можно получить категорию по имени или слагу, затем передать ID в эту функцию
* @uses get_term_children() Принимает $cats
* @uses in_category() Принимает $_post (может быть пустым)
* @version 2.7
* @link http://codex.wordpress.org/Function_Reference/in_category#Testing_if_a_post_is_in_a_descendant_category
*/
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() принимает только числовой ID
$descendants = get_term_children( (int) $cat, 'category' );
if ( $descendants && in_category( $descendants, $_post ) )
return true;
}
return false;
}
}
Используйте функцию для проверки ID родительской категории, а не имени или слага. Например, если ID категории 'movies' равен 50:
if ( post_is_in_descendant_category( 50 ) ) {
// сделать что-то
}
Если вы не знаете ID категории 'movies', вы можете получить его с помощью get_term_by() и передать в post_is_in_descendant_category():
$category_to_check = get_term_by( 'name', 'movies', 'category' );
if ( post_is_in_descendant_category( $category_to_check->term_id ) ) {
// сделать что-то
}

Если вам нужна любая глубина вложенности, используйте get_posts
.
/**
* Проверяет, находится ли запись в одной из категорий или любой дочерней категории.
*
* @param int|string|array $category_ids (ID одной категории) или (строка с ID, разделенными запятыми, или массив ID категорий).
* @param int $post_id ID записи для проверки. По умолчанию используется `get_the_ID()`.
* @return bool true, если запись находится в любой категории или дочерней категории.
*/
function is_post_in_category( $category_ids, $post_id = null ) {
$args = array(
'include' => $post_id ?? get_the_ID(),
'category' => $category_ids,
'fields' => 'ids',
);
return 0 < count( get_posts( $args ) );
}
Эту функцию можно расширить разными способами. Например, передавать массив ID записей и фильтровать их или позволять уточнять запрос.

Обновление для использования пользовательских таксономий:
/**
* Проверяет, являются ли какие-либо категории поста дочерними для целевых категорий
*
* @param int|array $cats Целевые категории. ID в виде числа или массив ID
* @param int|object $_post Пост. Если не указан, проверяется текущий пост в цикле или основном запросе
* @param string $target_cat Название таксономии для запроса. Если не указано, используется стандартная таксономия 'category' для постов
* @return bool Возвращает true, если хотя бы одна из категорий поста является дочерней для любой из целевых категорий
* @see get_term_by() Можно получить категорию по имени или слагу, затем передать ID в эту функцию
* @uses get_term_children() Передает $cats
* @uses in_category() Передает $_post (может быть пустым)
* @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() принимает только числовой ID
$descendants = get_term_children((int) $cat, $target_cat);
if($descendants && has_term($descendants, $target_cat, $_post)) {
return true;
}
}
return false;
}
}
Немного контекста
in_category
использует has_category
, который в свою очередь вызывает has_term( $category, 'category', $post )
с жестко заданной таксономией 'category'.
Использование has_term()
напрямую позволяет нам проверять пользовательские таксономии, такие как product_cat (WooCommerce) или любые другие таксономии.
Функция использует category по умолчанию, поэтому может использоваться как прямая замена.
Использование
Вызовите функцию следующим образом:
if(post_is_in_descendant_category($category_to_check->term_id, $post, 'product_cat')) {
// выполнить какое-то действие
}
