È possibile ordinare per tassonomia usando wp_query?
La mia domanda è semplice, sto usando WP_Query
per recuperare alcuni post di tipo personalizzato filtrando per tassonomia utilizzando tax_query
.
Ora il mio problema è che vorrei utilizzare orderby
per ordinare per taxonomy
, ma dalla documentazione e cercando sul web non riesco a trovare una soluzione.
Il parametro orderby
in WP_Query
ti permette di ordinare per una serie di campi, inclusi i campi meta personalizzati, ma non sembra supportare l'ordinamento per tassonomia.
Qualche suggerimento nella giusta direzione?
Grazie a tutti.

La risposta accettata per questa domanda è inaccettabile. È illogico assumere che ordinare per tassonomia "non abbia senso". La risposta fornita non ha senso.
Considera di avere un post type "menu". Poi hai una tassonomia personalizzata "CategorieCibo" con i termini "Colazione", "Pranzo" e "Cena". Se esegui una query utilizzando il parametro tax_query, ottieni un set di risultati con tutti i termini, ma sono ordinati per data del post.
Per ottenere l'ordine corretto rispetto ai loro termini e visualizzarli correttamente nel front-end separando i post nelle varie categorie, devi scorrere il set di risultati, interrogare ogni singolo post per trovare i suoi termini e confrontarli con il termine corrente, filtrarli in un array e continuare. Poi devi ripetere il ciclo attraverso il nuovo array per la visualizzazione. Questo non è produttivo.
Sarebbe bello se WordPress avesse un'opzione "tax__in" per orderby come ha "post__in", ma poiché non c'è, devi o fare il ridicolo processo sopra descritto; personalizzare la query tramite i filtri 'posts_orderby' e 'posts_join' per modificare il metodo di ordinamento e aggiungere il termine al set di risultati; oppure fare una nuova query per ogni termine che vuoi filtrare all'interno delle sezioni html relative a quei termini.
Il metodo più efficiente sarebbe modificare la stringa di query tramite filtri. Il più semplice sarebbe fare tre query separate. L'API di WordPress dovrebbe gestire l'ordinamento per tassonomia, o qualsiasi parametro di query restrittivo. Se stai restringendo una query in base a certe condizioni, è probabile che molti avranno bisogno di ordinare per quelle stesse condizioni.

Spiacente, ma ti sbagli. Ordinare per tassonomia non ha alcun senso nemmeno nel tuo caso. Cosa vuoi mostrare? Tutte le colazioni prima, seguite da tutte le cene e poi da tutti i pranzi? Dovresti selezionare ciò che desideri e l'ordine in cui vuoi mostrarlo, ma la tassonomia è solo un'etichetta di raggruppamento. Non è un "dato" significativo per cui dovresti ordinare. Se lo è, allora non dovrebbe essere un termine in una tassonomia, dovresti invece renderlo un post-meta.

