I want to create a page that displays all the taxonomy terms within a particular category as links. (When clicked, the term links should display all the nodes associated with that taxonomy term.) I don't want to use the taxonomy menu module, because my list of terms will be too long to fit in nicely with the navigation. I tried the categories module and it did exactly what I wanted, but I didn't like the way it treated every term as a node and added the term to the main menu by default. (I also had some problems with importing older taxonomies and I'm just hoping to avoid using the categories module altogether.) I've read some posts on this already and I think there might already be a snippet that will work for me, but I don't know WHERE I'm supposed to copy and paste the snippets I have seen. It seems like some of the people who respond just assume the reader will know what PHP file or what administration area I'm supposed to be in when pasting in the snippet, and sadly, I have no idea. Here are some examples where people provided snippets, but I don't know what to do with them:

http://drupal.org/node/114686

http://drupal.org/node/85740

Can someone help me make use of one of the snippets from these forums? My other concern is that I don't know enough about PHP syntax to do much "tweaking" of a snippet. So, if the snippet only displays a list of terms but doesn't link them to nodes associated with that term, I probably won't be able to add that code myself. Thanks in advance!

Comments

Anonymous’s picture

The code can be pasted into a block, if you want the display of links in your sidebar, or in the body of a page if you want a separate page of links. You have to choose PHP Code as the input format. This holds true for most snippets, except maybe for theme snippets which go in your custom theme files. You'll need to read up on theming to make use of theme snippets. However, have you looked at the Taxonomy List module?

http://drupal.org/project/taxonomy_list

Using this module, you could create links to the urls that produce the lists you want.

nevets’s picture

Create a page (or a story), place

<?php
$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 ) {
  $items[] = l($term->name, "taxonomy/term/$term->tid");
}

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

in the body, make sure you set the $vid to the vocabulary you want to see.

Also. make sure the input format is 'PHP code' and you probably do not want the page promoted to the front page.

dstanford’s picture

That worked beautifully...now there's just one more thing that I dared not ask for initially, but that was so easy that I'm getting a bit greedy. What could I add to the code to make it so each term has a number after it that indicates how many total nodes are associated with that term? So, a list of terms with associated nodes would look like this (as an example):

Restaurant Reviews (1)
Movie Reviews (4)
Nightclub Reviews (2)
Music Reviews (0)

nevets’s picture

Here is the updated snippet, one extra line and one changed line

<?php
$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);
}
?>
dstanford’s picture

Perfect!

macm’s picture

Yes it is works, but how can I print my full taxonomy tree?

1
-1.1
-1.2
-1.3
2
-2.1
-2.2
--2.2.1
--2.2.2
-2.3
etc..

I cant find in Drupal forum. Could you help me?

I just want insert a snippet into my custom-page.tpl.php and tell. Print my full tree of $vid=10 for example.

I tried a lot of modules but isnt possible and I cant believe. Just print full tree just like a Navigation tree.

Will be fine of course the .output follow correct ul li syntax or will be fine respect hierarchy syntax.

nevets’s picture

Create a new node (say a page) and paste the following in to the body. Make sure the 'Input format' is 'PHP code'.
Make sure you set $vid to the vocabulary id you want to list. Also you may want to change $indent which is the string printed based on depth of the term.

<?php
$vid = 6;  // Set the vid to the vocabulary id of the vocabulary you wish to list the terms from
$indent = "--";  // Set to what you want the indent to be
$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));
  print '<div>' . str_repeat($indent, $term->depth) . l($term->name, "taxonomy/term/$term->tid") . " ($count)"  . '</div>';
}

?>
macm’s picture

Hi Nevets, good see you again

This function is very similar with taxonomy drop down menu or is there in taxonomy.module

This function not meet my needs too because I need re-create ul li list.

Probably I will use treeview Jquery plugin so I need prepare my html to respect the syntax

How can I tell by php to print ul if have childs ? and How can I close /ul tag?

If you can take a look in DOM of http://jquery.bassistance.de/treeview/

I am trying something like this:

