At last night's DUG I asked the group if anyone had a good solution/module recommendation for showing related content in a block, based on taxonomy. A block like this could be used to show blog entries/forum discussions related to the blog entry in focus ("You might also be interested in"), or to show FAQs related to a piece of content, etc, etc. Solr was suggested, but while it is an excellent search option, it does not seem to be well suited to this.
There are some modules out there that can do this and if any of you have any recommendations I'd love to hear them. I've tried Taxonomy Quick Find, but it's approach is not ideal for my needs.
What I really wanted was to do this through Views and get all of the fine-grained control over the way you select and display your information that only Views gives you, but also in a way that is dynamic, rather than a collection of duplicated blocks with hard-coded taxonomy codes. After digging around I found a blog post on how to use views 2 in Drupal 6 to create a related content block. The post is a bit dated, but otherwise is solid and easy to follow.
There are some issues with the solution, most raised and solved in the comments (as usual). It does not exclude the current node from the display and it crashes when there is no taxonomy specified for the node in focus. Both of these can be fixed and I did. I don't claim this is the best way to do things and I'd welcome suggestions/alternatives.
He provides a PHP code snippet that picks up the taxonomy terms for the node in focus. My latest PHP code to replace his, with some comments and formatting for those who are not coders and defensive code that fixes a couple of little bugs, is as follows:
// Pick up the taxonomy for the node in focus
$node = node_load(arg(1));
if ($node && $node->taxonomy) { // If we have a node with taxonomy specified
$terms = array();
// Loop through and collect this node's taxonomy terms
foreach($node->taxonomy as $term) {
$terms[] = $term->tid;
}
if($terms) {
return implode('+',$terms); // Return all terms found separated by +
}
}
// If we get to this point we found no terms and return null
return; // Nothing to see hereTo make sure that the node in focus in not shown in this list I then created a second argument, similar to the first, for a node id with the following PHP:
// Pick up the node in focus
$node = node_load(arg(1));
//Return the current Node id
return $node->nid;Then I checked the "Exclude the argument" box.
Others solved this by getting the node id from the url (see comments), but since I use pathauto this did not work for me.
As he says in his post, the rest you handle from blocks as per normal and the new block then only shows up for nodes with taxonomy, which you can again control more finely from blocks. You can use Views to limit the related nodes to select content type and to control the sort order and so on.
Some folks said in the comments they needed more fine-grained control on the taxonomy. This is not something I've needed thus far, but you can find a solution to this in the comments.
I hope this is useful to some of you and I welcome any improvements. I'm still getting my feet wet on all this and I'm sure there will be further tweaks needed down the line. Further, I think Panels can handle this too, but last I heard it was still dicey in 6.

