Одна таксономия для нескольких типов записей: как скрыть пустые для конкретного типа записи?
У меня есть таксономия "artist" (артист), которая используется для двух типов записей: "project" (проект) и "product" (товар).
Мне нужно отобразить список "артистов", но только если у них есть связанные "товары", и только если эти товары есть в наличии.
$artists = get_terms( array(
'taxonomy' => 'artist',
'hide_empty' => 1,
) );
Этот код включает артистов, у которых есть "проекты", но нет "товаров". Можно ли указать, для какого типа записей должен применяться аргумент "hide_empty"?
ОБНОВЛЕНИЕ Вот что у меня получилось на данный момент:
/*
Полезно, когда одна таксономия применяется к нескольким типам записей
источник: http://wordpress.stackexchange.com/a/24074/82
*/
function get_terms_by_post_type( $taxonomies, $post_types ) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT t.*, COUNT(*) from $wpdb->terms AS t
INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id
WHERE p.post_type IN('%s') AND tt.taxonomy IN('%s')
GROUP BY t.term_id",
join( "', '", $post_types ),
join( "', '", $taxonomies )
);
$results = $wpdb->get_results( $query );
return $results;
}
$artists = get_terms_by_post_type( array('artist'), array('product'));
//*
if( !empty($artists) && !is_wp_error( $artists ) ){
// фильтруем артистов с товарами не в наличии
foreach($artists as $k=>$artist){
$args = array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => -1,
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'artist',
'field' => 'id',
'terms' => array( $artist->term_id )
),
array(
'key' => '_stock_status',
'value' => 'instock'
)
)
);
$query = new WP_Query($args);
echo $artist->slug;
pr($query->post_count);
if($query->post_count<1){
unset($artists[$k]);
}
}
}
Код почти работает, но не исключает товары, которых нет в наличии.

Ещё одно решение той же проблемы, которое немного короче и менее сложное:
function get_terms_by_posttype($taxonomy, $postType) {
// Получаем все термины, у которых есть записи
$terms = get_terms($taxonomy, [
'hide_empty' => true,
]);
// Удаляем термины, у которых нет записей текущего типа поста
$terms = array_filter($terms, function ($term) use ($postType, $taxonomy) {
$posts = get_posts([
'fields' => 'ids',
'numberposts' => 1,
'post_type' => $postType,
'tax_query' => [[
'taxonomy' => $taxonomy,
'terms' => $term,
]],
]);
return (count($posts) > 0);
});
// Возвращаем оставшиеся термины
return $terms;
}

Благодаря этому ответу, я смог разобраться. Вот как можно запросить термины таксономии, связанные с товарами (woocommerce), которые есть "в наличии". В этом примере используются как tax_query (для связи товаров с таксономией), так и meta_query (для исключения товаров, отсутствующих на складе).
$artists = get_terms_by_post_type( array('artist'), array('product'));
if( !empty($artists) && !is_wp_error( $artists ) ){
// фильтруем артистов, у которых нет товаров в наличии
foreach($artists as $k=>$artist){
$args = array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => -1,
'meta_query' =>array(
'relation' => 'AND',
array(
'key' => '_stock_status',
'value' => 'instock',
'compare' => '='
)
,
array(
'key' => '_stock',
'value' => '0',
'compare' => '>'
)
,
array(
'key' => '_stock',
'value' => '',
'compare' => '!='
)
),
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'artist',
'field' => 'id',
'terms' => array( $artist->term_id )
),
)
);
$query = new WP_Query($args);
if($query->post_count<1){
unset($artists[$k]);
}
}
}
function get_terms_by_post_type( $taxonomies, $post_types ) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT t.*, COUNT(*) from $wpdb->terms AS t
INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id
WHERE p.post_type IN('%s') AND tt.taxonomy IN('%s')
GROUP BY t.term_id",
join( "', '", $post_types ),
join( "', '", $taxonomies )
);
$results = $wpdb->get_results( $query );
return $results;
}