$vid = 10;  // Set the vid to the vocabulary id of the vocabulary you wish to list the terms from
$indent = "--";  // Set to what you want the indent to be
$items = array();

$terms = taxonomy_get_tree($vid);
foreach ( $terms as $term ) {
	$child1 = count(taxonomy_get_children($term->tid, $vid));
  $count = db_result(db_query("SELECT COUNT(nid) FROM {term_node} WHERE tid = %d", $term->tid));
  if ($child1 > 0 ) {
  print '<ul>';
  print '<li>' . str_repeat($indent, $term->depth) . l($term->name, "taxonomy/term/$term->tid") . " ($count)" . " ($child1)"  . '</li>';
	  foreach($child1 AS $c1tid => $c1term){
	  $child2 = taxonomy_get_children($c1term->tid, $vid);
	  if ($child2 > 0 ) {
		print '<ul>';
	  print '<li>' . l($term->name, "taxonomy/term/$term->tid") . " ($count)" . " ($child2)"  . '</li>';
		  foreach($child2 AS $c2tid => $c2term){
  		$child3 = count(taxonomy_get_children($c2term->tid, $vid));
		  if ($child2 > 0 ) {
			print '<ul>';
		  print '<li>' . l($term->name, "taxonomy/term/$term->tid") . " ($count)" . " ($child3)"  . '</li>';
			  foreach($child3 AS $c3tid => $c3term){
	  		$child4 = count(taxonomy_get_children($c3term->tid, $vid));
			  if ($child3 > 0 ) {
				print '<ul>';
			  print '<li>' . l($term->name, "taxonomy/term/$term->tid") . " ($count)" . " ($child4)"  . '</li>';
						foreach($child4 AS $c4tid => $c4term){
			  		$child5 = count(taxonomy_get_children($c4term->tid, $vid));
					  if ($child5 > 0 ) {
						print '<ul>';
					  print '<li>' . l($term->name, "taxonomy/term/$term->tid") . " ($count)" . " ($child5)"  . '</li>';
					  
} else {print '</ul>';}
}
} else {print '</ul>';}
}
} else {print '</ul>';}
}
} else {print '</ul>';}
}
} else {print '</ul>';}
}

But isnt working yet. If you can help. I am printing . " ($childX)" and . str_repeat($indent, $term->depth) to try find my erros of course I will delete when be done.

Regards

nevets’s picture

Here is a version that produces nested lists. The 'if' statement around the function keeps it from being redeclared.

<?php
if ( ! function_exists('private_get_children') ) {
	function private_get_children($vid, $parent = 0) {
		$items = array();
		$terms = taxonomy_get_tree($vid, $parent, -1, 1);
		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)" . private_get_children($vid, $term->tid);
		} 
		if ( count($items) ) {
			return theme('item_list', $items);
		}
	}
}

$vid = 6;  // Set the vid to the vocabulary id of the vocabulary you wish to list the terms from

print private_get_children($vid);
?>
macm’s picture

Hi Nevets,

Thanks, It is done. Well Done by the way.

Regards

macm’s picture

Hi Nevets,

I have hundreds of terms in my taxonomy. I tried super_select but in my case spend + - 25 seconds to load in the cck node form. I tried cache_set to optimize this too but at this moment dont work well. I tried bootstrap.inc to load remote page with AJAX but it is hard. Could not work.

So I was thinking if we can merge your solution with

http://drupal.org/node/98253
http://drupal.org/node/101092

to generate something like this

http://www.scbr.com/docs/products/dhtmlxTree/ or
http://www.blueshoes.org/_bsJavascript/components/tree/examples/example3...

We could use Jquery to generate the treeview.

Regards

nevets’s picture

While an interesting thought converting the snippet to work as a form input is more than a little work. I am also not sure that with hundreds of terms how much time that would save you. I would look to using auto complete in a case like this as it would minimize the load of the page.

macm’s picture

Yes, you are right.

But I think to large taxonomy, autocomplete is very annoying (some cases) because isnt possible see the tree.

So I will try convert my form into multi-steps:

the first step (text, body, images) and

second with JQuery/AJAX to "category box" because it is this box that delay my node-form. While user fill title/body AJAX do the job.

