Este posibil să sortezi după taxonomie folosind wp_query?
Întrebarea mea este simplă, folosesc WP_Query
pentru a prelua niște postări de tip personalizat filtrând după o taxonomie folosind tax_query
.
Problema mea acum este că aș dori să sortez după taxonomie
, dar din documentație și căutări pe internet nu găsesc o soluție.
Parametrul orderby
din WP_Query
îți permite să sortezi după o mulțime de câmpuri, chiar și după câmpuri meta personalizate, dar nu pare să suporte taxonomiile.
Aveți vreo sugestie în direcția corectă?
Vă mulțumesc tuturor.

Răspunsul acceptat pentru această întrebare este inacceptabil. Este ilogic să presupui că ordonarea după taxonomie „nu are sens”. Răspunsul pe care l-a dat nu are sens.
Luați în considerare un tip de postare de meniu. Apoi aveți o taxonomie personalizată „CategoriiAlimentare”. Taxonomia CategoriiAlimentare are termenii „MicDejun”, „Pranz” și „Cină”. Dacă trimiteți o interogare care utilizează parametrul tax_query, acum aveți un set de rezultate cu toți termenii, însă aceștia sunt ordonați după data postării.
Pentru a obține ordinea corectă a acestora, relativ la termenii lor, și apoi pentru a le afișa corespunzător în front-end separând postările în categoriile lor respective, trebuie să parcurgeți setul de rezultate, apoi să interogați fiecare postare individuală din setul de rezultate pentru a-i găsi termenii și a-i compara cu termenul curent, să filtrați într-un array și să continuați. Apoi trebuie din nou să parcurgeți noul array pentru afișare. Acest lucru nu este productiv.
Ar fi frumos dacă WP ar avea o opțiune „tax__in” pentru orderby așa cum are una „post__in”, dar din moment ce nu are, fie trebuie să faceți procesul ridicol menționat mai sus, fie să personalizați interogarea prin filtrele 'posts_orderby' și 'posts_join' pentru a ajusta metoda de ordonare și a adăuga termenul în setul de rezultate, respectiv, sau trebuie să faceți o nouă interogare pentru fiecare termen pe care îl filtrați în cadrul secțiunilor html relative la acei termeni.
Cea mai eficientă metodă ar fi modificarea șirului de interogare prin filtre. Cea mai ușoară ar fi să faceți trei interogări separate. API-ul WP ar trebui să se ocupe de ordonarea după taxonomie sau orice parametri de interogare restrictivi. Dacă restricționați o interogare pe baza anumitor condiții, există o probabilitate mare ca mulți să aibă nevoie să ordoneze după aceleași condiții.

Îmi pare rău, dar greșești. Ordonarea după taxonomie nu are sens nici în cazul tău. Ce vrei să afișezi? Toate micile dejunuri primele, urmate de toate cinele, apoi toate prânzurile? Ar trebui să selectezi ce dorești și ordinea în care vrei să apară, dar taxonomia este doar o etichetă de grupare. Nu este o "informație" semnificativă după care ar trebui să ordonezi. Dacă este, atunci nu ar trebui să fie un termen într-o taxonomie, ci ar trebui să-l faci un post-meta în schimb.

Hai să fim serioși, desigur că vor exista cazuri în care vei dori să ordonezi postările după termenii taxonomiei. Un alt exemplu este un tip de postare Film cu o taxonomie de Evaluare. Într-o listă de filme, este foarte ușor să-ți imaginezi oamenii care doresc să ordoneze lista de filme după evaluare, astfel încât toate filmele cu evaluarea G, apoi PG etc. să apară primele. (În acest caz și în exemplul cu mesele, acestea ar putea fi ordonate după term_id în loc de nume.) Există o zonă mare de cazuri în care probabil că e mai bine să folosești o taxonomie și nu meta, dar este probabil util și ca acea taxonomie să poată fi ordonată.

Evaluările PG și G și altele asemenea sunt o alegere bună de taxonomie, cu excepția faptului că sunt date despre filme specifice. Prin urmare, sunt meta. Sunt date, nu categorii. Doar pentru că ai un număr limitat de opțiuni nu înseamnă că ai o taxonomie. Dacă trebuie să poți ordona, atunci fie o faci meta, fie forțezi ordonarea prin taxonomie folosind cod specific taxonomiei. Apropo, NC17 vine după PG. Deci, oricum ai nevoie de cod pentru a face acea ordonare.

