Using Views 2 and Drupal 6 to Create a Related Pages Block

Published June 17, 2008

Today's question comes from Dale at NFi Studios in Orlando, FL - my home town:

Essentially:, what i'm trying to do is
1. Determine the current nodes taxonomy terms
2. Determine all other pages that share taxonomy terms
3. Display the title (and link) to those pages in a block

Using Drupal 6.2 and Views - Looked at a few modules, but nothing quite
exact - Reviewing some module snippets right now to see if I can
potentially use an argument to do it.

Dale asks a good question: before the release of Panels for Drupal 6, how can one associate a block with the node it's being displayed next to without writing a custom module? It turned out to be simpler than I expected. I actually started going down the path of custom modules, but in the process I noticed that Views still have the ability to load Arguments with PHP Code, and my solution wrote itself.

Dale, you're already pretty far along: you know you need a view inside of a block, displayed based on taxonomy terms to relate the view to the pages. Instead of giving you a full-fledged tutorial on Views and the Black Arts, you'll be getting a recipe that outlines how to create the block in question.

First, you'll want to download and install Views 2 for Drupal 6, currently in Beta 4, then enable the module under admin/build/modules - remember that Views also requires you to activate Views UI, as the views.module is more of an API for creating views.

The first step in your new Views journey is to Add a new view at admin/build/views. Just click on the tab near the top of the screen:
add a view

Now you'll be asked to name your view something computer-friendly - in this case you'll name it related_by_term:
Name your view

Once you click through, you'll be presented with the granddaddy of all administration screens, but don't be afraid, things move pretty quickly in here if you know what you're doing. Notice the Orange text in the top right: New view. Until you push the Save button at the bottom of the screen, all you hard work could be lost, and especially don't forget to save once you've finished configuring your view.
Main views screen

I want you to skip all those fancy options and dive right in: you've got to eat your vegetables, so let's get the hard part over with and set up the arguments:
Add an argument

Arguments were the most powerful (and hardest to understand) feature of the old Views - think of this as the WHERE clause of your SQL statement. Your first and only argument will be keyed off of a Taxonomy Term ID:
taxonomy argument type

Since you don't have Panels at your disposal, you'll need to specify a Default Argument. There are several (powerful) ways to accomplish this, but in your case, resort to tried-and-true PHP Code. The code displayed here loads the object for the current $node (if any) and concatenates a list of all the Term IDs on that node, then returns the string to Views in the format 1+2+3, just like the arguments on taxonomy/term pages:
use PHP to specify the default argument

In order to activate this muitliple-term-driven argument scheme, you need to check a few boxes below the PHP code. The first sets up the fact that you can use the 1+2+3 format, and the second removes duplicate entries that have more than one term. Make sure you read the warnings about performance; if you don't use multiple taxonomy terms, leave this box unchecked. You can proceed by clicking the Update button:
Allow multiple terms, reduce duplicates

At this point, you'll see an error message inviting you to extract some fields in your view, which is set up to display fields by default. If you wanted to view full nodes or teasers, you could change that option and be safe, but the block you want to build needs titles that link to the node:egads, an error message

Now you want to tackle adding fields to your view. This is the building block of any view, analogous to the SELECT part of a SQL statement:
Add a field

You should recognize this next picture, because it's very similar to the way you chose your argument type, and how you'll choose your filter in the future. Use the Add button to move to the next screen:
you want to see the node title

If you don't delete the word "Title" in the Label text box, it will appear next to all your links. There are some situations where this is wanted; yours is not one of them. You also said you wanted the titles to be links, so check that box:remove the Label and enable links

At this stage, you should be able to get a working preview of your view. Just type a number or a 1+2 in the arguments area and push the button to trigger the AJAX. That blue text is your view, and there's also some geeky information below. Notice that currently "This display has no path"; that's OK, you want a block:
use some arguments to get a live preview

At this point, you still haven't told Views that you want your view to be a block, so make sure you choose block from the drop-down in the main interface. If you're working strictly with Page nodes, you may also want to throw a filter on your view to limit the results. You also should never forget the all-important Save button:filter and save your view

