get_categories для произвольного типа записей с привязанной специальной таксономией

3 мар. 2011 г., 11:32:14
Просмотры: 21.6K
Голосов: 8

В основном у меня есть произвольный тип записи '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);

Кто-нибудь делал это раньше или знает способ напрямую запросить базу данных для получения необходимых результатов?

Буду благодарен за любую помощь, спасибо

0
Все ответы на вопрос 3
2

Если вам нужно вывести список всех доступных категорий для пользовательского типа записи (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>' );

Вы увидите объект, который поможет вам в дальнейшей работе.

28 янв. 2016 г. 16:06:44
Комментарии

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

Rodrigo Zuluaga Rodrigo Zuluaga
8 июл. 2020 г. 01:08:00

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

mfru mfru
3 мая 2022 г. 13:08:16
8

Привет @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;
}
3 мар. 2011 г. 12:51:28
Комментарии

да, это тот SQL-запрос, о котором я говорил :)

Bainternet Bainternet
3 мар. 2011 г. 12:59:19

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

daveaspinall daveaspinall
3 мар. 2011 г. 13:22:59

@Bainternet также большое спасибо за вашу помощь :-)

daveaspinall daveaspinall
3 мар. 2011 г. 13:23:31

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

daveaspinall daveaspinall
3 мар. 2011 г. 13:29:36

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

MikeSchinkel MikeSchinkel
3 мар. 2011 г. 13:38:20

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

daveaspinall daveaspinall
7 мар. 2011 г. 16:25:01

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

MikeSchinkel MikeSchinkel
8 мар. 2011 г. 01:52:13

@MikeSchinkel как нам изменить пользовательский SQL-запрос, чтобы он выводил ссылки на категории, а не просто названия? Спасибо!

Ioannis Baltzakis Ioannis Baltzakis
28 сент. 2011 г. 01:56:23
Показать остальные 3 комментариев
4

Вы можете либо написать собственный 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, из которого вы можете получить всю необходимую информацию.

3 мар. 2011 г. 12:58:21
Комментарии

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

MikeSchinkel MikeSchinkel
3 мар. 2011 г. 13:09:04

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

Bainternet Bainternet
3 мар. 2011 г. 13:11:41

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

MikeSchinkel MikeSchinkel
3 мар. 2011 г. 13:13:27

Говоришь, больше 20, значит мне осталось всего 15 до этой цифры.

Bainternet Bainternet
3 мар. 2011 г. 13:19:31