За допомогою wp_query можна замовити таксономію?


49

Моє запитання просте, я використовую WP_Query, щоб отримати деякі користувацькі публікації типу, фільтруючі за системою таксономії, використовуючи tax_query.

Тепер моя проблема полягає в тому, що я хотів би замовити таксономію, але з документації та пошуку в Інтернеті я не можу знайти рішення.

Замовлення в WP_Query дозволить вам замовити за купою полів навіть власні метаполя, але, схоже, це не підтримує таксономію.

Будь-які покажчики в потрібному напрямку?

Дякую вам всім.

Відповіді:


12

Ні, замовити за системою таксономії неможливо, оскільки з певного типу точки зору це насправді не має великого сенсу.

Таксономії - це способи групування речей разом. Тож сенсом існування систематики на посадах було б насправді мати терміни в цій таксономії, які поділяються між посадами. Якщо в систематиці були терміни, які використовувались лише по одній посаді кожен, то це зробило б таксономію безглуздою. І якби умови були поділені такими, якими вони мають бути, то впорядкування ним не принесло б нічого корисного.

Що вам слід використати в такій ситуації - це постмета. Ви можете замовити поштовий мета, і це унікально для кожної публікації.

Редагувати: з цього приводу, ви можете замовити за системою таксономії, зробивши спеціальний запит SQL за допомогою фільтра, ви просто не можете це зробити з немодифікованого WP_Query: http://scribu.net/wordpress/sortable-taxonomy-columns.html

Однак, якщо вам доводиться вдаватися до подібних дій, то ваша структура дизайну даних в першу чергу неправильна. "Терміни" в систематиці не є фактичними "даними". Самі терміни не мають властивого значення, вони просто мітки для певної групи, яку вони описують. Якщо ви ставитесь до них як до значущих даних, у вас є основний недолік дизайну.

Таксономії групують речі, призначаючи їм терміни. Це групування - вся суть таксономій, терміни - це просто симпатичні грані у групуванні. Якщо у вас є змістовні метадані, які потрібно призначити публікації, ви повинні замість цього використовувати мета мета публікації. І це ви можете замовити, оскільки мета meta використовує і ключі, і значення для зберігання інформації. З систематикою ви насправді зберігаєте лише ключі, їх значення - це публікації, згруповані за цим терміном.

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


Привіт Отто, дякую за відповідь. Я бачу вашу думку, і, можливо, я йду неправильним шляхом з цим. У моєму прикладі сайт телевізійних шоу, я маю таксономію для серій 1, серії 2, серії 3 тощо. Тому я можу групувати всі різні телешоу за номером серії. Тоді я маю те ж саме для епізодів, Епізод 01, Епізод 02 тощо. Що мені хотілося б, коли показувати список усіх епізодів, які слід замовляти за епізодами та серіями. Я проаналізую потім розміщення мета та користувальницьких полів. Дякую Отто.
yeope

@yeope, ваша таксономія повинна бути серією, а ваші умови - серіями 1, серії 2 тощо. З епізодами я припускаю, що серія містить декілька епізодів, щоб вона могла використовувати ту саму систематику, "серію", і якщо вони є ієрархальною, то епізод 1, Епізод 2 тощо матиме батьківський термін "серія х". Тоді ви можете запитати цілу серію, щоб епізоди падали в рядку, де вони повинні.
Chris_O

@Chris_O Я бачу, ти можеш там на гроші! Єдина проблема, яку я бачу, - це факт повторення термінів "Епізод 1", "Епізод 2" для кожної серії. Також не в змозі згрупувати всі епізоди 1, не залежно від серіалу, але я думаю, що існує спосіб, як обійти його. Дякую Chris_O
yeope

2
Використання таксономії для епізодів насправді не має особливого сенсу, оскільки групування нічого не варте. Подумайте про це, якщо у вас є "епізод 1" як термін, то ви групуєте епізод 1 з кожним іншим епізодом 1 з усіх інших телешоу. Номери епізодів та серій мають більше сенсу як post_meta, оскільки вони специфічні для цього конкретного шоу, а не корисні як група. Назва телешоу буде корисною як термін в систематиці телевізійних шоу, оскільки тоді ви групуєте шоу в цілому разом.
Отто

