Cum să afișezi o listă ierarhică de termeni?

13 apr. 2011, 17:23:30
Vizualizări: 69.2K
Voturi: 49

Am o taxonomie ierarhică numită 'locații geografice'. Aceasta conține continente pe primul nivel, și apoi țările pentru fiecare continent. Exemplu:

Europa
- Irlanda
- Spania
- Suedia
Asia
- Laos
- Thailanda
- Vietnam

etc.

Folosind get_terms() am reușit să afișez lista completă de termeni, dar continentele se amestecă cu țările, într-o singură listă plată.

Cum pot afișa o listă ierarhică precum cea de mai sus?

1
Comentarii

În cazul în care cineva are nevoie de o LISTĂ DE VERIFICARE ierarhică (nu este întrebarea de aici, dar este înrudită pentru cei care construiesc interfețe personalizate pentru taxonomii ierarhice), cel mai bun răspuns este să utilizați wp_terms_checklist() cu taxonomia dumneavoastră personalizată.

jerclarke jerclarke
23 feb. 2016 18:27:48
Toate răspunsurile la întrebare 12
3
64

Înțeleg că aceasta este o întrebare foarte veche, dar dacă aveți nevoie să construiți o structură reală de termeni, această metodă vă poate fi utilă:

/**
 * Sortează recursiv un array de termeni ai taxonomiei ierarhic. Categoriile copil vor fi
 * plasate într-un membru 'children' al termenului lor părinte.
 * @param Array   $cats     obiecte ale termenilor taxonomiei de sortat
 * @param Array   $into     array-ul rezultat în care vor fi plasați
 * @param integer $parentId ID-ul părintelui curent în care vor fi plasați
 */
function sorteaza_termenii_ierarhic(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();
        sorteaza_termenii_ierarhic($cats, $topCat->children, $topCat->term_id);
    }
}

Utilizarea este următoarea:

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

var_dump($categoryHierarchy);
15 mai 2013 09:54:30
Comentarii