Dai, ovviamente ci saranno alcuni casi in cui vorrai ordinare i post per termine di tassonomia. Un altro esempio è un tipo di post Film con una tassonomia di Valutazione. In un elenco di film, è facile immaginare che le persone vogliano ordinare un elenco di film per valutazione in modo che tutti i film con valutazione G, poi PG, ecc. compaiano per primi. (In questo e nell'esempio dei pasti potrebbero essere ordinati per term_id invece che per nome.) C'è un'ampia zona grigia di casi in cui probabilmente è meglio usare una tassonomia e non i meta, ma probabilmente è anche utile che quella tassonomia sia ordinabile.

Le valutazioni PG, G e simili sono una buona scelta per una tassonomia, tranne per il fatto che sono dati su film specifici. Quindi, sono meta. Sono dati, non categorie. Il semplice fatto di avere un numero limitato di scelte non rende qualcosa una tassonomia. Se deve essere ordinabile, allora rendilo meta, o forza l'ordinamento per tassonomia tramite codice specifico per la tassonomia. BTW, NC17 viene dopo PG. Quindi, hai comunque bisogno di codice per fare quell'ordinamento.

Sono consapevole di essere in ritardo con questo commento, ma l'ho appena trovato. Ordinare per tassonomia può avere senso in alcune situazioni. In un progetto abbiamo annunci di lavoro come tipo di post e poi Stato e Città in cui si trova il lavoro come tassonomie. Vogliamo che possano essere facilmente raggruppabili (mostrare tutti i lavori in uno stato o mostrare tutti i lavori in una città) quindi la tassonomia era la soluzione migliore. Allo stesso tempo c'è una ricerca generale di lavoro dove vogliamo ordinarli prima per titolo, poi per stato, poi per città.

Un altro caso d'uso: un cliente ha una serie di articoli, ognuno dei quali ha una categoria. Il cliente vuole che ci sia una pagina che elenchi tutti gli articoli, che può essere ordinata alfabeticamente, per data o per categoria. Le categorie possono anche essere filtrate, ma elencare tutti gli articoli per categoria in ordine alfabetico non è un caso d'uso così folle e lo si vede comparire abbastanza spesso.

Un altro caso d'uso qui: abbiamo una serie di 'clienti' in un custom post type, e c'è una tassonomia di regione che ci permette di specificare dove ogni cliente svolge la propria attività. Ci è stato chiesto di aggiungere una funzionalità in modo che quando un visitatore visualizza l'elenco dei clienti, questi siano ordinati per regione, con i clienti vicini a loro per primi.

Otto ha ragione nel dire che se stai cercando di fare questo, devi guardare la tua struttura dei dati; nove volte su dieci è sbagliata. TUTTAVIA insistere dogmaticamente con "tutti gli altri hanno torto" non è intelligente. Ecco il mio caso d'uso: I cognomi devono essere ordinati per la prima lettera maiuscola; de Courcy va sotto C e De Haan sotto D. È facile creare una tassonomia personalizzata 'alfabeto' con regex che ordini questi correttamente; tuttavia ora per visualizzare tutte le mie persone con una semplice query (attraverso 'meta_key' => 'alfabeto') non è possibile. Devo duplicare il mio codice e definire il mio filtro 'orderby' => 'quasi_alfabetico_per_titolo'.

Sì, ma è piuttosto complesso...
Aggiungi al file functions.php del tuo tema:
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 );
Questo codice è un mix tra cose trovate e modifiche che ho fatto io. Spiegarlo è piuttosto difficile, ma in sostanza con questa funzione attiva, puoi usare ?orderby=(taxonomy query var)&order=ASC (o DESC) e funzionerà perfettamente!

Grazie Drew, proverò a eseguire quella query SQL, devo modificarla un po', ma potrebbe funzionare. Il mio unico problema ora è che potrei essere sulla strada sbagliata come ha fatto notare Otto. Grazie Drew. EDIT - Non c'è bisogno di modificare, ora vedo dove serve qualche ritocco :) Grazie

Se l'hai presa negli ultimi due minuti, non funzionerà, prendila ora, l'ho sistemata. Era impostata per due tassonomie specifiche, ho migliorato il codice per funzionare con tutte le tassonomie registrate.

Grazie ancora una volta. Per completezza ho provato la tua soluzione e funziona più o meno. Inoltre, se qualcun altro vuole usarla, devi cambiare add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );
in add_filter('posts_clauses', 'todo_tax_clauses', 10, 2 );
Grazie :)

Sì, ora è stato corretto nel blocco di codice, ho preso questo da un progetto su cui sto lavorando e mi sono dimenticato di cambiare il nome della funzione anche se l'ho modificato nell'hook.

Sai se è possibile ordinare le tassonomie per ID invece che per nome? Sto cercando di ottenere lo stesso risultato ordinando i gruppi di tassonomie per ID