1
Отто прослідкував за цим цікавою публікацією в блозі: Коли (не) використовувати користувальницьку систематику .
Ян Фабрі

47

Прийнята відповідь на це питання неприйнятна. Нелогічно вважати, що впорядкувати податковий «не має сенсу». Відповідь, яку він дав, не має сенсу.

Подумайте про тип публікації в меню. Тоді у вас є митний податок "FoodCategories". Податок на харчові категорії містить умови "сніданок", "обід" та "вечеря". Якщо ви подаєте запит, використовуючи параметр tax_query, тепер у вас є набір результатів із усіма умовами, однак вони впорядковані за датою публікації.

Для того, щоб вивести правильний порядок з них, відносно їх термінів, а потім відобразити на передньому кінці належним чином, розділивши публікації на їх різні категорії, вам потрібно пройти цикл результатів, а потім запитувати кожну окрему публікацію в набір результатів, щоб знайти його терміни та порівняти з поточним терміном, фільтрувати в масив і продовжувати впродовж усього. Тоді вам доведеться знову провести цикл через новий масив для відображення. Це не продуктивно.

Було б непогано, якби у WP був варіант "tax__in" для замовлення, оскільки це "post__in", але, оскільки цього не відбувається, вам або доведеться робити вищезазначений смішний процес; налаштувати запит самостійно за допомогою фільтра "posts_orderby" та фільтра "posts_join", щоб відрегулювати метод замовлення та відповідно додати термін до набору результатів; або вам потрібно зробити новий запит для кожного терміна, який ви фільтруєте, в розділах html щодо цих термінів.

Найефективнішим буде зміна рядка запиту за допомогою фільтрів. Найпростіше було б зробити три окремі запити. API WP повинен обробляти замовлення податком або будь-якими обмежувальними параметрами запиту. Якщо ви обмежуєте запит на основі певних умов, існує велика ймовірність, що багатьом доведеться замовляти ці самі умови.


2
Вибачте, але ви помиляєтесь. Упорядкування за системою таксономії теж не має сенсу у вашому випадку. Що ти хочеш показати? Усі сніданки спочатку, за ними всі вечері, потім всі обіди? Вам слід вибрати те, що ви хочете, і порядок, у якому ви хочете, але таксономія - це лише мітка групування. Це не значимі "дані", які ви повинні замовляти. Якщо це так, то він не повинен бути терміном в систематиці, замість цього слід зробити його постмета.
Отто

15
Скажімо, звичайно, є кілька випадків, коли ви хочете замовити повідомлення за терміном таксономії. Інший приклад - тип публікації у фільмі з таксономією рейтингу. У списку фільмів дуже легко уявити людей, які хочуть замовити список фільмів за рейтингом, тому всі фільми з рейтингом G, потім PG-рейтинги тощо. Фільми відображаються вгорі. (У цьому прикладі їжі вони можуть бути впорядковані терміном_id замість імені.) Існує велика сіра область випадків, коли вам, мабуть, найкраще служить таксономія, а не мета, але, мабуть, також корисно, щоб ця таксономія була замовлена -можливий.
СьомийСтейль

2
Рейтинги PG та G - це хороший вибір таксономії, за винятком того, що це дані про конкретні фільми. Таким чином, вони мета. Це дані, а не категорії. Просто наявність обмеженої кількості варіантів не є систематикою. Якщо це потрібно сортувати за, то або зробіть це мета, або примушуйте сортування за системою таксономії за допомогою специфічного коду таксономії. BTW, NC17 приходить після PG. Отже, для виконання замовлення вам потрібен код.
Отто