The last thing you need to view is activate your block on admin/build/block (you may need to use block visibility rules, but that's another tutorial), and finally visit one of your Taxonomy-tagged pages to see if your other taxonomy-tagged pages shows up. If you've followed all the steps here, everything should be a snap. Maybe the best feature about your new block is the handy links that pop up when you mouse over your new block (if you have administer views access, at least):
your finished block with edit links

Well Dale, I think that should just about answer your question. Since this is my first Drupal 6 tutorial, I'll have to say, this was a lot more fun for me than I'm sure the last few days have been for you. Wave hello to Corey and Sterling and Derek and Daniel and the other NFi folks, and I hope I was able to save you some precious time with this post.

Comments

ok, but i my case the Argument need to be Taxonomy Term and alias is differnet the taxonomy,
example of one of my taxonomy, 'artist':
i have Robbie Williams
but in the path is robbie-williams

how can i solve that coz it is obviously did not match! what is taxonomy structure for that?

Submitted by Guest (not verified) on Wed, 03/18/2009 - 09:06

Hi,
Have successfully set this up. How do i change the length of the teaser, and also how do i provide a "read more" link after each teaser.
thanks!!!

Submitted by sam (not verified) on Wed, 03/18/2009 - 09:11

Thanks for the video but I got only as far as the very last line where you say all you have to do is admin/build/block activate. Nothing shows up anywhere and I don't know what I'm supposed to see. Would be nice if you showed in the beginning what you were going to get, then finished with that. I put in the code well enough and got the same argument back - so that was fine.

Submitted by Guest (not verified) on Sat, 03/21/2009 - 19:46

Beats creating a new view for each taxonomy term or putting a bunch of code in page.tpl.php! This is EXACLY what I was looking for, thanks!

Submitted by Eric (not verified) on Tue, 03/31/2009 - 12:55

At the top you meant "determine the current node's taxonomy terms."

Submitted by Guest (not verified) on Tue, 03/31/2009 - 19:45

Hi
I have content type 1 with vocabulary 1 and content type 2 with vocabulary 2.
Vocabulary 1 and 2 have same term names.
Now, I want to create a view that is displayed on content type 2 that picks up the term name from current node (of content type 2) and searches for the same term name in vocabulary 1(of content type 1) and then outputs the desired fields, say imagefield.
Something like,

Select imagefield from content type 1 WHERE vocabulary 1 -> term = vocabulary 2 -> term {of the current node}.

URL of the current node (content type 2) is aliased as www.examle.com/article-network.

Any help would be highly appreciated! Thanks!!

Submitted by sej123 (not verified) on Wed, 04/01/2009 - 07:19

How would one embed this "related" view in a template so that one can pass a Node ID as argument?

I set this up via this nice tutorial, but it only gives me the results I want when I place a taxonomy ID into the preview. I want to pass it a Node ID. Then I want to embed the view into a node template and pass it the Node ID. I'm only getting results fro the Preview if I pass it a Taxonomy Term ID, which kind of defeats the purpose for me. I can easily create a view that accepts Taxonomy IDs as arguments.

This recipe relies on the user seeing the view via a block in a node.

So, unless I use this as a block that automatically passes the node ID to the view, how do I test it by passing it Node IDs?

Just FYI, the site I am working on is not using sidebars or blocks. Most everything is being coded into the layout via template files.

Submitted by ccshannon (not verified) on Wed, 04/01/2009 - 17:26

Following up on my own comment, I guess the answer is that the only way to actually test it is to embed it into a node template and don't pass it any arguments.

Preview won't help me.

Submitted by ccshannon (not verified) on Wed, 04/01/2009 - 17:47

Any help for query#12??
I am really lost! just want to have term name of my current node and let the view return desired fields from the nodes that share same taxonomy term name.
I would be highly obliged for any help.

Submitted by sej123 (not verified) on Thu, 04/02/2009 - 01:34

sej123, are you using NAT to link content type to vocabulary? Also, I'm not sure I understand why you have two identical vocabularies. I understand you have two content types, but why can't they just share one vocabulary? Why make a second vocabulary at all (unless there's a chance of course the two vocabularies _could_ diverge at a later date). If the two Vocabularies will always be identical, I don't understand the need to have 2.

Let me tell you what I'm doing and see if this is similar to your project:

I am using NAT so that editors can have a node for each term in certain vocabularies. NAT lets you sync a content type with a vocabulary, so if you create a node of content type A, it will create a matching term (uses title field) in Vocabulary A.

Then I have node types which are strictly for content, not categorization. So, my Story type does not require a matching term be created. It is not a NAT content type.

When I create a node type Story, I assign it a term from Vocabulary A. So let's call this Term 1.

So now I have a Vocabulary A, with 'Term 1' term. 'Term 1' is also the name of a NAT node of content type 'A'. And I have Story nodes assigned to 'Term 1' term.

When I go to view 'Term 1' the NODE I want to see a block of all the Story nodes assigned 'Term 1' the TERM.

Does this sound similar to what you are trying to do? If so, I can offer some info based on what I'm currently working on.

Submitted by ccshannon (not verified) on Mon, 04/13/2009 - 16:01

Hi, how to make this use terms from only 2 or 3 vocabularys?
thankx

Submitted by molly (not verified) on Tue, 04/21/2009 - 04:45

I can't seem to get this to work.

If I type "2" or "1" in the preview bar, it refreshes using AJAX and shows the results I expect it to show, however, when I look at the page on which the taxonomy terms are present, it does not display any "same" tagged items....

is there an issue with this and path auto?

Submitted by Careless (not verified) on Fri, 04/24/2009 - 16:28

Hi Ryan.... stupid mistake on my part.

I have it set up so that About Us is the main page, and Our Team, Our Residents, Our Philosophy are the sub pages... so naturally, I only applied the taxonomy to the sub pages like an idiot, and not to the About Us page as well... so the About Us page never showed the sub-page links menu because there was no taxonomy attached to the main page.

Thanks for your tutorial.

Submitted by Careless (not verified) on Sat, 04/25/2009 - 14:28

When using an nid argument to exclude the current node, I discovered something briefly confusing.

If you are calling the view using the views_embed_view function, if arguments preceding the nid argument are NULL, they don't pass a NULL argument in that place - they ignore them, and pass whatever arguments come afterward! Eeek!

Example:
view with a tid argument, and an nid argument.
$tid = '1234';
$nid = '1991';
$output = views_embed_view('viewname', 'default', $tid, $nid);
$output will be the view with tid and nid passed as parameters.

But, if you do:
// $tid = NULL;
$nid = '1991';
$output = views_embed_view('viewname', 'default', $tid, $nid);

the resulting data that comes out is as if you passed:
views_embed_view('viewname', 'default', '1991');
not
views_embed_view('viewname', 'default', NULL, '1991');

Because $tid isn't set, the function takes the next variable and uses it instead, so you'll be feeding a node id into that spot, instead of a term id. Results can be a little unpredictable there!

So, if you do this, make sure to set some kind of value, and if necessary, put in some argument or default argument code in the views interface to handle the empty value.

Hope that made sense - I know I was confused.

Submitted by Guest (not verified) on Thu, 04/30/2009 - 23:04

Views Arguments has a feature called "wildcard", which lets you pass a placeholder argument that means "everything", instead of just passing NULL.

This is probably what you're looking for.

I am also trying to exclude a vocabulary from the arguments. I have a total of 5 Vocabs, and I only want to use 4 of them for the argument. is there another way to do this rather than pulling my hair out.

Submitted by Sarah (not verified) on Fri, 05/01/2009 - 19:01

i think i found a solution to use terms from only 3 vocabs.


$node = node_load(arg(1));
if ($node) {
$termsa = taxonomy_node_get_terms_by_vocabulary($node, 1);
$termsb = taxonomy_node_get_terms_by_vocabulary($node, 2);
$termsc = taxonomy_node_get_terms_by_vocabulary($node, 3);
$terms = array_merge($termsa, $termsb, $termsc);
foreach ($terms as $tid => $term) {
$tids[] = $tid;
}
return implode ("+", $tids);
}
return false;

based on this modification

Submitted by drufishes (not verified) on Sat, 05/09/2009 - 10:45

Works fine in Views administrative area but doesn't validate when shown on page as a block.

Any help please? What should I specify under Validator?

Submitted by wexy (not verified) on Sun, 05/17/2009 - 20:15

In addition to my previous comment I want to add that control doesn't even reach inside next block for some reason, this is the cause of the problem because the terms string is not being created. Now.. why doesn't $node = node_load(arg(1)); work? :(

$node = node_load(arg(1));
if ($node) {

Submitted by wexy (not verified) on Sun, 05/17/2009 - 21:01

Wexy,

At least in the context of this tutorial, it's meant to work on a node page - is that what you're after? Can you tell me what the url is? (not the url alias, but the actual path you're pointing to?

In the case of something like "node/305", arg(1) is going to return 305. There should be a node with the ID 305 and that gets brought up by node_load.

In the last year (or longer) since this article was written, several modules have been created or upgraded to Drupal 6 that may be able to help. At the time this was written, I couldn't make the same claim.

Tanks for your quick reply, I've tried several modules after my comment here and non of them worked. I've observed the values of arg(x) on several pages and in several blocks and most of them didn't make any sense (names of categories, my custom url aliases, etc..). In the end after I disabled the module called Node Breadcrumb everything worked fine and I was able to get node id from arg(1).

On that module page I've read that it changes internal paths in Drupal and that it's pretty much impossible to get node id on current page while the module is enabled. So.. heads up for everyone if you use it and this tutorial doesn't work for you that's probably the reason.

Submitted by wexy (not verified) on Tue, 05/19/2009 - 09:13

This is brilliant. My question is can you then apply this to a taxonomy term page? This works on an individual node but what if I wanted to display a 'most visited' top 5 block on the terms main page?

e.g I have a Vocabulary called 'Category' and then I have a Term called 'Fishing' which displays all nodes in the 'Fishing' category - how would I then display a block for related nodes for that main page, rather than an individual node? how do I get the main tid for that main page whose nodes all share the same tid?

Is it possible to sort the terms with most related terms??

For example I have a content with the terms: Drupal, CMS, PHP, Apache

Then I have other contents with terms:

1: Drupal, CMS, PHP,Apache
2: CMS, PHP
3: Apache

Then I want to sort these contents as 1-2-3.

Do you think it is possible??

Thanks a lot for the tutorial but still I am having a very hard time to solve my problem.

I have 2 content types (book and news) that share same taxonomy terms (science, fiction, etc) and their paths are aliased.

Books - www.example.com/book//
News - www.example.com/news//

Now I want a block in all the news pages to display the book-images of the books that shares the same taxonomy term as of the current active news page.

For eg, if the news page - www.example.com/news/fiction/news1 is active than it should have automatically placed block at the bottom for all the book-images related to fiction.

Please guide me for how to do this???

Thanks in advance!!

Submitted by sejpal (not verified) on Wed, 06/03/2009 - 05:50

Sejpal,

The easiest way to accomplish this is by using Filters. In this case, you want to filter by node type.

Views doesn't have a lot of decision-making power built-in, so you'll have to create two block displays, one that filters out News, and one that filters out Books.

It's pretty smart to have them share a vocabulary. Good move.

Ryan

Thanks Ryan!

I was having problems with the same vocabulay and things were getting complicated, as in when clicked on a term name, all the content irrespective of the type was getting displayed. And, I want if term on article page is clicked, it should list all the articles of that particular term.
So, I got this implemented by using different vocabularies for both the content types. Though the term names are same in both the vocabularies!! But, now most of the things are easy.

But, I am still stuck with my original problem. As you suggested to use filters for the node type but in addition to this how can I implement to display only the book-images (a CCK field of node-books) of the books that shares the same taxonomy term as of the current active news page.

Is it possible for view to detect the term name of the current news page and than display the cck fields of other content type that shares the same term name but of different vocabulary?

I really tried my luck, but no success!!
Please help!!!!
Thanks again!

Submitted by sejpal (not verified) on Thu, 06/04/2009 - 02:38

Ryan, I really want to thank you for taking the time to write such a great explanation for this.

I also got a lot out of the comments that it provoked: I was especially helped by yaph's comments on how to exclude the current node. Simple but I'd never thought about how to do it before..

Really great work, keep it up! You know when merlinofchaos makes a comment like he did, it must be well done!

Andrew

Submitted by andrewsuth (not verified) on Thu, 06/11/2009 - 17:02

This worked like a charm. Thanks!

How would something like this be implemented while in a taxonomy preview? Example: I have content tagged by region and type. When the taxonomy view is "Bay Area", "Artist" (showing a list of artists in the Bay Area) I want to show a block view listing content that is "Bay Area" (region), "Organization" (type) (a list of organizations working in the area in the side menu).

Submitted by Guest (not verified) on Sat, 06/13/2009 - 22:47

Thanks a million for this snippet. Adding in

$node = node_load(arg(1));
if($node) {
foreach($node->taxonomy as $term) { $terms[] = $term->tid; }
return implode('+',$terms);
} else { return; }

into your argument will steal the tid from the current node and pass it on. Brilliant, saved me from wasting another dozen hours.

Really informative and useful description. I was about to wade through trying to install a bunch of modules and test them to perform this function as I don't know PHP but your tutorial saved the day. Thanks so much.

Submitted by summerofb (not verified) on Wed, 06/24/2009 - 01:53

would it be possible to pull a location field additionally, so that only nodes show up, that have the same term and for example same province (provided by location module)?

Submitted by rucx (not verified) on Mon, 07/20/2009 - 18:29

thanks for the hint, i added a "location" relation and a "location:province" argument (which i related to "location"), but with that the block either wont show up (hide if no argument) or shows tags of all provinces not only the current node (display all values)
2 guesses:
1.I need some php code for "location:province"
2. I might have to add a "Location" relation to the "Term ID" argument as well? (that turns out in php errors with the current code.)

Submitted by rucx (not verified) on Tue, 07/21/2009 - 12:12

Can I just say I love you? I've been trying to figure out how to do this for a couple months now.

Submitted by Blue Muse (not verified) on Tue, 07/21/2009 - 12:56

@rucx I think you need some PHP code

@Blue Muse you're welcome. Please follow us on Twitter, and leave us a good review on our iTunes podcast.

On twitter, we have daily quicktips and announcements about upcoming webinars and in-person training. The podcast has Drupal news, tips, and interviews with awesome people from the community.

http://twitter.com/drupaleasy
http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=305745…

Submitted by admin on Tue, 07/21/2009 - 18:13

Hi,

Thank you so much for this tutorial. I've tried all the different options in this article, but always receive an error in dblog when cron runs:

Invalid argument supplied for foreach() in /home/public_html/modules/taxonomy/taxonomy.module on line 1214.

The argument is as follows:

$node = node_load(arg(1));
if ($node && $node->taxonomy) {
foreach($node->taxonomy as $term) {$terms[] = $term->tid;}
return implode('+' , $terms);
} else { return; }

and query outputs:

SELECT node.nid AS nid, node.title AS node_title, node.vid AS node_vid, DATE_FORMAT((FROM_UNIXTIME(node.created) + INTERVAL 7200 SECOND), '%Y%m%d%H%i') AS node_created_minute FROM drupal_node node INNER JOIN drupal_term_node term_node_value_0 ON node.vid = term_node_value_0.vid AND term_node_value_0.tid = 3 WHERE (node.type in ('jobs')) AND (node.status <> 0) AND (term_node_value_0.tid = 3) ORDER BY node_created_minute DESC

Please, in Drupal 6, Views 6.x-2.x-dev how would I go about to fix the error?

Look so forward to any reply.
Lilian

[...] to a quick Google search, I found an excellent article over at DrupalEasy for creating a related nodes by term block using Views 2. (Yay! one of my [...]

I must have missed something important. I can get the view to work up to the point that if i click the preview I get the expected result.

I can't see how I am supposed to trigger that view to display?

If i activate the block at admin/blocks/ I get this php errors:

warning: implode() [function.implode]: Bad arguments. in /var/www/html/drupal/sites/all/modules/views/plugins/views_plugin_argument_default_php.inc(48) : eval()'d code on line 4.

I've tried the patch suggested above but it didn't help.

IfI cliick on any node that contains a taxonomy term I get:

Fatal error: Cannot use object of type stdClass as array in /var/www/html/drupal/sites/all/modules/views/plugins/views_plugin_argument_default_php.inc(48) : eval()'d code on line 3

This is on a test site, but it's exactly the sort of thing that I need to do in production.

Any help appreciated.

Submitted by David (not verified) on Sun, 08/16/2009 - 01:35

* the problem turned out to be a typo... I though I had checked - my apologies

* On your suggestion I tried similar_terms which also lead me to relevant_content. Both of these are much easier to configure, but don't give the layout options that your views solution does. For instance, I have a lot of node titles that are going to relate (perhaps over a hundred) and I can use views to lay them out in a grid within the block.

* Is there a reason to avoid using this as a permanent solution, having regard to the layout issue? I'm obviously fairly new to Drupal.

Submitted by David (not verified) on Mon, 08/17/2009 - 05:54

For some reason when I add "Node: Comment count" as a field I get no results at all, when I remove it I get the normal results. Node: Teaser and Node Statistics: View count work normaly it just bugs when I wanna print out number of comments for the node.

Any ideas? Pretty much tried everything :/

Submitted by wexy (not verified) on Fri, 08/21/2009 - 17:55

Wexy,

You may need to include the Comments as a Views Relationship, but I don't think so.

First, try creating a new View with just node title and comment count and see what happens.

Pretty good tutorial, I actually understood it (still being a drupal noob). Still have a lot to learn about Drupal...the platform just rocks.

Sign up to receive email notifications of whenever we publish a new blog post or quicktip!

Name
CAPTCHA