No, non è possibile ordinare per tassonomia, perché da un certo punto di vista, ciò non avrebbe molto senso.
Le tassonomie sono modi per raggruppare elementi insieme. Quindi lo scopo di avere una tassonomia sugli articoli sarebbe quello di avere termini in quella tassonomia condivisi tra gli articoli. Se una tassonomia avesse termini utilizzati solo su un singolo articolo ciascuno, ciò renderebbe la tassonomia piuttosto inutile. E se i termini fossero condivisi come dovrebbero essere, allora ordinarli non produrrebbe nulla di particolarmente utile.
Ciò che dovresti utilizzare in una situazione del genere sono i metadati degli articoli (post meta). Puoi ordinare per metadati, e sono unici per ogni articolo.
Nota: Detto questo, è possibile ordinare per tassonomia creando una query SQL personalizzata utilizzando un filtro, ma non puoi farlo da una WP_Query non modificata: http://scribu.net/wordpress/sortable-taxonomy-columns.html
Tuttavia, se devi ricorrere a fare questo tipo di cosa, allora la struttura del tuo design dei dati è sbagliata fin dall'inizio. I "termini" nella tassonomia non sono veri e propri "dati". I termini stessi non hanno un significato intrinseco, sono solo etichette per il particolare raggruppamento che descrivono. Se li tratti come dati significativi, allora hai un difetto di progettazione sottostante.
Le tassonomie raggruppano elementi assegnando loro dei termini. Questo raggruppamento è lo scopo principale delle tassonomie, i termini sono solo facce carine sul raggruppamento. Se hai metadati significativi da assegnare a un articolo, dovresti invece utilizzare i metadati (post meta). E quelli puoi ordinarli, perché i metadati utilizzano sia chiavi che valori per memorizzare informazioni. Con una tassonomia, stai davvero memorizzando solo chiavi, con i loro valori rappresentati dagli articoli raggruppati da quel termine.
Le cose sono più facili a lungo termine se utilizzi l'approccio corretto. Non sto dicendo che non puoi fare qualcosa di strano con le tassonomie, ma ti stai solo complicando la vita a lungo termine utilizzandole in modo errato.

Ciao Otto, grazie per la risposta. Capisco il tuo punto di vista e forse sto prendendo la strada sbagliata con questo approccio. Nel mio esempio di un sito di serie TV, ho una tassonomia per serie 1, serie 2, serie 3 ecc... In questo modo posso raggruppare tutte le diverse serie TV per numero di stagione. Poi ho lo stesso per gli episodi, Episodio 01, Episodio 02, ecc... Quello che vorrei è che quando mostro un elenco di tutti gli episodi, siano ordinati per episodio e serie. Analizzerò poi i post meta e i campi personalizzati. Grazie Otto.

@yeope la tua tassonomia dovrebbe essere "series" e i tuoi termini dovrebbero essere serie 1, serie 2 ecc. Per gli episodi, presumo che una serie contenga più episodi quindi potrebbe usare la stessa tassonomia "series" e se sono gerarchici allora episodio 1, episodio 2 ecc avrebbero come termine genitore "serie x". In questo modo potresti interrogare un'intera serie in ordine con gli episodi che cadono al posto giusto.

@Chris_O Capisco, potresti aver centrato il problema! L'unico problema che vedo è il fatto di dover ripetere i termini "Episodio 1", "Episodio 2" per ogni serie. Inoltre non poter raggruppare tutti gli episodi 1 indipendentemente dalla serie, ma penso che probabilmente ci sia un modo per aggirare il problema. Grazie Chris_O

Utilizzare una tassonomia per gli episodi non ha molto senso, in realtà, perché il raggruppamento è inutile. Pensaci, se hai "episodio 1" come termine, allora stai raggruppando l'episodio 1 con ogni altro episodio 1 di ogni altra serie TV. I numeri dell'episodio e della serie hanno più senso come post_meta, perché sono specifici per quella particolare serie e non utili come gruppo. Il nome della serie TV sarebbe utile come termine in una tassonomia tv-show, perché così stai raggruppando l'intera serie insieme.

Ma una tassonomia per le serie in un certo senso funziona, ma solo perché raggruppa insieme le serie in una stagione o qualcosa del genere, anche se dovresti interrogarla insieme alla tassonomia tv-show. In una tale tassonomia di serie, i tuoi termini sarebbero 1, 2, 3, che rappresentano il numero della stagione a cui appartiene la serie. Ma vorresti comunque queste informazioni più come postmeta, dato che vuoi ordinarle in base a questo. E poiché puoi anche interrogare i postmeta, non ha molto senso duplicarli come tassonomia.

