Фильтрация get_categories() для термина таксономии в WordPress

1 дек. 2010 г., 09:36:30
Просмотры: 18.1K
Голосов: 2

Я хочу показывать категорию только если кастомный пост находится в этой категории И регион = $name для этого поста.

Например, у меня есть кастомный пост (тип "business") с названием "Mamma Mia" в дочерней категории: "pizzerias" (и в родительской категории "food"), и в регионе "Rotterdam" (кастомная таксономия: "region", термин таксономии: "rotterdam").

=> должна отображаться категория "pizzerias" (и родительская категория "food")

Но я не понимаю, как этого добиться. Буду благодарен за помощь с этой задачей.

<?php 

// $filter = array('region'=>$name); 

$categories = get_categories(); 
foreach ($categories as $cat) 
{ 
    if($cat->parent < 1) 
    { 
    $cat_name = $cat->cat_name; 
    $catid = get_cat_ID( $cat_name ); 
    echo $cat_name. '<br/>'; 

    $args=array( 
      'orderby' => 'name', 
      'order' => 'ASC', 
      'child_of' => $catid 
      ); 
    $categories=get_categories($args); 
      foreach($categories as $category) {  
        echo '<a href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "Просмотреть все записи в %s" ), $category->name ) . '" ' . '>' . $category->name.'</a><br/>'; 
        }  

    } 
} 

// print_r($categories);  


?>
3
Комментарии

Итак, вы хотите вывести список терминов категории terms, у которых есть привязанные business, которые также привязаны к определенному region?

Rarst Rarst
6 дек. 2010 г. 15:04:01

@Henk, не могли бы вы пояснить, где именно вы хотите это сделать? На странице отдельной записи? В архиве таксономии? В архиве категории?

TheDeadMedic TheDeadMedic
6 дек. 2010 г. 15:30:44

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

Jan Fabry Jan Fabry
6 дек. 2010 г. 16:47:49
Все ответы на вопрос 8
1

цель - показать список категорий, но только те категории, которые содержат записи с установленной пользовательской таксономией region для Rotterdam

Это реализовано в плагине Query Multiple Taxonomies:

http://plugins.trac.wordpress.org/browser/query-multiple-taxonomies/trunk/core.php?rev=308185#L10

8 дек. 2010 г. 08:20:26
Комментарии

И более конкретно, в его виджете детализированной навигации. Отлично! Теперь это нужно расширить, чтобы показывать также родительские категории: если пост прикреплен к Пиццериям, я также вижу его при просмотре Еды, но Еда не отображается в виджете, если пост не прикреплен к ней явно.

Jan Fabry Jan Fabry
8 дек. 2010 г. 09:27:25
3

Основная идея - сделать запрос для определенного набора записей, собрать все их категории, отфильтровать и привести в нужный вид с помощью функции.

Общий код:

$posts = get_posts(array(
    'tag' => 'linux'
));

$categories = array();

foreach( $posts as $post ) {

    $cats = get_the_category($post->ID);

    foreach($cats as $c)
        $categories[] = $c->term_id;
}

$categories = array_unique($categories);
sort($categories);
$categories = implode(',', $categories);

$result = get_categories(array(
    'include' => $categories
));

Проблемы в том, что, насколько я помню, нормальные запросы для нескольких таксономий появятся только в WordPress 3.1, и этот подход может быть очень ресурсоемким, поэтому потребуется кэширование (вероятно, для каждого региона).

6 дек. 2010 г. 15:22:21
Комментарии

Как параметр include влияет на иерархические результаты? Если есть записи в Пиццерии, но ни одной напрямую прикрепленной к родительской категории Еда, будет ли отображаться Еда? Или записи автоматически прикрепляются и к родительским категориям?

Jan Fabry Jan Fabry
6 дек. 2010 г. 16:24:36

