Возможно ли сортировать по таксономии используя wp_query?

8 апр. 2011 г., 18:44:50
Просмотры: 91.6K
Голосов: 62

Мой вопрос прост, я использую WP_Query для получения записей пользовательского типа с фильтрацией по таксономии используя tax_query.

Теперь моя проблема в том, что я хотел бы использовать orderby для сортировки по taxonomy, но из документации и поиска в интернете я не могу найти решение.

Параметр orderby в WP_Query позволяет сортировать по множеству полей, даже по пользовательским мета-полям, но похоже не поддерживает сортировку по таксономии.

Есть ли какие-либо указания в правильном направлении?

Спасибо всем.

0
Все ответы на вопрос 13
7
72

Принятый ответ на этот вопрос неприемлем. Логически неверно предполагать, что сортировка по таксономии «не имеет смысла». Данный ответ нелогичен.

Представьте, что у вас есть тип записи «Меню». Затем у вас есть произвольная таксономия «FoodCategories» с терминами «Завтрак», «Обед» и «Ужин». Если вы выполните запрос с использованием параметра tax_query, вы получите набор результатов со всеми терминами, однако они будут упорядочены по дате публикации.

Чтобы получить правильный порядок относительно их терминов и затем корректно отобразить на фронтенде, разделив записи по различным категориям, вам придется перебирать набор результатов, затем запрашивать каждую отдельную запись в наборе, чтобы найти её термины, сравнить с текущим термином, отфильтровать в массив и продолжить процесс. После этого вам снова придется перебирать новый массив для отображения. Это непродуктивно.

Было бы удобно, если бы в WordPress была опция orderby "tax__in", как есть "post__in". Но поскольку её нет, вам придется либо выполнять описанный выше громоздкий процесс, либо настраивать запрос вручную с помощью фильтров 'posts_orderby' и 'posts_join', чтобы изменить метод сортировки и добавить термины в набор результатов соответственно. Либо делать отдельный запрос для каждого термина в соответствующих разделах HTML.

Наиболее эффективным было бы изменение строки запроса через фильтры. Самый простой вариант — выполнить три отдельных запроса. API WordPress должен поддерживать сортировку по таксономии или любым другим ограничивающим параметрам запроса. Если вы ограничиваете запрос определенными условиями, высока вероятность, что многим потребуется сортировка по этим же условиям.

28 июл. 2014 г. 14:36:51
Комментарии

Извините, но вы ошибаетесь. Сортировка по таксономии в вашем случае тоже не имеет смысла. Что вы хотите показать? Сначала все завтраки, затем все ужины, потом все обеды? Вы должны выбрать то, что вам нужно, и порядок, в котором это должно быть, но таксономия — это просто метка группировки. Это не значимые "данные", по которым следует сортировать. Если это значимые данные, то это не должно быть термином таксономии, а должно быть мета-полем записи.

Otto Otto
20 окт. 2014 г. 14:57:21

Да ладно, конечно, бывают случаи, когда нужно сортировать записи по терминам таксономии. Другой пример — тип записи "Фильм" с таксономией "Рейтинг". В списке фильмов легко представить, что люди захотят сортировать фильмы по рейтингу, чтобы все фильмы с рейтингом G, затем PG и т.д. были в начале. (В этом и примере с приемами пищи можно сортировать по term_id вместо имени.) Есть большая серая зона случаев, где таксономия подходит лучше, чем мета-поля, но при этом было бы полезно, чтобы таксономия поддерживала сортировку.

SeventhSteel SeventhSteel
10 мар. 2015 г. 22:51:49

Рейтинги PG, G и подобные — хороший выбор для таксономии, за исключением того, что это данные о конкретных фильмах. Следовательно, это мета-данные. Это данные, а не категории. Просто ограниченное количество вариантов не делает что-то таксономией. Если нужна сортировка, то либо сделайте это мета-полем, либо принудительно сортируйте через специфичный для таксономии код. Кстати, NC17 идет после PG. Так что вам все равно понадобится код для такой сортировки.

Otto Otto
10 нояб. 2015 г. 03:05:34

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

Dennis Puzak Dennis Puzak
23 окт. 2018 г. 13:39:32

Ещё один сценарий использования: у клиента есть множество статей, каждая из которых относится к определённой категории. Клиент хочет иметь страницу со списком всех статей, которые можно сортировать по алфавиту, дате или категории. Категории также можно фильтровать, но список всех статей, отсортированных по категориям в алфавитном порядке, — это не такая уж редкая задача, и она встречается довольно часто.