Știu că am întârziat cu acest comentariu, dar tocmai am dat peste el. Ordonarea după taxonomie poate avea sens în anumite situații. Într-un proiect avem anunțuri de joburi ca tip de postare, iar statul și orașul în care se află jobul sunt taxonomii. Dorim să le putem grupa ușor (afișează toate joburile dintr-un stat sau toate joburile dintr-un oraș), așa că taxonomia a fost cea mai bună soluție. În același timp, există o căutare generală de joburi unde dorim să le sortăm mai întâi după titlu, apoi după stat și apoi după oraș.

Un alt caz de utilizare: Un client are o mulțime de articole, fiecare având o categorie. Clientul dorește să existe o pagină care listează toate articolele, care pot fi sortate alfabetic, după dată sau după categorie. Categoriile pot fi și filtrate, dar listarea tuturor articolelor pe categorii în ordine alfabetică nu este un caz de utilizare atât de ciudat și apare destul de des.

Încă un caz de utilizare aici: avem o mulțime de 'clienți' într-un tip de postare personalizat și există o taxonomie de regiune care ne permite să indicăm unde își desfășoară afacerile fiecare client. Ni s-a cerut să adăugăm funcționalitatea astfel încât, atunci când un vizitator vede lista de clienți, aceștia să fie ordonați după regiune, cu clienții din apropierea lor primi.

Otto are dreptate că dacă încerci să faci asta, trebuie să te uiți la structura ta de date; de nouă ori din zece este greșită. ÎNSĂ a insista dogmatic că "toți ceilalți greșesc" nu este inteligent. Iată cazul meu de utilizare: Numele de familie trebuie sortate după prima literă scrisă cu majusculă; de Courcy se plasează sub C și De Haan sub D. Este ușor să folosești o expresie regulată pentru o taxonomie personalizată 'alfabet' care sortează acestea corect; însă acum, pentru a afișa toți oamenii mei cu o simplă interogare (prin 'meta_key' => 'alfabet') nu este posibil. Trebuie să duplic codul meu și să definesc propriul meu filtru 'orderby' => 'quasi_alphabetic_by_title'.

Da, dar este destul de complex...
Adaugă în functions.php din tema ta:
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 );
Aceasta este o combinație între cod găsit pe net și modificări personale. Explicarea este destul de dificilă, dar concluzia este că, odată ce rulează acest cod, poți folosi ?orderby=(taxonomy query var)&order=ASC (sau DESC) și va funcționa imediat!

Mulțumesc Drew, voi încerca să rulez acel SQL, trebuie să-l editez puțin, dar ar putea funcționa. Singura mea problemă acum este că s-ar putea să merg în direcția greșită, așa cum a subliniat Otto. Mulțumesc Drew. EDIT - Nu e nevoie să editez, văd unde trebuie făcute ajustările :) Mulțumesc

Dacă l-ai luat în ultimele două minute, nu va funcționa, ia-l acum, l-am reparat. Era setat pentru două taxonomii specifice, am îmbunătățit codul să funcționeze pentru toate taxonomiile înregistrate.

mulțumesc încă o dată. Doar pentru cazul în care, am încercat soluția ta și funcționează oarecum. De asemenea, dacă altcineva vrea să o folosească, trebuie să schimbi add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );
în add_filter('posts_clauses', 'todo_tax_clauses', 10, 2 );
Mulțumesc :)

Da, acum este rezolvat în blocul de cod, am luat asta dintr-un proiect la care lucrez și am uitat să schimb numele funcției chiar dacă l-am schimbat în hook.

Știi dacă este posibil să ordonezi taxonomiile după ID în loc de nume? Încerc să obțin același rezultat ordonând grupurile de taxonomii după ID

