¿Cómo mostrar una lista jerárquica de términos?


34

Tengo una taxonomía jerárquica llamada 'ubicaciones geográficas'. Contiene continentes en un primer nivel, y luego los países para cada uno. Ejemplo:

Europe
- Ireland
- Spain
- Sweden
Asia
- Laos
- Thailand
- Vietnam

etc.

Usando get_terms () logré generar la lista completa de términos, pero los continentes se mezclan con los países, en una gran lista plana.

¿Cómo puedo generar una lista jerárquica como la anterior?


2
En caso de que alguien necesite una LISTA DE VERIFICACIÓN jerárquica (no es la pregunta aquí, sino que está relacionada con personas que crean una IU personalizada para taxonomías jerárquicas), la mejor respuesta es usar wp_terms_checklist () con su taxonomía personalizada.
jerclarke

Respuestas:


19

Úselo wp_list_categoriescon el 'taxonomy' => 'taxonomy'argumento, está diseñado para crear listas de categorías jerárquicas, pero también admitirá el uso de una taxonomía personalizada.

Ejemplo del Codex:
Mostrar términos en una taxonomía personalizada

Si la lista vuelve a verse plana, es posible que solo necesite un poco de CSS para agregar relleno a las listas, para que pueda ver su estructura jerárquica.


¿Podría esto ser revertido? Mostrar niños primero ..
Arg Geo

43

Me doy cuenta de que esta es una pregunta muy antigua, pero si necesita construir una estructura de términos real , este podría ser un método útil para usted:

/**
 * Recursively sort an array of taxonomy terms hierarchically. Child categories will be
 * placed under a 'children' member of their parent term.
 * @param Array   $cats     taxonomy term objects to sort
 * @param Array   $into     result array to put them in
 * @param integer $parentId the current parent ID to put them in
 */
function sort_terms_hierarchically(Array &$cats, Array &$into, $parentId = 0)
{
    foreach ($cats as $i => $cat) {
        if ($cat->parent == $parentId) {
            $into[$cat->term_id] = $cat;
            unset($cats[$i]);
        }
    }

    foreach ($into as $topCat) {
        $topCat->children = array();
        sort_terms_hierarchically($cats, $topCat->children, $topCat->term_id);
    }
}

El uso es el siguiente:

$categories = get_terms('my_taxonomy_name', array('hide_empty' => false));
$categoryHierarchy = array();
sort_terms_hierarchically($categories, $categoryHierarchy);

var_dump($categoryHierarchy);

