Filtrar get_categories() por término de taxonomía en WordPress

1 dic 2010, 09:36:30
Vistas: 18.1K
Votos: 2

Quiero mostrar una categoría solo si un post (personalizado) está en esa categoría Y región = $name para ese post.

Por ejemplo, tengo un post personalizado (tipo "business") llamado "Mamma Mia" en la subcategoría: "pizzerías" (y en la categoría padre "comida"), y en la región "Rotterdam" (taxonomía personalizada: "region", término de taxonomía: "rotterdam").

=> mostrar categoría "pizzerías" (y categoría padre "comida")

El problema es que no tengo idea de cómo lograrlo. Agradecería cualquier ayuda con este rompecabezas.

<?php 

// $filter = array('region'=>$name); 

$categories = get_categories(); 
foreach ($categories as $cat) 
{ 
    if($cat->parent < 1) 
    { 
    $cat_name = $cat->cat_name; 
    $catid = get_cat_ID( $cat_name ); 
    echo $cat_name. '<br/>'; 

    $args=array( 
      'orderby' => 'name', 
      'order' => 'ASC', 
      'child_of' => $catid 
      ); 
    $categories=get_categories($args); 
      foreach($categories as $category) {  
        echo '<a href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "Ver todos los posts en %s" ), $category->name ) . '" ' . '>' . $category->name.'</a><br/>'; 
        }  

    } 
} 

// print_r($categories);  


?>
3
Comentarios

¿Entonces quieres listar los terms de categoría que tienen asignado business y que también están asignados a un region específico?

Rarst Rarst
6 dic 2010 15:04:01

@Henk, ¿puedes explicar un poco más dónde te gustaría hacer esto? ¿En una página de post individual? ¿En un archivo de taxonomía? ¿En un archivo de categoría?

TheDeadMedic TheDeadMedic
6 dic 2010 15:30:44

Creo que podemos generalizar esto a búsqueda facetada. Existe un plugin con este nombre, pero parece que no puedes combinar múltiples taxonomías. Como esto es muy interesante, he añadido la recompensa.

Jan Fabry Jan Fabry
6 dic 2010 16:47:49
Todas las respuestas a la pregunta 8
1

la intención es mostrar una lista de categorías, pero solo aquellas categorías que tienen publicaciones donde la taxonomía personalizada región está configurada como Rotterdam

Esto se realiza en el plugin Query Multiple Taxonomies:

http://plugins.trac.wordpress.org/browser/query-multiple-taxonomies/trunk/core.php?rev=308185#L10

8 dic 2010 08:20:26
Comentarios

Y más específicamente, en su widget de navegación en profundidad. ¡Genial! Ahora solo falta extenderlo para que también muestre las categorías padre: si una publicación está adjunta a Pizzerías también la veo cuando navego por Comida, pero Comida no se muestra en el widget si la publicación no está explícitamente adjunta a ella.

Jan Fabry Jan Fabry
8 dic 2010 09:27:25
3

Idea general: consultar un conjunto específico de publicaciones, recopilar todas sus categorías, filtrarlas y dejar que la función las organice.

Código genérico:

$posts = get_posts(array(
    'tag' => 'linux'
));

$categories = array();

foreach( $posts as $post ) {

    $cats = get_the_category($post->ID);

    foreach($cats as $c)
        $categories[] = $c->term_id;
}

$categories = array_unique($categories);
sort($categories);
$categories = implode(',', $categories);

$result = get_categories(array(
    'include' => $categories
));

Los problemas son, según recuerdo, que las consultas decentes para múltiples taxonomías solo llegarán en WP 3.1 y esto podría volverse muy intensivo, por lo que requerirá caché (probablemente para cada región).

6 dic 2010 15:22:21
Comentarios

¿Cómo afecta el parámetro include a los resultados jerárquicos? Si hay algunas publicaciones en Pizzerías, pero ninguna directamente adjunta a su categoría padre Comida, ¿se mostrará Comida? ¿O las publicaciones se adjuntan automáticamente a las categorías padre también?

