Este posibil să obții get_terms după taxonomie ȘI post_type?
Am 2 tipuri de postări personalizate 'bookmarks' și 'snippets' și o taxonomie comună 'tag'. Pot genera o listă cu toți termenii din taxonomie folosind get_terms(), dar nu reușesc să găsesc o modalitate de a limita lista la tipul de postare. În principiu, caut ceva de genul acesta:
get_terms(array('taxonomy' => 'tag', 'post_type' => 'snippet'));
Există vreo modalitate de a realiza acest lucru? Orice idei sunt apreciate!!
Ah, folosesc WP 3.1.1

S-a întâmplat să am nevoie de ceva similar pentru un proiect la care lucrez. Am scris pur și simplu o interogare pentru a selecta toate articolele de un tip personalizat, apoi am verificat ce termeni ai taxonomiei mele sunt folosiți efectiv.
Apoi am obținut toți termenii acelei taxonomii folosind get_terms()
și am utilizat doar cei care se aflau în ambele liste, am încapsulat totul într-o funcție și am terminat.
Dar apoi am avut nevoie de mai mult decât doar ID-uri: aveam nevoie de nume, așa că am adăugat un nou argument numit $fields
pentru a putea specifica ce să returneze funcția. Apoi mi-am dat seama că get_terms
acceptă multe argumente, iar funcția mea era limitată la termenii folosiți de un tip de postare, așa că am adăugat încă o condiție if
și iată rezultatul:
Funcția:
/* obține termenii limitați la un tip de postare
@ $taxonomies - (string|array) (obligatoriu) Taxonomiile din care se extrag termenii.
@ $args - (string|array) toate argumentele posibile ale get_terms http://codex.wordpress.org/Function_Reference/get_terms
@ $post_type - (string|array) tipuri de postare pentru a limita termenii
@ $fields - (string) Ce să returneze (implicit 'all') acceptă ID, name, all, get_terms.
dacă doriți să utilizați argumentele get_terms, atunci $fields trebuie setat la 'get_terms'
*/
function get_terms_by_post_type($taxonomies,$args,$post_type,$fields = 'all'){
$args = array(
'post_type' => (array)$post_type,
'posts_per_page' => -1
);
$the_query = new WP_Query( $args );
$terms = array();
while ($the_query->have_posts()){
$the_query->the_post();
$curent_terms = wp_get_object_terms( $post->ID, $taxonomy);
foreach ($curent_terms as $t){
//evită duplicatele
if (!in_array($t,$terms)){
$terms[] = $c;
}
}
}
wp_reset_query();
//returnează array de obiecte termen
if ($fields == "all")
return $terms;
//returnează array de ID-uri de termeni
if ($fields == "ID"){
foreach ($terms as $t){
$re[] = $t->term_id;
}
return $re;
}
//returnează array de nume de termeni
if ($fields == "name"){
foreach ($terms as $t){
$re[] = $t->name;
}
return $re;
}
// obține termeni cu argumentele get_terms
if ($fields == "get_terms"){
$terms2 = get_terms( $taxonomies, $args );
foreach ($terms as $t){
if (in_array($t,$terms2)){
$re[] = $t;
}
}
return $re;
}
}
Utilizare:
Dacă aveți nevoie doar de o listă de ID-uri de termeni:
$terms = get_terms_by_post_type('tag','','snippet','ID');
Dacă aveți nevoie doar de o listă de nume de termeni:
$terms = get_terms_by_post_type('tag','','snippet','name');
Dacă aveți nevoie doar de o listă de obiecte termen:
$terms = get_terms_by_post_type('tag','','snippet');
Și dacă trebuie să utilizați argumente suplimentare ale get_terms precum: orderby, order, hierarchical ...
$args = array('orderby' => 'count', 'order' => 'DESC', 'hide_empty' => 1);
$terms = get_terms_by_post_type('tag',$args,'snippet','get_terms');
Bucurați-vă!
Actualizare:
Pentru a corecta numărul de termeni pentru un tip specific de postare, schimbați:
foreach ($current_terms as $t){
//evită duplicatele
if (!in_array($t,$terms)){
$terms[] = $t;
}
}
cu:
foreach ($current_terms as $t){
//evită duplicatele
if (!in_array($t,$terms)){
$t->count = 1;
$terms[] = $t;
}else{
$key = array_search($t, $terms);
$terms[$key]->count = $terms[$key]->count + 1;
}
}