Nu, nu este posibil să ordonezi după taxonomie, deoarece, dintr-o anumită perspectivă, acest lucru nu prea are sens.
Taxonomiile sunt modalități de a grupa lucruri împreună. Scopul unei taxonomii pentru articole este să ai termeni în acea taxonomie care sunt partajați între articole. Dacă o taxonomie ar avea termeni folosiți doar pe câte un articol, atunci taxonomia ar fi cam inutilă. Și dacă termenii sunt partajați așa cum ar trebui, atunci ordonarea după ei nu ar produce ceva util.
Ceea ce ar trebui să folosești într-o astfel de situație sunt metadatele articolului (post meta). Poți ordona după metadate, iar acestea sunt unice pentru fiecare articol.
Edit: Cu toate acestea, poți ordona după taxonomie prin crearea unei interogări SQL personalizate folosind un filtru, dar nu poți face acest lucru direct dintr-un WP_Query nemodificat: http://scribu.net/wordpress/sortable-taxonomy-columns.html
Totuși, dacă trebuie să recurgi la astfel de metode, atunci structura datelor tale este greșită din start. "Termenii" din taxonomie nu sunt date reale. Termenii în sine nu au o semnificație intrinsecă, sunt doar etichete pentru gruparea pe care o descriu. Dacă îi tratezi ca date semnificative, atunci ai o problemă la nivel de design.
Taxonomiile grupează lucruri prin atribuirea de termeni. Această grupare este întregul scop al taxonomiilor, termenii sunt doar etichetele acestei grupări. Dacă ai metadate semnificative de atribuit unui articol, atunci ar trebui să folosești metadatele articolului (post meta). Și pe acelea poți să le folosești pentru ordonare, deoarece metadatele articolului folosesc atât chei cât și valori pentru a stoca informații. În cazul unei taxonomii, stochezi doar chei, iar valorile sunt articolele grupate prin acel termen.
Lucrurile sunt mai ușoare pe termen lung dacă folosești abordarea corectă. Nu spun că nu poți face ceva neobișnuit cu taxonomiile, dar îți faci viața mai grea pe termen lung dacă le folosești greșit.

Salut Otto, mulțumesc pentru răspuns. Înțeleg punctul tău de vedere și poate abordez problema greșit. În exemplul meu cu un site de seriale TV, am o taxonomie pentru sezonul 1, sezonul 2, sezonul 3 etc. Așa pot grupa toate serialele TV după numărul sezonului. Apoi am același lucru pentru episoade, Episodul 01, Episodul 02 etc. Ceea ce aș dori este ca atunci când afișez o listă cu toate episoadele, acestea să fie ordonate după episod și sezon. Voi analiza apoi post meta și câmpurile personalizate. Mulțumesc, Otto.

@yeope taxonomia ta ar trebui să fie "sezoane" și termenii ar trebui să fie sezonul 1, sezonul 2 etc. Presupun că un sezon conține mai multe episoade, așa că poate folosi aceeași taxonomie, "sezoane", iar dacă sunt ierarhice, atunci episodul 1, episodul 2 etc. ar avea termenul părinte "sezonul x". Apoi ai putea interoga un întreg sezon în ordine, cu episoadele așezate corespunzător.

@Chris_O Înțeleg, s-ar putea să ai dreptate! Singura problemă pe care o văd este faptul că trebuie să repet termenii "Episodul 1", "Episodul 2" pentru fiecare sezon. De asemenea, să nu pot grupa toate episoadele 1 independent de sezon, dar cred că probabil există o soluție. Mulțumesc, Chris_O.

Folosirea unei taxonomii pentru episoade nu prea are sens, de fapt, pentru că gruparea este inutilă. Gândiți-vă, dacă aveți "episodul 1" ca termen, atunci grupați episodul 1 cu toate celelalte episoade 1 din toate celelalte seriale TV. Numerele de episod și serie au mai mult sens ca post_meta, pentru că sunt specifice acelui serial anume și nu sunt utile ca grup. Numele serialului TV ar fi util ca termen într-o taxonomie tv-show, pentru că atunci grupați serialul ca întreg.

Dar o taxonomie pentru serii cam funcționează, dar doar pentru că grupează serialele într-un sezon sau ceva de genul, deși ar trebui să o interogați împreună cu taxonomia tv-show. Într-o astfel de taxonomie de serii, termenii voștri ar fi 1, 2, 3, care reprezintă numărul sezonului în care se afla serialul. Dar tot ați dori mai mult această informație ca postmeta, deoarece doriți să ordonați după ea. Și din moment ce puteți interoga și postmeta, nu prea are sens să o duplicați ca taxonomie.

