it-swarm.com.de

get_terms nach benutzerdefiniertem Beitragstyp

Ich habe zwei benutzerdefinierte Beitragstypen "Land" und "Stadt" und eine gemeinsame Taxonomie "Flagge".

Wenn ich benutze:

<?php $flags = get_terms('flag', 'orderby=name&hide_empty=0');

Ich erhalte eine Liste aller Begriffe in der Taxonomie, möchte die Liste jedoch auf den Beitragstyp "Land" beschränken.

Wie kann ich es tun?


Verwenden der neuen Lösung

<?php 
$flags = wpse57444_get_terms('flags',array('parent' => 0,'hide_empty' => 1,'post_types' =>array('country')));
foreach ($flags as $flag) {
    $childTerms = wpse57444_get_terms('flags',array('parent' => $flag->term_id,'hide_empty' => 1,'post_types' =>array('country')));
    foreach ($childTerms as $childTerm) {
        echo $childTerm->name.'<br />';
    }
}
?>

Ich kann $ childTerm-> name nicht wiedergeben. Warum?

19
user1443216

Ich fürchte, das ist von Haus aus (noch?) Nicht möglich. Siehe diesen Trac: http://core.trac.wordpress.org/ticket/18106

In ähnlicher Weise spiegelt die Postanzahl auf der Taxonomie-Verwaltungsseite all Posttypen wider. (Ich bin mir ziemlich sicher, dass es dafür auch ein Trac-Ticket gibt)http://core.trac.wordpress.org/ticket/14084

Siehe auch, dieser verwandte Beitrag .


Neue Lösung

Nachdem ich das Folgende geschrieben habe, habe ich eine viel bessere Möglichkeit (zumindest in dem Sinne, dass Sie mehr tun können) herausgebracht, die im Aufruf get_terms() bereitgestellten Filter zu verwenden. Sie können eine Wrapper-Funktion erstellen, die get_terms verwendet und (bedingt) einen Filter hinzufügt, um die SQL-Abfrage zu bearbeiten (um sie nach Post-Typ einzuschränken).

Die Funktion akzeptiert die gleichen Argumente wie get_terms($taxonomies, $args). $args akzeptiert das zusätzliche Argument von post_types, das ein Array von Post-Typen akzeptiert.

Aber ich kann nicht garantieren, dass alles "wie erwartet" funktioniert (ich denke, die Zählung auffüllen). Es scheint nur mit dem $args für get_terms zu funktionieren.