If I find a solution I will post here. If you have ideas how do this please let me know. I will use cck with super_select.

Regards and thanks.

Ps: Please see http://drupal.org/node/116418#comment-255217 to this idea

johnhanley’s picture

Here's a small enhancement to Nevets' excellent snippet.

For multiple vocabularies, define an array with the vid's and wrap the function call in a loop. For example:

$vocabularies = array(3,4); // the vocabulary vids
for ($i = 0; $i <= count($vocabularies); $i++) {
  print private_get_children($vocabularies[$i]);
}

Another option would be to insert the vocabulary name at the start of each list, but I didn't need it.

virtualdrupal’s picture

Just fyi, here's a slight modification so it pulls only the child terms of whatever term you're currently on...

<?php
if ( ! function_exists('private_get_children') ) {
    function private_get_children($vid, $parent = NULL) {
	    if (empty($parent)) { $parent = arg(2); }
        $items = array();
        $terms = taxonomy_get_tree($vid, $parent, -1, 1);
        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)" . private_get_children($vid, $term->tid);
        }
        if ( count($items) ) {
            return theme('item_list', $items);
        }
    }
}

$vid = 3;  // Set the vid to the vocabulary id of the vocabulary you wish to list the terms from
$parent = 57;
print private_get_children($vid);
?>
virtualdrupal’s picture

Also, use this one to get the parents of whatever taxonomy term you're on


$all_parents = taxonomy_get_parents_all(arg(2));
$parentmenu = '<ul id="someparentmenu">';
foreach($all_parents as $parent){
if($parent->tid != arg(2)){
$parentmenu .= '<li>'.l($parent->name,'taxonomy/term/'.$parent->tid).'</li>';
}
}
$parentmenu .= '</ul>';
print $parentmenu;
deomurari’s picture

Dear mikenotmike....

Although it's an old thread still looking for the help.....

I was searching for this snippet fro my website.....
is it possible to limit show only next two levels in this code....

eg.
Currently it shows

Aegothelidae (0)
--Aegotheles (0)
----Aegotheles affinis (0)
----Aegotheles albertisi (0)
----Aegotheles archboldi (0)
----Aegotheles bennettii (0)
----Aegotheles crinifrons (0)
----Aegotheles cristatus (0)
----Aegotheles insignis (0)
----Aegotheles savesi (0)
----Aegotheles tatei (0)
----Aegotheles wallacii (0)
Apodidae (0)
--Aeronautes (0)
----Aeronautes andecolus (0)
----Aeronautes montivagus (0)
----Aeronautes saxatalis (0)

Where it should show
Aegothelidae (0)
--Aegotheles (0)
Apodidae (0)
--Aeronautes (0)

regards

harmonyhalo’s picture

Hi, i'm wondering if there's an easy way to modify this snippet to list the nodes in the node count as a numerical list. So rather than just presenting the node count, it lists a count of those nodes from 1 to x. I know you can do this through views, but that will only list the node title or node id, what i'm trying to do for each term is have a block for each term that contains a numerical link for each node assigned to that term. So it's almost like providing a list of the next level down from the above snippet (if that makes sense).

nevets’s picture

But it should have a line like

            $count = db_result(db_query("SELECT COUNT(nid) FROM {term_node} WHERE tid = %d", $term->tid));

Trying changing that to

            $results = db_query("SELECT nid FROM {term_node} WHERE tid = %d", $term->tid);
            $nid_list = array();
            $i = 1;
            while ( $next = db_fetch_object($results) ) {
                $nid_list[] = l($i++, "node/$next->nid");
            }
            // Seperate the links with a space character
            $count = implode(' ', $nid_list);

You may wish to change

            $results = db_query("SELECT nid FROM {term_node} WHERE tid = %d", $term->tid);

to

            $max_records = 9;
            $results = db_query_range("SELECT nid FROM {term_node} WHERE tid = %d", $term->tid), 0, $max_records);

to limit the number of links shown.

harmonyhalo’s picture