Otto a urmat acest lucru cu un articol interesant pe blog: Când să (nu) folosești o Taxonomie Personalizată.

@otto Mulțumesc pentru share, e foarte util să citesc mai multe detalii despre taxonomii și utilizările lor. În mod special sunt interesat să aflu părerea ta despre o situație precum cea descrisă în postarea Coloane Sortabile de Taxonomii. Care ar fi cea mai bună soluție când vreau să pot interoga toate postările dintr-o gamă de culori, dar și să le pot sorta după culoare? Poate ar fi mai bine să pun o întrebare separată...

Dacă vrei să sortezi după acest criteriu, atunci ar trebui să folosești meta date în loc de o taxonomie. Sortarea după taxonomii nu prea are sens, în realitate.

Mulțumesc @Otto. Deși nu sunt de acord cu afirmația ta: "Cu toate acestea, dacă trebuie să apelezi la astfel de soluții, atunci structura datelor tale este greșită de la început."... Ar putea fi util să poți reordona lista de articole după termenul categoriei în interfața de administrare...

@ClemC Nu prea are sens. Articolele pot avea multiple categorii. După ce anume sortezi? Care este criteriul secundar de sortare când două articole au aceeași categorie? Acesta este genul de problemă cu care te confrunți, taxonomiile sunt doar grupări, "termenul" este doar o fațadă frumoasă pentru acea grupare, nu partea importantă. Partea importantă este grupa în sine. Nu ai sorta numele animalelor alfabetic după taxonomia lor linneană. Nu te ajută cu nimic.

Salut @Otto, ai dreptate. Am luat ca referință cazul proiectului meu curent, care este destul de particular... Un CPT (film) care permite doar un singur termen dintr-o taxonomie personalizată (festival) cu butoane radio pentru selecție. Ordinea implicită a listei CPT este după termen (festival), ceea ce în acest caz particular este destul de logic, nu? Nu mă pot gândi la o abordare mai bună privind "designul datelor"... Am implementat "festivaluri" ca o taxonomie pentru că singurele date de care au nevoie sunt descrierea lor și grupează logic "filmele". PS: Îmi cer scuze pentru engleza mea.

Da, corect, dar atunci este un grup. Grupezi lucruri împreună. Ce înseamnă "sortează după" în acest context? Dacă ai o serie de lucruri în același grup, atunci poți "selecta după" acel grup, și asta are sens, dar "sortarea" este ceva complet diferit. Sortezi după câmpuri care au valori diferite, nu după câmpuri care au toate aceleași valori.

Îmi pare rău @Otto, abia acum am observat răspunsul tău... Sunt complet de acord cu punctele tale semantice și logica ta. Dar în contextul meu, "sortarea după" ar fi în principal o problemă ergonomică. Gruparea vizuală a proiecțiilor după "festival" ar putea ajuta în mod semnificativ utilizatorul să obțină o imagine de ansamblu bazată pe cel mai important factor pentru el, și asta dintr-o privire. Prin urmare, nu sunt sigur că pot realiza acest lucru altfel decât prin "sortare", care, sunt de acord, nu este un termen potrivit...

Am ajuns puțin mai târziu la această discuție, dar există o modalitate mai simplă și mai specifică WordPress de a face acest lucru.
Construiește interogarea de taxonomie în mod normal.
$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;
Configurează argumentele pentru query_posts sau WP_Query
$args = array(
'post_type'=>'post',
'posts_per_page'=>12,
'paged'=>$paged,
'tax_query' => $tax_query,
);
Înainte de a face apelul query_posts / WP_Query, conectează-te la filtrul orderby și suprascrie-l
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');
Nu uita să elimini filtrul după utilizare...
Această metodă funcționează deoarece tax_query creează automat join-urile necesare, tu trebuie doar să sortezi după unul dintre câmpurile din join.

Ai vreo idee despre cum să sortezi după nume în loc de term_taxonomy_id? Schimbarea term_taxonomy_id în orderby_statement aruncă erori