Otto ha seguito questo con un interessante post sul blog: Quando (non) usare una Tassonomia Personalizzata.

@otto Grazie per aver condiviso questo, è davvero utile approfondire un po' di più le tassonomie e i loro utilizzi. In particolare, sono interessato a conoscere il tuo pensiero su una situazione come quella descritta nel post Colonne di Tassonomia Ordinabili. Quale sarebbe la soluzione migliore quando voglio sia poter interrogare tutti i post in una gamma di colori, ma anche voler ordinare per colore? Forse sarebbe meglio come domanda separata...

Se vuoi ordinare per questo, allora dovrebbe davvero essere un meta piuttosto che una tassonomia. Ordinare per tassonomia non ha molto senso, realisticamente.

Grazie @Otto. Anche se non sono d'accordo con la tua affermazione: "Tuttavia, se devi ricorrere a fare questo genere di cose, allora la struttura del tuo design dei dati è sbagliata fin dall'inizio"... Potrebbe essere utile poter riordinare la lista dei post per termine di categoria nella parte admin...

@ClemC Non ha molto senso. I post possono avere più categorie. In base a cosa li stai ordinando? Qual è il tuo criterio di ordinamento secondario quando due post hanno la stessa categoria? Questo è il tipo di problema in cui ti imbatti, le tassonomie sono solo raggruppamenti, il "termine" è solo una bella facciata per quel raggruppamento, non è la parte importante. La parte importante è il gruppo stesso. Non ordineresti i nomi degli animali in ordine alfabetico in base alla loro tassonomia linneana. Non ti aiuterebbe.

Ciao @Otto, hai ragione. Ho preso come riferimento il caso del mio progetto attuale che è abbastanza particolare... Un CPT (film) che permette solo un singolo termine di una tassonomia personalizzata (festival) con pulsanti radio per la sua selezione. L'ordine predefinito della lista del CPT è per termine (festival) che in questo caso particolare è abbastanza logico, no? Non riesco a pensare a un approccio migliore riguardo al "design dei dati"... Ho implementato i "festival" come una tassonomia perché l'unico dato di cui hanno bisogno è la loro descrizione e raggruppa logicamente i "film". PS: Scusa per il mio inglese.

Sì, giusto, ma allora è un gruppo. Stai raggruppando le cose insieme. Cosa significa "ordina per" in un tale contesto? Se hai un insieme di elementi nello stesso gruppo, allora puoi "selezionare per" quel gruppo, e questo ha senso, ma "ordinare" è qualcosa di totalmente diverso. Si ordina in base a campi che hanno valori diversi, non per campi che hanno tutti gli stessi valori.

Scusa @Otto, solo ora noto la tua risposta... Sono totalmente d'accordo con i tuoi punti semantici e logici. Ma nel mio contesto, "ordinare per" sarebbe principalmente una questione ergonomica. Raggruppare visivamente le proiezioni per "festival" potrebbe aiutare in modo significativo l'utente a ottenere a colpo d'occhio un riepilogo visivo basato sul fattore più importante per lui. Quindi, non sono sicuro di poter ottenere questo in qualche altro modo che non sia "ordinando", il che concordo non sia un termine appropriato...

Arrivo un po' in ritardo qui, ma c'è un modo più semplice e più WordPress per fare questo.
Crea la tua tax query come al solito.
$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;
Configura i tuoi argomenti per query_posts o WP_Query
$args = array(
'post_type'=>'post',
'posts_per_page'=>12,
'paged'=>$paged,
'tax_query' => $tax_query,
);
Prima di effettuare la chiamata query_posts / WP_Query, agganciati al filtro orderby e sovrascrivilo
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');
non dimenticare di rimuovere il filtro successivamente...
questo funziona perché la tax_query crea i join etc per te, devi solo ordinare per uno dei campi del join.

Qualche idea su come ordinare per nome invece che per term_taxonomy_id? Cambiare term_taxonomy_id in orderby_statement genera errori