nu ar fi mai bine să folosești (array) $args
în loc de o listă de 4 $vars? Asta ar permite să nu te mai gândești la ordinea în care introduci argumentele, deci ceva de genul get_terms_by_post_type( $args = array( 'taxonomies', 'args', 'post_type', 'fields' => 'all') )
și apoi să le apelezi în interiorul funcției cu $args['taxonomies']
. Asta te-ar ajuta să eviți adăugarea de valori goale și să nu fii nevoit să-ți amintești ordinea argumentelor. Aș sugera și să folosești ghilimele simple în loc de cele duble. Am văzut că pot fi de până la cinci ori mai rapide.

@kaiser - Șirurile de caractere cu ghilimele duble trebuie parsate, în timp ce valorile cu ghilimele simple sunt întotdeauna tratate ca literale. Când folosești variabile într-un șir de caractere are sens și este perfect în regulă să folosești ghilimele duble, dar pentru valori de șir fără variabile, ghilimele simple sunt mai ideale (pentru că nu vor trebui parsite) și puțin mai rapide (vorbim de milisecunde în majoritatea cazurilor).

@t31os - Absolut corect. Eu tot prefer 'aceasta este starea mea: '.$value
în loc de "aceasta este starea mea: $value"
, din cauza lizibilității. Când vine vorba de viteză: Nu este puțin - am măsurat până la cinci ori mai rapid. Și când folosești ghilimele duble în întreaga temă peste tot, ele se adună rapid când ai multe solicitări. Oricum, bine că ai clarificat asta.

@t31os După o discuție, am măsurat din nou viteza dintre "
și '
și am greșit. Diferența este mult dincolo de orice ce ar putea observa cineva.

Excelentă întrebare și răspunsuri solide.
Mi-a plăcut foarte mult abordarea lui @jessica folosind filtrul terms_clauses, deoarece extinde funcția get_terms într-un mod foarte rezonabil.
Codul meu este o continuare a ideii ei, cu o parte din sql de la @braydon pentru a reduce duplicatele. De asemenea, permite utilizarea unui array de post_types:
/**
* my_terms_clauses
*
* filtrează clauzele termenilor
*
* @param $clauses array
* @param $taxonomy string
* @param $args array
* @return array
**/
function my_terms_clauses($clauses, $taxonomy, $args)
{
global $wpdb;
if ($args['post_types'])
{
$post_types = implode("','", array_map('esc_sql', (array) $args['post_types']));
// permite array-uri
if ( is_array($args['post_types']) ) {
$post_types = implode( "','", $args['post_types'] );
}
$clauses['join'] .= " INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id";
$clauses['where'] .= " AND p.post_type IN ('". $post_types. "') GROUP BY t.term_id";
}
return $clauses;
}
add_filter('terms_clauses', 'my_terms_clauses', 99999, 3);
Deoarece get_terms nu are o clauză pentru GROUP BY, a trebuit să o adaug la sfârșitul clauzei WHERE. Observați că am setat prioritatea filtrului foarte mare, în speranța că va rula întotdeauna ultimul.

Ar trebui să înlocuiești $post_types = $args['post_types'];
cu $post_types = implode("','", array_map('esc_sql', (array) $args['post_types']));
și să elimini esc_sql()
din clauza IN
altfel această clauză va avea \'
între tipurile de postări atunci când furnizezi mai multe tipuri de postări în $args['post_types']

Singura soluție care mi-a permis să folosesc get_terms și a funcționat pentru mine în 2022

Iată o altă metodă de a face ceva similar, folosind o singură interogare SQL:
static public function get_terms_by_post_type( $taxonomies, $post_types ) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT t.*, COUNT(*) from $wpdb->terms AS t
INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id
WHERE p.post_type IN('%s') AND tt.taxonomy IN('%s')
GROUP BY t.term_id",
join( "', '", $post_types ),
join( "', '", $taxonomies )
);
$results = $wpdb->get_results( $query );
return $results;
}

