Como mostrar uma lista hierárquica de termos?


34

Eu tenho uma taxonomia hierárquica chamada 'localizações geográficas'. Ele contém continentes em um primeiro nível e, em seguida, os países de cada um. Exemplo:

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

etc.

Usando get_terms (), consegui exibir a lista completa de termos, mas os continentes se misturam com os países, em uma grande lista simples.

Como posso gerar uma lista hierárquica como acima?


2
Caso alguém precise de uma CHECKLIST hierárquica (não a pergunta aqui, mas relacionada a pessoas que criam UI personalizada para taxonomias hierárquicas), a melhor resposta é usar wp_terms_checklist () com sua taxonomia personalizada.
Jerclarke

Respostas:


19

Use wp_list_categoriescom o 'taxonomy' => 'taxonomy'argumento, ele foi criado para criar listas hierárquicas de categorias, mas também suporta o uso de uma taxonomia customizada.

Exemplo de códice:
Exibir termos em uma taxonomia customizada

Se a lista voltar plana, é possível que você precise apenas de um pouco de CSS para adicionar preenchimento às listas, para poder ver sua estrutura hierárquica.


Isso poderia ser revertido? Exibir primeiro os filhos ..
Arg Geo

43

Sei que essa é uma pergunta muito antiga, mas se você precisar criar uma estrutura real de termos, talvez seja um método útil para você:

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

O uso é o seguinte:

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

var_dump($categoryHierarchy);

3
Isso é realmente muito bom. Eu mudaria uma coisa: $into[$cat->term_id] = $cat;em $into[] = $cat;Ter o ID do termo como a chave da matriz é irritante (você não pode obter o primeiro elemento facilmente usando a tecla 0) e inútil (você já está armazenando o $catobjeto e pode obter o ID usando a term_idpropriedade.
Nahuel

Se, como eu, você estiver tentando aplicar esta função a um subnível de categorias, precisará passar o ID do nível em que está atualmente para que isso funcione. Mas funciona muito bem, obrigado @popsi.
Ben Everard

isso funciona, obrigado
Luca Reghellin 12/11

10

Não conheço nenhuma função que faça o que você deseja, mas você pode criar algo assim:

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

Eu não testei isso, mas você pode ver no que estou falando. O que o código acima fará é fornecer apenas dois níveis

EDIT: ahh sim, você pode usar wp_list_categories () para fazer o que depois.


Na verdade, isso é bastante útil, pois preciso ter links personalizados (com um parâmetro GET) no termo links, o que não parece possível com a maneira wp_list_categories () de fazê-lo.
precisa saber é o seguinte

1
Sim, este método dará mais controle sobre sua saída. Mas você pode encontrar e substituir na saída de wp_list_categories()para adicionar seus parâmetros GET. Ou ainda melhor, crie um filtro para a função adicionar os bits que você deseja. Não me pergunte como fazer isso como eu ainda não tenho sido capaz de colocar minha cabeça em torno dele :(
Brady

3
Eu sugiro usar uma categoria personalizada walker com wp_list_categoriesse você quiser um maior controle sobre a saída, ele vai fazer o seu código muito mais reutilizável ..
t31os

6

Você pode usar wp_list_categories (), com um argumento 'taxonomy'.


3

Como eu estava procurando o mesmo, mas para obter os termos de um post, finalmente compilei isso e funciona para mim.

O que faz:
• obtém todos os termos de um nome de taxonomia para uma postagem específica.
• para uma taxonomia hierárquica com dois níveis (ex: nível1: 'país' e nível2: 'cidades'), cria um h4 com o nível1 seguido por uma lista ul do nível2 e para todos os itens do nível1.
• se a taxonomia não for hierárquica, ela criará apenas uma lista ul de todos os itens. Aqui está o código (eu o escrevo para mim, então tentei ser o mais genérico possível, mas ...):

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

Então, finalmente, você chama a função com isso (obviamente, você substitui my_taxonomy pelo seu): finishingLister('my_taxonomy');

Eu não finjo que é perfeito, mas como eu disse, funciona para mim.


3

O código a seguir gerará uma lista suspensa com termos, mas também poderá gerar qualquer outro elemento / estrutura editando a variável $ outputTemplate e editando as linhas 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

Eu tive esse problema e nenhuma das respostas aqui funcionou para mim, por um motivo ou outro.

Aqui está minha versão atualizada e 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;
}

E uso:

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

1

Usei o código @popsi que estava funcionando muito bem e o tornei mais eficiente e fácil de ler:

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

Certifique-se de que hierarchical=trueseja passado para sua get_terms()ligação.

Observe que esse hierarchical=trueé o padrão, portanto, apenas certifique-se de que ele não tenha sido substituído false.


Oi Chip, sim 'hierárquico' é 'verdadeiro' por padrão.
precisa saber é o seguinte

Você pode fornecer um link para um exemplo ao vivo da saída?
Chip Bennett

Comentando uma resposta deixada quase dois anos atrás? Sério? Na verdade, é uma resposta proposta, mesmo se formulada como uma pergunta. Devo editá-lo para ser uma declaração, e não uma pergunta?
Chip Bennett

get_terms()retornará uma lista completa dos termos (como indicado no OP), mas não uma lista hierárquica mostrando o relacionamento pai / filho conforme solicitado.
Jdm2112

-1

Aqui eu tenho uma lista suspensa de quatro níveis com o primeiro item 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 que isso poderia resolver o problema.
fuxia

Eu acho que a lógica é que é um problema relacionado. Eu encontrei este post tentando descobrir como obter uma lista de verificação hierárquica no estilo de categoria e estou tentado a adicionar uma resposta aqui agora que eu a descobri. Não vou, porque, como você ressalta, não responde o OQ.
23416 jerclarke
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.