@tehlivi questo metodo non funziona per l'ordinamento per nome perché il nome si trova nella tabella wp_terms
. WordPress sembra memorizzare nella cache i termini della tassonomia, quindi anche se la tua query tassonomica cerca per slug o nome, che sono anch'essi nella tabella wp_terms
, WordPress li elabora attraverso la sua lista memorizzata e li sostituisce con gli ID archiviati in term_relationships.term_taxonomy_id
, così non deve interrogare la tabella wp_terms
come parte della query principale. Ciò significa che né il nome né lo slug sono inclusi nella query SQL risultante. Devi aggiungere dei join.

@EthanC ehi amico, grazie per la tua risposta dettagliata, e spero che se qualcuno la troverà in futuro, troverà utile la tua risposta. Ma per quanto mi riguarda, è sicuramente difficile ricordare qualsiasi cosa del 2016. Penso di aver finito per far passare l'array attraverso una funzione di ordinamento dopo il completamento della query. Sono sicuro che qualsiasi sviluppatore che ha preso in carico quel progetto dopo che ho lasciato l'azienda mi odia. Ah ah.

@tehlivi Sì, alla fine ho ignorato completamente la query principale nel caso in cui alcuni post fossero assegnati a più termini. Ho preferito invece eseguire get_terms()
e poi get_posts
per ogni termine. Ho aggiunto circa 15 query al caricamento della pagina, ma ho ottenuto il risultato che il designer voleva.

Non sono sicuro del perché tutte le soluzioni qui siano eccessivamente complicate. OK, è passato mezzo decennio, ma sto eseguendo il seguente codice attualmente e funziona:
<?php // Default
$wheels_args = array(
'post_type' => 'wheels',
'posts_per_page' => '96',
'orderby' => 'taxonomy, name', // Basta inserire 2 parametri qui, separati da virgola
'order'=>'ASC'
);
$loop = new WP_Query($wheels_args);
?>
Questo ordinerà prima le tassonomie del tuo CPT (Custom Post Type) per tassonomia in ordine alfabetico e all'interno di questi gruppi di tassonomia anche per ordine alfabetico.

@yeope Perché questa è la risposta accettata!? grazie al cielo ho fatto scorrere la pagina

non sono riuscito a farlo funzionare. puoi indicare un sito con qualche spiegazione a riguardo? niente qui, che supporti il tuo codice

Non viene analizzato, specialmente con questa virgola, e viene ignorato da WP (6.x).

Vorrei condividere la mia esperienza nell'ordinamento di custom post type per categoria/tassonomia.
IL SITO WEB
- Un sito web di un'agenzia di viaggi basato su WordPress
- Contenuto principale su un custom post type chiamato 'ruta'
- Tassonomia con questa struttura Tipo-di-viaggio > continente > paese
IL CASO
Nelle pagine di archivio delle categorie, il cliente voleva che i post fossero ordinati per:
- Continente, ordinati per numero di rotte in ciascuno
- Paese, ordinati alfabeticamente
I PASSAGGI
Primo, ho catturato la richiesta dalla query della pagina di archivio non modificata che risultava essere così:
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
Secondo, ho modificato il codice SQL in Sequel Pro contro il database per adattarlo alle mie esigenze. Sono arrivato a questo (sì, probabilmente può essere migliorato: la mia conoscenza di MySQL non è eccezionale):
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
Terzo, ho agganciato la query nel file functions.php con tre filtri: posts_fields, posts_join e posts_orderby
Il codice in 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;
}
Infine ho attivato i filtri dall'hook pre_get_post in base ad alcune condizioni
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');
Spero che questo possa aiutare qualcuno