print_r(get_terms_by_post_type(array('category') , array('event') ));
afișează Warning: Missing argument 2 for wpdb::prepare()

S-ar putea să greșesc, dar din capul locului, nu cred că acele instrucțiuni 'join' vor funcționa - adică, ar funcționa doar dacă sunt transmise array-uri cu o singură valoare. Acest lucru se întâmplă pentru că funcția prepare ar escapa toate ghilimelele simple generate și ar considera fiecare instrucțiune 'join' întreagă ca un singur șir de caractere.

Am scris o funcție care permite să transmiți post_type
în array-ul $args
către funcția get_terms()
:
HT lui @braydon pentru scrierea SQL-ului.
/**
* terms_clauses
*
* filtrează clauzele de termeni
*
* @param $clauses array
* @param $taxonomy string
* @param $args array
* @return array
**/
function terms_clauses($clauses, $taxonomy, $args)
{
global $wpdb;
if ($args['post_type'])
{
$clauses['join'] .= " INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id";
$clauses['where'] .= " AND p.post_type='{$args['post_type']}'";
}
return $clauses;
}
add_filter('terms_clauses', 'terms_clauses', 10, 3);

Nu am reușit să fac argumentele get_terms să funcționeze cu versiunea lui Gavin a codului de mai sus, dar în final am reușit prin schimbarea
$terms2 = get_terms( $taxonomy );
în
$terms2 = get_terms( $taxonomy, $args );
așa cum era în funcția originală de la Bainternet.

@Bainternet: Mulțumesc! A trebuit să modific ușor funcția pentru că nu funcționa (avea câteva greșeli de tipar). Singura problemă acum este că numărarea termenilor nu este corectă. Numărarea nu ține cont de tipul de postare, așa că nu cred că poți folosi get_terms() în acest caz.
function get_terms_by_post_type($post_type,$taxonomy,$fields='all',$args){
$q_args = array(
'post_type' => (array)$post_type,
'posts_per_page' => -1
);
$the_query = new WP_Query( $q_args );
$terms = array();
while ($the_query->have_posts()) { $the_query->the_post();
global $post;
$current_terms = get_the_terms( $post->ID, $taxonomy);
foreach ($current_terms as $t){
//evită duplicatele
if (!in_array($t,$terms)){
$t->count = 1;
$terms[] = $t;
}else{
$key = array_search($t, $terms);
$terms[$key]->count = $terms[$key]->count + 1;
}
}
}
wp_reset_query();
//returnează array de obiecte termeni
if ($fields == "all")
return $terms;
//returnează array de ID-uri termeni
if ($fields == "ID"){
foreach ($terms as $t){
$re[] = $t->term_id;
}
return $re;
}
//returnează array de nume termeni
if ($fields == "name"){
foreach ($terms as $t){
$re[] = $t->name;
}
return $re;
}
// obține termeni cu argumentele get_terms
if ($fields == "get_terms"){
$terms2 = get_terms( $taxonomy, $args );
foreach ($terms as $t){
if (in_array($t,$terms2)){
$re[] = $t;
}
}
return $re;
}
}
EDIT: Am adăugat corecțiile. Dar cumva tot nu funcționează pentru mine. Numărarea încă afișează valoarea incorectă.

Asta e altceva, dar poți număra când eviți duplicatele în bucla while.

Am actualizat răspunsul meu cu o corecție pentru numărarea termenilor.

Te rog să nu adaugi întrebări suplimentare ca răspunsuri, decât dacă răspunzi în mod specific la propria întrebare. Adăugările ar trebui făcute în întrebarea originală.

@t31os: Ah da, mă întrebam cum să adaug un adaos. Nu m-am gândit să editez întrebarea mea. Mulțumesc!

Evită duplicatele:
//evită duplicatele
$mivalor=$t->term_id;
$arr=array_filter($terms, function ($item) use ($mivalor) {return isset($item->term_id) && $item->term_id == $mivalor;});
if (empty($arr)){
$t->count=1;
$terms[] = $t;
}else{
$key = array_search($t, $terms);
$terms[$key]->count = $terms[$key]->count + 1;
}
