Comment afficher une liste de termes hiérarchiques?

34

J'ai une taxonomie hiérarchique appelée «lieux géographiques». Il contient les continents sur un premier niveau, puis les pays pour chacun. Exemple :

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

etc.

En utilisant get_terms (), j’ai réussi à afficher la liste complète des termes, mais les continents se confondent avec les pays, dans une grande liste à plat.

Comment puis-je sortir une liste hiérarchique comme ci-dessus?

mike23
la source
2
Si quelqu'un a besoin d'une liste de contrôle hiérarchique (pas la question ici, mais liée pour les personnes construisant une interface utilisateur personnalisée pour les taxonomies hiérarchiques), la meilleure réponse consiste à utiliser wp_terms_checklist () avec votre taxonomie personnalisée.
jerclarke

Réponses:

19

À utiliser wp_list_categoriesavec l' 'taxonomy' => 'taxonomy'argument, il est conçu pour créer des listes de catégories hiérarchiques, mais prend également en charge l'utilisation d'une taxonomie personnalisée.

Exemple Codex:
Afficher les termes dans une taxonomie personnalisée

Si la liste revient à plat, il est possible que vous ayez juste besoin d'un peu de CSS pour ajouter du remplissage aux listes, afin de voir leur structure hiérarchique.

t31os
la source
Cela pourrait-il être inversé? Afficher les enfants d'abord ..
Arg Geo
43

Je me rends compte qu’il s’agit d’une question très ancienne, mais si vous avez besoin de mettre en place une structure réelle de termes, cette méthode pourrait vous être utile:

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

L'utilisation est la suivante:

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

var_dump($categoryHierarchy);
pospi
la source
3
C'est vraiment très bien. Je changerais une chose: $into[$cat->term_id] = $cat;en $into[] = $cat;ayant l'ID du terme car la clé du tableau est ennuyeuse (vous ne pouvez pas obtenir facilement le premier élément en utilisant la clé 0) et inutile (vous stockez déjà l' $catobjet et vous pouvez obtenir l'ID en utilisant la term_idpropriété.
Nahuel
Si, comme moi, vous essayez d'appliquer cette fonction à un sous-niveau de catégories, vous devrez transmettre l'ID du niveau actuel pour que cela fonctionne. Mais travaillez bien, merci @popsi.
Ben Everard
ça marche, merci
Luca Reghellin
10

Je ne connais aucune fonction qui fasse ce que vous voulez, mais vous pouvez construire quelque chose comme ceci:

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

Je n'ai pas testé cela, mais vous pouvez voir où je veux en venir. Le code ci-dessus ne vous donnera que deux niveaux.

EDIT: ahh oui, vous pouvez utiliser wp_list_categories () pour faire ce que vous voulez.

Brady
la source
En fait, c’est très utile, car j’ai besoin de liens personnalisés (avec un paramètre GET) sur les liens de terme, ce qui ne semble pas possible avec la méthode wp_list_categories ().
mike23
1
Oui, cette méthode donnera plus de contrôle sur votre sortie. Mais vous pourriez faire un peu de recherche et de remplacement à la sortie de wp_list_categories()pour ajouter vos paramètres GET. Ou mieux encore, créez un filtre pour que la fonction ajoute les bits que vous souhaitez. Ne me demandez pas comment vous faites cela car je n'ai pas encore réussi à comprendre ce qui se passe :(
Brady
3
Je suggère d' utiliser un marcheur de catégorie personnalisée avec wp_list_categoriessi vous voulez plus de contrôle sur la sortie, il va rendre votre code beaucoup plus réutilisable ..
t31os
6

Vous pouvez utiliser wp_list_categories () avec un argument 'taxonomy'.

scribu
la source
3

Comme je cherchais la même chose, mais pour obtenir les conditions d'un poste, je l'ai finalement compilé, et cela fonctionne pour moi.

Ce qu'il fait:
• Il donne tous les termes d'un nom de taxonomie pour un poste spécifique.
• pour une taxonomie hiérarchique à deux niveaux (ex: niveau1: 'pays' et niveau2: 'villes'), il crée un h4 avec le niveau1 suivi d'une liste ul de niveau2 et ceci pour tous les éléments de niveau1.
• si la taxonomie n'est pas hiérarchique, il ne créera qu'une liste ul de tous les éléments. voici le code (je l’écris pour moi alors j’ai essayé d’être aussi générique que possible mais ...):

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

Alors finalement, vous appelez la fonction avec ceci (évidemment, vous remplacez my_taxonomy par le vôtre): finishingLister('my_taxonomy');

Je ne prétends pas que c'est parfait, mais comme je l'ai dit, cela fonctionne pour moi.

Trouille2
la source
3

Le code suivant générera une liste déroulante avec les termes, mais peut également générer tout autre élément / structure en modifiant la variable $ outputTemplate et en modifiant les lignes 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>';  
wesamly
la source
1

J'ai eu ce problème et aucune des réponses ici ne fonctionnait pour moi, pour une raison ou une autre.

Voici ma version mise à jour et de travail.

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

Et utilisation:

$selector = locationSelector('locationSelectClass');
echo $selector;
Joe Tannorella
la source
1

J'ai utilisé le code @popsi qui fonctionnait très bien et je l'ai rendu plus efficace et plus facile à lire:

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

Utilisation:

$sorted_terms = sort_terms_hierarchicaly($terms);
Pierre R
la source
-1

Assurez-vous que cela hierarchical=trueest passé à votre get_terms()appel.

Notez que hierarchical=truec'est la valeur par défaut, alors assurez-vous simplement qu'elle n'a pas été remplacée false.

Chip Bennett
la source
Bonjour Puce, oui 'hiérarchique' est 'vrai' par défaut.
mike23
Pouvez-vous fournir un lien vers un exemple en direct de la sortie?
Chip Bennett
Commenter une réponse laissée il y a presque deux ans? Vraiment? En fait, il est une proposition de réponse, même si formulée comme une question. Dois-je le modifier pour qu'il s'agisse d'une déclaration plutôt que d'une question?
Chip Bennett
get_terms()renverra une liste complète des termes (comme indiqué par le PO), mais pas une liste hiérarchique indiquant la relation parent / enfant demandée.
jdm2112
-1

Ici, j'ai une liste de sélection à quatre niveaux avec le premier élément caché

<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>
Powiększanie biustu
la source
2
S'il vous plaît expliquer pourquoi cela pourrait résoudre le problème.
fuxia
Je pense que la logique est que c'est un problème connexe. J'ai trouvé cet article en train d'essayer de comprendre comment obtenir une liste de contrôle hiérarchique de type catégorie et je suis tenté d'ajouter une réponse ici maintenant que je l'ai compris. Je ne le ferai pas car, comme vous le soulignez, cela ne répond pas à la QO.
jerclarke