Ho affrontato un problema molto simile: volevo ordinare un archivio di un custom post-type (articoli di rivista) in base a una tassonomia personalizzata (numeri della rivista). Non eseguo mai query SQL dirette sul mio sito - e di solito, se sei come queste altre risposte, dovresti ripensare al tuo approccio.
PROBLEMI:
1) WordPress non permette di ordinare le tassonomie in modo intelligente.
2) WordPress semplicemente non consente l'uso di orderby
con le tassonomie nelle query WP_Query per i post-type (come chiaramente spiegato da Otto).
SOLUZIONI:
1) L'ordinamento delle tassonomie si ottiene al meglio con il plugin Custom Taxonomy Order NE al momento. Ti permette di ordinare la tassonomia tramite un editor WYSIWYG in wp-admin
, non è il modo in cui lo farei io ma non ho trovato nulla di meglio.
Quando configuri il plugin, otterrai qualcosa di simile a quello che ho fatto qui. Prendi nota dell'opzione Auto-sort Queries of this Taxonomy
- impostala su Custom Order as Defined Above
; questo ti darà l'ordinamento di cui hai bisogno. Screenshot:
2) Con una tassonomia ordinata, puoi ora creare una serie di chiamate WP_Query che scorrono ogni termine, creando effettivamente un archivio ordinato per tassonomia. Usa get_terms()
per creare un array di tutti i termini della tassonomia, poi esegui un foreach
su ogni termine. Questo crea una WP_Query
per ogni termine che restituirà tutti i post per quel termine, creando un archivio ordinato per termini di tassonomia. Codice per implementarlo:
// Ottieni i termini e inseriscili in un array
$issue_terms = get_terms([
'taxonomy' => 'issues',
'hide_empty' => false,
]);
// Esegui foreach su ogni termine per impostare query e visualizzazione post
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'
)
)
) );
// Esegui loop su ogni query
while($the_query->have_posts()) :
$the_query->the_post();
// IL TUO TEMPLATE DI OUTPUT PER OGNI POST
endwhile;
}
Letture correlate su questo sito: Mostra tutti i post in un custom post-type, raggruppati per una tassonomia personalizzata

Ecco la soluzione che ho utilizzato per questo problema specifico. Questa soluzione è per casi estremi in cui non è possibile utilizzare un filtro pre_get_posts
e c'è già una paginazione esistente nella query (ad esempio in 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})"; // Aggiungi ulteriori ordinamenti specifici qui
$results = $wpdb->get_results($term_sql, ARRAY_A);
Ho utilizzato questo codice per creare un menu di navigazione ordinato per tassonomia, termine e conteggio di post per termine.
Se vuoi semplicemente ottenere i post, modifica la query in SELECT p.*
e GROUP BY p.ID

Mi piace ordinare i miei termini manualmente, quindi uso un plugin per farlo. Sono un fan del filtro pre_get_posts
, quindi ho preso l'esempio funzionante di Drew Gourley e l'ho adattato per farlo funzionare con quello. Questo è un caso un po' particolare, ma lo posto comunque nel caso possa aiutare qualcuno. Il codice seguente va inserito in functions.php o in un plugin personalizzato.
Iniziamo con il filtro. Ordiniamo il custom post type music
per la tassonomia personalizzata 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');
Poi chiamiamo il filtro 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);
Ora tutto ciò che devi fare è ordinare le tue tassonomie con il seguente plugin: Simple Custom Post Order. Questo plugin è obbligatorio per questa soluzione, poiché aggiunge la colonna term_order
al database!
E questa riga qui:
$clauses['orderby'] .= ", {$wpdb->posts}.post_name ASC"
ordina i post per titolo, quindi l'ordinamento completo della soluzione sopra è: termine della tassonomia => titolo del post.

Grazie mille, questo è molto utile. È fantastico avere un modo per ordinare visivamente. Sai perché c'è la parte "OR taxonomy IS NULL"? Sembra qualcosa che non è necessario.

Mostra correttamente il primo termine, ma dopo quei post il termine successivo non segue logicamente l'ordine del menu come impostato con SCP Order. Mi chiedo se sia perché sto provando a farlo con i prodotti, e WooCommerce ha già un ordinamento degli attributi... forse i due sono in conflitto. Nel database però gli ID nella colonna term_order sono corretti...