function wpse57444_get_terms( $taxonomies, $args=array() ){
    //Parse $args in case its a query string.
    $args = wp_parse_args($args);

    if( !empty($args['post_types']) ){
        $args['post_types'] = (array) $args['post_types'];
        add_filter( 'terms_clauses','wpse_filter_terms_by_cpt',10,3);

        function wpse_filter_terms_by_cpt( $pieces, $tax, $args){
            global $wpdb;

            // Don't use db count
            $pieces['fields'] .=", COUNT(*) " ;

            //Join extra tables to restrict by post type.
            $pieces['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 ";

            // Restrict by post type and Group by term_id for COUNTing.
            $post_types_str = implode(',',$args['post_types']);
            $pieces['where'].= $wpdb->prepare(" AND p.post_type IN(%s) GROUP BY t.term_id", $post_types_str);

            remove_filter( current_filter(), __FUNCTION__ );
            return $pieces;
        }
    } // endif post_types set

    return get_terms($taxonomies, $args);           
}

Verwendungszweck

$args =array(
    'hide_empty' => 0,
    'post_types' =>array('country','city'),
);

$terms = wpse57444_get_terms('flag',$args);

Ursprüngliche Umgehung

Inspiriert von dem obigen Trac-Ticket (getestet, und es funktioniert bei mir)

function wpse57444_filter_terms_by_cpt($taxonomy, $post_types=array() ){
    global $wpdb;

    $post_types=(array) $post_types;
    $key = 'wpse_terms'.md5($taxonomy.serialize($post_types));
    $results = wp_cache_get($key);

    if ( false === $results ) {
       $where =" WHERE 1=1";
       if( !empty($post_types) ){
            $post_types_str = implode(',',$post_types);
            $where.= $wpdb->prepare(" AND p.post_type IN(%s)", $post_types_str);
       }

       $where .= $wpdb->prepare(" AND tt.taxonomy = %s",$taxonomy);

       $query = "
          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
          GROUP BY t.term_id";

       $results = $wpdb->get_results( $query );
       wp_cache_set( $key, $results );
    }        

    return $results;
}

Verwendungszweck

 $terms = wpse57444_filter_terms_by_cpt('flag',array('country','city'));

oder

 $terms = wpse57444_filter_terms_by_cpt('flag','country');
16
Stephen Harris

Zwei benutzerdefinierte Beitragstypen "Land" und "Stadt" und eine gemeinsame Taxonomie "Flagge". Sie möchten die Liste auf den Beitragstyp "Land" beschränken.

Hier ist eine einfachere Lösung:

$posts_in_post_type = get_posts( array(
    'fields' => 'ids',
    'post_type' => 'country',
    'posts_per_page' => -1,
) );
$terms = wp_get_object_terms( $posts_in_post_type, 'flag', array( 'ids' ) ); ?>
2
Alex

@ stephen-harris Antwort oben hat nur teilweise bei mir funktioniert. Wenn ich versucht habe, es zweimal auf der Seite zu verwenden, hat es nicht funktioniert. Die Idee, solche MySQL-Abfragen zu vergraben, beunruhigt mich. Ich denke, es ist besser, Kernmethoden zu verwenden, um eine Lösung zu finden und Konflikte mit zukünftigen WP Updates zu vermeiden. Hier ist meine Lösung, basierend auf einigen Kommentar # 7 auf dem Trac-Ticket, auf das er verweist

function get_terms_by_custom_post_type( $post_type, $taxonomy ){
  $args = array( 'post_type' => $post_type);
  $loop = new WP_Query( $args );
  $postids = array();
  // build an array of post IDs
  while ( $loop->have_posts() ) : $loop->the_post();
    array_Push($postids, get_the_ID());
  endwhile;
  // get taxonomy values based on array of IDs
  $regions = wp_get_object_terms( $postids,  $taxonomy );
  return $regions;
}

Verwendungszweck:

$terms = get_terms_by_custom_post_type('country','flag');

Dies funktioniert nur für einen Beitragstyp und eine Taxonomie, da ich das benötige, aber es wäre nicht zu schwierig, dies zu ändern, um mehrere Werte zu akzeptieren.

Es wurde auf diesem Trac-Thread erwähnt, dass dies möglicherweise nicht gut skaliert, aber ich arbeite in einem ziemlich kleinen Maßstab und hatte keine Probleme mit der Geschwindigkeit.

2
Mark Pruce

Ich habe auch versucht, die Antwort von @Stephen Harris zu verwenden, aber die Abfrage, die ich benötigte, war als einzelne Abfrage und unter Verwendung der Filterelemente ziemlich schwer zu schreiben.

Darüber hinaus musste ich diese Funktion auch mehrmals auf derselben Seite verwenden und habe das Problem behoben, bei dem die Funktion wpse_filter_terms_by_cpt außerhalb der Wrapper-Funktion deklariert wurde.

Trotzdem passt die Antwort von @Mark Pruce meiner Meinung nach aus den gleichen Gründen besser, wie er sagte, obwohl Sie eine weitere Abfrage (und die zugehörige Schleife) durchführen müssen, um die Argumente für die Funktion wp_get_object_terms vorzubereiten.

1
Sgaddo

[edit] Dies ist ein Kommentar zu der hervorragenden Antwort von Stephen Harris.

Es gibt keine Begriffe zurück, wenn es mit mehreren Beitragstypen wie diesem verwendet wird. $flags = wpse57444_get_terms('flags', array('post_types' => array('country','city')));. Dies liegt daran, dass $ wpdb-> prepare die Zeichenfolge $ post_types_str zu p.post_type IN('country,city') bereinigt, während es p.post_type IN('country','city') sein sollte. Siehe dieses Ticket: 11102 . Verwenden Sie die Lösung aus diesem Thema, um dies zu umgehen: https://stackoverflow.com/a/10634225

1
keesiemeijer