@tehlivi această metodă nu funcționează pentru sortarea după nume deoarece numele se află în tabelul wp_terms
. WordPress pare să cache-ze termenii de taxonomie, astfel încât chiar dacă interogarea ta de taxonomie caută după slug sau nume, care sunt de asemenea în tabelul wp_terms
, WordPress le procesează prin lista sa cache și le înlocuiește cu ID-uri stocate în term_relationships.term_taxonomy_id
, astfel încât nu trebuie să interogheze tabelul wp_terms
ca parte a interogării principale. Ceea ce înseamnă că nici numele, nici slug-ul nu sunt incluse în interogarea SQL rezultată. Trebuie să adaugi join-uri.

@EthanC salut omule, mulțumesc pentru răspunsul detaliat și sper că dacă cineva va găsi asta în viitor, le va fi util răspunsul tău. Dar pentru mine, este cu siguranță greu să-mi amintesc ceva din 2016. Cred că am ajuns să rulez array-ul printr-o funcție de sortare după ce interogarea s-a finalizat. Sunt sigur că orice dezvoltator care a preluat acel proiect după ce am părăsit compania mă urăște. Haha.

@tehlivi Da, am ajuns să ignor interogarea principală în cazul în care unele articole aveau atribuit mai mult de un termen. Am ales în schimb să rulez get_terms()
și apoi get_posts
pentru fiecare termen. Am adăugat ~15 interogări suplimentare la încărcarea paginii, dar designerul a obținut rezultatul dorit.

Nu sunt sigur de ce toate soluțiile de aici sunt cam exagerate. OK, a trecut jumătate de decadă, dar acum rulez următorul cod și funcționează:
<?php // Implicit
$wheels_args = array(
'post_type' => 'wheels',
'posts_per_page' => '96',
'orderby' => 'taxonomy, name', // Introduceți doar 2 parametri aici, separați prin virgulă
'order'=>'ASC'
);
$loop = new WP_Query($wheels_args);
?>
Aceasta va sorta taxonomiile CPT-ului mai întâi după taxonomie în ordine alfabetică și în cadrul acestor grupuri de taxonomii, tot în ordine alfabetică.

@yeope De ce este acesta răspunsul acceptat!? slavă Domnului că am derulat

nu am reușit să fac asta să funcționeze. poți indica un site cu o explicație pentru asta? nimic aici, care să susțină codul tău

Nu se parsează, mai ales cu această virgulă, și este ignorat de WP (6.x).

Ei bine, aș dori să împărtășesc experiența mea în sortarea postărilor personalizate după categorie/taxonomie.
SITUAȚIA PE WEB
- Un site web al unei agenții de turism care rulează pe WordPress
- Conținutul principal pe un tip de postare personalizat numit 'ruta'
- Taxonomie cu următoarea structură Tip-de-călătorie > continent > țară
PROBLEMA
În paginile de arhivă ale listei de categorii, clientul dorea ca postările să fie sortate după:
- Continent, ordonate după numărul de rute din fiecare.
- Țară, ordonate alfabetic.
PAȘII URMAȚI
În primul rând, am interceptat cererea din interogarea originală a paginii de arhivă, care arăta astfel:
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
În al doilea rând, am modificat codul SQL în Sequel Pro pentru a se potrivi nevoilor mele. Am ajuns la această variantă (da, probabil poate fi îmbunătățită: cunoștințele mele despre MySQL nu sunt excepționale):
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
În al treilea rând, am conectat interogarea în fișierul functions.php folosind trei filtre: posts_fields, posts_join și posts_orderby
Codul din 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;
}
În final, am declanșat filtrele din hook-ul pre_get_post în funcție de anumite condiții
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');
Sper că acest lucru poate ajuta pe cineva

