WP_Query для пользовательской таксономии со всеми терминами?

6 нояб. 2010 г., 00:49:49
Просмотры: 67.1K
Голосов: 12

Есть ли простой способ сделать запрос для получения всех записей, которые отмечены любым термином из определенной таксономии?

Я знаю этот метод:

$custom_taxonomy_query = new WP_Query( 
 array(
  'taxonomy_name' => 'term_slug',
 )
);

Но я хотел бы либо использовать wildcard вместо term_slug, либо просто пустую строку. Тогда это дало бы мне все записи, которые отмечены любым термином в этой таксономии, а не только одним конкретным термином.

Спасибо за помощь, Dave

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

Я столкнулся с похожей ситуацией, Дейв. Этот код отлично сработал для моих целей. Это не самое оптимальное решение в мире, но оно хорошо выполняет свою работу:

// Получаем все ID терминов в указанной таксономии
$taxonomy = 'taxonomy_name';
$taxonomy_terms = get_terms( $taxonomy, array(
    'hide_empty' => 0,
    'fields' => 'ids'
) );

// Используем новый аргумент tax_query в WP_Query (доступен с версии 3.1)
$taxonomy_query = new WP_Query( array(
    'tax_query' => array(
        array(
            'taxonomy' => $taxonomy,
            'field' => 'id',
            'terms' => $taxonomy_terms,
        ),
    ),
) );

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

Кевин

5 дек. 2011 г. 20:02:26
Комментарии

Это было чрезвычайно полезно для меня. Спасибо @kevinlearynet

Tyrun Tyrun
22 окт. 2012 г. 23:26:52

Актуально до сих пор

user1676224 user1676224
18 окт. 2018 г. 18:59:53
1
12

Что-то вроде этого может сработать:

$args = array(
    'post_type' => 'post',
    'tax_query' => array(
        array(
            'taxonomy' => 'your_custom_taxonomy',
            'operator' => 'EXISTS'
        ),
    ),
);
$query = new WP_Query( $args );

По сути, вы запрашиваете любую запись, привязанную к любому термину в вашей пользовательской таксономии.

29 янв. 2016 г. 20:44:00
Комментарии

Я подтверждаю, что это работает.

certainlyakey certainlyakey
3 янв. 2021 г. 20:59:02
10

Привет, @Dave Morris:

Ты прав, WordPress решает, что если у тебя нет термина, он просто проигнорирует твою таксономию.

Есть три (3) основных подхода, которые ты можешь попробовать:

  1. Использовать полный SQL-запрос с $wpdb->get_results(),

  2. Получить список $post->ID для всех записей в твоей таксономии и затем передать их с помощью аргумента 'post__id', или

  3. Добавить SQL, используемый WP_Query, с помощью одного из хуков, который позволяет добавить SQL INNER JOIN, ссылающийся на таблицы таксономий.

Я стараюсь избегать полных SQL-запросов в WordPress до тех пор, пока это действительно необходимо или если просто возвращается список ID. И в этом случае я бы избегал получения списка $post-ID для использования с аргументом 'post__id', потому что это может привести к проблемам с производительностью и даже с памятью, если у тебя много записей. Так что остаётся вариант №3.

Я создал класс для расширения WP_Query под названием PostsByTaxonomy, который использует хук 'posts_join'. Вот он:

class PostsByTaxonomy extends WP_Query {
  var $posts_by_taxonomy;
  var $taxonomy;
  function __construct($args=array()) {
    add_filter('posts_join',array(&$this,'posts_join'),10,2);
    $this->posts_by_taxonomy = true;
    $this->taxonomy = $args['taxonomy'];
    unset($args['taxonomy']);
    parent::query($args);
  }
  function posts_join($join,$query) {
    if (isset($query->posts_by_taxonomy)) {
      global $wpdb;
      $join .=<<<SQL
INNER JOIN {$wpdb->term_relationships} ON {$wpdb->term_relationships}.object_id={$wpdb->posts}.ID
INNER JOIN {$wpdb->term_taxonomy} ON {$wpdb->term_taxonomy}.term_taxonomy_id={$wpdb->term_relationships}.term_taxonomy_id
  AND {$wpdb->term_taxonomy}.taxonomy='{$this->taxonomy}'
SQL;
    }
    return $join;
  }
}

Ты можешь вызвать этот класс, как показано ниже. Аргумент 'taxonomy' обязателен, но ты также можешь передать любые (все?) другие параметры, которые ожидает WP_Query, например 'posts_per_page':

$query = new PostsByTaxonomy(array(
  'taxonomy' => 'category',
  'posts_per_page' => 25,
));
foreach($query->posts as $post) {
  echo " {$post->post_title}\n";
}

Ты можешь скопировать класс PostsByTaxonomy в файл functions.php твоей темы или использовать его в .php файле плагина, который ты, возможно, пишешь.

Если ты хочешь быстро протестировать его, я опубликовал самодостаточную версию кода на Gist, которую ты можешь скачать, скопировать в корень веб-сервера как test.php, изменить под свои нужды и запросить в браузере по URL типа http://example.com/test.php.

ОБНОВЛЕНИЕ

Чтобы исключить sticky posts из записей, включаемых в запрос, попробуй так:

$query = new PostsByTaxonomy(array(
  'taxonomy' => 'category',
  'posts_per_page' => 25,
  'caller_get_posts' => true,
));

