Last updated 27 March 2009. Created on 16 March 2009.
Edited by LeeHunter, Steven Jones, druvision. Log in to edit this page.

This PHP snippet displays all top-level taxonomy terms in a page or a block.

For each term, the count of sub-terms is displayed.

The code is using the taxonomy API, so it's compatible with taxonomy_redirect (verified). It should also be compatible with other add-on modules which change the term path.

$vid = 3;
$terms = taxonomy_get_children(0, $vid);
if (count($terms)) {
  echo '
    '; foreach ($terms as $term){ echo "
  • " . l($term->name, taxonomy_term_path ($term)) ; $children = taxonomy_get_children($term->tid, $vid); $cnt = count($children); if ($cnt) echo " ($cnt)"; echo "
  • "; } echo '
'; }

Looking for support? Visit the forums, or join #drupal-support in IRC.


Summit’s picture

Hi, See no ask question this way, sorry if not appropriate..
Does somebody know how to use above code and bring it through $block->content to use it themable in "panels" delegator custom php content?
Thanks a lot in advance, greetings, Martijn

fehin’s picture

Is there a way to get this to show only the top level term under the vocabulary and list it's children in hierachy form? Right now it lists all terms under the vocabulary in one long list. Thanks.

lindsayo’s picture

I'd love to know that, too.

venusrising’s picture

me too


Marko B’s picture

here u go, put this into block, put vid on second line and u have it. this is from block snipets on

// The ID of the taxonomy vocabulary for which you'd like to create a nested list
$vid = 2;
$debug = false;
// Dado un elemento reconstruido con sus children enlazados,
// busca entre sus hijos y va añadiendo los ids estos útlimos
// al array buffer pasado por referencia.
function fill_children_ids_recursive(&$term_rebuilt, &$children_ids) {
    global $debug;

    if ($term_rebuilt["children_count"]>0) {
        for ($i=0;$i<$term_rebuilt["children_count"];$i++) {
            if ($debug) {
            if (!in_array($term_rebuilt["children"][$i]["id"], $children_ids)) {
            fill_children_ids_recursive($term_rebuilt["children"][$i], $children_ids);

// Los terminos que nos devuelve esta función no tienen hijos enlazados
// con lo que nos vemos obligados a reconstruir la matriz de términos
// para enlazar también los hijos.
$tree = taxonomy_get_tree($vid);
$terms = array();
// Reconstruimos el array de terminos
// añadiendo algunos campos que nos hacen falta
// y que no están establecidos por defecto.
foreach ($tree as &$term) {
    $terms[] = array(
foreach ($terms as $key => &$term_rebuilt) {
    for ($x=0;$x<sizeof($term_rebuilt["parents"]);$x++) {
        $parent_tid = $term_rebuilt["parents"][$x];

        $not_found = true;
        while($not_found&&($idx<sizeof($terms))) {
            if ($terms[$idx]["id"]==$parent_tid) {
                if ($debug) {
                    echo "<pre>found: \$idx = $idx\n";
                    echo "</pre>";
                $not_found = false;

if ($debug) {
    echo "<pre>Arbol de elementos recontruidos\n\n";
    echo "</pre>";

// Creación de la lista HTML.
print "<ul><li>";

$depth = 2;
foreach($terms as $index => &$term_rebuilt) {
    // Para cada elemento reconstruido se buscan los ids de los
    // hijos, no importa a qué nivel de profundad.
    $children_ids = array();
    fill_children_ids_recursive($term_rebuilt, $children_ids);

    // Con los ids de los hijos consultamos para que nos devuelva
    // el número de nodos que cuelgan tanto directamente de el cómo
    // de sus hijos.
    $sql_count = "SELECT COUNT(nid) FROM {term_node} WHERE tid = '".$term_rebuilt["id"]."' ";    
    if (sizeof($children_ids)>0) {
        $sql_count .= " OR tid = '";
        $sql_count .= join("' OR tid = '",$children_ids);
        $sql_count .= "'";
    if ($debug) {
        echo "<pre>SQL for term: ".$term_rebuilt["name"]." -> ".$sql_count."\n</pre>";
    $term_rebuilt["global_node_count"] = db_result(db_query($sql_count));

    // Se expulsa la lista.
    if ($term_rebuilt["depth"] > $depth) {
        print '<ul>';
        $depth = $term_rebuilt["depth"];
    if ($term_rebuilt["depth"] < $depth) {
        for ($i=($depth - $term_rebuilt["depth"]);$i>=1;$i--) {
        print '</ul></li>';
        $depth = $term_rebuilt["depth"];
    print '<li>' . l($term_rebuilt["name"], 'rep/term/' .$term_rebuilt["id"]) . " (".$term_rebuilt["global_node_count"].")";

for ($i=$depth; $i>=0; $i--)
      print "</li>\n</ul>\n";

if ($debug) {
    echo "<pre>Arbol original, obtenido por: taxonomy_get_tree\n\n";
    echo "<pre>";
klidifia’s picture

None of this was any help to me however I ended up doing this myself which I thought I would share:

// Get the terms from a particular vocabulary.
$terms = taxonomy_get_tree(VID);
// Iterate through the terms.
foreach ($terms as $key => $term) {
  // Get the parent TID(s) of the terms.
  $parents = current($term->parents);
  // If there is no parent, remove the term from our list.
  if ($parents !== '0') {
// Dump the term list, we should have top level ones only.