Currently, I'm using the following code to create a page that lists all the terms associated with vocab term 1 in my site taxonomy:

$vid = 1;  // Set the vid to the vocabulary id of the vocabulary you wish to list the terms from
$items = array();

$terms = taxonomy_get_tree($vid);
foreach ( $terms as $term ) {
  $count = db_result(db_query("SELECT COUNT(nid) FROM {term_node} WHERE tid = %d", $term->tid));
  $items[] = l($term->name, "taxonomy/term/$term->tid") . " ($count)";
}

if ( count($items) ) {
  print theme('item_list', $items);
}

The only problem is that child terms aren't indented when listed below their parent term(s). They're just displayed like the top-level terms in the list. Can anyone tell me how I can modify this code so that child terms are indented below their parent(s)? I don't know PHP, but I'm assuming some kind of if statement is needed to evaluate whether or not each term is a child of the previous term or not. I realize that currently, the array $items is just being fed a list of all the terms, so as far as the array is concerned, there is no hierarchy.

You can see an example of my problem here: http://www.iddresources.org/?q=node/2

In this list, the term Language has a child named English, but they're both just displayed flush left, as though they're unrelated. (English should be indented, and ideally, if I added the term "English Grammar" as a child of "English", I'd like English Grammar to be indented relative to the position of its parent, English.) Thanks in advance!

Comments

nancydru’s picture

Merlin has struggled with this. His code is at http://www.angrydonuts.com/taxonomy_checkboxes_v2_the_reven

Nancy W.
now running 5 sites on Drupal so far
Drupal Cookbook (for New Drupallers)
Adding Hidden Site Design Notes

dstanford’s picture

I really don't know enough PHP to figure out how to take some piece of that code and use it to modify what I've already got. I don't need checkboxes, so I'm not really sure what to do with that. Thanks for the suggestion anyway.

stella’s picture

I had the same issue. The problem is the theme_item_list() function expects you to have the input data in the format in the example below for nested lists.

Nested list:

  • foo
  • data
    • 1st child item
    • 2nd child item, who has children
      • 1st grandchild
  • bar

example code:

$grandchild_items = array();
$grandchild_items[] = array("data" => "1st grandchild");

$child_items = array();
$child_items[] = "1st child item";
$child_items[] = array("data" => "2nd child item, who has children", "children" => $grandchild_items);

$items = array();
$items[] = "foo";
$items[] = array("data" => "nested terms", "children" => $child_items);
$items[] = "bar";

theme('item_list', $items);

The solution I found involves using a recursive function to get the children of the terms. See below.

<?php
  $vid = 1;  // Set the vid to the vocabulary id of the vocabulary you wish to list the terms from
  $items = get_indented_terms($vid, 0);

  if (count($items) ) {
    print theme('item_list', $items);
  }
?>

Where get_indented_terms() is defined as:

<?php
function get_indented_terms($vid, $tid) {
  $items = array();
  $terms = taxonomy_get_tree($vid, $tid, -1, 1);
  foreach ( $terms as $term ) {
    $count = db_result(db_query("SELECT COUNT(nid) FROM {term_node} WHERE tid = %d", $tid));
    $item_data = l($term->name, "taxonomy/term/$term->tid") . " ($count)";
    
    $term_items = get_indented_terms($vid, $tid);
    $items[] = array("data" => $item_data, "children" => $term_items);
  }
  return $items;
}

?>

autonetex’s picture

I tried to insert these two into block's PHP input, but it didn't work. Please tell me how can I use it...

Thanks

stella’s picture

Change the line "$term_items = get_indented_terms($vid, $tid);" to "$term_items = get_indented_terms($vid, $term->tid);"

autonetex’s picture

It's working like a charm. Thank you so much. You're the best.
I like drupal and we started to get into some project, but this taxonomy child stuff is so confusing...

akolahi’s picture

I found a better solution to indenting taxonomy and correctly showing the item count here:
http://nanwich.info/taxonomy-term-count

I slightly cleaned it up for my purposes:

  $vid = 3; /* <---- put correct vocabulary ID here */
  $items = array();
  $terms = taxonomy_get_tree($vid);
  foreach ( $terms as $term ) {
    $count = taxonomy_term_count_nodes($term->tid);
    if ($count) { /* don't show terms with 0 count */
      $items[] = str_repeat(' - ', $term->depth) . l($term->name,'taxonomy/term/'.$term->tid)." (".$count.")  ".$term->description;
    }
  } /* end foreach */
  print theme('item_list', $items);
nancydru’s picture

a JOIN to check the status to count only published nodes. Alternatively, use "taxonomy_term_count_nodes($term->tid)" to get the count.

BTW, you can also theme each level individually, including that output as an item in the parent level.

Nancy W.
Drupal Cookbook (for New Drupallers)
Adding Hidden Design or How To notes in your database

autonetex’s picture

Here's my problem:
I have taxonomy vocab. for Cars. Makes are attached to Models, Models to styles.
Make
- Model
- Style

Now when you want to display Parent-Child count: Audi > A4, user have to select both every time. Which is no making sense, because user already preselected Audi as a Parent by clicking (I use Taxonomy super select)
Otherwise I get (0) count for Audi and (1) for A4. And if I do not force user to do this - the logic of whole tree is breaking: Audi (0) A4 (1)?
How can I "theme each level" - I don't understand the term "level".

Thank you for answer.

nancydru’s picture

When I say theming each level, what I am referring to is that I get to the bottom level of the list and do my theme ('item_list', $items) that becomes the item value of the parent term. I guess I don't have to do it that way, I just do. But it does give the opportunity add in a <div> for extra display control.

I believe that if you use taxonomy to count the nodes, it will roll up the count to the parent terms. So if there is one A4, then there will also be one Audi.

Nancy W.
Drupal Cookbook (for New Drupallers)
Adding Hidden Design or How To notes in your database

Berto’s picture

Great function snpower! Here's how you can limit the number of levels deep it goes:

function get_indented_terms($vid, $tid, $depth, $currentlevel=0) {
$items = array();
$terms = taxonomy_get_tree($vid, $tid, -1, 1);
foreach ( $terms as $term ) {
$item_data = l($term->name, "taxonomy/term/$term->tid");

$term_items = get_indented_terms($vid, $term->tid, $depth, $currentlevel+1);
if ($currentlevel < $depth) {
$items[] = array("data" => $item_data, "children" => $term_items);
}
}
return $items;
}

Now what I need to find out is, how well is this cached? Because I have it in a block that's displayed on every page. I hear trees are cached, so we should be good. Otherwise, I might make it static if it's bogging my site down.

summit’s picture

Subscribing,
Does somebody have the full code coming from this thread?
Thanks a lot in advance!

greetings, Martijn

vincentdemers’s picture

<?php
function get_indented_terms($vid, $tid) {
  $items = array();
  $terms = taxonomy_get_tree($vid, $tid, -1, 1);
  foreach ( $terms as $term ) {
    $count_query=db_query("SELECT COUNT(nid) FROM {term_node} WHERE tid = %d", $term->tid);
    $count = db_result($count_query);
    $item_data = l($term->name, "taxonomy/term/".$term->tid."") . " ($count)";
    $term_items = get_indented_terms($vid, $term->tid);
    $items[] = array("data" => $item_data, "children" => $term_items);
  }
  return $items;
}

$vid = 2;  // Set the vid to the vocabulary id of the vocabulary you wish to list the terms from
$items = get_indented_terms($vid, 0);

if (count($items) ) {
  print theme('item_list', $items);
}

?>
summit’s picture

Thanks Vincent. Will this also work for D6?

Greetings,
Martijn

fehin’s picture

What if you only want to list one specified term and it's children in a hierachy format? Please see this post to see my description http://drupal.org/node/436108. Thanks.