Filtrar get_categories() por término de taxonomía en WordPress
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);
?>
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

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.

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
).

¿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 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.

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);
?>

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

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.

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.

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: 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.

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.

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
.

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.

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

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: 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?

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: 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?

<?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=¤t_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.