Я знаю, що я запізнився на вечірку з цим коментарем, але просто наткнувся на це. Упорядкування за системою таксономії може мати сенс у деяких ситуаціях. У нас є списки вакансій для одного проекту як тип посади, а потім штат та місто, в яких це робота, - таксономії. Ми хочемо, щоб вони легко групувались (показували всі робочі місця в штаті або показували всі робочі місця в місті), щоб таксономія була найкращим рішенням. У той же час існує загальний пошук роботи, де ми хочемо сортувати їх спочатку за назвою, потім за державою, потім за містом.
Денніс Пузак

Інший випадок використання: клієнт має купу статей, кожна з яких має категорію. Клієнт хоче, щоб там була сторінка з переліком усіх статей, які можна сортувати за алфавітом, за датою чи за категоріями. Категорії також можуть бути відфільтровані, але перерахування всіх статей за категоріями в алфавітному порядку не є таким божевільним випадком використання, і ви бачите, що це спливає досить часто.
Вілсон Біггс

15

Так, але це дуже причетно ...

Додайте до функції.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 = (запит таксономії var) & order = ASC (або DESC), і вона зніметься!


Дякую, Дрю, я підкажу і спробую запустити цей SQL, потрібно трохи відредагувати, але це може спрацювати. Моя єдина проблема зараз - це те, що я можу йти неправильними напрямками, на які вказував Отто. Дякую Дрю. EDIT - Не потрібно редагувати Я можу побачити, де вона потребує налаштування :) Дякую
yeope

Якщо ви схопили його впродовж останніх двох хвилин, він не спрацює, продовжуйте і захоплюйте його зараз, я це зафіксував. Він був встановлений для двох конкретних таксономій, я вдосконалив код для роботи над усіма зареєстрованими таксономіями.
Дрю Гурлі

ще раз дякую На всякий випадок я спробував ваше рішення, і це начебто спрацює. Також якщо хтось хоче його використовувати, вам потрібно змінити add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );на add_filter('posts_clauses', 'todo_tax_clauses', 10, 2 );Дякую :)
yeope

Так, це тепер виправлено в блоці коду, я взяв це з проекту, над яким працюю, і забув змінити назву функції, хоча я змінив її на гачку.
Дрю Гурлі

1
Чи знаєте ви, чи можна замовити таксономії за ідентифікатором замість назви? Я намагаюся отримати той самий результат, замовляючи групи таксономії за ID
Хав'єр Віллануєва

9

Я пізно заходжу до гри тут, але є більш простий спосіб WordPressy зробити це.

Створіть свій податковий запит як звичайний.

$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, підключіть до фільтра замовлення і перекрийте його

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');

не забудьте потім видалити фільтр ...

це працює b / c tax_query створює для вас приєднання тощо, вам просто потрібно замовити одне з полів з приєднання.


2
Будь-яка ідея, як замовити по імені замість term_taxonomy_id? зміна term_taxonomy_id у orderby_statement кидає помилки
tehlivi

Це правильна відповідь для всіх, хто цікавиться!
Майра М

2

Ну, я хотів би розкрити свій досвід сортування користувацьких типів публікацій за категоріями / систематикою.

ВЕБ

  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  

По-третє , я підключив запит на файл function.php з трьома фільтрами: posts_fields, posts_join та posts_orderby

Код у function.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' );
}// end if in_array

  }// end if is_archive

}
 add_filter('pre_get_posts', 'filtra_queries');

Сподіваюся, це може комусь допомогти


Приємна робота, смішна, що ця кількість коду приймала, щоб сортувати щось за систематикою. Величезна проблема з WP.
serraosays

2

У мене була дуже схожа проблема, з якою я вирішувався: я хочу замовити спеціальний архів після публікації (статті журналів) за власною систематикою (випуски). Я ніколи не здійснюю прямих SQL запитів на своєму сайті - і зазвичай, якщо ви подібні до інших відповідей - вам потрібно переосмислити свій підхід.

ПРОБЛЕМИ:

1) Wordpress не дозволяє замовляти таксономії будь-яким розумним способом.

