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->ID
s pentru toate articolele din taxonomia ta și apoi trece-le folosind argumentul'post__id'
, sauAdnotează SQL-ul folosit de
WP_Query
cu unul dintre hook-urile care îți permit să adaugi unINNER JOIN
SQL 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-ID
s 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.

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.

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

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ă.

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 - 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... :)

A funcționat! Mulțumesc mult pentru ajutor. Îmi place să învăț trucuri noi în WordPress, mai ales cele orientate pe obiect.

@Dave Morris - Cu plăcere. Apropo, tocmai am aflat că în WP 3.1 se va numi 'ignore_sticky_posts'
.

@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

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?

@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ă.

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 - 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.

Î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