Comments
Too bad I missed the meeting
Too bad I missed the meeting yesterday (again!) but here's my 2 cents.
Actually getting node ID from the url works even when you use pathauto. I'm using a similar approach to related content on one of our sites using term ID with depth - that is truly awesome feature of Views taxonomy term argument.
To get terms from one specific vocabulary only you'll need to replace your $terms[] = $term->tid with
if($term->vid == $vid ) {$terms[] = $term->tid;
}
where $vid is the id of the vocabulary you want to include
nid retrieval change
Thanks very much. That's cool on both counts. I changed the way I pull the nid as this method seems better... and I should have guessed that. I'm also starting to suspect that I'll soon be needing that limitation by vocabulary.
Sala kahle,
Grant
Loops be gone
Even though the taxonomy module loads up $node->taxonomy it's still probably better to go through the API to get the node's terms. Taxonomy caches the data, so it's not going to cause any extra load on the database. So, that big first box of code can be replaced with:
// Load the node in focus
$node = node_load(arg(1));
// Get all the terms for this node
$terms = taxonomy_node_get_terms($node);
if (!empty($terms)) {
return implode('+', array_keys($terms)); // Return all terms found separated by +
}
And, then, if you wanted to pull the terms from just one vocabulary, you'd use
taxonomy_node_get_terms_by_vocabulary()instead oftaxonomy_node_get_terms()and you could stay out of the wholeforeachbusiness.Disclaimer: I didn't test the code!
And, seconded that arg(1) should be the nid regardless of whether or not the node is aliased. Oh, and you should probably check arg(0) for 'node' and arg(1) for being numeric, but I'm guessing that you did that in the block visibility settings.
Marc
http://www.funnymonkey.com
Click. Connect. Learn.
The whole $node =
The whole
$node = node_load(arg(1));orif ($node = node_load(arg(1)) && arg(0) == 'node')are a little clunky, and a pattern that I wish would go away. While it might have made more sense in Drupal versions of yore, a handy (arguably preferred) way to handle this in Drupal 6 would be with menu_get_object();. It makes the process of getting the current node a bit simpler. Callingmenu_get_objectwith no arguments will default to node, and it won't return anything if the current page does not have a node associated with it.Coolness
Thanks! This works great. Refinements upon refinements. Between the three of you my code looks very different, so much simpler and easier to read, but also most stable and reliable. Thanks to all of you. I'm so glad I posted this and I hope it helps others. I may do a screen-cast for this at some point as payback, or a flash presentation.
Sala kahle,
Grant
Much better
Thanks! That is much slicker. I'm still getting in to this aspect of things and it's always good to get exposed to better methodology. It worked great. Nothing has changed visually, between the changes I made based on the first three comments made to this post, but it's good to know that it's more maintainable and likely has more longevity. Much appreciated.
Sala kahle,
Grant
menu_get_object
Yep, Mike is right on the money with menu_get_object() -- goodbye to that node_load(arg(1)) junk! I've been stuck in D5-land way too long. Grant - it'd be nice to see your polished code...
Revised Code
Of course Marc. For the nid there is no longer any code, but rather the default argument type is set to, "Node ID from URL" and "Exclude the argument" remains checked.
For the taxonomy the code is now:
// Pick up the node in focus (if any)
$node = menu_get_object();
// Get all the taxonomy terms for this node (if any)
$terms = taxonomy_node_get_terms($node);
// If taxonomy terms were found, return them to the view
if (! empty($terms)) {
return implode('+', array_keys($terms)); // Return all terms found separated by +
}
For myself, since I'm old-school and am always thinking about maintainability, I also add the following at the end. It does absolutely nothing, but it does highlight the "not found" scenario to the next coder working on this project. YMMV
// If we get to this point we found no terms and return nullreturn; // Nothing to see here
I've not yet needed to limit the view by vocabulary using taxonomy_node_get_terms_by_vocabulary(). If I do I'll aim to come back and post updates. I keep muddling along. One day I'll get there.
Sala kahle,
Grant
Exclude current node?
Hi Grant, thanks for putting this post out there. It was just what I was looking for.
The only problem that I can't solve is the second argument you have for excluding the current node from the view, you call it the "node in focus". I've added an additional argument for Node: nid, inserted the PHP snip you have above in your original post, and then made double sure to click the "exclude this argument" type box.
What I get is a missing block. Something about that logic kills the view altogether. I'm not an argument wizard, in fact its one of my weakest points in building Drupal sites. Any tips to help me sort this out?
I'm using this as an example:
http://cctvcambridge.org/node/20294
I would actually like to apply this "hide current node from view" arg trick to a few of the blocks on this sample page.
Thanks for the help.
No worries. I'm still
No worries. I'm still getting into arguments myself. Following some of the advice here I changed the way I was picking up the nid. The new way is as follows, and I welcome any additions from those who can explain it better:
What this does is pull in the nid in your URL as an argument and then tells the view not to include this node in the list. Of course this will only work if the node in your URL is the one you want to exclude. I hope this answers your question.
Sala kahle,
Grant
Bingo!
Thanks, Grant. That did the trick. I'm reading between your lines and getting the sense that this trick doesn't work with aliased nodes since the nid doesn't appear in the URL. Is that right?
This should work with
This should work with aliased nodes with no issue.
FunnyMonkey
Click. Connect. Learn.
Using Drupal in Education
FunnyMonkey
Last question
I noticed that these blocks appear on the node edit pages, where the URL says mysite.com/node/100/edit.
I have been hiding blocks with PHP visibility snippets for content type and URL. But if I can handle this View's block visibility with an argument then my block visibility settings can become simple.
How would I handle an argument based on Node: node type to return no results on certain node types and not others? Then my block vis settings can simply say something like "show on all pages except where URL = edit* ".
Arguments can be validated by node type
Create an argument for nids.
Under Validation Options, select "Node"
You will then have the option to only validate the argument on specific node types.
Views 2 rocks :)
Cheers,
Bill
FunnyMonkey
Click. Connect. Learn.
Using Drupal in Education
FunnyMonkey
Thanks
Just as you prescribed, thanks very much. I set the view argument to validate on my choice of content types, then set the block visibility to not show on edit or admin pages.
Similar Entries Module
http://drupal.org/project/similar
The module above is pretty nifty for creating a block like this w/o dependence on taxonomy. Jonathan Hedstrom used it to build the related content block on http://247townhall.org. The only PITA is the lack of CCK support.
Anyone seen a patch for this? As far as I can tell, there isn't one in the issues queue.
Cheers,
Sean
terms from just one vocabulary
This helped Thanks!
http://api.drupal.org/api/function/taxonomy_node_get_terms_by_vocabulary
// Get all the taxonomy terms for this node in one vocabulary (if any) replace $vid with vocab id
$terms = taxonomy_node_get_terms($node,$vid);
Cheers
On Term pages but not on node pages, please help?
Hi,
I am not able to get this working on my node/NID pages. It works on term/TID pages.
My view has same settings and code as above.
My query also gives the term-id as argument and NOT the node-id.
What do I do wrong please?
Query code:
SELECT node.nid AS nid,node.title AS node_title,
node_revisions.body AS node_revisions_body,
node_revisions.format AS node_revisions_format
FROM node node
INNER JOIN term_node term_node_value_0 ON node.vid = term_node_value_0.vid AND term_node_value_0.tid = 147
LEFT JOIN node_revisions node_revisions ON node.vid = node_revisions.vid
WHERE term_node_value_0.tid = 147
EDIT: Got it working. I needed first to have the NID argument and then the Taxonomy argument.!
Views and Views Group By Module
I am just seeing thread thread and the tutorial mentioned... wish I found it yesterday!
I've done something similar (using the old school way with node_load). Here's the views export using views and the views group by module to show the block with node id, title, and the number of common terms:
http://kristen.org/content/use-drupal-views-group-module-show-closest-ma...
Also, for Drupal 6, you can check out the featured content module for easily creating lots of different kinds of featured and related content blocks including sorting by closest match by terms:
http://drupal.org/project/featured_content
Cheers,
Kristen
Contact: https://www.hook42.com/contact
Drupal 7 Multilingual Sites: http://www.kristen.org/book
subscribe
subscribe
Depth?
This is excellent, but I need one more refinement. I'm using this to link to related content as sort of a navigation method as I have way too many nested landing pages, based off the taxonomy terms, for a section of my site.
I'd like to put related pages three levels down, for instance, starting at that level in the vocabulary, rather than showing the entire vocabulary list from the top... but inclusive of taxonomy terms below the one that the current page is related to.
Does this make sense?
Ideas?
Alternative Solution
Hi all!
check out my solution to this problem: http://speedev.wordpress.com/2010/11/23/drupal-related-by-terms-view/
With this solution you have a view that show you nodes by number of term in commons with the nodes for which you need related content.
Well, my English isn't optimal and this is also my blog's first post, so, be patient!
Let me know what do you think about my solution!
Also code corrections are welcome, 'cause I've made the code this morning in a big rush for this functionality on our online newspaper: www.viveregenova.comune.genova.it. Well, the functionality works pretty good I think.
Byez,
Antonio