2) Wordpress просто не дозволяє orderbyвикористовувати таксономії на WP_Query після типу (як написано Отто).

РІШЕННЯ:

1) Сортування систематики найкраще виконується плагіном NE Порядок користування системою таксономії . Це дозволяє замовити таксономію через WYSIWYG, в wp-adminякій не так, як я це зробив би, але нічого кращого я не знайшов.

Коли ви налаштуєте плагін, ви отримаєте щось подібне до того, що я тут зробив. Зверніть увагу на варіант Auto-sort Queries of this Taxonomy- встановіть це Custom Order as Defined Above; це дає вам необхідне замовлення. Знімок екрана:

Спеціальне замовлення таксономії

2) Маючи впорядковану систематику, тепер ви можете створити серію викликів WP_Query, які проходять через кожен термін, ефективно створюючи архів, упорядкований систематикою. Використовуйте , get_terms()щоб створити масив всіх податкових термінів, а потім запустити в foreachпротягом кожного семестру. Це створює WP_Queryдля кожного елемента терміна, який буде повертати всі повідомлення за заданий термін, фактично створюючи архів, упорядкований терміном таксономії. Код для цього:

  // Get your terms and put them into an array
  $issue_terms = get_terms([
    'taxonomy' => 'issues',
    'hide_empty' => false,
  ]);

  // Run foreach over each term to setup query and display for posts
  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'
        )
      )
    ) );

    // Run loop over each query
    while($the_query->have_posts()) :
      $the_query->the_post();

      // YOUR TEMPLATE OUTPUT FOR EACH POST

    endwhile;
  }

Пов’язане читання на цьому сайті: Відображення всіх публікацій у користувацькому типі публікацій, згрупованих за спеціальною систематикою


2

Я не впевнений, чому всі рішення тут в значній мірі завищують це. Гаразд, це вже пів десятиліття тому, але я просто виконую наступний код, і він працює:

   <?php // Default
    $wheels_args = array(
        'post_type' => 'wheels',
        'posts_per_page' => '96',
        'orderby' => 'taxonomy, name', // Just enter 2 parameters here, seprated by comma
        'order'=>'ASC'
    );
    $loop = new WP_Query($wheels_args);
    ?>

Це впорядкує таксономії вашої CPT спочатку за її систематикою в алфавітному порядку, а в межах цих груп таксономії також за алфавітом.


@yeope Чому це прийнята відповідь !? слава богу, я прокрутив
Хуан Солано

1

Ось рішення, яке я використав для цієї конкретної проблеми. Це рішення призначено для крайніх випадків, коли неможливо використовувати 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})"; // Add further specific ordering here

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

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

Якщо ви просто хочете публікації, то змініть запит на SELECT p.*іGROUP BY p.ID


0

Це як запит перед запитом, але не буде турбувати, якщо ми не запитуємо занадто багато публікацій ... Ідея полягає в тому, щоб змінити основний запит, щоб нам навіть не потрібно було відвідувати шаблони та генерувати нові запити та петлі ...

function grouped_by_taxonomy_main_query( $query ) {

    if ( $query->is_home() && $query->is_main_query() ) { // Run only on the homepage

        $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, // as you wish...
                'post_type' => 'my_custom_post_type', // If needed... Default is posts
                'fields' => 'ids', // we only want the ids to use later in 'post__in'
                'tax_query' => array( array( 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id, )))) // getting posts in the current term
            );
        }

        $query->query_vars['post_type'] = 'my_custom_post_type'; // Again, if needed... Default is posts
        $query->query_vars['posts_per_page'] = 16; // If needed...
        $query->query_vars['post__in'] = $post_ids; // Filtering with the post ids we've obtained above
        $query->query_vars['orderby'] = 'post__in'; // Here we keep the order we generated in the terms loop
        $query->query_vars['ignore_sticky_posts'] = 1; // If you dont want your sticky posts to change the order

    }
}

// Hook my above function to the pre_get_posts action
add_action( 'pre_get_posts', 'grouped_by_taxonomy_main_query' );
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.