Jan Fabry Jan Fabry
6 dic 2010 16:24:36

@Jan Fabry probé, si solo se pasa el ID de la categoría hija a get_categories() entonces no se recupera la categoría padre. :( Así que un paso más sería recorrer las categorías y obtener los padres. Un lío aún mayor.

Rarst Rarst
6 dic 2010 16:34:06

Creo que deberíamos mirar en la dirección de una consulta SQL personalizada, uniendo múltiples tablas de taxonomía. Y caché, efectivamente.

Jan Fabry Jan Fabry
6 dic 2010 16:41:17
0

En la versión de WordPress que estoy usando, que es la 3.1.2. Si agregas 'taxonomy' => 'taxonomy_term' al array de argumentos debería funcionar. Aquí tienes una modificación de tu código original para incluir la taxonomía en el array. No sé el nombre de la taxonomía que estás intentando usar o no:

<?php 

// $filter = array('region'=>$name); 

$categories = get_categories(); 
foreach ($categories as $cat) 
{ 
    if($cat->parent < 1) 
    { 
    $cat_name = $cat->cat_name; 
    $catid = get_cat_ID( $cat_name ); 
    echo $cat_name. '<br/>'; 

    $args=array( 
      'taxonomy' => 'taxonomy_term', 
      'orderby' => 'name', 
      'order' => 'ASC', 
      'child_of' => $catid 
      ); 
    $categories=get_categories($args); 
      foreach($categories as $category) {  
        echo '<a href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "Ver todas las entradas en %s" ), $category->name ) . '" ' . '>' . $category->name.'</a><br/>'; 
        }  

    } 
} 

// print_r($categories);  
?>
31 may 2011 17:50:16
0

He adaptado la respuesta de @rarst de arriba para usar 3 taxonomías personalizadas. Solo quiero mostrar los términos que están asociados a una o más de las publicaciones en el loop.

Aquí está mi función que he añadido a functions.php:

function dv_setup_sidebar_cats() {
    global $wp_query;

    $designers = array();
    $sizes     = array();
    $colors    = array();

    foreach( $wp_query->posts as $post ) {

        $des   = get_the_terms($post->ID, 'designer');
        $siz   = get_the_terms($post->ID, 'size');
        $col   = get_the_terms($post->ID, 'color');    

        foreach($des as $d) {
            $designers[] = $d->term_id;
        }

        foreach($siz as $s) {
            $sizes[] = $s->term_id;
        }

        foreach($col as $c) {
            $colors[] = $c->term_id;
        }

    }

    if ( !empty($designers) ) {
        $designers = array_unique($designers);
        sort($designers);
        $designers = implode(',', $designers);

        $dresult   = get_categories(array(
            'include'  => $designers,
            'taxonomy' => 'designer'
        ));
    }

    if ( !empty($sizes) ) {
        $sizes = array_unique($sizes);
        sort($sizes);
        $sizes = implode(',', $sizes);

        $sresult   = get_categories(array(
            'include'  => $sizes,
            'taxonomy' => 'size'
        ));
    } 

    if ( !empty($colors) ) {
        $colors = array_unique($colors);
        sort($colors);
        $colors = implode(',', $colors);

        $cresult   = get_categories(array(
            'include'  => $colors,
            'taxonomy' => 'color'
        ));
    }

    $return = array(
        'size'     => $sresult,
        'color'    => $cresult,
        'designer' => $dresult
    );


    return $return;

}

Espero que esto ayude a alguien más.

-J

10 may 2012 20:37:20
3

Perdóname si me he perdido algo, pero ¿no sería tan simple como?

if (is_object_in_term($post->ID, 'region', 'rotterdam'))
    the_category(); // muestra las categorías asociadas con la entrada actual

En el administrador, ¿estás asignando la entrada tanto a 'pizzerias' como a 'food' (marcando ambas casillas), o solo a 'pizzerias'?

Si es lo último, the_category() no mostrará 'Food' por defecto, así que tendrás que obtener la jerarquía de categorías tú mismo.

6 dic 2010 12:52:03
Comentarios

No, la intención es mostrar una lista de categorías, pero solo aquellas categorías que tienen posts donde la taxonomía personalizada region está configurada como Rotterdam. Esta pregunta fue también formulada en SO, por cierto.

Jan Fabry Jan Fabry
6 dic 2010 13:28:48

A menos que lo esté entendiendo mal, parece una respuesta adecuada. Si Mamma Mia es pizzeria en rotterdam, entonces por definición existen pizzerías en Rotterdam y la categoría debería mostrarse. De lo contrario, no entiendo cómo se supone que la categoría está conectada con la región.

Rarst Rarst
6 dic 2010 14:11:16

@Rarst: La forma en que entendí la pregunta es que la lista de categorías no debería mostrarse solo en una página de post, sino por ejemplo en region/rotterdam/: para todos los posts que usan este término de taxonomía personalizada, dame un árbol de todas las categorías a las que están vinculados. El OP usa get_categories(), que no está limitado a las categorías del post actual.

Jan Fabry Jan Fabry
6 dic 2010 14:48:05
2

Puedes obtener la taxonomía para un custom post con una pequeña función:

    function get_the_taxonomy( $taxonomy, $id = FALSE ) {
        global $post;

        $id = (int) $id;
        if ( !$id )
            $id = (int) $post->ID;

        $categories = get_object_term_cache( $id, $taxonomy );
        if ( FALSE === $categories ) {
            $categories = wp_get_object_terms( $id, $taxonomy );
            wp_cache_add($id, $categories, $taxonomy . '_relationships');
        }

        if ( !empty( $categories ) )
            usort( $categories, '_usort_terms_by_name' );
        else
            $categories = array();

        foreach ( (array) array_keys( $categories ) as $key ) {
            _make_cat_compat( $categories[$key] );
        }

        return $categories;
    }

También puedes usar la función del núcleo de WordPress:

$taxonomys = get_the_term_list($id, YOUR_CUSTOM_POST_TYPE, '', ', ', '' );

Y puedes consultar por taxonomías con is_tax(), revisa el codex para esta etiqueta condicional

Quizás esto te ayude, si entendí correctamente tu problema. Disculpa por mi inglés.

7 dic 2010 00:14:21
Comentarios

Creo que Henk Jan quiere obtener una lista de categorías, independientemente de un post actual. Simplemente todas las categorías que tienen posts asignados al término personalizado rotterdam.

Jan Fabry Jan Fabry
7 dic 2010 00:41:47

Gracias por la pista; creo que es posible usar una consulta personalizada con el término personalizado. El post devuelve todos los términos, y la consulta debe usar todos o el primer término para listar en el loop todos los posts de este término. También es posible devolver todas las categorías de los posts en esta consulta.

bueltge bueltge
7 dic 2010 10:11:19
4

Gracias a todos por su ayuda - realmente es genial. Me gustaría compartir con ustedes lo que he desarrollado. Sé que no es la solución más inteligente. La desventaja es que se muestra una categoría padre para una región cuando no hay una entrada personalizada asociada a ella para esa región (pero sí hay una entrada personalizada asociada para otra región).

Estoy usando esto en una página de región (archivo de taxonomía).

<?php
$categories = get_categories();
foreach ($categories as $cat)
{
    if($cat->parent < 1)
    {
        $cat_name = $cat->cat_name;                         
        $catid = get_cat_ID( $cat_name );

        echo '<div class="indexcolumn-top">';

        $img = $taxonomy_images_plugin->get_image_html( 'fullsize', $cat->term_taxonomy_id );
        if( !empty( $img ) )
            print $img;
        else 
            echo '<h2>' .$cat_name. '</h2>';

        $input = array();
        $args=array(
          'child_of' => $catid,
          'orderby' => 'name',
          'order' => 'ASC'
          );

        $categories = get_categories($args);
        foreach ($categories as $cat)
        {
            $cat_name = $cat->cat_name;
            $catid = get_cat_ID( $cat_name );

            $args = array(
                'post_status' => 'publish',
                'taxonomy_name' => 'region',
                'taxonomy_term' => $name,
            );
            $custom_posts = get_posts_by_taxonomy($args);
            if ($custom_posts):
                foreach ($custom_posts as $post):
                    setup_postdata($post);
                    $postcategory = get_the_category(); $postcat = $postcategory[0]->cat_name;
                    if ($postcat == $cat_name):
                        $category = get_the_category(); 
                        $input[] = $catid;
                    endif;
                endforeach;
            endif;
        }
        echo '<br/>';
        $output = array_unique($input);
        if (empty($output)):
            echo '<p>No hay empresas</p>';
            echo '</div>';
        else :
            echo '<ul class="port-box">';
            foreach ($output as $output) {
                $cat_name = get_cat_name($output);  
                echo '<li><a href="' . get_category_link($output) . '" title="' . sprintf( __( "Ver todas las entradas en %s" ), $cat_name ) . '" ' . '>' . $cat_name .'</a></li>';                             
            }
            echo '</ul></div>';
        endif;
    }                                                   
}
?>
8 dic 2010 12:09:53
Comentarios

No creo que esta sea una forma eficiente de hacerlo: realizas muchas consultas, y no entiendo el bucle interno de publicaciones: si se encuentra una publicación en la categoría actual, probablemente podrías simplemente agregar esa categoría a la lista sin recorrer todas las publicaciones.

Jan Fabry Jan Fabry
8 dic 2010 14:58:14

@Jan: Sé que no es la solución más inteligente. Sin embargo, no entiendo tu observación sobre el bucle interno de publicaciones. Necesitarás el bucle interno para encontrar una coincidencia, o no. ¿O puedes salir del bucle en caso de acierto? Pero, ¿cómo lo harías entonces?

Henk Jan Henk Jan
8 dic 2010 16:32:17

No importa, pensé que tu función get_posts_by_taxonomy() seleccionaba tanto por taxonomía como por categoría. La siguiente pregunta es por qué repites esta consulta una y otra vez, en lugar de hacerla una vez y reutilizar los resultados. ¿Y por qué verificar solo la primera categoría? Si un negocio está tanto en Pizzeria como en French Fries, solo se devolverá una de ellas, por lo que posiblemente te pierdas una al final.

Jan Fabry Jan Fabry
8 dic 2010 16:45:43

@Jan: OK. Solo estoy revisando la primera categoría porque mis negocios solo pueden estar en una categoría. No entiendo tu primera pregunta. El if ($custom_posts): endif; se puede eliminar. Pero, necesitarás hacer un bucle para encontrar una coincidencia - o no. ¿Qué quieres decir con reutilizar?

Henk Jan Henk Jan
8 dic 2010 17:20:20
0
<?php $cat_id = $_GET["cat"];?>     
      <li id="category-active"><a><?php if ($cat_id){echo get_the_category_by_id($li_id);}else{ echo "Categoría seleccionada";}?></a></li>            <?php   $subcategories1 = wp_list_categories("title_li&child_of=$cat_id&hide_empty");
                wp_list_categories("title_li=&current_category="); ?>
                    </ul><?php ?>

Gracias por tu ayuda.

Pero creo que no hay necesidad de usar foreach o ningún bucle, podemos obtener los hijos de cualquier categoría usando este código simple. Primero $li_id obtiene el ID de la categoría actual y lo pasamos dinámicamente a child_of=$cat_id y muestra los hijos de la categoría seleccionada. Lo estoy usando en la barra lateral de mi sitio.

18 ene 2011 18:58:37