¿Cómo listar solo los términos hijos de una taxonomía y no sus padres?
Estoy creando un menú de selección de edad en el admin, poblado desde una taxonomía de age
. La taxonomía es jerárquica de la siguiente manera:
- 18-25 (padre, ID 183)
- 18 (hijo)
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26-30 (padre, ID 184)
- 26
- 27
- 28
- 29
- 30
Me gustaría listar solo los hijos (18, 19 etc) y no los padres (18-25, 26-30) etc. Actualmente estoy usando get_terms
con el argumento parent
, pero no acepta más de 1 ID padre. Esto es lo que tengo hasta ahora, que muestra los hijos de 18-25.
$ages = get_terms( 'age', array(
'hide_empty' => 0,
'parent' => '183',
));
Esto es lo que quiero hacer, pero no está soportado. También lo he intentado con un array pero no funciona.
$ages = get_terms( 'age', array(
'hide_empty' => 0,
'parent' => '183,184',
));
Veo que existe una función get_term_children pero tampoco estoy seguro de cómo usarla ya que parece que solo acepta un valor también. Por ejemplo: En este ejemplo construiría una lista desordenada pero podría modificarla para un menú select.
<?php
// ID del término
$termID = 183;
// Nombre de la taxonomía
$taxonomyName = "age";
$termchildren = get_term_children( $termID, $taxonomyName );
echo '<ul>';
foreach ($termchildren as $child) {
$term = get_term_by( 'id', $child, $taxonomyName );
echo '<li><a href="' . get_term_link( $term->name, $taxonomyName ) . '">' . $term->name . '</a></li>';
}
echo '</ul>';
?>

Esto debería funcionar para ti:
$taxonomyName = "age";
// Esto obtiene solo los términos de nivel superior. Se hace estableciendo parent en 0.
$parent_terms = get_terms(
$taxonomyName,
array(
'parent' => 0,
'orderby' => 'slug',
'hide_empty' => false
)
);
echo '<ul>';
foreach ( $parent_terms as $pterm ) {
// Obtener los términos hijos
$terms = get_terms(
$taxonomyName,
array(
'parent' => $pterm->term_id,
'orderby' => 'slug',
'hide_empty' => false
)
);
foreach ( $terms as $term ) {
echo '<li><a href="'. get_term_link($term) . '">'. $term->name .'</a></li>';
}
}
echo '</ul>';

Gracias @Manny, funcionó de maravilla. Tomé lo que proporcionaste y lo integré en el menú desplegable que estaba buscando. Excelente material.

Consulta la respuesta de karimhossenbux más abajo para una solución mucho más eficiente.

También podrías hacer:
$terms = get_terms($taxonomyName);
foreach($terms as $term) {
if ($term->parent != 0) { // evitar categorías padre
//tus instrucciones aquí
}
}
He notado que los elementos padre tienen el campo "parent" igual a 0, y un hijo tiene el ID de su padre en este campo.

La respuesta aceptada ejecuta N llamadas a get_terms() y se ejecuta en tiempo polinómico. Esta respuesta ejecuta una única llamada a get_terms() y se ejecuta en tiempo lineal. Esta es una respuesta mucho mejor.

@dotancohen Puedes hacer esto sin tener que excluir términos de nivel superior en la salida, puedes eliminar los términos de nivel superior con el parámetro wpse_exclude_top
añadido a los argumentos de la consulta ;-). Sin embargo, estoy de acuerdo en que esto es más rápido que la respuesta aceptada

@PieterGoosen: Gracias Pieter. Acabo de buscar en el código fuente de la versión 4.4.2 las cadenas wpse_exclude_top
y exclude_top
pero no las encontré. Tampoco google sabe sobre eso. ¿Dónde está documentado?

Podemos excluir los padres de nivel superior filtrándolos utilizando el filtro terms_clauses
para alterar la consulta SQL antes de que se ejecute. De esta manera, no necesitamos omitir los padres en el bucle foreach
final, ya que no estarán en el array de términos devuelto. Esto nos ahorra trabajo y código innecesarios.
Puedes probar lo siguiente:
add_filter( 'terms_clauses', function ( $pieces, $taxonomies, $args )
{
// Verifica si nuestro argumento personalizado está establecido y es igual a 1, si no, salimos
if ( !isset( $args['wpse_exclude_top'] )
|| 1 !== $args['wpse_exclude_top']
)
return $pieces;
// Todo verificado, eliminamos los padres
$pieces['where'] .= ' AND tt.parent > 0';
return $pieces;
}, 10, 3 );
Para excluir los padres de nivel superior, ahora podemos pasar 'wpse_exclude_top' => 1
con nuestro array de argumentos. El nuevo parámetro wpse_exclude_top
es compatible con el filtro anterior.
$terms = get_terms( 'category', ['wpse_exclude_top' => 1] );
if ( $terms
&& !is_wp_error( $terms )
) {
echo '<ul>';
foreach ($terms as $term) {
echo '<li><a href="' . get_term_link( $term ) . '">' . $term->name . '</a></li>';
}
echo '</ul>';
}
Solo una nota: get_term_link()
no acepta el nombre del término, solo el slug, ID o el objeto de término completo. Por rendimiento, siempre pasa el objeto de término a get_term_link()
si el objeto de término está disponible (como en este caso).

Hola, ¿alguna idea de cómo solucionar este problema? stackoverflow.com/q/70327174/9036446

establecer el argumento childless
como verdadero significa que solo puedes profundizar 1 nivel, por lo que esto no funciona para taxonomías con 3 o más niveles.

Si necesitas mostrar múltiples términos hijos de un padre, puedes probar esto. Muestra los términos hijos de los IDs mencionados.
$termIds = array(367, 366, 365, 364, 363, 362);
$taxonomyName = "age";
$args = array(
'orderby' => 'term_id',
'order' => 'DESC',
'hide_empty' => false,
'childless' => false,
);
$terms = get_terms( $taxonomyName, $args );
if ( ! empty( $terms ) && ! is_wp_error( $terms ) ){
$inc = 1;
foreach ( $terms as $term ) {
if (in_array($term->parent, $termIds)) {
echo '<option value="'.$term->term_id.'"><font><font>'.$term->name.'</font></font></option>';
}
}
}
