get_categories для произвольного типа записей с привязанной специальной таксономией
В основном у меня есть произвольный тип записи 'products' с двумя прикрепленными таксономиями... обычная 'category' и пользовательская таксономия под названием 'brands'.
У меня есть страница, специфичная для 'brand'. На этой странице я хотел бы вывести все 'категории', в которых есть 'product' с прикрепленным термином 'brand' той страницы, на которой я нахожусь.
Например, если я нахожусь на странице "Nike". Я хочу вывести список всех категорий, в которых есть 'product' с прикрепленным к ним 'brand' "Nike".
Изначально я думал использовать get_categories, но нет способа определить конкретную таксономию или 'brand'?
$categories = get_categories('orderby=name&depth=1&hide_empty=0&child_of='.$cat);
Кто-нибудь делал это раньше или знает способ напрямую запросить базу данных для получения необходимых результатов?
Буду благодарен за любую помощь, спасибо

Если вам нужно вывести список всех доступных категорий для пользовательского типа записи (CPT), этот фрагмент кода может вам помочь.
Просто используйте стандартную функцию get_categories()
и передайте параметры $args
, относящиеся к таксономии, которую вы зарегистрировали для вашего CPT. Например, если вы определили таксономию следующим образом:
register_taxonomy( 'the_taxonomy_named_in_your_CPT' );
Тогда вы можете отобразить эту таксономию для пользователей на фронтенде с помощью:
$args = array(
'taxonomy' => 'the_taxonomy_named_in_your_CPT',
'orderby' => 'name',
'show_count' => 1,
'pad_counts' => 1,
'hierarchical' => 1,
'echo' => 0
);
$allthecats = get_categories( $args );
echo ( '<pre>' );
print_r( $allthecats );
echo ( '</pre>' );
Вы увидите объект, который поможет вам в дальнейшей работе.

После долгих часов и головной боли это сработало как нужно. Спасибо! Плохая документация по выводу категорий пользовательских типов записей.

Привет @daveaspi:
То, что ты хочешь сделать, является распространённой задачей, но плохо реализовано в ядре WordPress. Возможно, есть способы сделать это без кастомного SQL, но я не думаю, что они будут масштабируемы для большого количества записей. Ниже приведена функция get_cross_referenced_terms()
, которую я написал — она получит то, что тебе нужно, вместе с примером её использования.
Следующий код можно разместить в корне твоего WordPress-сайта в файле test.php
, чтобы увидеть его в работе. Затем ты можешь скопировать функцию get_cross_referenced_terms()
в файл functions.php
твоей темы или в .php
файл плагина, над которым ты работаешь:
<?php
include('wp-load.php');
$nike = get_term_by('slug','nike','brand'); // Это здесь просто для примера
$terms = get_cross_referenced_terms(array(
'post_type' => 'product',
'related_taxonomy' => 'brand',
'term_id' => $nike->term_id,
));
foreach($terms as $term) {
echo "<p>{$term->name}</p>";
}
function get_cross_referenced_terms($args) {
global $wpdb;
$args = wp_parse_args($args,array(
'post_type' => 'post',
'taxonomy' => 'category',
'related_taxonomy' => 'post_tag',
'term_id' => 0,
));
extract($args);
$sql = <<<SQL
SELECT DISTINCT
{$wpdb->terms}.*,
COUNT(*) AS post_count
FROM
{$wpdb->terms}
INNER JOIN {$wpdb->term_taxonomy} ON {$wpdb->terms}.term_id={$wpdb->term_taxonomy}.term_id
INNER JOIN {$wpdb->term_relationships} ON {$wpdb->term_taxonomy}.term_taxonomy_id={$wpdb->term_relationships}.term_taxonomy_id
INNER JOIN {$wpdb->posts} ON {$wpdb->term_relationships}.object_id={$wpdb->posts}.ID
INNER JOIN {$wpdb->term_relationships} related_relationship ON {$wpdb->posts}.ID=related_relationship.object_id
INNER JOIN {$wpdb->term_taxonomy} related_term_taxonomy ON related_relationship.term_taxonomy_id=related_term_taxonomy.term_taxonomy_id
INNER JOIN {$wpdb->terms} related_terms ON related_term_taxonomy.term_id=related_terms.term_id
WHERE 1=1
AND (related_term_taxonomy.taxonomy<>{$wpdb->term_taxonomy}.taxonomy OR related_terms.term_id<>{$wpdb->terms}.term_id)
AND {$wpdb->posts}.post_type='%s'
AND {$wpdb->term_taxonomy}.taxonomy='%s'
AND related_term_taxonomy.taxonomy='%s'
AND related_terms.term_id=%d
GROUP BY
{$wpdb->terms}.term_id
SQL;
$sql = $wpdb->prepare($sql,$post_type,$taxonomy,$related_taxonomy,$term_id);
$terms = $wpdb->get_results($sql);
return $terms;
}

Привет @MikeSchinkel, это именно то, что мне было нужно! Отлично работает. Огромное спасибо!

Небольшой вопрос: есть ли способ ограничить 'глубину' до 1? Чтобы получать только категории верхнего уровня? :-) Спасибо, ребята

@daveaspi: Добавьте AND {$wpdb->term_taxonomy}.parent=0
в условие WHERE.

@MikeSchinkel, @Bainternet привет, ребята, есть ли способ добавить переменную в $args чтобы определить категорию так же как и бренд? Например: 'post_type' => 'post', 'taxonomy' => 'category', 'related_taxonomy' => 'post_tag', 'term_id' => 0, 'category_id' => $cat

@davesapi - Похоже, это должен быть новый вопрос.

Вы можете либо написать собственный SQL-запрос, либо запросить записи вашего типа поста для этого "бренда", собрать категории и затем отобразить их, например так:
//получаем все записи данного типа для конкретного бренда
$my_query = new WP_Query();
$my_query->query(array(
'post_type' => 'products',
'posts_per_page' => -1,
'tax_query' => array(
array(
'taxonomy' => 'brand',
'field' => 'slug',
'terms' => $wp_query->query_vars['brand']
)
)
));
$my_cats = array();
if ($my_query->have_posts()){
//перебираем все записи и собираем категории в массив
while ($my_query->have_posts()){
$my_query->the_post();
foreach((get_the_category($post->ID)) as $category) {
if (!in_array($category->cat_ID ,$my_cats)){
$my_cats[] = $category->cat_ID;
}
}
}
}
Теперь у вас есть список всех ID категорий в массиве $my_cats, из которого вы можете получить всю необходимую информацию.

Да, гораздо чище и отлично подходит для небольшого сайта, но при большом количестве записей это может быть очень медленным.

@MikeSchinkel - да, на сайте, где у каждого бренда куча товаров, это займет какое-то время, но, видимо, мой "SQL-фу" не так силён, как у тебя, мастер!

Ха! Я тоже не за один день этому научился! Потребовалось 20+ лет работы с SQL, чтобы дойти до этого. :)