W Biggs W Biggs
6 июн. 2019 г. 19:06:27

Ещё один пример из нашей практики: у нас есть множество "клиентов" в пользовательском типе записи, а таксономия "регион" позволяет указать, где каждый клиент ведёт свой бизнес. Нас попросили добавить функционал, чтобы при просмотре списка клиентов посетители видели их, отсортированных по региону, с клиентами поблизости в начале списка.

Matt Keys Matt Keys
2 окт. 2020 г. 22:21:23

Отто прав в том, что если вы пытаетесь это сделать, вам нужно внимательно изучить структуру ваших данных; в девяти случаях из десяти она окажется неправильной. ОДНАКО упорно настаивать на догматичном "все остальные не правы" просто неразумно. Вот мой пример использования: Фамилии должны сортироваться по первой заглавной букве; de Courcy идет под C, а De Haan - под D. Легко создать пользовательскую таксономию 'alphabet' с помощью регулярных выражений, которая сортирует эти случаи правильно; однако теперь для простого вывода всех моих людей с помощью запроса (через 'meta_key' => 'alphabet') это невозможно. Мне приходится дублировать свой код и определять собственный фильтр 'orderby' => 'quasi_alphabetic_by_title'.

user3445853 user3445853
20 янв. 2023 г. 14:24:43
Показать остальные 2 комментариев
6
19

Да, но это довольно сложно...

Добавьте в functions.php вашей темы:

function orderby_tax_clauses( $clauses, $wp_query ) {
    global $wpdb;
    $taxonomies = get_taxonomies();
    foreach ($taxonomies as $taxonomy) {
        if ( isset( $wp_query->query['orderby'] ) && $taxonomy == $wp_query->query['orderby'] ) {
            $clauses['join'] .=<<<SQL
LEFT OUTER JOIN {$wpdb->term_relationships} ON {$wpdb->posts}.ID={$wpdb->term_relationships}.object_id
LEFT OUTER JOIN {$wpdb->term_taxonomy} USING (term_taxonomy_id)
LEFT OUTER JOIN {$wpdb->terms} USING (term_id)
SQL;
            $clauses['where'] .= " AND (taxonomy = '{$taxonomy}' OR taxonomy IS NULL)";
            $clauses['groupby'] = "object_id";
            $clauses['orderby'] = "GROUP_CONCAT({$wpdb->terms}.name ORDER BY name ASC) ";
            $clauses['orderby'] .= ( 'ASC' == strtoupper( $wp_query->get('order') ) ) ? 'ASC' : 'DESC';
        }
    }
    return $clauses;
}

    add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );

Этот код собран из найденных решений и моих собственных наработок. Объяснить его довольно сложно, но суть в том, что после его добавления вы можете использовать параметры ?orderby=(название таксономии)&order=ASC (или DESC) и все заработает как надо!

8 апр. 2011 г. 19:36:19
Комментарии

Спасибо, Дрю, я попробую запустить этот SQL, нужно немного подредактировать, но, возможно, сработает. Единственная моя проблема сейчас — я, возможно, двигаюсь в неправильном направлении, как отметил Отто. Спасибо, Дрю. EDIT — Не нужно редактировать, я вижу, где нужна корректировка :) Спасибо

yeope yeope
8 апр. 2011 г. 19:45:12

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

Drew Gourley Drew Gourley
8 апр. 2011 г. 19:48:14

Ещё раз спасибо. На всякий случай я попробовал ваше решение, и оно вроде работает. Также, если кто-то ещё захочет его использовать, нужно заменить add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 ); на add_filter('posts_clauses', 'todo_tax_clauses', 10, 2 );. Спасибо :)

yeope yeope
9 апр. 2011 г. 01:29:02

Да, теперь это исправлено в блоке кода. Я взял это из проекта, над которым работаю, и забыл изменить название функции, хотя изменил его в хуке.

Drew Gourley Drew Gourley
9 апр. 2011 г. 09:39:39

Вы знаете, можно ли отсортировать таксономии по ID вместо имени? Я пытаюсь получить тот же результат, упорядочивая группы таксономий по ID.

Javier Villanueva Javier Villanueva
17 июл. 2013 г. 01:43:36

Я обернул это в if (is_admin) {}, чтобы избежать доступности в других местах...

stephendwolff stephendwolff
25 мар. 2022 г. 17:56:09
Показать остальные 1 комментариев
14
16

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