Acesta este de fapt foarte bun. Aș schimba un singur lucru: $into[$cat->term_id] = $cat; în $into[] = $cat; Folosirea ID-ului termenului ca cheie de array este enervant (nu poți obține primul element ușor folosind cheia 0) și inutil (deja stochezi obiectul $cat și poți obține ID-ul folosind proprietatea term_id.

Nahuel Nahuel
7 mar. 2017 17:03:31

Dacă ca și mine încerci să aplici această funcție la un sub-nivel de categorii, va trebui să transmiți ID-ul nivelului la care te afli pentru ca aceasta să funcționeze. Dar funcționează foarte bine, mulțumesc @popsi.

Ben Everard Ben Everard
16 aug. 2018 13:19:47

funcționează, mulțumesc

Luca Reghellin Luca Reghellin
12 nov. 2019 18:35:57
1
24

Folosește wp_list_categories cu argumentul 'taxonomy' => 'taxonomy', această funcție este concepută pentru a crea liste ierarhice de categorii, dar poate fi folosită și cu o taxonomie personalizată.

Exemplu din Codex:
Afișarea termenilor dintr-o taxonomie personalizată

Dacă lista afișată pare plată, este posibil să ai nevoie de puțin CSS pentru a adăuga padding la liste, astfel încât să poți vedea structura lor ierarhică.

13 apr. 2011 17:38:04
Comentarii

Acest lucru poate fi inversat? Afișează întâi copiii..

Arg Geo Arg Geo
6 mar. 2016 09:57:09
3
14

Nu cunosc nicio funcție care să facă exact ceea ce doriți, dar puteți construi ceva de genul acesta:

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

Nu am testat acest cod, dar puteți înțelege ideea. Codul de mai sus va afișa doar două niveluri ierarhice.

EDIT: A, da, puteți folosi wp_list_categories() pentru a obține ceea ce doriți.

13 apr. 2011 17:39:21
Comentarii

De fapt, acest lucru este destul de util, deoarece am nevoie să am link-uri personalizate (cu un parametru GET) pe link-urile termenilor, ceea ce nu pare posibil cu metoda wp_list_categories().

mike23 mike23
13 apr. 2011 18:04:23

Da, această metodă îți va oferi mai mult control asupra rezultatului. Dar ai putea face o operațiune de căutare și înlocuire pe rezultatul funcției wp_list_categories() pentru a adăuga parametrii tăi GET. Sau chiar mai bine, poți crea un filtru pentru funcție pentru a adăuga elementele dorite. Nu mă întreba cum se face asta, pentru că încă nu am reușit să înțeleg cum :(

Scott Scott
13 apr. 2011 18:19:04

Aș sugera să folosești un walker de categorii personalizat cu wp_list_categories dacă dorești un control mai mare asupra rezultatului, asta va face codul tău mult mai reutilizabil.

t31os t31os
13 apr. 2011 19:09:53
0

Puteți utiliza wp_list_categories(), cu un argument 'taxonomy'.

13 apr. 2011 17:37:03
0

Următorul cod va genera un meniu derulant cu termeni, dar poate genera și orice alt element/structură prin editarea variabilei $outputTemplate și a liniilor str_replace:

function get_terms_hierarchical($terms, $output = '', $parent_id = 0, $level = 0) {
    //Șablonul de ieșire
    $outputTemplate = '<option value="%ID%">%PADDING%%NAME%</option>';

    foreach ($terms as $term) {
        if ($parent_id == $term->parent) {
            //Înlocuirea variabilelor din șablon
            $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>';  
13 ian. 2016 13:18:11
0

Am folosit codul lui @popsi care funcționa foarte bine și l-am făcut mai eficient și mai ușor de citit:

/**
 * Sortează recursiv un array de termeni de taxonomie ierarhic. Categoriile copil vor fi
 * plasate sub un membru 'children' al termenului lor părinte.
 * @param Array   $cats     obiecte de termeni de taxonomie de sortat
 * @param integer $parentId ID-ul părintelui curent în care să fie plasați
 */
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;
}

Utilizare:

$sorted_terms = sort_terms_hierarchicaly($terms);
9 iul. 2018 15:44:10
0

Când căutam același lucru dar pentru a obține termenii unui post, am compilat în final această soluție care funcționează pentru mine.

Ce face funcția:
• Obține toți termenii unei taxonomii pentru un post specific.
• Pentru o taxonomie ierarhică cu două niveluri (ex: nivel1:'țară' și nivel2:'orașe'), creează un h4 cu nivel1 urmat de o listă neordonată (ul) cu nivel2, și asta pentru toate elementele de nivel1.
• Dacă taxonomia nu este ierarhică, va crea doar o listă neordonată cu toate elementele. Iată codul (l-am scris pentru mine, așa că am încercat să fie cât mai generic posibil, dar...):

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

În final, apelezi funcția astfel (evident, înlocuiește my_taxonomy cu taxa ta): finishingLister('my_taxonomy');

Nu pretind că este perfect, dar cum am spus, funcționează pentru mine.

21 feb. 2013 17:55:39
0

Am avut această problemă și niciunul dintre răspunsurile de aici nu a funcționat pentru mine, dintr-un motiv sau altul.

Iată versiunea mea actualizată și funcțională.

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

Și utilizarea:

$selector = locationSelector('locationSelectClass');
echo $selector;
30 nov. 2013 12:35:57
0

Această soluție este mai puțin eficientă decât codul lui @popsi, deoarece face o nouă interogare pentru fiecare termen, dar este și mai ușor de utilizat într-un șablon. Dacă site-ul tău utilizează caching, poate, ca și mine, să nu te deranjeze ușoara suprasolicitare a bazei de date.

Nu este nevoie să pregătești un array care va fi umplut recursiv cu termeni. Pur și simplu apelezi funcția în același mod în care ai apela get_terms() (forma nedeprecieată cu doar un array ca argument). Returnează un array de obiecte WP_Term cu o proprietate suplimentară numită children.

function get_terms_tree( Array $args ) {
    $new_args = $args;
    $new_args['parent'] = $new_args['parent'] ?? 0;
    $new_args['fields'] = 'all';

    // Termenii pentru acest nivel
    $terms = get_terms( $new_args );

    // Copiii fiecărui termen de pe acest nivel
    foreach( $terms as &$this_term ) {
        $new_args['parent'] = $this_term->term_id;
        $this_term->children = get_terms_tree( $new_args );
    }

    return $terms;
}

Utilizarea este simplă:

$terms = get_terms_tree([ 'taxonomy' => 'my-tax' ]);
4 mai 2020 23:45:56
0

Un ultim lovitură de grație pentru acest cal (similar cu răspunsurile de mai sus) cu un pic mai multă rafinare... permițându-vă să transformați lista într-o listă ierarhic-plată cu un parametru depth.

În plus, această funcție utilizează clone pentru a evita modificarea array-ului original.

/**
 * Sortează lista de obiecte termeni ierarhic sau ierarhic-plat.
 */
function sort_terms_hierarchically( $terms, $parent_id = 0, $flat = FALSE, $depth = 0 ) {
    $data = [];
    foreach ( $terms as $term ) {
        if ( $parent_id != $term->parent ) continue;
        $data_term = clone $term;
        $data_term->depth = $depth;
        $children = sort_terms_hierarchically( $terms, $term->term_id, $flat, $depth + 1 );
        if ( ! $flat ) $data_term->children = $children;
        $data[] = $data_term;
        if ( $flat ) foreach( $children as $child ) $data[] = $child;
    }
    return $data;
}

function sort_terms_hierarchically_flat( $terms, $parent_id = 0 ) {
    return sort_terms_hierarchically( $terms, $parent_id, TRUE );
}

Utilizarea este următoarea:

$terms = get_terms( [
    'taxonomy' => 'regions',
    'hide_empty' => FALSE,
] );

$terms_sorted = sort_terms_hierarchically( $terms );
$terms_sorted_flat = sort_terms_hierarchically_flat( $terms );
22 aug. 2023 18:48:33
4
-1

Asigurați-vă că hierarchical=true este transmis în apelul dvs. get_terms().

Rețineți că hierarchical=true este valoarea implicită, așa că, de fapt, trebuie doar să vă asigurați că nu a fost suprascrisă pentru a fi false.

13 apr. 2011 17:31:53
Comentarii

Salut Chip, da, 'hierarchical' este implicit setat pe 'true'.

mike23 mike23
13 apr. 2011 17:37:19

Poți oferi un link către un exemplu live al rezultatului?

Chip Bennett Chip Bennett
13 apr. 2011 17:44:33

Comentezi la un răspuns lăsat acum aproape doi ani? Serios? De fapt, este un răspuns propus, chiar dacă este formulat ca o întrebare. Să-l editez să fie o afirmație, în loc de o întrebare?

Chip Bennett Chip Bennett
12 feb. 2013 01:22:18

get_terms() va returna o listă completă a termenilor (așa cum a menționat OP), dar nu o listă ierarhică care să arate relația părinte/copil așa cum a fost solicitat.

jdm2112 jdm2112
17 mar. 2016 07:00:22
2
-1

Aici am o listă derulantă cu patru niveluri cu primul element ascuns

<select name="lokalizacja" id="ucz">
            <option value="">Toate locațiile</option>
            <?php
            // Obține termenul exclus după slug
            $excluded_term = get_term_by('slug', 'podroze', 'my_travels_places');
            $args = array(
                'orderby' => 'slug', // Ordonează după slug
                'hierarchical' => 'true', // Afișare ierarhică
                'exclude' => $excluded_term->term_id, // Exclude termenul specificat
                'hide_empty' => '0', // Arată și termenii fără elemente
                'parent' => $excluded_term->term_id, // Filtrează după părinte
            );              
            $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";

                // Obține termenii de nivel 2
                $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";

                    // Obține termenii de nivel 3
                    $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>Selectează tipul locației</label>
        <select name="rodzaj_miejsca" id="woj">
            <option value="">Toate tipurile</option>
            <?php
            // Obține toți termenii ordonați după nume
            $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>
25 mar. 2013 11:31:18
Comentarii

Te rog să explici de ce asta ar putea rezolva problema.

fuxia fuxia
25 mar. 2013 12:00:39

Cred că logica este că este o problemă înrudită. Am găsit acest post încercând să înțeleg cum să obțin o listă de verificare ierarhică în stil de categorii și sunt tentat să adaug un răspuns aici acum că am reușit să înțeleg. Nu o voi face totuși pentru că, după cum subliniezi tu, nu răspunde la întrebarea inițială.

jerclarke jerclarke
23 feb. 2016 18:26:24