Obtener términos por taxonomía Y post_type

16

Tengo 2 tipos de publicaciones personalizadas 'marcadores' y 'fragmentos' y una 'etiqueta' de taxonomía compartida. Puedo generar una lista de todos los términos en la taxonomía con get_terms (), pero no puedo averiguar cómo limitar la lista al tipo de publicación. Lo que básicamente estoy buscando es algo como esto:

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

¿Hay una manera de lograr esto? ¡Las ideas son muy apreciadas!

Oh, estoy en WP 3.1.1

    
pregunta Gavin Hewitt 09.04.2011 - 02:38

7 respuestas

11

Aquí hay otra forma de hacer algo similar, con una consulta 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;

}
    
respondido por el Braydon 26.07.2011 - 10:40
14

Entonces, simplemente sucede que necesitaba algo así para un proyecto en el que estoy trabajando. Simplemente escribí una consulta para seleccionar todas las publicaciones de un tipo personalizado, luego verifico cuáles son los términos reales de mi taxonomía que están usando.

Luego obtuve todos los términos de esa taxonomía utilizando get_terms() y luego solo usé los que estaban en ambas listas, lo envolví en una función y terminé.

Pero luego necesitaba más que solo las ID: necesitaba los nombres, así que agregué un nuevo argumento llamado $fields para poder decirle a la función qué devolver. Entonces me di cuenta de que get_terms acepta muchos argumentos y mi función se limitaba a los términos que utiliza un tipo de publicación, así que agregué una declaración if más y ya está:

La función:

/* 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;
    }
}

Uso:

Si solo necesita una lista de ID de término, entonces:

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

Si solo necesita una lista de nombres de términos, entonces:

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

Si solo necesita una lista de objetos de términos, entonces:

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

Y si necesita utilizar argumentos adicionales de get_terms como: orderby, order, hierarchical ...

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

¡Disfruta!

Actualización:

Para corregir el recuento de términos para un cambio de tipo de publicación específico:

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

a:

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;
    }
}
    
respondido por el Bainternet 09.04.2011 - 03:21
8

Escribí una función que te permite pasar post_type en la matriz $args a la función get_terms() :

HT a @braydon para escribir el 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);
    
respondido por el jessica 08.06.2012 - 07:14
7

Gran pregunta y respuestas sólidas.

Realmente me gustó el enfoque de @jessica usando el filtro de términos_clausas, porque extiende la función get_terms de una manera muy razonable.

Mi código es una continuación de su idea, con algunos sql de @braydon para reducir duplicados. También permite una variedad de tipos de correos:

/**
 * 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);

Dado que get_terms no tiene una cláusula para GROUPY BY, tuve que agregarla al final de la cláusula WHERE. Tenga en cuenta que tengo una prioridad de filtro muy alta, con la esperanza de que siempre sea la última.

    
respondido por el daggerhart 04.04.2015 - 05:09
3

No pude hacer los argumentos de get_terms para trabajar con la versión de Gavin del código anterior, pero finalmente lo hice cambiando

$terms2 = get_terms( $taxonomy );

a

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

como estaba en la función original de Bainternet.

    
respondido por el tzeldin88 10.04.2011 - 04:16
0

@Bainternet: ¡Gracias! Tuve que alterar la función ligeramente porque no estaba funcionando (algunos errores tipográficos). El único problema ahora es que el término conteo está desactivado. El recuento no tiene en cuenta el tipo de publicación, por lo que no creo que puedas usar get_terms () en esto.

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;
    }
}

EDITAR: Se agregaron los arreglos. Pero de alguna manera todavía no funciona para mí. La cuenta todavía muestra el valor incorrecto.

    
respondido por el Gavin Hewitt 09.04.2011 - 13:45
0

Evita los duplicados:

//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;
        }
    
respondido por el Kaotiko 26.02.2013 - 18:10

Lea otras preguntas en las etiquetas