Как показать иерархический список терминов?

34

У меня есть иерархическая таксономия, называемая «географические местоположения». Он содержит континенты на первом уровне, а затем страны для каждого. Пример :

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

и т.п.

Используя get_terms () мне удалось вывести полный список терминов, но континенты перепутаны со странами в одном большом плоском списке.

Как вывести иерархический список, как указано выше?

mike23
источник
2
В случае, если кому-то нужен иерархический CHECKLIST (здесь не вопрос, а вопрос для людей, создающих пользовательский интерфейс для иерархических таксономий), лучшим решением будет использование wp_terms_checklist () с вашей пользовательской таксономией.
Джеркларке

Ответы:

19

Используйте wp_list_categoriesс 'taxonomy' => 'taxonomy'аргументом, он построен для создания иерархических списков категорий, но также будет поддерживать использование пользовательской таксономии.

Пример кодекса:
отображение терминов в пользовательской таксономии

Если список снова выглядит плоским, возможно, вам просто нужно немного CSS, чтобы добавить отступы в списки, чтобы вы могли увидеть их иерархическую структуру.

t31os
источник
Может ли это быть полностью изменено? Сначала покажите детям ..
Arg Geo
43

Я понимаю, что это очень старый вопрос, но если вам нужно создать реальную структуру терминов, это может быть полезным для вас способом:

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

Использование заключается в следующем:

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

var_dump($categoryHierarchy);
pospi
источник
3
Это действительно очень хорошо. Я бы изменил одну вещь: $into[$cat->term_id] = $cat;на $into[] = $cat;наличие идентификатора термина, так как ключ массива раздражает (вы не можете легко получить первый элемент, используя клавишу 0) и бесполезно (вы уже храните $catобъект, и вы можете получить идентификатор используя term_idсобственность.
Науэль
Если вы, как и я, пытаетесь применить эту функцию к подуровню категорий, вам нужно будет указать идентификатор того уровня, на котором вы сейчас находитесь, чтобы это работало. Но работает хорошо, спасибо @popsi.
Бен Эверард,
это работает, спасибо
Luca Reghellin
10

Я не знаю ни одной функции, которая делает то, что вы хотите, но вы можете создать что-то вроде этого:

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

Я не проверял это, но вы можете видеть, к чему я клоню. То, что приведенный выше код будет делать, это дать вам только два уровня

РЕДАКТИРОВАТЬ: ах да, вы можете использовать wp_list_categories (), чтобы делать то, что вы после.

Brady
источник
На самом деле это весьма полезно, так как мне нужно иметь пользовательские ссылки (с параметром GET) на термин «ссылки», что не представляется возможным при использовании способа wp_list_categories ().
mike23
1
Да, этот метод даст больше контроля над вашим выводом. Но вы могли бы сделать немного приятного поиска и замены на выходе, wp_list_categories()чтобы добавить в ваши параметры GET. Или даже лучше построить фильтр для функции, чтобы добавить нужные биты. Не спрашивай меня, как ты это делаешь, так как я пока не смог разобраться в этом :(
Брэди,
3
Я предложил бы использовать пользовательские категории ходунок с , wp_list_categoriesесли вы хотите большего контроля над выходом, это сделает ваш код более многократного использования ..
t31os
6

Вы можете использовать wp_list_categories () с аргументом таксономии.

scribu
источник
3

Поскольку я искал то же самое, но чтобы получить условия одного поста, я наконец скомпилировал это, и это работает для меня.

Что он делает:
• получает все термины названия таксономии для определенного поста.
• для иерархической таксономии с двумя уровнями (например, уровень 1: «страна» и уровень 2: «города») создается h4 с уровнем 1, за которым следует список ul уровня 2 и это для всех элементов уровня 1.
• если таксономия не является иерархической, она создаст только список ul всех элементов. вот код (я пишу его для себя, поэтому я старался быть как можно более универсальным, но ...):

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

Итак, наконец, вы вызываете функцию с этим (очевидно, вы заменяете my_taxonomy на ваш): finishingLister('my_taxonomy');

Я не притворяюсь, что это идеально, но, как я уже сказал, это работает для меня.

Trouille2
источник
3

Следующий код создаст раскрывающийся список с терминами, но также может сгенерировать любой другой элемент / структуру, отредактировав переменную $ outputTemplate и отредактировав строки 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
источник
1

У меня была эта проблема, и ни один из ответов здесь не работал для меня, по той или иной причине.

Вот моя обновленная и рабочая версия.

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

И использование:

$selector = locationSelector('locationSelectClass');
echo $selector;
Джо Таннорелла
источник
1

Я использовал код @popsi, который работал очень хорошо, и я сделал его более эффективным и легким для чтения:

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

Использование :

$sorted_terms = sort_terms_hierarchicaly($terms);
Пьер Р
источник
-1

Будьте уверены, что hierarchical=trueпередается на ваш get_terms()звонок.

Обратите внимание, что hierarchical=trueэто значение по умолчанию, поэтому просто убедитесь, что оно не было переопределено false.

Чип Беннетт
источник
Привет Чип, да «иерархический» по умолчанию «правда».
mike23
Можете ли вы предоставить ссылку на живой пример вывода?
Чип Беннетт
Комментировать комментарий, оставленный почти два года назад? В самом деле? На самом деле, это является планируемым ответом, даже если сформулировать в виде вопроса. Должен ли я изменить это как утверждение, а не вопрос?
Чип Беннетт
get_terms()возвратит полный список терминов (как указано в OP), но не иерархический список, показывающий родительские / дочерние отношения в соответствии с запросом.
jdm2112
-1

Здесь у меня есть четыре уровня выпадающего списка со скрытым первым элементом

<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
источник
2
Пожалуйста, объясните, почему это может решить проблему.
fuxia
Я думаю, что логика в том, что это связанная проблема. Я обнаружил, что этот пост пытается выяснить, как получить иерархический контрольный список в стиле категории, и у меня возникает желание добавить здесь ответ, когда я понял это. Я не буду, хотя, потому что, как вы указываете, это не отвечает OQ.
Джеркларке