Jak wyświetlić hierarchiczną listę terminów?

34

Mam hierarchiczną taksonomię zwaną „lokalizacjami geograficznymi”. Zawiera kontynenty na pierwszym poziomie, a następnie kraje dla każdego z nich. Przykład:

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

itp.

Za pomocą get_terms () udało mi się wypisać pełną listę terminów, ale kontynenty mieszają się z krajami, w jednej dużej płaskiej liście.

Jak wygenerować hierarchiczną listę jak wyżej?

mike23
źródło
2
Jeśli ktoś potrzebuje hierarchicznej LISTY KONTROLNEJ (nie pytania tutaj, ale odnoszą się do osób budujących niestandardowy interfejs użytkownika dla hierarchicznych taksonomii), najlepszą odpowiedzią jest użycie wp_terms_checklist () z niestandardową taksonomią.
jerclarke

Odpowiedzi:

19

Użyj wp_list_categoriesz 'taxonomy' => 'taxonomy'argumentem, jest zbudowany do tworzenia hierarchicznych list kategorii, ale będzie również obsługiwał niestandardową systematykę.

Przykład Kodeksu:
Wyświetl warunki w niestandardowej taksonomii

Jeśli lista wróci i wygląda płasko, możliwe jest, że wystarczy trochę CSS, aby dodać dopełnienie do list, aby zobaczyć ich hierarchiczną strukturę.

t31os
źródło
Czy można to odwrócić? Pokaż dzieci jako pierwsze ..
Arg Geo
43

Zdaję sobie sprawę, że jest to bardzo stare pytanie, ale jeśli musisz zbudować rzeczywistą strukturę terminów, może to być przydatna metoda:

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

Użycie jest następujące:

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

var_dump($categoryHierarchy);
pospi
źródło
3
To jest naprawdę bardzo dobre. Zmieniłbym jedną rzecz: $into[$cat->term_id] = $cat;na $into[] = $cat;Posiadanie identyfikatora terminu, ponieważ klucz tablicy jest denerwujący (nie można łatwo uzyskać pierwszego elementu za pomocą klawisza 0) i jest bezużyteczny (przechowuje się już $catobiekt i można uzyskać identyfikator korzystając z term_idnieruchomości
Nahuel
Jeśli podobnie jak ja próbujesz zastosować tę funkcję do podrzędnego poziomu kategorii, musisz przekazać identyfikator poziomu, na którym obecnie jesteś, aby to zadziałało. Ale działa ładnie, dzięki @popsi.
Ben Everard,
to działa, dziękuję
Luca Reghellin
10

Nie znam żadnej funkcji, która robi to, co chcesz, ale możesz zbudować coś takiego:

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

Nie testowałem tego, ale widać, o co mi chodzi. Powyższy kod da ci tylko dwa poziomy

EDYCJA: ahh tak, możesz użyć wp_list_categories () do robienia tego, co chcesz.

Brady
źródło
W rzeczywistości jest to dość przydatne, ponieważ muszę mieć niestandardowe linki (z parametrem GET) w terminach links, co nie wydaje się możliwe w przypadku sposobu wp_list_categories ().
mike23
1
Tak, ta metoda da większą kontrolę nad twoją produkcją. Ale możesz zrobić trochę miłego wyszukiwania i zamiany na wyjściu, wp_list_categories()aby dodać parametry GET. Lub jeszcze lepiej zbuduj filtr dla funkcji, aby dodać żądane bity. Nie pytaj mnie, jak to robisz, ponieważ nie byłem jeszcze w stanie tego ogarnąć :(
Brady,
3
Sugeruję użyciu niestandardowych kategorii chodzika ze wp_list_categoriesjeśli chcesz większą kontrolę nad wyjściem, będzie to zrobić znacznie więcej kodu wielokrotnego użytku ..
t31os
6

Możesz użyć wp_list_categories () z argumentem „taksonomia”.

scribu
źródło
3

Ponieważ szukałem tego samego, ale aby uzyskać warunki jednego posta, w końcu skompilowałem to i działa dla mnie.

Co robi:
• otrzymuje wszystkie warunki nazwy taksonomicznej dla określonego stanowiska.
• dla taksonomii hierarchicznej z dwoma poziomami (np. Poziom 1: „kraj” i poziom 2: „miasta”), tworzy h4 z poziomem 1, po którym następuje lista ul poziomu 2 i to dla wszystkich elementów poziomu 1.
• jeśli taksonomia nie jest hierarchiczna, utworzy tylko listę ul wszystkich pozycji. oto kod (piszę go dla siebie, więc starałem się być tak ogólny, jak tylko potrafię, ale ...):

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

Więc w końcu wywołujesz funkcję w ten sposób (oczywiście zamieniasz my_taxonomy na swój): finishingLister('my_taxonomy');

Nie udaje, że jest idealny, ale jak powiedziałem, działa dla mnie.

Trouille2
źródło
3

Poniższy kod wygeneruje listę rozwijaną z terminami, ale może również wygenerować dowolny inny element / strukturę, edytując zmienną $ outputTemplate i edytując linie 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
źródło
1

Miałem ten problem i żadna z odpowiedzi tutaj nie działała dla mnie z tego czy innego powodu.

Oto moja zaktualizowana i działająca wersja.

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 użycie:

$selector = locationSelector('locationSelectClass');
echo $selector;
Joe Tannorella
źródło
1

Użyłem kodu @popsi, który działał naprawdę dobrze i uczyniłem go bardziej wydajnym i łatwym do odczytania:

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

Stosowanie :

$sorted_terms = sort_terms_hierarchicaly($terms);
Pierre R.
źródło
-1

Upewnij się, że hierarchical=truezostał przekazany do twojego get_terms()połączenia.

Pamiętaj, że hierarchical=truejest to ustawienie domyślne, więc naprawdę upewnij się, że nie zostało to nadpisane false.

Chip Bennett
źródło
Cześć Chip, tak, domyślnie „hierarchiczny” to „prawda”.
mike23
Czy możesz podać link do przykładowego wyjścia?
Chip Bennett
Komentujesz odpowiedź pozostawioną prawie dwa lata temu? Naprawdę? W rzeczywistości jest to proponowana odpowiedź, nawet sformułowana jako pytanie. Czy powinienem edytować to, aby było stwierdzeniem, a nie pytaniem?
Chip Bennett
get_terms()zwróci pełną listę warunków (jak stwierdził PO), ale nie hierarchiczną listę pokazującą relacje rodzic / dziecko zgodnie z żądaniem.
jdm2112
-1

Tutaj mam czteropoziomową listę wyboru z ukrytym pierwszym elementem

<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
źródło
2
Proszę wyjaśnić, dlaczego to może rozwiązać problem.
fuxia
Myślę, że logika jest związana z tym problemem. Znalazłem ten post, próbując dowiedzieć się, jak uzyskać hierarchiczną listę kontrolną w stylu kategorii i kusi mnie, aby dodać odpowiedź teraz, kiedy to wymyśliłem. Nie zrobię tego, ponieważ, jak zauważyłeś, nie odpowiada OQ.
jerclarke