Thanks so much for your assistance nevets!
Just wondering, is there an easy way to then turn off the display of the terms so it just lists the array of node numbers?
here's a hard coded version of my webpage that kind of illustrates what i'm trying to do
http://www.renewal.org.au/object/photos/index.html
I'm a total php dunce so i'm struggling to work out what little tweaks to make.
But yeah, thanks also for your suggestion Wonder95 - i looked into that, but i wanted to be able to get the individual nodes listed as numbers inside a block so i can then place that block inside different image galleries so you have an immediate sense of how many images are in the gallery, but also be able to click on each one and go directly to the node. I realise you can kind of do this with views, but i couldn't work out how to get this to substitute the nid or title for a number specific to that taxonomy term.
Thanks again!

nevets’s picture

If I understand correctly you want a list of all the nodes associated with a particular vocabulary and print them as numbered links (linked to each node/image). This should do the trick

<?php
$vid = 1;  // Set the vid to the vocabulary id of the vocabulary you wish to list the terms from

$sql = "SELECT DISTINCT(nid) FROM term_node t JOIN term_data td USING(tid) WHERE vid = %d ORDER BY nid";
$results = db_query($sql, $vid);
$nid_list = array();
$i = 1;
while ( $next = db_fetch_object($results) ) {
	   $nid_list[] = l($i++, "node/$next->nid");
}
// print the links seperated with a : character
print implode(' : ', $nid_list);
?>
harmonyhalo’s picture

Thanks so much ! - believe it or not it's actually been a huge hurdle in the porting of my site to a drupal system and i'd spent hours looking for the right snippet so much gratitude to you for your help!
I actually found that for my purposes i needed a numbered listing of the tid not the vid, but it was easy enough to change in the code you supplied to give the required result. thanks again Nevets.

harmonyhalo’s picture

When I modified the above snippet on my test server it worked fine (replacing the vid with tid to list the term's child count) but when I implement this on a live server I get the following error message
"user warning: Column 'tid' in where clause is ambiguous query: SELECT DISTINCT(nid) FROM term_node t JOIN term_data td USING(tid) WHERE tid = 1 ORDER BY nid in /home/objectno/public_html/test/includes/database.mysql.inc on line 172."
Here's the a link to where the error is popping up http://objectnotfound.net/test/photos/gallery-one/sale-4-chairs
on this page i've got the above snippet using the vid active as well as my modification to the code (which is causing the error). The reason I'm trying to change this is so i can show only the nodes assigned to the one term (the photos in one gallery) rather than the whole vocabulary which is currently happening as you can see in the top block.
Here's the erroneous code:

$tid = 3; 

$sql = "SELECT DISTINCT(nid) FROM term_node t JOIN term_data td USING(tid) WHERE tid = %d ORDER BY nid";
$results = db_query($sql, $tid);
$nid_list = array();
$i = 1;
while ( $next = db_fetch_object($results) ) {
       $nid_list[] = l($i++, "node/$next->nid");
}
// print the links seperated with a : character
print implode(' : ', $nid_list);
nevets’s picture

In the query try changing

WHERE tid

to

WHERE t.tid
harmonyhalo’s picture

nevets - i think i love you! thanks again! :)

harmonyhalo’s picture

Thanks so much for your assistance nevets!
Just wondering, is there an easy way to then turn off the display of the terms so it just lists the array of node numbers?
here's a hard coded version of my webpage that kind of illustrates what i'm trying to do
http://www.renewal.org.au/object/photos/index.html
I'm a total php dunce so i'm struggling to work out what little tweaks to make.
But yeah, thanks also for your suggestion Wonder95 - i looked into that, but i wanted to be able to get the individual nodes listed as numbers inside a block so i can then place that block inside different image galleries so you have an immediate sense of how many images are in the gallery, but also be able to click on each one and go directly to the node. I realise you can kind of do this with views, but i couldn't work out how to get this to substitute the nid or title for a number specific to that taxonomy term.
Thanks again!

CtrlAltDelete’s picture

Is there a simple way to add a pager to the results so the list can be limited to say 25 or so terms per page? I haven't been able to figure out how to page results returned by the "taxonomy_get_tree" function.