Am avut o problemă foarte asemănătoare cu care m-am confruntat: vreau să ordonez un arhiv de postări personalizate (articole din revistă) după o taxonomie personalizată (numere). Nu folosesc niciodată interogări SQL directe pe site-ul meu - și de obicei dacă sunteți ca celelalte răspunsuri de aici - trebuie să vă reconsiderați abordarea.
PROBLEME:
1) WordPress nu vă permite să ordonați taxonomiile într-un mod inteligent.
2) WordPress pur și simplu nu permite folosirea taxonomiilor în parametrul orderby
pentru WP_Query pe tipuri de postări (așa cum a explicat Otto).
SOLUȚII:
1) Sortarea taxonomiilor se realizează cel mai bine în acest moment cu plugin-ul Custom Taxonomy Order NE. Acesta vă permite să ordonați taxonomia printr-un editor WYSIWYG în wp-admin
, ceea ce nu este modul meu preferat, dar nu am găsit ceva mai bun.
Când configurați plugin-ul, veți obține ceva similar cu ceea ce am făcut eu aici. Luați notă de opțiunea Auto-sort Queries of this Taxonomy
- setați-o la Custom Order as Defined Above
; astfel obțineți ordonarea necesară. Captură de ecran:
2) Cu o taxonomie sortată în loc, puteți acum crea o serie de interogări WP_Query care parcurg fiecare termen, creând efectiv un arhiv ordonat după taxonomie. Folosiți get_terms()
pentru a crea un array cu toți termenii taxonomiei, apoi rulați un foreach
pentru fiecare termen. Acest lucru creează o interogare WP_Query
pentru fiecare termen care va returna toate postările pentru acel termen, creând efectiv un arhiv ordonat după termenii taxonomiei. Codul pentru implementare:
// Obțineți termenii și puneți-i într-un array
$issue_terms = get_terms([
'taxonomy' => 'issues',
'hide_empty' => false,
]);
// Rulați foreach pentru fiecare termen pentru a configura interogarea și afișarea postărilor
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'
)
)
) );
// Rulați bucla pentru fiecare interogare
while($the_query->have_posts()) :
$the_query->the_post();
// AFIȘAREA ȘABLONULUI PENTRU FIECARE POSTARE
endwhile;
}
Lectură recomandată pe acest site: Afișați toate postările dintr-un tip personalizat, grupate după o taxonomie personalizată

Iată soluția pe care am folosit-o pentru această problemă specifică. Această soluție este pentru cazurile extreme în care nu este posibil să folosești un filtru pre_get_posts
și există deja paginare pe interogare (de exemplu: 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})"; // Adaugă aici ordonarea suplimentară specifică
$results = $wpdb->get_results($term_sql, ARRAY_A);
Am folosit acest cod pentru a crea un meniu de navigare ordonat după taxonomie, termen și număr de postări pe termen.
Dacă dorești doar postările, modifică interogarea în SELECT p.*
și GROUP BY p.ID

Îmi place să sortez termenii manual, așa că folosesc un plugin pentru asta. Și sunt un fan al filtrului pre_get_posts
, așa că am luat exemplul funcțional corect al lui Drew Gourley și l-am adaptat să funcționeze cu acesta. Deci, acesta este un caz oarecum special, dar postez oricum, în caz că ajută pe cineva. Următorul cod se adaugă în functions.php sau într-un plugin personalizat.
Mai întâi, să începem cu filtrul. Sortăm tipul de postare personalizat music
după taxonomia personalizată 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');
Apoi apelăm filtrul 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);
Acum tot ce trebuie să faci este să sortezi taxonomiile cu următorul plugin: Simple Custom Post Order. Acest plugin este obligatoriu pentru această soluție, deoarece adaugă coloana term_order
în baza de date!
Iar această linie:
$clauses['orderby'] .= ", {$wpdb->posts}.post_name ASC"
sortează postările după titlu, astfel încât sortarea completă a soluției de mai sus este: termen de taxonomie => titlul postării.

Mulțumesc mult, acest lucru este foarte util. Este minunat să ai o modalitate de a ordona vizual. Știi de ce partea "OR taxonomy IS NULL" este acolo? Pare a fi ceva care nu este necesar.

Afișează primul termen corect, dar după acele postări următorul termen nu urmează logic ordinea din meniu stabilită cu SCP Order. Mă întreb dacă este pentru că încerc să fac asta cu produse, iar WooCommerce are deja o ordine pentru atribute... poate cele două intră în conflict. În baza de date însă ID-urile din coloana term_order sunt corecte...