Или, если для тебя важно, чтобы класс PostsByTaxonomy никогда не включал sticky posts, ты можешь добавить это в конструктор:

  function __construct($args=array()) {
    add_filter('posts_join',array(&$this,'posts_join'),10,2);
    $this->posts_by_taxonomy = true;
    $this->taxonomy = $args['taxonomy'];
    $args['caller_get_posts'] = true     // Без Sticky Posts
    unset($args['taxonomy']);
    parent::query($args);
  }

ОБНОВЛЕНИЕ 2

После публикации вышеизложенного я узнал, что 'caller_get_posts' будет устаревшим, и в WordPress 3.1 будет использоваться 'ignore_sticky_posts'.

6 нояб. 2010 г. 09:45:53
Комментарии

Майк, спасибо за помощь. По какой-то причине у меня не получается заставить это работать. Запрос возвращает не только записи с терминами из моей пользовательской таксономии. Всегда возвращаются и другие записи. Однако он не возвращает все записи, так что определенно что-то делает... Можно ли использовать функцию $query->have_posts() для итерации? Ни один из методов у меня не работает.

Dave Morris Dave Morris
6 нояб. 2010 г. 15:40:15

А, это интересно. Я нашел в логе mysql запрос, который получает две записи, которые я ожидаю, и он работает. Но почему-то при переборе $query->posts возвращается пять записей. Единственное, что я заметил - сразу после выполнения запроса к пользовательской таксономии выполняется еще один запрос, который выбирает три дополнительные записи по их post_id. И затем, видимо, все пять записей помещаются в один массив результатов.

Dave Morris Dave Morris
6 нояб. 2010 г. 16:07:54

Кажется, я разобрался. Похоже, этот пользовательский запрос включает sticky-записи, даже если они не принадлежат этой пользовательской таксономии. Есть идеи, как правильно учитывать sticky-записи или хотя бы исключить их из этого конкретного запроса? Спасибо, Дейв

Dave Morris Dave Morris
6 нояб. 2010 г. 16:14:12

Ну они же "прилипчивые", верно? :)

Довольно странное поведение, на мой взгляд, но если использовать caller_get_posts=1, они должны исчезнуть:

http://codex.wordpress.org/Function_Reference/query_posts#Sticky_Post_Parameters

Надеюсь, это поможет.

MikeSchinkel MikeSchinkel
6 нояб. 2010 г. 18:54:51

Этот if(isset($query->posts_by_taxonomy)) — отличный трюк для совмещения объектно-ориентированной методологии с хуковой методологией WordPress.

Jan Fabry Jan Fabry
6 нояб. 2010 г. 20:21:08

@Jan Fabry - Да, спасибо! Мне потребовалось всего около 2 лет проб и ошибок, прежде чем до меня это дошло. Конечно, теперь это кажется очевидным... :)

MikeSchinkel MikeSchinkel
7 нояб. 2010 г. 01:06:20

Это сработало! Большое спасибо за помощь. Мне нравится изучать новые трюки в WordPress, особенно связанные с ООП.

Dave Morris Dave Morris
7 нояб. 2010 г. 16:22:30

@Dave Morris - Пожалуйста. Кстати, я только что узнал, что в WP 3.1 это будет называться 'ignore_sticky_posts'.

MikeSchinkel MikeSchinkel
7 нояб. 2010 г. 22:50:02

@MikeSchinkel А что насчёт пагинации? Всё работает хорошо, но пагинация для этого запроса в моём случае не работает должным образом... http://wordpress.stackexchange.com/q/57884/12261

Ajay Patel Ajay Patel
9 июл. 2012 г. 14:09:16

Это отличный приём, и он до сих пор работает! Но что если я хочу включить массив таксономий? 2 или 3 таксономии, что нужно изменить в запросе?

Rounds Rounds
30 окт. 2015 г. 00:06:33
Показать остальные 5 комментариев
6

Вы можете просто указать таксономию и исключить термин..

Например:

<?php
$your_query = new WP_query;
$your_query->query( array( 'taxonomy' => 'your-taxonomy-name' ) );
?>

Это будет практически эквивалентно запросу, который выполняет архив таксономии.

6 нояб. 2010 г. 01:33:32
Комментарии

Это не работает.

Dave Morris Dave Morris
6 нояб. 2010 г. 01:43:21

Строка 1432 в query.php проверяет, пусты ли таксономия ИЛИ термин, поэтому просто не передавать slug не получится... Есть другие идеи?

Dave Morris Dave Morris
6 нояб. 2010 г. 01:50:04

@t31os - Моей первой реакцией было то же самое; я уже не раз попадался на этом, потому что постоянно забываю. Но @Dave Morris прав; если это не пара таксономия/термин, то WP_Query просто игнорирует это.

MikeSchinkel MikeSchinkel
6 нояб. 2010 г. 09:47:17

Вау, я этого не знал, это действительно немного глупо... урок усвоен... :) Я почему-то ожидал, что это будет работать как параметры meta_key / meta_value (не знаю почему)...

t31os t31os
6 нояб. 2010 г. 10:24:58

@t31os - Да, WP_Query, к сожалению, реализован не так элегантно. Это почти 1200 строк жёстко закодированных частных случаев.

MikeSchinkel MikeSchinkel
6 нояб. 2010 г. 19:06:30

"почти 1200 строк жёстко закодированных частных случаев"... это заставило меня посмеяться, пришлось поставить +1 к комментарию... ;)

t31os t31os
6 нояб. 2010 г. 19:19:19
Показать остальные 1 комментариев
0

Оглядываясь назад, я объединил предложения MikeSchinkel и t31os. Можно динамически добавить это в существующие запросы, но для этого требуется WordPress 3.1:

Плагин для получения RSS-ленты записей, содержащих любой термин из таксономии.

5 февр. 2011 г. 18:06:56