@Jan Fabry проверил, если передать только ID дочерней категории в get_categories(), то родительская категория не извлекается. :( Так что придётся дополнительно пройтись по категориям и получить родителей. Ещё большая путаница.

Rarst Rarst
6 дек. 2010 г. 16:34:06

Думаю, нам стоит рассмотреть вариант пользовательского SQL-запроса, соединяющего несколько таблиц таксономий. И конечно, кэширование.

Jan Fabry Jan Fabry
6 дек. 2010 г. 16:41:17
0

В версии WordPress, которую я использую (3.1.2), если добавить 'taxonomy' => 'taxonomy_term' в массив аргументов, это должно сработать. Вот модифицированная версия вашего исходного кода с включением таксономии в массив. Правда, я не знаю название таксономии, которую вы пытаетесь использовать:

<?php 

// $filter = array('region'=>$name); 

$categories = get_categories(); 
foreach ($categories as $cat) 
{ 
    if($cat->parent < 1) 
    { 
    $cat_name = $cat->cat_name; 
    $catid = get_cat_ID( $cat_name ); 
    echo $cat_name. '<br/>'; 

    $args=array( 
      'taxonomy' => 'taxonomy_term', 
      'orderby' => 'name', 
      'order' => 'ASC', 
      'child_of' => $catid 
      ); 
    $categories=get_categories($args); 
      foreach($categories as $category) {  
        echo '<a href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "Просмотреть все записи в %s" ), $category->name ) . '" ' . '>' . $category->name.'</a><br/>'; 
        }  

    } 
} 

// print_r($categories);  
?>
31 мая 2011 г. 17:50:16
0

Я адаптировал ответ @rarst из вышеприведённого примера для работы с 3 пользовательскими таксономиями. Мне нужно выводить только те термины, которые прикреплены к одному или нескольким записям в цикле.

Вот моя функция, которую я добавил в functions.php:

function dv_setup_sidebar_cats() {
    global $wp_query;

    $designers = array();
    $sizes     = array();
    $colors    = array();

    foreach( $wp_query->posts as $post ) {

        $des   = get_the_terms($post->ID, 'designer');
        $siz   = get_the_terms($post->ID, 'size');
        $col   = get_the_terms($post->ID, 'color');    

        foreach($des as $d) {
            $designers[] = $d->term_id;
        }

        foreach($siz as $s) {
            $sizes[] = $s->term_id;
        }

        foreach($col as $c) {
            $colors[] = $c->term_id;
        }

    }

    if ( !empty($designers) ) {
        $designers = array_unique($designers);
        sort($designers);
        $designers = implode(',', $designers);

        $dresult   = get_categories(array(
            'include'  => $designers,
            'taxonomy' => 'designer'
        ));
    }

    if ( !empty($sizes) ) {
        $sizes = array_unique($sizes);
        sort($sizes);
        $sizes = implode(',', $sizes);

        $sresult   = get_categories(array(
            'include'  => $sizes,
            'taxonomy' => 'size'
        ));
    } 

    if ( !empty($colors) ) {
        $colors = array_unique($colors);
        sort($colors);
        $colors = implode(',', $colors);

        $cresult   = get_categories(array(
            'include'  => $colors,
            'taxonomy' => 'color'
        ));
    }

    $return = array(
        'size'     => $sresult,
        'color'    => $cresult,
        'designer' => $dresult
    );


    return $return;

}

Надеюсь, это поможет кому-то ещё.

-J

10 мая 2012 г. 20:37:20
3

Прошу прощения, если я что-то упустил, но разве не будет так просто:

if (is_object_in_term($post->ID, 'region', 'rotterdam'))
    the_category(); // отображает категории, связанные с текущей записью

В админке вы прикрепляете запись и к 'pizzerias', и к 'food' (отмечая оба чекбокса), или только к 'pizzerias'?

Если последнее, то the_category() по умолчанию не покажет 'Food', поэтому вам придется получать иерархию категорий самостоятельно.

6 дек. 2010 г. 12:52:03
Комментарии

Нет, цель — показать список категорий, но только тех категорий, у которых есть записи, где пользовательская таксономия region установлена в значение Rotterdam. Кстати, этот вопрос также задавался на SO.

Jan Fabry Jan Fabry
6 дек. 2010 г. 13:28:48

Если я правильно понимаю, то это кажется подходящим ответом. Если Mamma Mia — это pizzeria в rotterdam, то по определению там есть пиццерии в Роттердаме, и категория должна отображаться. Иначе я не понимаю, как категория должна быть связана с регионом.

Rarst Rarst
6 дек. 2010 г. 14:11:16

@Rarst: Как я понял вопрос, список категорий должен отображаться не только на странице записи, но, например, на region/rotterdam/: для всех записей, использующих этот термин пользовательской таксономии, нужно получить одно дерево всех категорий, к которым они привязаны. Автор использует get_categories(), который не ограничен категориями текущей записи.

Jan Fabry Jan Fabry
6 дек. 2010 г. 14:48:05
2

Вы можете получить таксономию для пользовательского типа записи с помощью небольшой функции:

    function get_the_taxonomy( $taxonomy, $id = FALSE ) {
        global $post;

        $id = (int) $id;
        if ( !$id )
            $id = (int) $post->ID;

        $categories = get_object_term_cache( $id, $taxonomy );
        if ( FALSE === $categories ) {
            $categories = wp_get_object_terms( $id, $taxonomy );
            wp_cache_add($id, $categories, $taxonomy . '_relationships');
        }

        if ( !empty( $categories ) )
            usort( $categories, '_usort_terms_by_name' );
        else
            $categories = array();

        foreach ( (array) array_keys( $categories ) as $key ) {
            _make_cat_compat( $categories[$key] );
        }

        return $categories;
    }

Также вы можете использовать встроенную функцию WordPress:

$taxonomys = get_the_term_list($id, YOUR_CUSTOM_POST_TYPE, '', ', ', '' );

Или проверить таксономию с помощью is_tax(), см. кодекс для этого условного тега

Возможно, это поможет, если я правильно понял вашу проблему. Извините за мой плохой английский.

7 дек. 2010 г. 00:14:21
Комментарии

Я думаю, Henk Jan хочет получить список категорий, независимо от текущей записи. Просто все категории, у которых есть записи, связанные с пользовательским термином rotterdam.

Jan Fabry Jan Fabry
7 дек. 2010 г. 00:41:47

Спасибо за подсказку; я думаю, можно использовать пользовательский запрос с пользовательским термином. Запись возвращает все термины, и запрос должен использовать все или первый термин, чтобы в цикле вывести все записи для этого термина. Также возможно вернуть все категории для записей в этом запросе.

bueltge bueltge
7 дек. 2010 г. 10:11:19
4

Спасибо всем за помощь — это действительно здорово. Хочу поделиться с вами тем, что у меня получилось. Я знаю, что это не самое умное решение. Недостаток в том, что родительская категория отображается для региона, когда к ней не прикреплены пользовательские записи для этого региона (но есть пользовательские записи для другого региона).

Я использую это на странице региона (архив таксономии).

<?php
$categories = get_categories();
foreach ($categories as $cat)
{
    if($cat->parent < 1)
    {
        $cat_name = $cat->cat_name;                         
        $catid = get_cat_ID( $cat_name );

        echo '<div class="indexcolumn-top">';

        $img = $taxonomy_images_plugin->get_image_html( 'fullsize', $cat->term_taxonomy_id );
        if( !empty( $img ) )
            print $img;
        else 
            echo '<h2>' .$cat_name. '</h2>';

        $input = array();
        $args=array(
          'child_of' => $catid,
          'orderby' => 'name',
          'order' => 'ASC'
          );

        $categories = get_categories($args);
        foreach ($categories as $cat)
        {
            $cat_name = $cat->cat_name;
            $catid = get_cat_ID( $cat_name );

            $args = array(
                'post_status' => 'publish',
                'taxonomy_name' => 'region',
                'taxonomy_term' => $name,
            );
            $custom_posts = get_posts_by_taxonomy($args);
            if ($custom_posts):
                foreach ($custom_posts as $post):
                    setup_postdata($post);
                    $postcategory = get_the_category(); $postcat = $postcategory[0]->cat_name;
                    if ($postcat == $cat_name):
                        $category = get_the_category(); 
                        $input[] = $catid;
                    endif;
                endforeach;
            endif;
        }
        echo '<br/>';
        $output = array_unique($input);
        if (empty($output)):
            echo '<p>Нет компаний</p>';
            echo '</div>';
        else :
            echo '<ul class="port-box">';
            foreach ($output as $output) {
                $cat_name = get_cat_name($output);  
                echo '<li><a href="' . get_category_link($output) . '" title="' . sprintf( __( "Просмотреть все записи в %s" ), $cat_name ) . '" ' . '>' . $cat_name .'</a></li>';                             
            }
            echo '</ul></div>';
        endif;
    }                                                   
}
?>
8 дек. 2010 г. 12:09:53
Комментарии

Я не считаю это эффективным способом: вы выполняете множество запросов, и мне не понятен внутренний цикл по записям: если запись найдена в текущей категории, вы, вероятно, можете просто добавить эту категорию в список без перебора всех записей?

Jan Fabry Jan Fabry
8 дек. 2010 г. 14:58:14

@Jan: Я знаю, что это не самое умное решение. Однако мне не понятно ваше замечание насчёт внутреннего цикла по записям. Вам нужен внутренний цикл, чтобы найти совпадение — или нет. Или можно прервать цикл при нахождении совпадения? Но как тогда это сделать?

Henk Jan Henk Jan
8 дек. 2010 г. 16:32:17

Неважно, я думал, что ваша функция get_posts_by_taxonomy() выбирает записи и по таксономии, и по категории. Тогда вопрос: зачем повторять этот запрос снова и снова, вместо того чтобы выполнить его один раз и повторно использовать результаты? И почему проверяете только первую категорию? Если бизнес находится и в Пиццерии, и в Картошке фри, вернётся только одна из них, так что в итоге можно упустить одну.

Jan Fabry Jan Fabry
8 дек. 2010 г. 16:45:43

@Jan: OK. Я проверяю только первую категорию, потому что мои бизнесы могут быть только в одной категории. Я не понимаю твой первый вопрос. Конструкцию if ($custom_posts): endif; можно убрать. Но тебе нужно будет сделать цикл, чтобы найти совпадение - или нет. Что ты имеешь в виду под повторным использованием?

Henk Jan Henk Jan
8 дек. 2010 г. 17:20:20
0
<?php $cat_id = $_GET["cat"];?>     
      <li id="category-active"><a><?php if ($cat_id){echo get_the_category_by_id($li_id);}else{ echo "Выбранная категория";}?></a></li>            <?php   $subcategories1 = wp_list_categories("title_li&child_of=$cat_id&hide_empty");
                wp_list_categories("title_li=&current_category="); ?>
                    </ul><?php ?>

Спасибо за вашу помощь.

Но я думаю, что здесь не нужен foreach или любой другой цикл, мы можем получить дочерние элементы любой категории, используя этот простой код. Сначала $li_id получает ID текущей категории, затем мы динамически передаем этот ID в child_of=$cat_id, и это показывает дочерние элементы выбранной категории. Я использую это в боковой панели своего сайта.

18 янв. 2011 г. 18:58:37