Таксономии — это способ группировки объектов. Основная идея использования таксономии для записей заключается в том, чтобы термины в этой таксономии были общими для нескольких записей. Если бы каждый термин таксономии использовался только для одной записи, это сделало бы таксономию бессмысленной. А если термины действительно являются общими (как и должно быть), то сортировка по ним не даст ничего полезного.

В такой ситуации следует использовать метаданные записей (post meta). По ним можно сортировать, и они уникальны для каждой записи.

Примечание: Хотя технически можно сортировать по таксономии с помощью пользовательского SQL-запроса, используя фильтр, стандартный WP_Query этого не поддерживает: http://scribu.net/wordpress/sortable-taxonomy-columns.html

Однако, если вам приходится прибегать к таким методам, это говорит о проблемах в структуре данных. Термины таксономии не являются "данными" в прямом смысле. Они не несут самостоятельного значения — это просто метки для определенных групп. Если вы используете их как значимые данные, это указывает на ошибку в проектировании.

Таксономии группируют объекты, назначая им термины. В этом и заключается их суть — термины лишь обозначают группы. Если у вас есть значимые метаданные для записей, следует использовать post meta. По ним действительно можно сортировать, поскольку post meta хранит информацию в виде пар "ключ-значение". В таксономиях же по сути хранятся только ключи, а значениями являются группы записей, связанных этим термином.

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

8 апр. 2011 г. 19:20:29
Комментарии

Привет, Отто, спасибо за ответ. Я понимаю твою точку зрения, и, возможно, я иду неверным путем в этом вопросе. В моем примере сайта с сериалами у меня есть таксономии для сезона 1, сезона 2, сезона 3 и т.д. Таким образом я могу группировать все различные сериалы по номеру сезона. Затем у меня аналогично для эпизодов: Эпизод 01, Эпизод 02 и т.д. Мне бы хотелось, чтобы при отображении списка всех эпизодов они сортировались сначала по эпизоду, затем по сезону. Я проанализирую post meta и пользовательские поля. Спасибо, Отто.

yeope yeope
8 апр. 2011 г. 19:35:58

@yeope твоя таксономия должна называться "сезоны", а терминами должны быть "сезон 1", "сезон 2" и т.д. Что касается эпизодов, я предполагаю, что в сезоне содержится несколько эпизодов, поэтому можно использовать ту же таксономию "сезоны", и если они иерархические, то "эпизод 1", "эпизод 2" и т.д. будут иметь родительский термин "сезон x". Тогда ты сможешь запросить весь сезон по порядку с эпизодами, расположенными в правильном месте.

Chris_O Chris_O
8 апр. 2011 г. 22:17:02

@Chris_O Понятно, возможно, ты прав! Единственная проблема, которую я вижу, это необходимость повторять термины "Эпизод 1", "Эпизод 2" для каждого сезона. А также невозможность группировать все эпизоды 1 независимо от сезона, но думаю, что наверняка есть способ обойти это. Спасибо, Chris_O.

yeope yeope
9 апр. 2011 г. 01:26:19

Использование таксономии для эпизодов на самом деле не имеет особого смысла, потому что группировка бесполезна. Подумайте: если у вас есть термин "эпизод 1", то вы группируете эпизод 1 со всеми другими первыми эпизодами из всех других сериалов. Номера эпизодов и сезонов больше подходят в качестве post_meta, потому что они относятся к конкретному шоу и бесполезны для группировки. Название ТВ-шоу было бы полезно как термин в таксономии tv-show, потому что тогда вы группируете всё шоу целиком.

Otto Otto
15 апр. 2011 г. 22:28:37

Но таксономия для сезонов вроде как работает, но только потому, что она группирует серии в сезоне или что-то подобное, хотя вам всё равно придётся запрашивать её вместе с таксономией tv-show. В такой таксономии сезонов вашими терминами будут 1, 2, 3, представляющие номер сезона шоу. Но всё равно эту информацию лучше хранить в postmeta, так как вам нужно по ней сортировать. А поскольку вы можете делать запросы и по postmeta, нет особого смысла дублировать это в таксономии.

Otto Otto
15 апр. 2011 г. 22:31:30

@Otto, в итоге я использовал произвольные поля :) Это было логичнее.

yeope yeope
4 мая 2011 г. 21:01:59

Затем Otto опубликовал интересный пост в блоге: Когда (не) следует использовать пользовательскую таксономию.

Jan Fabry Jan Fabry
5 мая 2011 г. 09:55:59

@otto Спасибо, что поделились этим, очень полезно глубже разобраться в таксономиях и их применении. Меня особенно интересует ваше мнение о ситуации, описанной в посте Сортируемые колонки таксономий. Какое решение было бы оптимальным, если я хочу иметь возможность запрашивать все записи в диапазоне цветов, но также сортировать по цвету? Возможно, это стоило бы оформить отдельным вопросом...

