web-dev-qa-db-de.com

Begriffe nach Taxonomie UND post_type abrufen

Ich habe 2 benutzerdefinierte Beitragstypen "Lesezeichen" und "Snippets" und ein gemeinsames Taxonomie "Tag". Ich kann mit get_terms () eine Liste aller Begriffe in der Taxonomie erstellen, aber ich kann nicht herausfinden, wie ich die Liste auf den Beitragstyp beschränken kann. Was ich im Grunde suche, ist ungefähr so:

get_terms(array('taxonomy' => 'tag', 'post_type' => 'snippet'));

Gibt es einen Weg, dies zu erreichen? Ideen werden sehr geschätzt !!

Oh, ich bin bei WP 3.1.1

17
Gavin Hewitt

Hier ist eine andere Möglichkeit, mit einer SQL-Abfrage etwas Ähnliches zu tun:

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;

}
11
Braydon

Es kommt also einfach vor, dass ich so etwas für ein Projekt brauchte, an dem ich arbeite. Ich habe einfach eine Abfrage geschrieben, um alle Posts eines benutzerdefinierten Typs auszuwählen, und dann überprüft, welche Begriffe in meiner Taxonomie tatsächlich verwendet werden.

Dann bekam ich alle Begriffe dieser Taxonomie mit get_terms() und dann habe ich nur die verwendet, die in beiden Listen waren, es in eine Funktion verpackt und ich war fertig.

Aber dann brauchte ich mehr als nur die IDs: Ich brauchte die Namen, also fügte ich ein neues Argument mit dem Namen $fields hinzu, damit ich der Funktion mitteilen konnte, was zurückgegeben werden soll. Dann stellte ich fest, dass get_terms viele Argumente akzeptiert und meine Funktion auf einfache Begriffe beschränkt war, die von einem Beitragstyp verwendet werden. Also fügte ich eine weitere if-Anweisung hinzu und los geht's:

Die Funktion:

/* get terms limited to post type 
 @ $taxonomies - (string|array) (required) The taxonomies to retrieve terms from. 
 @ $args  -  (string|array) all Possible Arguments of get_terms http://codex.wordpress.org/Function_Reference/get_terms
 @ $post_type - (string|array) of post types to limit the terms to
 @ $fields - (string) What to return (default all) accepts ID,name,all,get_terms. 
 if you want to use get_terms arguments then $fields must be set to '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){
          //avoid duplicates
            if (!in_array($t,$terms)){
                $terms[] = $c;
            }
        }
    }
    wp_reset_query();
    //return array of term objects
    if ($fields == "all")
        return $terms;
    //return array of term ID's
    if ($fields == "ID"){
        foreach ($terms as $t){
            $re[] = $t->term_id;
        }
        return $re;
    }
    //return array of term names
    if ($fields == "name"){
        foreach ($terms as $t){
            $re[] = $t->name;
        }
        return $re;
    }
    // get terms with get_terms arguments
    if ($fields == "get_terms"){
        $terms2 = get_terms( $taxonomies, $args );
        foreach ($terms as $t){
            if (in_array($t,$terms2)){
                $re[] = $t;
            }
        }
        return $re;
    }
}

Verwendungszweck:

Wenn Sie nur eine Liste mit Term-IDs benötigen, gehen Sie wie folgt vor:

$terms = get_terms_by_post_type('tag','','snippet','ID');

Wenn Sie nur eine Liste mit Begriffsnamen benötigen, gehen Sie wie folgt vor:

$terms = get_terms_by_post_type('tag','','snippet','name');

Wenn Sie nur eine Liste von Termobjekten benötigen, dann:

$terms = get_terms_by_post_type('tag','','snippet');

Und wenn Sie zusätzliche Argumente von get_terms verwenden müssen, wie: orderby, order, hierarchical ...

$args = array('orderby' => 'count', 'order' => 'DESC',  'hide_empty' => 1);
$terms = get_terms_by_post_type('tag',$args,'snippet','get_terms');

Genießen!

Aktualisieren:

So korrigieren Sie die Anzahl der Begriffe für eine bestimmte Änderung des Beitragstyps:

foreach ($current_terms as $t){
          //avoid duplicates
            if (!in_array($t,$terms)){
                $terms[] = $t;
            }
        }

zu:

foreach ($current_terms as $t){
    //avoid duplicates
    if (!in_array($t,$terms)){
        $t->count = 1;
        $terms[] = $t;
    }else{
        $key = array_search($t, $terms);
        $terms[$key]->count = $terms[$key]->count + 1;
    }
}
14
Bainternet

Ich habe eine Funktion geschrieben, mit der Sie post_type im Array $args an die Funktion get_terms() übergeben können:

HT an @braydon zum Schreiben der SQL.

 /**
 * terms_clauses
 *
 * filter the terms clauses
 *
 * @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);
8
jessica

Tolle Frage und solide Antworten.

Der Ansatz von @jessica, den Filter terms_clauses zu verwenden, hat mir sehr gut gefallen, da er die Funktion get_terms auf sehr vernünftige Weise erweitert.

Mein Code ist eine Fortsetzung ihrer Idee, mit etwas SQL von @braydon, um Duplikate zu reduzieren. Es erlaubt auch ein Array von post_types:

/**
 * my_terms_clauses
 *
 * filter the terms clauses
 *
 * @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 = $args['post_types'];

    // allow for arrays
    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 ('". esc_sql( $post_types ). "') GROUP BY t.term_id";
  }
  return $clauses;
}
add_filter('terms_clauses', 'my_terms_clauses', 99999, 3);

Da get_terms keine Klausel für GROUPY BY hat, musste ich sie am Ende der WHERE-Klausel einfügen. Beachten Sie, dass ich die Filterpriorität sehr hoch eingestellt habe, in der Hoffnung, dass sie immer die letzte ist.

7
daggerhart

Ich war nicht in der Lage, die Argumente get_terms für Gavins Version des obigen Codes zu verwenden, habe es aber schließlich durch Ändern getan

$terms2 = get_terms( $taxonomy );

zu

$terms2 = get_terms( $taxonomy, $args );

wie es in der ursprünglichen Funktion von Bainternet war.

3
tzeldin88

@Bainternet: Danke! Ich musste die Funktion leicht ändern, da sie nicht funktionierte (einige Tippfehler). Das einzige Problem ist jetzt, dass die Anzahl der Begriffe deaktiviert ist. Die Anzahl berücksichtigt nicht den Post-Typ, daher kann get_terms () hier nicht verwendet werden.

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){
            //avoid duplicates
            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();

    //return array of term objects
    if ($fields == "all")
        return $terms;
    //return array of term ID's
    if ($fields == "ID"){
        foreach ($terms as $t){
            $re[] = $t->term_id;
        }
        return $re;
    }
    //return array of term names
    if ($fields == "name"){
        foreach ($terms as $t){
            $re[] = $t->name;
        }
        return $re;
    }
    // get terms with get_terms arguments
    if ($fields == "get_terms"){
        $terms2 = get_terms( $taxonomy, $args );

        foreach ($terms as $t){
            if (in_array($t,$terms2)){
                $re[] = $t;
            }
        }
        return $re;
    }
}

BEARBEITEN: Das Update wurde hinzugefügt. Aber irgendwie funktioniert es immer noch nicht für mich. Die Zählung zeigt immer noch den falschen Wert.

0
Gavin Hewitt

Vermeiden Sie Duplikate:

//avoid duplicates
    $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;
        }
0
Kaotiko