Отображение всех записей в произвольном типе записей, сгруппированных по произвольной таксономии

4 нояб. 2011 г., 14:09:32
Просмотры: 64.2K
Голосов: 22

Я работаю над страницей участников, где использую произвольный тип записей с пользовательской таксономией. Мой произвольный тип записи называется member, а пользовательская таксономия - member_groups.

Я хочу вывести список всех участников, но сгруппировать их по соответствующим группам.

Для ясности: у меня есть 35 участников, разделенных на 9 групп – вместо того, чтобы делать один и тот же запрос девять раз, я хочу сделать его единожды, но сгруппировать участников вместе, чтобы Участник1, Участник4 и Участник11 были сгруппированы вместе в одной группе под названием "Маркетинг".

Я использую WP_Query для получения всех записей типа member. Я пробовал различные варианты, но без успешного результата.

Как можно этого достичь?

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

Итак, вы можете рассмотреть возможность автоматизации множественных запросов.

Сначала получите список терминов в вашей пользовательской таксономии, используя get_terms():

<?php
$member_group_terms = get_terms( 'member_group' );
?>

Затем пройдитесь по каждому из них, выполняя новый запрос каждый раз:

<?php
foreach ( $member_group_terms as $member_group_term ) {
    $member_group_query = new WP_Query( array(
        'post_type' => 'member',
        'tax_query' => array(
            array(
                'taxonomy' => 'member_group',
                'field' => 'slug',
                'terms' => array( $member_group_term->slug ),
                'operator' => 'IN'
            )
        )
    ) );
    ?>
    <h2><?php echo $member_group_term->name; ?></h2>
    <ul>
    <?php
    if ( $member_group_query->have_posts() ) : while ( $member_group_query->have_posts() ) : $member_group_query->the_post(); ?>
        <li><?php echo the_title(); ?></li>
    <?php endwhile; endif; ?>
    </ul>
    <?php
    // Сбросим данные для надежности
    $member_group_query = null;
    wp_reset_postdata();
}
?>

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

25 янв. 2012 г. 16:31:55
Комментарии

Да, это работает отлично. Только одна проблема: я хочу выводить произвольные поля вот так <?php get_post_meta($member_group_term->ID, 'job_title', true);?>, но это не сработало. Я также пробовал с $post->ID, но тоже не получилось. Можете помочь, @Chip Bennett, пожалуйста?

Ana DEV Ana DEV
21 дек. 2015 г. 09:53:23

Я понимаю, что прошло уже больше десяти лет, но в этом подходе есть серьёзная проблема — вы создаёте отдельный запрос для каждого элемента таксономии. Когда речь идёт о небольшом количестве элементов, мы не заметим существенного падения производительности. Но как только их количество превысит 20-30, такой цикл серьёзно повлияет на скорость загрузки и время отклика сервера. Я предлагаю сначала получить все записи, а затем отсортировать их с помощью usort. Таким образом, вы не нагружаете базу данных множеством запросов, а получаете результат в два этапа.

maiorano84 maiorano84
26 янв. 2025 г. 21:58:23
3

Я нашел решение, используя пользовательский запрос с последующей группировкой по названию термина:

SELECT * 
FROM wp_term_taxonomy AS cat_term_taxonomy
INNER JOIN wp_terms AS cat_terms ON cat_term_taxonomy.term_id = cat_terms.term_id
INNER JOIN wp_term_relationships AS cat_term_relationships ON cat_term_taxonomy.term_taxonomy_id = cat_term_relationships.term_taxonomy_id
INNER JOIN wp_posts AS cat_posts ON cat_term_relationships.object_id = cat_posts.ID
INNER JOIN wp_postmeta AS meta ON cat_posts.ID = meta.post_id
WHERE cat_posts.post_status =  'publish'
AND meta.meta_key =  'active'
AND meta.meta_value =  'active'
AND cat_posts.post_type =  'member'
AND cat_term_taxonomy.taxonomy =  'member_groups'

Затем с помощью обычного цикла foreach я могу извлечь нужную мне информацию.

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

4 нояб. 2011 г. 14:31:36
Комментарии

Я только что добавил альтернативный метод. Я стараюсь избегать всего, что требует написания сырых SQL-запросов.

Chip Bennett Chip Bennett
25 янв. 2012 г. 16:32:45

Рад видеть, что этот ответ помечен как правильный, даже если запрос перестанет работать в WordPress при изменении схемы базы данных... Концепция сбора всех данных в одном запросе — это правильный ответ. Итерация для группировки таксономий в PHP не будет масштабироваться так же хорошо, как этот подход.

wowo_999 wowo_999
13 нояб. 2013 г. 01:03:29

ОМГ, вы серьезно пишете сырой запрос? Наверное, вы только что попали в мир WP или никогда не заботились о соблюдении его стандартов. Этот ответ не должен быть выбран.

pixelngrain pixelngrain
1 июл. 2020 г. 10:35:13
0

ещё проще:

$terms = get_terms('tax_name');
$posts = array();
foreach ( $terms as $term ) {
    $posts[$term->name] = get_posts(array( 'posts_per_page' => -1, 'post_type' => 'post_type', 'tax_name' => $term->name ));
}

В результирующем массиве $posts каждый таксономический термин является ключом к вложенному массиву, содержащему соответствующие записи.

4 апр. 2012 г. 16:12:29
0

У меня была точно такая же потребность, и решение Chip'а сработало, за исключением одного момента: обязательно нужно указать 'field' => 'slug'.

    foreach ( $service_categories as $category ) {
        $services = new WP_Query( 
            array(
                'post_type'     => 'service',
                'tax_query'     => array(
                    array(
                        'taxonomy'  => 'service_category',
                        'terms'     => array( $category->slug ),
                        'operator'  => 'IN',
                        'get'       => 'all',
                        'field'     => 'slug'
                    )
                )
            ) 
        ); ?>
        <h2><?php echo $category->slug; ?></h2>
        <?php if ( $services->have_posts() ) {  // здесь должен быть цикл ?>

Мне также нужно было, чтобы результат отображался в плоском виде, поэтому здесь установлен параметр 'get' => 'all'.

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

24 янв. 2013 г. 03:38:15
0

Мне пришлось реализовать это в одном из проектов несколько лет назад. Похожий ответ на djb, но с немного большей детализацией. Этот код выведет все названия таксономий как заголовки h3, с маркированным списком каждого заголовка записи, связанного с их страницей.

<?php // Вывод всех названий таксономий с соответствующими элементами
$terms = get_terms('member_groups');
foreach( $terms as $term ):
?>                          
    <h3><?php echo $term->name; // Выводим название термина ?></h3>                          
    <ul>
      <?php                         
          $posts = get_posts(array(
            'post_type' => 'member',
            'taxonomy' => $term->taxonomy,
            'term' => $term->slug,                                  
            'nopaging' => true, // чтобы показать все записи в этой таксономии, можно также использовать 'numberposts' => -1
          ));
          foreach($posts as $post): // начинаем цикл по записям этой таксономии
            setup_postdata($post); // настраиваем данные записи для использования в цикле (позволяет использовать the_title() и др. без указания ID записи)
      ?>        
          <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>    
        <?php endforeach; ?>
    </ul>                                                   
<?php endforeach; ?>
11 февр. 2015 г. 19:55:36
0
$query = new WP_Query( 
   array ( 
      'post_type' => 'member', 
      'orderby'   => 'meta_value', 
      'meta_key'  => 'member_group' 
   ) 
);

Затем при переборе результатов этого запроса вы можете использовать условие if примерно такого вида (псевдокод на PHP):

$groupName = "";
$counter = 0;
if havePosts: while havePosts: thePost

if( $groupName != post->meta_value )
{
if ($counter > 0)
{
</ul>
}
<h1>Имя группы</h1>
<ul>
<li>имя участника</li>
}
else
{
<li>имя участника</li>
}

endwhile;endif

</ul>

Надеюсь, это поможет. Мне кажется, вы слишком усложняли решение этой задачи.

Дополнительная информация: http://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters

5 нояб. 2011 г. 07:01:14
0

Это старая тема, но если кто-то заглянет сюда, как и я, возможно это поможет. Идея в том, чтобы модифицировать основной запрос, чтобы не пришлось лезть в шаблоны и создавать новые запросы и циклы...

P.S.: Еще не тестировалось на больших базах данных. В моем случае сработало удовлетворительно.

function grouped_by_taxonomy_main_query( $query ) {

    if ( $query->is_home() && $query->is_main_query() ) { // Выполняем только на главной странице

        $post_ids = array();

        $terms = get_terms('my_custom_taxonomy');

        foreach ( $terms as $term ) {
            $post_ids = array_merge( $post_ids, get_posts( array( 
                'posts_per_page' => 4, // на ваше усмотрение...
                'post_type' => 'my_custom_post_type', // Если нужно... По умолчанию - записи
                'fields' => 'ids', // нам нужны только ID для использования в 'post__in'
                'tax_query' => array( array( 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id, )))) // получаем записи для текущего элемента таксономии
            );
        }

        $query->query_vars['post_type'] = 'my_custom_post_type'; // Опять же, если нужно... По умолчанию - записи
        $query->query_vars['posts_per_page'] = 16; // Если нужно...
        $query->query_vars['post__in'] = $post_ids; // Фильтруем по ID записей, полученных выше
        $query->query_vars['orderby'] = 'post__in'; // Сохраняем порядок, сгенерированный в цикле по терминам
        $query->query_vars['ignore_sticky_posts'] = 1; // Если не хотите, чтобы sticky-записи меняли порядок

    }
}

// Подключаем нашу функцию к действию pre_get_posts
add_action( 'pre_get_posts', 'grouped_by_taxonomy_main_query' );
22 апр. 2017 г. 09:33:04