Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I have a hierarchical taxonomy called 'geographical locations'. It contains continents on a first level, and then the countries for each one. Example :

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

etc.

Using get_terms() I managed to output the full list of terms, but the continents get mixed up with the countries, in one big flat list.

How can I output a hierarchical list like above?

share|improve this question

8 Answers 8

up vote 10 down vote accepted

Use wp_list_categories with the taxonomy argument, it's built for creating hierarchal category lists but will also support using a custom taxonomy..

Codex Example:
Display terms in a custom taxonomy

If the list comes back looking flat it's possible you just need a little CSS to add padding to the lists, so you can see their hierarchal structure.

share|improve this answer

Be sure that hierarchical=true is passed to your get_terms() call.

Note that hierarchical=true is the default, so really, just be sure that it hasn't been overridden to be false.

share|improve this answer
    
Hi Chip, yes 'hierarchical' is 'true' by default. –  mike23 Apr 13 '11 at 14:37
    
Can you provide a link to a live example of the output? –  Chip Bennett Apr 13 '11 at 14:44
    
This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. –  brasofilo Feb 11 '13 at 20:04
    
Commenting on an answer left almost two years ago? Really? Actually, it is a proposed answer, even if worded as a question. Shall I edit it to be a statement, rather than a question? –  Chip Bennett Feb 11 '13 at 23:22

You can use wp_list_categories(), with a 'taxonomy' argument.

share|improve this answer

I dont know of any function that does what you want but you can build up something like this:

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

I haven't tested this but you can see what I'm getting at. What the above code will do is give you only two levels

EDIT: ahh yes you can use wp_list_categories() to do what you after.

share|improve this answer
    
Actually this is quite useful, as I need to have custom links (with a GET param) on the term links, which doesn't seem possible with the wp_list_categories() way of doing it. –  mike23 Apr 13 '11 at 15:04
1  
Yes this method will give more control over your output. But you could do some nice bit of find and replace on the output of wp_list_categories() to add in your GET parameters. Or even better build a filter for the function to add in the bits you want. Don't ask me how you do that as I've not yet been able to get my head around it :( –  Brady Apr 13 '11 at 15:19
3  
I'd suggest using a custom category walker with wp_list_categories if you want greater control over the output, it'll make your code much more reusable.. –  t31os Apr 13 '11 at 16:09

As I was looking for the same but to get terms of one post, finally I compiled this, and it works for me.

What it does :
• it gets all terms of a taxonomy name for a specific post.
• for a hierachical taxonomy with two levels (ex: level1:'country' and level2:'cities'), it creates a h4 with the level1 followed by an ul list of level2 and this for all level1 items.
• if the taxonomy is not hierarchical, it will create only an ul list of all items. here is the code (I write it for me so I tried to be as generic as I can but...) :

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

So finally you call the function with this (obviously, you replace my_taxonomy by yours) : finishingLister('my_taxonomy');

I don't pretend it's perfect but as I said it works for me.

share|improve this answer

Here I have four level dropdown select list with hidden first item

<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>
share|improve this answer
2  
Please explain why that could solve the problem. –  toscho Mar 25 '13 at 10:00

I realise this is a very old question, but if you have a need to build up an actual structure of terms, this might be a useful method for you:

/**
 * 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_hierarchicaly(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_hierarchicaly($cats, $topCat->children, $topCat->term_id);
    }
}

Usage is as follows:

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

var_dump($categoryHierarchy);
share|improve this answer

I had this problem and none of the answers here worked for me, for one reason or another.

Here is my updated and working version.

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

And usage:

$selector = locationSelector('locationSelectClass');
echo $selector;
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.