3
Esto es realmente muy bueno. Que cambiaría una cosa: $into[$cat->term_id] = $cat;en $into[] = $cat;Tener el ID del término como la clave de la matriz es molesto (no se puede conseguir el primer elemento fácilmente utilizando la tecla 0) e inútil (que ya está almacenando el $catobjeto y se puede obtener el ID utilizando la term_idpropiedad.
Nahuel

Si, como yo, está tratando de aplicar esta función a un subnivel de categorías, deberá pasar el ID del nivel en el que se encuentra actualmente para que esto funcione. Pero funciona bien, gracias @popsi.
Ben Everard

eso funciona, gracias
Luca Reghellin

10

No conozco ninguna función que haga lo que quieres, pero puedes construir algo como esto:

<ul>
    <?php $hiterms = get_terms("my_tax", array("orderby" => "slug", "parent" => 0)); ?>
    <?php foreach($hiterms as $key => $hiterm) : ?>
        <li>
            <?php echo $hiterm->name; ?>
            <?php $loterms = get_terms("my_tax", array("orderby" => "slug", "parent" => $hiterm->term_id)); ?>
            <?php if($loterms) : ?>
                <ul>
                    <?php foreach($loterms as $key => $loterm) : ?>
                        <li><?php echo $loterm->name; ?></li>
                    <?php endforeach; ?>
                </ul>
            <?php endif; ?>
        </li>
    <?php endforeach; ?>
</ul>

No he probado esto, pero puedes ver a lo que me refiero. Lo que hará el código anterior es darte solo dos niveles

EDITAR: ahh sí, puedes usar wp_list_categories () para hacer lo que quieras después.


En realidad, esto es bastante útil, ya que necesito tener enlaces personalizados (con un parámetro GET) en el término enlaces, lo que no parece posible con la forma wp_list_categories () de hacerlo.
mike23

1
Sí, este método le dará más control sobre su salida. Pero podría hacer un poco de búsqueda y reemplazo en la salida de wp_list_categories()para agregar sus parámetros GET. O incluso mejor, cree un filtro para que la función agregue los bits que desee. No me pregunten cómo lo hacen, ya que aún no he podido entenderlo :(
Brady

3
Me gustaría sugerir el uso de una categoría personalizada andador con wp_list_categoriessi desea un mayor control sobre la salida, que va a hacer el código mucho más reutilizable ..
t31os

6

Puede usar wp_list_categories (), con un argumento de 'taxonomía'.


3

Como estaba buscando lo mismo pero para obtener los términos de una publicación, finalmente compilé esto, y funciona para mí.

Lo que hace:
• obtiene todos los términos de un nombre de taxonomía para una publicación específica.
• para una taxonomía jerárquica con dos niveles (por ejemplo, nivel1: 'país' y nivel2: 'ciudades'), crea un h4 con el nivel1 seguido de una lista ul de nivel2 y esto para todos los elementos de nivel1.
• si la taxonomía no es jerárquica, creará solo una lista ul de todos los elementos. aquí está el código (lo escribí para mí, así que traté de ser lo más genérico posible pero ...):

function finishingLister($heTerm){
    $myterm = $heTerm;
    $terms = get_the_terms($post->ID,$myterm);
    if($terms){
        $count = count($terms);
        echo '<h3>'.$myterm;
        echo ((($count>1)&&(!endswith($myterm, 's')))?'s':"").'</h3>';
        echo '<div class="'.$myterm.'Wrapper">';
        foreach ($terms as $term) {
            if (0 == $term->parent) $parentsItems[] = $term;
            if ($term->parent) $childItems[] = $term; 
        };
        if(is_taxonomy_hierarchical( $heTerm )){
            foreach ($parentsItems as $parentsItem){
                echo '<h4>'.$parentsItem->name.'</h4>';
                echo '<ul>';
                foreach($childItems as $childItem){
                    if ($childItem->parent == $parentsItem->term_id){
                        echo '<li>'.$childItem->name.'</li>';
                    };
                };
                echo '</ul>';
            };
        }else{
            echo '<ul>';
            foreach($parentsItems as $parentsItem){
                echo '<li>'.$parentsItem->name.'</li>';
            };
            echo '</ul>';
        };
        echo '</div>';
    };
};

Entonces finalmente llamas a la función con esto (obviamente, reemplazas my_taxonomy por la tuya): finishingLister('my_taxonomy');

No pretendo que sea perfecto, pero como dije, funciona para mí.


3

El siguiente código generará un menú desplegable con términos, pero también puede generar cualquier otro elemento / estructura editando la variable $ outputTemplate y editando las líneas str_replace:

function get_terms_hierarchical($terms, $output = '', $parent_id = 0, $level = 0) {
    //Out Template
    $outputTemplate = '<option value="%ID%">%PADDING%%NAME%</option>';

    foreach ($terms as $term) {
        if ($parent_id == $term->parent) {
            //Replacing the template variables
            $itemOutput = str_replace('%ID%', $term->term_id, $outputTemplate);
            $itemOutput = str_replace('%PADDING%', str_pad('', $level*12, '&nbsp;&nbsp;'), $itemOutput);
            $itemOutput = str_replace('%NAME%', $term->name, $itemOutput);

            $output .= $itemOutput;
            $output = get_terms_hierarchical($terms, $output, $term->term_id, $level + 1);
        }
    }
    return $output;
}

$terms = get_terms('taxonomy', array('hide_empty' => false));
$output = get_terms_hierarchical($terms);

echo '<select>' . $output . '</select>';  

1

Tuve este problema y ninguna de las respuestas aquí funcionó para mí, por una razón u otra.

Aquí está mi versión actualizada y funcional.

function locationSelector( $fieldName ) {
    $args = array('hide_empty' => false, 'hierarchical' => true, 'parent' => 0); 
    $terms = get_terms("locations", $args);

    $html = '';
    $html .= '<select name="' . $fieldName . '"' . 'class="chosen-select ' . $fieldName . '"' . '>';
        foreach ( $terms as $term ) {
            $html .= '<option value="' . $term->term_id . '">' . $term->name . '</option>';

            $args = array(
                'hide_empty'    => false, 
                'hierarchical'  => true, 
                'parent'        => $term->term_id
            ); 
            $childterms = get_terms("locations", $args);

            foreach ( $childterms as $childterm ) {
                $html .= '<option value="' . $childterm->term_id . '">' . $term->name . ' > ' . $childterm->name . '</option>';

                $args = array('hide_empty' => false, 'hierarchical'  => true, 'parent' => $childterm->term_id); 
                $granchildterms = get_terms("locations", $args);

                foreach ( $granchildterms as $granchild ) {
                    $html .= '<option value="' . $granchild->term_id . '">' . $term->name . ' > ' . $childterm->name . ' > ' . $granchild->name . '</option>';
                }
            }
        }
    $html .=  "</select>";

    return $html;
}

Y uso:

$selector = locationSelector('locationSelectClass');
echo $selector;

1

Utilicé el código @popsi que funcionaba muy bien y lo hice más eficiente y fácil de leer:

/**
 * Recursively sort an array of taxonomy terms hierarchically. Child categories will be
 * placed under a 'children' member of their parent term.
 * @param Array   $cats     taxonomy term objects to sort
 * @param integer $parentId the current parent ID to put them in
 */
function sort_terms_hierarchicaly(Array $cats, $parentId = 0)
{
    $into = [];
    foreach ($cats as $i => $cat) {
        if ($cat->parent == $parentId) {
            $cat->children = sort_terms_hierarchicaly($cats, $cat->term_id);
            $into[$cat->term_id] = $cat;
        }
    }
    return $into;
}

Uso:

$sorted_terms = sort_terms_hierarchicaly($terms);

-1

Asegúrese de que hierarchical=truese le pase a suget_terms() llamada.

Tenga en cuenta que ese hierarchical=truees el valor predeterminado, así que realmente, asegúrese de que no se haya anulado false.


Hola Chip, sí 'jerárquico' es 'verdadero' por defecto.
mike23

¿Puede proporcionar un enlace a un ejemplo en vivo de la salida?
Chip Bennett

¿Comentando una respuesta que dejó hace casi dos años? De Verdad? En realidad, es una respuesta propuesta, incluso si está redactada como una pregunta. ¿Debo editarlo para que sea una declaración, en lugar de una pregunta?
Chip Bennett

get_terms()devolverá una lista completa de los términos (como indicó el OP) pero no una lista jerárquica que muestre la relación padre / hijo como se solicitó.
jdm2112

-1

Aquí tengo una lista de selección desplegable de cuatro niveles con el primer elemento oculto

<select name="lokalizacja" id="ucz">
            <option value="">Wszystkie lokalizacje</option>
            <?php
            $excluded_term = get_term_by('slug', 'podroze', 'my_travels_places');
            $args = array(
                'orderby' => 'slug',
                'hierarchical' => 'true',
                'exclude' => $excluded_term->term_id,
                'hide_empty' => '0',
                'parent' => $excluded_term->term_id,
            );              
            $hiterms = get_terms("my_travels_places", $args);
            foreach ($hiterms AS $hiterm) :
                echo "<option value='".$hiterm->slug."'".($_POST['my_travels_places'] == $hiterm->slug ? ' selected="selected"' : '').">".$hiterm->name."</option>\n";

                $loterms = get_terms("my_travels_places", array("orderby" => "slug", "parent" => $hiterm->term_id,'hide_empty' => '0',));
                if($loterms) :
                    foreach($loterms as $key => $loterm) :

                    echo "<option value='".$loterm->slug."'".($_POST['my_travels_places'] == $loterm->slug ? ' selected="selected"' : '').">&nbsp;-&nbsp;".$loterm->name."</option>\n";

                    $lo2terms = get_terms("my_travels_places", array("orderby" => "slug", "parent" => $loterm->term_id,'hide_empty' => '0',));
                    if($lo2terms) :
                        foreach($lo2terms as $key => $lo2term) :

                        echo "<option value='".$lo2term->slug."'".($_POST['my_travels_places'] == $lo2term->slug ? ' selected="selected"' : '').">&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;".$lo2term->name."</option>\n";



                        endforeach;
                    endif;

                    endforeach;
                endif;

            endforeach;
            ?>
         </select>
        <label>Wybierz rodzaj miejsca</label>
        <select name="rodzaj_miejsca" id="woj">
            <option value="">Wszystkie rodzaje</option>
            <?php
            $theterms = get_terms('my_travels_places_type', 'orderby=name');
            foreach ($theterms AS $term) :
                echo "<option value='".$term->slug."'".($_POST['my_travels_places_type'] == $term->slug ? ' selected="selected"' : '').">".$term->name."</option>\n";                   
            endforeach;
            ?>
         </select>

2
Por favor explique por qué eso podría resolver el problema.
fuxia

Creo que la lógica es que es un problema relacionado. Encontré esta publicación tratando de descubrir cómo obtener una lista de verificación jerárquica de estilo de categoría y estoy tentado de agregar una respuesta aquí ahora que lo he descubierto. Sin embargo, no lo haré porque, como señalas, no responde el OQ.
jerclarke
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.