Gaffen Gaffen
20 дек. 2013 г. 22:54:54

Если вам нужно сортировать по этому параметру, то это скорее должно быть мета-полем, а не таксономией. Сортировка по таксономии, если разобраться, не имеет особого смысла.

Otto Otto
21 дек. 2013 г. 09:42:43

Спасибо, @Otto. Хотя я не согласен с вашим утверждением: "Однако, если вам приходится прибегать к подобным вещам, значит ваша структура данных изначально неправильна"... Было бы полезно иметь возможность сортировать список записей по терминам таксономии в админке...

ClemC ClemC
23 мая 2017 г. 16:14:47

@ClemC Это не имеет особого смысла. Записи могут принадлежать к нескольким категориям. По чему именно вы сортируете? Каковы ваши вторичные критерии сортировки, когда две записи относятся к одной категории? Это именно те проблемы, с которыми вы столкнётесь — таксономии это просто группировки, "термин" это просто внешнее представление этой группировки, не самая важная часть. Важна сама группа. Вы же не сортируете названия животных по алфавиту в соответствии с их таксономией Линнея. Это не даст вам никакой пользы.

Otto Otto
25 мая 2017 г. 00:37:37

Привет, @Otto, вы правы. Я исходил из специфики моего текущего проекта... Это CPT (фильмы) с возможностью выбора только одного термина пользовательской таксономии (фестиваль) через радиокнопки. Сортировка списка CPT по умолчанию идёт по термину (фестиваль), что в данном конкретном случае вполне логично, не так ли? Я не могу придумать лучшего подхода к "структуре данных"... Я реализовал "фестивали" как таксономию, потому что им нужны только описания, и они логически группируют "фильмы". P.S.: Извините за мой английский.

ClemC ClemC
25 мая 2017 г. 11:10:46

Да, справедливо, но тогда это группа. Вы объединяете элементы. Что тогда означает "сортировать по" в таком контексте? Если у вас есть набор элементов в одной группе, то вы можете "выбирать по" этой группе, и это имеет смысл, но "сортировка" — это совсем другое. Вы сортируете по полям с разными значениями, а не по полям, где все значения одинаковые.

Otto Otto
25 мая 2017 г. 11:36:37

Извините @Otto, я только сейчас заметил ваш ответ... Я полностью согласен с вашими семантическими замечаниями и логикой. Но в моём контексте "сортировка по" была бы в основном вопросом эргономики. Визуальное группирование проекций по "фестивалю" может существенно помочь пользователю получить визуальное представление на основе наиболее важного для него фактора, с первого взгляда. Поэтому не уверен, что смогу достичь этого как-то иначе, кроме как через "сортировку", хотя согласен, что этот термин не совсем подходит...

ClemC ClemC
19 авг. 2017 г. 22:26:55
Показать остальные 9 комментариев
5
13

Я немного опоздал к обсуждению, но есть более простой и "в духе WordPress" способ сделать это.

Создайте свой tax_query как обычно

$tax_query = array();
$tax_query['relation']="OR";
$tax_query[] = array(
    'taxonomy' => 'product_cat',
    'field'    => 'slug',
    'terms'    => $cat_terms,
);
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;

Настройте аргументы для query_posts или WP_Query

$args = array(
    'post_type'=>'post',
    'posts_per_page'=>12,
    'paged'=>$paged,
    'tax_query' => $tax_query,
);

Перед вызовом query_posts / WP_Query подключите фильтр orderby и переопределите его

add_filter('posts_orderby', 'edit_posts_orderby');
function edit_posts_orderby($orderby_statement) {
    $orderby_statement = " term_taxonomy_id ASC ";
    return $orderby_statement;
}
query_posts($args);
remove_filter('posts_orderby', 'edit_posts_orderby');

Не забудьте удалить фильтр после использования...

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

31 окт. 2014 г. 15:48:14
Комментарии

Есть идеи, как сортировать по имени вместо term_taxonomy_id? Замена term_taxonomy_id в orderby_statement вызывает ошибки

tehlivi tehlivi
5 окт. 2016 г. 00:52:51

Это правильный ответ для всех, кому это интересно!

Mayra M Mayra M
21 июн. 2018 г. 13:43:17