Un modo abbastanza semplice per farlo è aggiungere una funzione che dice:
- Quando il tuo articolo viene pubblicato...
- Ottieni l'ID/slug/ecc. della tua categoria...
- Salvalo come valore meta personalizzato per il tuo articolo
E poi, nel tuo loop, ordina gli articoli in base a quel valore meta.
Quindi:
// 1
add_action( 'publish_post', 'save_and_add_meta' );
function save_and_add_meta($post_id){
//Rimuovi temporaneamente l'azione per evitare un loop infinito
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);
//Aggiungi di nuovo l'azione
add_action( 'publish_post', 'save_and_add_meta' );
}
Poi nella tua query WP aggiungi nei tuoi $args:
'meta_key' => 'cat_slug',
'orderby' => 'meta_value',
'order' => 'DESC',
Questo funziona se riesci a trovare un modo per limitare gli utenti ad assegnare solo una categoria per articolo, o se le tue categorie si escludono a vicenda. Se assegnano più di una categoria, però, l'articolo verrebbe escluso da una di esse.

È come una query prima della query, ma non sarà un problema se non stiamo interrogando troppi articoli... L'idea è modificare la query principale così da non dover nemmeno passare ai template e generare nuove query e loop...
function grouped_by_taxonomy_main_query( $query ) {
if ( $query->is_home() && $query->is_main_query() ) { // Esegui solo nella 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, // come preferisci...
'post_type' => 'my_custom_post_type', // Se necessario... Di default è 'posts'
'fields' => 'ids', // vogliamo solo gli ID da usare dopo in 'post__in'
'tax_query' => array( array( 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id, )))) // otteniamo gli articoli nel termine corrente
);
}
$query->query_vars['post_type'] = 'my_custom_post_type'; // Ancora, se necessario... Di default è 'posts'
$query->query_vars['posts_per_page'] = 16; // Se necessario...
$query->query_vars['post__in'] = $post_ids; // Filtriamo con gli ID degli articoli ottenuti sopra
$query->query_vars['orderby'] = 'post__in'; // Manteniamo l'ordine generato nel loop dei termini
$query->query_vars['ignore_sticky_posts'] = 1; // Se non vuoi che gli sticky post alterino l'ordine
}
}
// Aggancio la mia funzione sopra all'azione pre_get_posts
add_action( 'pre_get_posts', 'grouped_by_taxonomy_main_query' );

Questo causerà un errore, non puoi utilizzare get_posts o WP_Query all'interno di pre_get_posts, creerà un loop infinito. Perché quando usi get_posts o WP_Query, verrà attivato l'hook pre_get_posts e questo causerà un loop infinito, anche se controlli is_main_query, non si fermerà e continuerà a eseguirsi all'infinito.

Alcune risposte sono piuttosto complesse, ho scritto questa soluzione che è abbastanza basilare da comprendere (penso/spero):
$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);
Ora la variabile $result
contiene tutti gli ID dei post, ordinati in modo ascendente per il nome della tassonomia personalizzata.
Attenzione: se un post contiene più categorie, è necessaria una soluzione diversa.
Puoi utilizzare gli ID in una funzione foreach, qualcosa come questo:
foreach($result as $id){
$image = get_the_post_thumbnail($id);
...ecc.
}
oppure puoi effettuare una seconda query in questo modo:
$loopnew = new WP_Query(array('post_type' => 'Teammember','post__in'=> $result));
if ( $loopnew->have_posts() ) {
while ( $loopnew->have_posts() ) {
$loopnew->the_post();
...ecc.
}
}

È piuttosto fastidioso che WordPress non ti permetta di farlo e ti obblighi praticamente ad avere due campi con le stesse informazioni..
MA posterò qui la mia soluzione. L'idea è di passare tutti i termini delle tassonomie selezionate alle meta informazioni del post.
(Attenzione, devi modificarlo se la tua tassonomia accetta più valori)
//aggiungi questo hook per salvare automaticamente i termini come meta dati del post quando salvi un 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);
}
}
Dopo aver inserito questo nel tuo functions.php puoi usare meta_key e orderby come al solito per ordinare i tuoi post così:
'meta_key' => TUA-TASSONOMIA,
'orderby' => array(
'meta_value' => 'ASC'
)
Spero che questo sia utile a qualcuno.
