Interogare WP_Query pentru taxonomie personalizată cu toate termenii dintr-o taxonomie?
Există o modalitate simplă de a interoga toate articolele care sunt etichetate cu orice termen dintr-o taxonomie specifică?
Cunosc această tehnică:
$custom_taxonomy_query = new WP_Query(
array(
'taxonomy_name' => 'term_slug',
)
);
Dar aș dori să pot folosi fie un wildcard în locul term_slug, fie poate doar un șir gol. Astfel aș putea obține toate articolele care sunt etichetate cu orice termen din acea taxonomie, nu doar cu un termen specific.
Mulțumesc pentru ajutor, Dave
Am întâlnit o situație similară, Dave. Acest cod a funcționat pentru nevoile mele. Nu este cea mai elegantă soluție, dar își face treaba:
// Obține toate ID-urile de termeni dintr-o taxonomie dată
$taxonomy = 'nume_taxonomie';
$taxonomy_terms = get_terms( $taxonomy, array(
'hide_empty' => 0,
'fields' => 'ids'
) );
// Folosește noul argument tax_query pentru WP_Query (disponibil din versiunea 3.1)
$taxonomy_query = new WP_Query( array(
'tax_query' => array(
array(
'taxonomy' => $taxonomy,
'field' => 'id',
'terms' => $taxonomy_terms,
),
),
) );
Sper că acest lucru te va ajuta pe tine sau pe alții care întâmpină aceeași problemă.
Kevin
Ceva de genul acesta ar putea funcționa:
$args = array(
'post_type' => 'post',
'tax_query' => array(
array(
'taxonomy' => 'your_custom_taxonomy',
'operator' => 'EXISTS'
),
),
);
$query = new WP_Query( $args );
În esență, ceri orice articol atribuit oricărui termen din your_custom_taxonomy.
Salut @Dave Morris:
Ai dreptate, WordPress decide că dacă nu ai un termen, pur și simplu va ignora taxonomia ta.
Există trei (3) abordări principale pe care le poți încerca:
Folosește o interogare SQL completă cu
$wpdb->get_results(),Obține o listă de
$post->IDs pentru toate articolele din taxonomia ta și apoi trece-le folosind argumentul'post__id', sauAdnotează SQL-ul folosit de
WP_Querycu unul dintre hook-urile care îți permit să adaugi unINNER JOINSQL referindu-te la tabelele de taxonomie.
Încerc să evit SQL-ul complet în WordPress până când nu se poate altfel sau până când returnează doar o listă de ID-uri. Și în acest caz, aș evita să extrag o listă de $post-IDs pentru a le folosi cu argumentul 'post__id' pentru că ar putea întâmpina probleme de performanță și chiar probleme de memorie dacă ai multe articole. Așa că ne rămâne varianta #3.
Am creat o clasă pentru a extinde WP_Query numită PostsByTaxonomy care folosește hook-ul 'posts_join'. O poți vedea aici:
class PostsByTaxonomy extends WP_Query {
var $posts_by_taxonomy;
var $taxonomy;
function __construct($args=array()) {
add_filter('posts_join',array(&$this,'posts_join'),10,2);
$this->posts_by_taxonomy = true;
$this->taxonomy = $args['taxonomy'];
unset($args['taxonomy']);
parent::query($args);
}
function posts_join($join,$query) {
if (isset($query->posts_by_taxonomy)) {
global $wpdb;
$join .=<<<SQL
INNER JOIN {$wpdb->term_relationships} ON {$wpdb->term_relationships}.object_id={$wpdb->posts}.ID
INNER JOIN {$wpdb->term_taxonomy} ON {$wpdb->term_taxonomy}.term_taxonomy_id={$wpdb->term_relationships}.term_taxonomy_id
AND {$wpdb->term_taxonomy}.taxonomy='{$this->taxonomy}'
SQL;
}
return $join;
}
}
Ai putea apela această clasă așa cum vezi mai jos. Argumentul 'taxonomy' este obligatoriu dar poți pasa oricare (toate?) dintre ceilalți parametri pe care WP_Query îi așteaptă, cum ar fi 'posts_per_page':
$query = new PostsByTaxonomy(array(
'taxonomy' => 'category',
'posts_per_page' => 25,
));
foreach($query->posts as $post) {
echo " {$post->post_title}\n";
}
Poți copia clasa PostsByTaxonomy în fișierul functions.php al temei tale, sau o poți folosi într-un fișier .php al unui plugin pe care îl scrii.
Dacă vrei să o testezi rapid, am postat o versiune independentă a codului pe Gist pe care o poți descărca și copia în root-ul serverului tău web ca test.php, modifică pentru cazul tău de utilizare, și apoi solicit-o din browser folosind un URL precum http://example.com/test.php.
ACTUALIZARE
Pentru a exclude Articolele Lipicioase din articolele incluse în interogare, încearcă asta:
$query = new PostsByTaxonomy(array(
'taxonomy' => 'category',
'posts_per_page' => 25,
'caller_get_posts' => true,
));
Sau dacă este important pentru tine ca clasa PostsByTaxonomy să nu includă niciodată articole lipicioase, ai putea pune asta în constructor:
function __construct($args=array()) {
add_filter('posts_join',array(&$this,'posts_join'),10,2);
$this->posts_by_taxonomy = true;
$this->taxonomy = $args['taxonomy'];
$args['caller_get_posts'] = true // Fără Articole Lipicioase
unset($args['taxonomy']);
parent::query($args);
}
ACTUALIZARE 2
După ce am postat cele de mai sus, am aflat că 'caller_get_posts' va fi depreciat și 'ignore_sticky_posts' va fi folosit în WordPress 3.1.
Mike, Mulțumesc pentru ajutor. Din anumite motive, nu reușesc să fac asta să funcționeze. Nu returnează doar postările care au termeni atribuiți din taxonomia mea personalizată. Pare să returneze întotdeauna și alte postări. Cu toate acestea, nu returnează toate postările, deci cu siguranță face ceva... Pot folosi funcția $query->have_posts() pentru a itera? Niciuna dintre metode nu pare să funcționeze pentru mine, în niciun caz.
Dave Morris
Ah, asta este interesant. Am găsit în jurnalul mysql interogarea care obține cele două postări pe care le aștept și funcționează. Dar, din anumite motive, când parcurg $query->posts, se întorc cinci postări. Singurul alt lucru pe care îl observ este că imediat după ce rulează interogarea pentru postările din taxonomia personalizată, rulează o altă interogare care preia încă trei postări, după post_id. Și apoi cred că toate cele cinci postări sunt puse într-un singur array de rezultate.
Dave Morris
Cred că am înțeles. Această interogare personalizată pare să includă postări lipicioase (sticky posts), chiar dacă acestea nu sunt în acea taxonomie personalizată. Ai idei despre cum să respectăm corect postările lipicioase sau măcar cum să le eliminăm din această interogare specifică? Mulțumesc, Dave
Dave Morris
Ei sunt "lipicioși", nu-i așa? :)
E un comportament ciudat, cred, dar dacă folosești caller_get_posts=1 ar trebui să dispară:
http://codex.wordpress.org/Function_Reference/query_posts#Sticky_Post_Parameters
Sper că te ajută.
MikeSchinkel
Acel if(isset($query->posts_by_taxonomy)) este un truc drăguț pentru a combina metodologia orientată pe obiecte cu metodologia de hook-uri din WordPress.
Jan Fabry
@Jan Fabry - Da, mulțumesc! Mi-a luat cam 2 ani de încercări și erori până să-mi vină ideea. Bineînțeles acum pare evident... :)
MikeSchinkel
A funcționat! Mulțumesc mult pentru ajutor. Îmi place să învăț trucuri noi în WordPress, mai ales cele orientate pe obiect.
Dave Morris
@Dave Morris - Cu plăcere. Apropo, tocmai am aflat că în WP 3.1 se va numi 'ignore_sticky_posts'.
MikeSchinkel
@MikeSchinkel Dar ce zici de paginare, asta funcționează bine dar paginarea pentru această interogare nu merge cum ar trebui în cazul meu... http://wordpress.stackexchange.com/q/57884/12261
Ajay Patel
Ar trebui să poți seta taxonomia și să excludeți un termen..
De exemplu:
<?php
$your_query = new WP_query;
$your_query->query( array( 'taxonomy' => 'numele-taxonomiei-tale' ) );
?>
Ceea ce ar fi practic același lucru ca interogarea pe care o execută o arhivă de taxonomie.
Linia 1432 din query.php verifică dacă taxonomia SAU termenul sunt goale, deci nu poți să nu transmiți un slug... Alte idei?
Dave Morris
@t31os - A fost și prima mea reacție; de fapt, am dat peste asta de mai multe ori pentru că tot uit. Dar @Dave Morris are dreptate; dacă nu este o pereche taxonomie/termen, atunci WP_Query pur și simplu o ignoră.
MikeSchinkel
Wow, nu știam asta, e cam aiurea... lecție învățată... :) Mă așteptam pe jumătate să se comporte ca parametrii meta_key / meta_value (nu știu de ce)..
t31os
@t31os - Da, WP_Query nu este implementat din păcate într-un mod atât de elegant. Sunt aproape 1200 de linii de cazuri speciale hardcodate.
MikeSchinkel
În retrospectivă, am combinat sugestiile lui MikeSchinkel și t31os. Este posibil să injectați acest lucru în interogările existente pe loc, dar necesită WordPress 3.1:
Plugin pentru a obține un flux RSS pentru articole care conțin orice termen dintr-o taxonomie