@tehlivi этот метод не работает для сортировки по имени, потому что имя находится в таблице wp_terms. WordPress, кажется, кэширует термины таксономии, поэтому, даже если ваш tax query ищет по слагу или имени (которые также находятся в таблице wp_terms), WordPress пропускает их через кэшированный список и заменяет на ID, хранящиеся в term_relationships.term_taxonomy_id, чтобы не нужно было запрашивать таблицу wp_terms в основном запросе. Это означает, что ни имя, ни слаг не включаются в итоговый SQL-запрос. Вам нужно добавить джойны.

Ethan C Ethan C
25 окт. 2021 г. 23:34:35

@EthanC Привет, чувак, спасибо за развернутый ответ. Надеюсь, если кто-то найдет это в будущем, твой ответ окажется полезным. Лично мне уже сложно вспомнить что-то из 2016 года. Кажется, я в итоге пропускал массив через функцию сортировки после выполнения запроса. Уверен, что разработчик, который взял этот проект после моего ухода из компании, теперь меня ненавидит. Ха.

tehlivi tehlivi
27 окт. 2021 г. 00:17:06

@tehlivi Да, в итоге я полностью проигнорировал основной запрос на случай, если некоторым записям было назначено больше одного термина. Вместо этого использовал get_terms() и затем get_posts для каждого термина. Добавило ~15 запросов к странице, но дизайнер получил нужный ему результат.

Ethan C Ethan C
28 окт. 2021 г. 02:03:53
4

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

   <?php // По умолчанию
    $wheels_args = array(
        'post_type' => 'wheels', // Тип записи
        'posts_per_page' => '96', // Количество записей на страницу
        'orderby' => 'taxonomy, name', // Просто укажите 2 параметра здесь, разделенные запятой
        'order'=>'ASC' // Сортировка по возрастанию
    );
    $loop = new WP_Query($wheels_args); // Создаем новый запрос
    ?>

Это позволит сначала отсортировать таксономии вашего пользовательского типа записи (CPT) по таксономиям в алфавитном порядке, а внутри этих групп таксономий - также по алфавитному порядку.

6 июл. 2017 г. 15:26:34
Комментарии

@yeope Почему это принятый ответ!? слава богу, что я пролистал дальше

Juan Solano Juan Solano
22 окт. 2019 г. 02:17:52

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

honk31 honk31
9 апр. 2020 г. 20:15:41

Не парсится, особенно с этой запятой, и игнорируется WP (6.x).

Picard Picard
2 сент. 2022 г. 17:05:44

Это сработало у меня на WP 6.5.4. Вам нужно изменить значение после запятой, например, если ваша таксономия — post_tag, вы должны написать буквально 'orderby' => 'taxonomy, post_tag',.

Tomas Mulder Tomas Mulder
24 июн. 2024 г. 19:21:12
1

Хочу поделиться своим опытом сортировки пользовательских типов записей по категориям/таксономиям.

ВЕБ-САЙТ

  1. Сайт туристического агентства на WordPress
  2. Основной контент в пользовательском типе записей 'ruta'
  3. Таксономия со следующей структурой: Тип-путешествия > континент > страна

ЗАДАЧА

На страницах архивов категорий клиент хотел сортировать записи по:

  1. Континентам — упорядоченным по количеству маршрутов в каждом
  2. Странам — в алфавитном порядке

ШАГИ

Первый шаг: Я получил исходный запрос архива без изменений, который выглядел так:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID 
FROM wp_posts 
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) 
WHERE 1=1 
AND ( wp_term_relationships.term_taxonomy_id IN (5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,25,26,28,29,31,32,33,35,38,95,101,102,193) )
AND wp_posts.post_type IN ('ruta', 'nav_menu_item') 
AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 45 
AND wp_posts.post_status = 'private') 
GROUP BY wp_posts.ID 
ORDER BY wp_posts.post_date DESC LIMIT 0, 20

Второй шаг: Я модифицировал SQL-запрос в Sequel Pro под свои нужды. Получилось следующее (возможно его можно улучшить — мои знания MySQL не идеальны):

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID, tt1.parent AS pare,
    (
    SELECT COUNT(*) 
    FROM  wp_posts
    INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
    INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
    INNER JOIN wp_term_taxonomy AS tt2 ON ( tt2.term_taxonomy_id = tt1.term_taxonomy_id )
    WHERE 1=1  
    AND tt1.parent = pare
    ) AS Total