O metodă destul de simplă de a face acest lucru este să adăugați o funcție care să facă următoarele:
- Când articolul este publicat...
- Obțineți ID-ul/slug-ul/etc. al categoriei...
- Salvați-l ca o valoare meta personalizată pentru articol
Apoi, în bucla (loop) WordPress, ordonați articolele după acea valoare meta.
De exemplu:
// 1
add_action( 'publish_post', 'save_and_add_meta' );
function save_and_add_meta($post_id){
//Elimină temporar acțiunea pentru a evita o buclă infinită
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);
//Adaugă acțiunea înapoi
add_action( 'publish_post', 'save_and_add_meta' );
}
Apoi, în interogarea WordPress (WP_Query), adăugați în argumentele $args:
'meta_key' => 'cat_slug',
'orderby' => 'meta_value',
'order' => 'DESC',
Această metodă funcționează dacă puteți restricționa utilizatorii să atribuie doar o singură categorie per articol sau dacă categoriile sunt mutual exclusive. Dacă atribuie mai multe categorii, articolul ar fi exclus din una dintre ele.

Este ca o interogare înaintea interogării, dar nu va deranja dacă nu interogăm prea multe articole... Ideea este de a modifica interogarea principală, astfel încât să nu fie nevoie să mergem la șabloane și să generăm noi interogări și bucle...
function grouped_by_taxonomy_main_query( $query ) {
if ( $query->is_home() && $query->is_main_query() ) { // Rulează doar pe pagina principală
$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, // după cum dorești...
'post_type' => 'my_custom_post_type', // Dacă este necesar... Implicit sunt articolele
'fields' => 'ids', // vrem doar ID-urile pentru a le folosi mai târziu în 'post__in'
'tax_query' => array( array( 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id, )))) // obținerea articolelor din termenul curent
);
}
$query->query_vars['post_type'] = 'my_custom_post_type'; // Din nou, dacă este necesar... Implicit sunt articolele
$query->query_vars['posts_per_page'] = 16; // Dacă este necesar...
$query->query_vars['post__in'] = $post_ids; // Filtrăm cu ID-urile articolelor obținute mai sus
$query->query_vars['orderby'] = 'post__in'; // Aici păstrăm ordinea generată în bucla termenilor
$query->query_vars['ignore_sticky_posts'] = 1; // Dacă nu dorești ca articolele lipicioase să schimbe ordinea
}
}
// Conectează funcția de mai sus la acțiunea pre_get_posts
add_action( 'pre_get_posts', 'grouped_by_taxonomy_main_query' );

Acesta va eșua, nu poți folosi get_posts sau WP_Query în interiorul pre_get_posts, va crea o buclă infinită. Deoarece atunci când folosești get_posts sau WP_Query, acesta va declanșa hook-ul pre_get_posts și va cauza o buclă infinită, chiar dacă verifici is_main_query, nu se va opri și va rula continuu.

Câteva răspunsuri sunt destul de complexe, am scris această soluție care este destul de simplă de înțeles (cred/sper):
$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);
Acum variabila $result
conține toate ID-urile postărilor, ordonate ascendent după numele taxonomiei personalizate.
Atenție: dacă o postare conține mai multe categorii, este necesară o soluție diferită.
Puteți folosi ID-urile într-o funcție foreach, cam așa:
foreach($result as $id){
$image = get_the_post_thumbnail($id);
...etc.
}
Sau puteți face o a doua interogare astfel:
$loopnew = new WP_Query(array('post_type' => 'Teammember','post__in'=> $result));
if ( $loopnew->have_posts() ) {
while ( $loopnew->have_posts() ) {
$loopnew->the_post();
...etc.
}
}

Este cam enervant că WordPress nu te lasă să faci asta și te forțează să ai practic două câmpuri cu aceeași informație...
DAR voi posta aici soluția mea. Ideea este să trecem toți termenii de taxonomie selectați în metadatele postului.
(Atenție, va trebui să ajustați dacă taxonomia dvs. permite valori multiple)
//adaugă acest hook pentru a salva automat termenii ca metadate la salvarea unui post
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);
}
}
După ce adăugați acest cod în functions.php, puteți folosi meta_key și orderby ca de obicei pentru a ordona postările astfel:
'meta_key' => TAXONOMIA-DVS,
'orderby' => array(
'meta_value' => 'ASC'
)
Sper că acest lucru este util pentru cineva.