tignux’s picture

Is about 3 weeks I search a solution to add a pager to this function

Anybody can help us?

|_0_|
InfoCongressi.com

wonder95’s picture

Have you tried the taxonomy_list module? I used it on a site of mine, and it does exactly what you need.

Anonymous’s picture

Not sure if it will work in the OP's situation, but it might help others looking for similar solutions. I recently discovered the Ubrowser module when integrating Ubercart. It is absolutely delightful. You generate php code to insert an interactive box that lists and links to all nodes in a specific vocabulary. It lists the terms in one box; when you click a term, the nodes are listed in a second box. Just select and click to visit that node.

Saves space, looks cool. I've already impressed one client by using it as a site map.

Happy day,
Anne

Akela’s picture

Nevets, thank you for your code.

I tried to modify the php to list hierarchical terms that have at least one node within them, but I cannot get it to work.

<?php
$vid = 5;  // Set the vid to the vocabulary id of the vocabulary you wish to list the terms from
$indent = "--";  // Set to what you want the indent to be
$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));
  if($count) {    // kick out the empty terms
  $pole[]=Array (l($term->name, "taxonomy/term/$term->tid") . " ($count)", $term->depth, $count, $term->tid)  ;
    }
  print '<div>' . str_repeat($indent, $term->depth) . l($term->name, "taxonomy/term/$term->tid") . " ($count)"  . '</div>';
}
?>

Would anyone, please, attempt to correct this (or link to a place where the answer is already provided)? I looked and I looked, but I cannot find the solution.

nevets’s picture

Because your version does not look like my previous answers this may be wrong but I think you want

<?php
$vid = 5;  // Set the vid to the vocabulary id of the vocabulary you wish to list the terms from
$indent = "--";  // Set to what you want the indent to be
$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));
  if($count) {    // kick out the empty terms
    print '<div>' . str_repeat($indent, $term->depth) . l($term->name, "taxonomy/term/$term->tid") . " ($count)"  . '</div>';
  }
}
?>
Akela’s picture

This works exactly as I need it to. Thank you so much!

mikeybusiness’s picture

Fabulous snippets nevets! So useful!

videoschaf’s picture

I just used your code, and it is awesome! Exactly what I am looking for soooo long now, almost...

How do I also get to display all empty terms, with no nodes assigned yet (with a count of 0 of course)?

And how could I limit the output to a defined term with other sub-terms on a 2 level hierarchy? I tried the code above for that, but it does not seem to work for me ...

craigkendall’s picture

This is a great thread. Thanks for the info and customizations. I'm looking for another variation if anyone has any ideas. I need to create a link around a box that is to the most current item posted in a single vocabulary id or of a certain content type.

So what I'm looking for is something that will let me do:

<a href="GENERATED-LINK-GOES-HERE">
Content I want to link is here but not the title from the node
</a>

Does that make sense?

Oh, and I'm on 6.x

Help MUCH appreciated!

manoz_79’s picture

Hi,

Am using the snippet, to show the count of number of nodes tagged with a term, how can I also show the count for total number of comments in the nodes.

The snippet I am using is:

unset ($output);
$vocabulary_id = 12;
$result = db_query("SELECT d.tid, d.name, MAX(n.created) AS updated, COUNT(*) AS count FROM {term_data} d INNER JOIN {term_node} USING (tid) INNER JOIN {node} n USING (nid) WHERE d.vid = $vocabulary_id AND n.status = 1 GROUP BY d.tid, d.name ORDER BY updated DESC, d.name");
  $items = array();
  while ($category = db_fetch_object($result)) {
    $items[] = l($category->name .' ('. $category->count .')', 'taxonomy/term/'. $category->tid) .'<br />';
  }
print theme('item_list', $items); 

Using the above snippet I am able to acheive:

- Holiday (4)
- Work (6)

I want to display:

# Holiday (4) nodes and (20) comments (This means that the term 'holiday' has 4 nodes tagged with the term and the 4 nodes in total have 20 comments)
# Work (6) nodes and (36) comments

Can somebody please help.

Thanks,
Manoj