FROM  wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
INNER JOIN wp_terms ON ( tt1.term_id = wp_terms.term_id )
WHERE 1=1  
AND ( wp_term_relationships.term_taxonomy_id IN (5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,25,26,28,29,31,32,33,35,38,95,101,102,193) ) 
AND wp_posts.post_type IN ('ruta', 'nav_menu_item') 
AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 45 
AND wp_posts.post_status = 'private') 
GROUP BY wp_posts.ID 
ORDER BY
total DESC,
wp_terms.name

Третий шаг: Я подключил запрос в файл functions.php через три фильтра: posts_fields, posts_join и posts_orderby

Код в functions.php:

function xc_query_fields( $fields ) {
   $fields = "wp_posts.ID, wp_posts.post_title, wp_terms.name, tt1.parent AS pare,
    (
    SELECT COUNT(*) 
    FROM  wp_posts
    INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
    INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
    INNER JOIN wp_term_taxonomy AS tt2 ON ( tt2.term_taxonomy_id = tt1.term_taxonomy_id )
    WHERE 1=1  
    AND tt1.parent = pare
    )
    AS Total";
     return $fields;
}

function xc_query_joins( $join ) {
$join .= "INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
   INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
   INNER JOIN wp_terms ON ( tt1.term_id = wp_terms.term_id )";
 return $join;
}

function xc_query_orderby( $join ) {
    $join = "total DESC, wp_terms.name ";
    return $join;
}

Итог: Я активировал фильтры через хук pre_get_post с определенными условиями

function filtra_queries( $query ) {
  if ( is_archive() && $query->is_main_query() && !is_admin() ) {
    $rutes = array('viajes-privados', 'asia', 'africa', 'oceania', 'america', 'oriente-proximo');
    if ( in_array( $query->get('category_name'), $rutes ) ) {
      add_filter( 'posts_fields', 'xc_query_fields' );
      add_filter( 'posts_join', 'xc_query_joins' );
      add_filter( 'posts_orderby', 'xc_query_orderby' );
    }
  }
}
add_filter('pre_get_posts', 'filtra_queries');

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

4 янв. 2015 г. 17:09:00
Комментарии

Хорошая работа, нелепо, что потребовалось такое количество кода для сортировки по таксономии. Огромная проблема в WP.

serraosays serraosays
21 июл. 2017 г. 02:27:03
0

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

ПРОБЛЕМЫ:

1) WordPress не позволяет упорядочивать таксономии каким-либо разумным способом.

2) WordPress просто не позволяет использовать таксономии в параметре orderby для WP_Query (как точно подметил Otto).

РЕШЕНИЯ:

1) Сортировка таксономий лучше всего реализуется с помощью плагина Custom Taxonomy Order NE на данный момент. Он позволяет упорядочивать таксономию через WYSIWYG в wp-admin, что не совсем мой предпочтительный метод, но я не нашел ничего лучше.

Когда вы настроите плагин, у вас будет что-то похожее на то, что сделал я. Обратите внимание на опцию Auto-sort Queries of this Taxonomy — установите ее в значение Custom Order as Defined Above; это даст вам нужное упорядочивание. Скриншот:

Интерфейс плагина Custom Taxonomy Order NE

2) С отсортированной таксономией вы можете создать серию вызовов WP_Query, которые перебирают каждый термин, эффективно создавая архив, упорядоченный по таксономии. Используйте get_terms() для создания массива всех терминов таксономии, затем пройдитесь по каждому термину с помощью foreach. Это создает WP_Query для каждого термина, который возвращает все записи для данного термина, формируя архив, упорядоченный по таксономии. Код для реализации:

  // Получаем термины и помещаем их в массив
  $issue_terms = get_terms([
    'taxonomy' => 'issues',
    'hide_empty' => false,
  ]);

  // Проходим по каждому термину для настройки запроса и вывода записей
  foreach ($issue_terms as $issue_term) {
    $the_query = new WP_Query( array(
      'post_type' => 'post',
      'tax_query' => array(
        array(
          'taxonomy' => 'issues',
          'field' => 'slug',
          'terms' => array( $issue_term->slug ),
          'operator' => 'IN'
        )
      )
    ) );

    // Запускаем цикл для каждого запроса
    while($the_query->have_posts()) :
      $the_query->the_post();

      // ВАШ ШАБЛОН ВЫВОДА ДЛЯ КАЖДОЙ ЗАПИСИ

    endwhile;
  }

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

10 апр. 2017 г. 17:45:43
0

Вот решение, которое я использовал для этой конкретной проблемы. Это решение предназначено для крайних случаев, когда невозможно использовать фильтр pre_get_posts и уже существует пагинация в запросе (например, в WooCommerce):

global $wpdb;

$taxonomies = array('my-tax-1', 'my-tax-2', 'my-tax-3');

$orderby = "'".implode("', '", array_keys($taxonomies))."'";
$id_sql = $GLOBALS['wp_query']->request;

$id_sql = preg_replace('/LIMIT\s+\d+\s?,?\s\d*/', '', $id_sql);
$id_sql = str_replace('SQL_CALC_FOUND_ROWS', '', $id_sql);

$term_sql = "SELECT
  tt.taxonomy AS `taxonomy`,
  t.name AS `term_name`,
  t.slug AS `term_slug`,
  count(*) AS `term_count`
FROM ({$id_sql}) p 
JOIN wp_term_relationships tr
  ON p.ID = tr.object_id
JOIN wp_term_taxonomy tt
  ON tr.term_taxonomy_id = tt.term_taxonomy_id
JOIN wp_terms t
  ON tt.term_id = t.term_id
WHERE tt.taxonomy IN ({$orderby})
GROUP BY t.slug
ORDER BY
  FIELD(tt.taxonomy, {$orderby})"; // Добавьте здесь дополнительную специфическую сортировку

$results = $wpdb->get_results($term_sql, ARRAY_A);

Я использовал это для создания навигационного меню, упорядоченного по таксономии, термину и количеству записей на термин.

Если вам просто нужны записи, измените запрос на SELECT p.* и GROUP BY p.ID

24 мар. 2017 г. 18:48:47
3

Мне нравится сортировать свои термины вручную, поэтому я использую для этого плагин. И я большой поклонник фильтра pre_get_posts, поэтому я взял рабочий пример от Drew Gourley и адаптировал его для работы с этим фильтром. Это несколько особый случай, но я всё равно публикую это, вдруг кому-то пригодится. Следующий код нужно добавить в functions.php или в собственный плагин.

Сначала начнём с фильтра. Мы сортируем пользовательский тип записей music по пользовательской таксономии style:

function so14306_pre_get_posts($query)
{
    if (is_admin()) :
        return;
    endif;

    if ($query->is_main_query()) :
        if (is_post_type_archive('music')) :
            $query->set('orderby', 'style');

        endif;
    endif;
}

add_action('pre_get_posts', 'so14306_pre_get_posts');

Затем мы вызываем фильтр post_clauses:

function so14306_posts_clauses($clauses, $wp_query)
{
    global $wpdb;

    if (isset($wp_query->query_vars['orderby']) && $wp_query->query_vars['orderby'] === 'style') {
        $orderby = $wp_query->query_vars['orderby'];
        $clauses['join'] .= <<<SQL
LEFT OUTER JOIN {$wpdb->term_relationships} ON {$wpdb->posts}.ID={$wpdb->term_relationships}.object_id
LEFT OUTER JOIN {$wpdb->term_taxonomy} USING (term_taxonomy_id)
LEFT OUTER JOIN {$wpdb->terms} USING (term_id)
SQL;
        $clauses['where'] .= " AND (taxonomy = '{$orderby}' OR taxonomy IS NULL)";
        $clauses['groupby'] = "object_id";
        $clauses['orderby'] = "GROUP_CONCAT({$wpdb->terms}.term_order ORDER BY {$wpdb->terms}.term_order ASC) ASC";
        $clauses['orderby'] .= ", {$wpdb->posts}.post_name ASC";
    }

    return $clauses;
}

add_filter('posts_clauses', 'so14306_posts_clauses', 10, 2);

Теперь всё, что вам нужно сделать — это сортировать ваши таксономии с помощью следующего плагина: Simple Custom Post Order. Этот плагин обязателен для данного решения, так как он добавляет в базу данных столбец term_order!

А эта строка: $clauses['orderby'] .= ", {$wpdb->posts}.post_name ASC" сортирует записи по заголовку, поэтому полная сортировка в данном решении выглядит так: термин таксономии => заголовок записи.

9 апр. 2020 г. 19:33:04
Комментарии

Большое спасибо, это очень полезно. Отлично иметь возможность визуально упорядочивать. Вы не знаете, зачем нужна часть "OR taxonomy IS NULL"? Кажется, что это что-то лишнее.

Jordan Carter Jordan Carter
6 окт. 2021 г. 22:14:27

Первый термин отображается правильно, но после этих записей следующий термин не следует логически порядку меню, заданному через SCP Order. Возможно, это потому что я пытаюсь сделать это с товарами, а WooCommerce уже имеет порядок атрибутов...может быть, они конфликтуют. Хотя в базе данных ID в столбце term_order правильные...

Jordan Carter Jordan Carter
6 окт. 2021 г. 22:32:44

Изменение строки GROUP_CONCAT orderby на следующее, кажется, помогает: $clauses['orderby'] = "{$wpdb->terms}.term_order ASC";

Jordan Carter Jordan Carter
6 окт. 2021 г. 22:44:09
1

Довольно простой способ сделать это — добавить функцию, которая выполняет следующие действия:

  1. Когда ваша запись публикуется...
  2. Получить ID/слаг/и т.д. вашей категории...
  3. Сохранить его как пользовательское мета-значение для вашей записи

Затем, в вашем цикле, отсортировать записи по этому мета-значению.

Итак:

// 1
add_action( 'publish_post', 'save_and_add_meta' );

function save_and_add_meta($post_id){

        //Временно удаляем действие, чтобы избежать бесконечного цикла
        remove_action( 'publish_post', 'save_and_add_meta' );

        // 2            
        $category_slug = get_the_terms($post_id, 'your_taxonomys_name')[0]->slug;

        //3
        add_post_meta($post_id, 'cat_slug', $category_slug);

        //Добавляем действие обратно
        add_action( 'publish_post', 'save_and_add_meta' );
}

Затем в вашем WP-запросе добавьте в аргументы $args:

'meta_key' => 'cat_slug',
'orderby' => 'meta_value',
'order' => 'DESC',

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

11 сент. 2020 г. 18:56:41
Комментарии

Я тоже так думаю, хотя это дублирует данные.

Sisir Sisir
22 сент. 2021 г. 23:18:54
1

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

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; // Если вы не хотите, чтобы избранные записи меняли порядок

    }
}

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

Это не сработает, вы не можете использовать get_posts или WP_Query внутри pre_get_posts, это создаст бесконечный цикл. Потому что при использовании get_posts или WP_Query срабатывает хук pre_get_posts, что приводит к бесконечному циклу. Даже если вы проверите is_main_query, это не остановит выполнение и цикл будет продолжаться бесконечно.

Den Pat Den Pat
23 мар. 2022 г. 12:31:21
0

Некоторые ответы довольно сложные, я написал это решение, которое довольно просто для понимания (надеюсь):

$args = array( 'post_type' => 'Teammember','posts_per_page' =>  -1);
$loop = new WP_Query($args);
if ( $loop->have_posts() ) {
     while ( $loop->have_posts() ) {
         $loop->the_post();
         $id = get_the_id();
         $name = get_the_terms( get_the_ID(), 'teammember-category' );
         $sort[$id] = $name[0]->name;
    }
}
wp_reset_postdata();
asort($sort);
$result = array_keys($sort);

Теперь переменная $result содержит все ID записей, отсортированные по возрастанию имени пользовательской таксономии. Внимание: если запись содержит несколько категорий, потребуется другое решение.

Вы можете использовать ID в функции foreach, например так:

foreach($result as $id){
$image = get_the_post_thumbnail($id);
...и т.д.
} 

Или можно сделать второй запрос, вот так:

$loopnew = new WP_Query(array('post_type' => 'Teammember','post__in'=> $result));
if ( $loopnew->have_posts() ) {
     while ( $loopnew->have_posts() ) {
         $loopnew->the_post();
         ...и т.д.
     }
 }
15 февр. 2023 г. 19:45:56
0
-1

Довольно раздражает, что WordPress не позволяет сделать это и заставляет вас по сути иметь два поля с одинаковой информацией...

НО я опубликую здесь своё решение. Идея заключается в передаче всех выбранных терминов таксономий в мета-данные записи.

(Будьте осторожны, вам нужно доработать код, если ваша таксономия допускает множественные значения)

// Добавляем этот хук для автоматического сохранения терминов как мета-данных записи при сохранении поста
add_action('save_post', 'add_custom_taxonomies_as_post_meta', 10, 1);
function add_custom_taxonomies_as_post_meta($id)
{
  $current_post = get_post($id);
  $taxonomies  = get_object_taxonomies($current_post);
  foreach ($taxonomies as $tax) {
    $post_terms = get_the_terms($id, $tax);
    $term = $post_terms[0];
    add_post_meta($id, $tax,  $term->name, true);
  }
}

После добавления этого кода в ваш functions.php вы можете использовать meta_key и orderby как обычно для сортировки записей следующим образом:

   'meta_key' => ВАША-ТАКСОНОМИЯ,
    'orderby'    => array(
      'meta_value' => 'ASC'
    )

Надеюсь, это будет полезно кому-нибудь.

14 июл. 2022 г. 15:43:13