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:
Now you'll be asked to name your view something computer-friendly - in this case you'll name it related_by_term:
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.
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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):
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
one of the few decent drupal
one of the few decent drupal tutorials that's both easy to follow and does what it says on the box. THANKS
Thanks for posting this
Thanks for posting this tutorial. I suffered the same errors as a few others (incorrect entry of the code) but after a quick browse through the comments and your replies amendments were fast, easy and effective.
The resulting functionality is excellent! kudos to you.
Views has now moved on
Views has now moved on 6.x-2.6, and unfortunately is quite a bit different to the screen dumps in this article - in particular the arguments screen - any chance of an update?
Thank you, Ryan! The solution
Thank you, Ryan!
The solution to this scenario was puzzling me the last couple of days, building a relatively simple Drupal based site. Couldn't figure out how to do it myself, but now got it working perfectly with your solution. It was the last pending piece of functionality, so I'm really glad someone at drupal.org forums pointed me to this post!
Thanks a great deal for contributing this!
Almost the PHP code I was
Almost the PHP code I was looking for, would it be possible to wish for a similar snipet for "Taxonomy: Term" instead of "Taxonomy: Term ID" ? :-P
Hi, There is one more thing
Hi,
There is one more thing to do with your 'related' view, please:
sorting by numer of common terms. This will make this view more useful in hardly tagged sites.
Thx,
Szy.
First, thank you so much for
First, thank you so much for this. It is of great help :D
Hoping that this is still alive, I would like to ask the following:
Having 4 vocabularies assigned to the node, how can i display relevant nodes that much terms for all 4 vocabularies?
In other words:
Right now, this works like an OR statement. Even if it finds a match for one of the four vocabularies, it will display a node as relevant.
Would it be possible to display relevant nodes with an AND? So that relevant nodes should have one common term from all four vocabularies?
Thanks :D
For anyone wanting to do a
For anyone wanting to do a similar thing but with node reference rather than taxonomy, you'd create the argument using content: the node reference field (rather than term id), and then use this code:
$node = node_load(arg(1));
if($node) {
$refnid = $node->node_ref_fieldname[0]['nid'];
return $refnid;
}
return false;
found that if use multiple
found that if use multiple vocabs to node, this trick pulls all of term.
to restrict turned this
foreach($node->taxonomy as $term){$terms[]=$term->tid;}
into this
foreach($node->taxonomy as $term){if ($term->vid=="4"){$terms[]=$term->tid;}}
-----------------------------------------------------------
ps
here we put number of our vocabulary, in my case 4
if ($term->vid=="4")
Any way to sort by the number
Any way to sort by the number of commun terms ? showing the nodes that have more commun terms first ?
I dig this method for making
I dig this method for making a related content block via Views - it works, except I've found that when I have the term in related nodes actually displayed as a field in my view powering this block only 1 term will display - the term field renders empty for any nodes tagged with different terms which the live node shares.
Odd.
q./
Thanks for such a good
Thanks for such a good article. I need some help here.
I have two content types.
1. Staff Profile.
2. Staff Video.
Now when one user create staff video content, he also select a staff profile in the Node reference field in Staff Video Content Type.
Now I want to make a view and embed it's link in the Staff Profile content type. SO that whenever any user views any Staff Profile content and click on the Views Link, he should be able to view only that Staff Video where the same name of the Staff profile node was selected. I hope that the picture is clear.
Kindly help me in this regard how am I going to make such a view.
Thanks and regards
Excellent post, as someone
Excellent post, as someone who has next to no PHP knowledge, this post just saved me a lot of time. Thank You.
Great tutorial! I'd also like
Great tutorial!
I'd also like to add that this will display the current node in the list... in order to exclude it you would need to add a second Node: Nid argument with the following PHP code:
$node = node_load(arg(1));
if($node){
return $node->nid;
} else {
return null;
}
And select the "Exclude the Argument" box.
Use of PHP inside views is
Use of PHP inside views is not a good approach because in this case the view is not cached first.
And also this piece of php executed by `eval` function which is not good for performance (afaik).
And even if so, you should not use `node_load`,-who knows which type will it be.
Or which hooks will run on node_load. This might be ve-e-ery heavy.
My suggestion is - if you are already write PHP . Why use views?
Use almost the same php in block.
<?php
$nid = str_replace('node/','',$_GET['q']);
if (!is_numeric($nid)) return; // i only work for nodes
$ns = db_query('select distinct nid,title from {node} n inner join {term_node} tn using (nid) where nid<> %d and tid in (select tid from {term_node} where nid=%d))',$nid,$nid);
$out = array();
while ($n=db_fetch_object($ns)) {
$out[] = l($n->title,'node/'.$n->nid);
}
echo theme('item_list',$out);
?>
something like this.
Good article but still lacks
Good article but still lacks the sorting mechanism. There is no way to dictate that the nodes with highest number of matches should come first.
Great Post. I have
Great Post. I have implemented a view that displays a picture in a block based on the taxonomy of the page with this. However I have a page that is generated by a view. How can I give the page from a view a taxonomy so that my block view can pick it up to display a page?
Or you could use the Related
Or you could use the Related Links Module and be done with it. Using Views is a very advanced concept for geeks not everyday users.
Great stuff, i just got
Great stuff, i just got related pages working by follow your great guide.
Thanks :-)
Thank you Ryan! And, thanks
Thank you Ryan! And, thanks to all the commenters who posted with fixes/updates/adjustments/additional use cases to consider. Stuff like this is why I love Drupal. :)
Great tutorial, it worked
Great tutorial, it worked perfectly.
Any chance of getting the sort by count(common tags) working ..?
The sort order should be:
1 - Drupal, CSS, HTML
2 - CSS, HTML
3 - Drupal
Thanks.
Pingback
[...] Using Views 2 and Drupal 6 to Create a Related Pages Block | DrupalEasy nice args code [...]
@TR_Master thanks for your
@TR_Master thanks for your comment. However, this tutorial is simply meant as an example. There are some great modules out there to handle similar situations. Read some of the earlier comments, which refer to numerous solutions.
Wish I would have seen this
Wish I would have seen this yesterday ;)
Before I found this, I created a similar one using the views group by module where it shows the number of terms in common. The views export is here:
http://kristen.org/content/use-drupal-views-group-module-show-closest-m…
Also, some less views-savvy folks may want to 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
Thank you - I learned
Thank you - I learned something important from this post!
Great tutorial! I've put it
Great tutorial! I've put it to good use already.
However, I tried to do something similar and failed miserably. Perhaps someone here could help.
I have two content types: 'person' and 'publication'. I want to create a view that shows up on an individual 'person' page, and shows all publications by this person. Both content types contain a field for the first name, one called field_firstname, the other field_pub_firstname. The view should show all the publications where field_pub_firstname == field_firstname (of the current visible single node).
If I add custom php argument code like so:
return 'John';
it correctly shows only the publications by John. However, using what I thought I learned from this page, I tried the following:
return $node->field_firstname[0]['view']
where, in case of John's 'person' page being open, should do the exact same thing.
This doesn't seem to work though. Can anyone tell me why, and what I should do to fix this?
@Hilko, You should look at
@Hilko,
You should look at using a special field called a user reference. While this article mostly refers to the node reference field, the concept is the same:
http://drupaleasy.com/blogs/ultimike/2009/07/using-views-relationships-…
and another:
http://drupaleasy.com/blogs/ultimike/2009/02/displaying-hierarchical-co…
Peace,
Ryan
Great tutorial! If you do
Great tutorial!
If you do this, consider adding a sort criteria for Taxonomy: Term ID descending and put it at the top of your criteria list. That way, newer tags - which are more likely to be *specific* tags - take precedence over more general ones.
For example, I might have an article tagged "Anthrocon" and "conventions". As the "Anthrocon" tag was created later, I get all the stories related to Anthrocon before the ones about other conventions, which is what I want.
Thanks a lot for this step by
Thanks a lot for this step by step guide! How can I change to code to limit this to a specific vocabulary and multiple terms?
Othe steps are clear! Thanks a lot for this guide
James
hi in my site which is
hi
in my site which is created with drupal 6 if i write the url as
www.hellotravel.com/members
it works fine but when i write
www.hellotravel.com/members/dkfjdjfkdjkfjdjfkdjfkdjkfd
it should display page not found error but it reloads the same members page
this bug is happen only with those pages which are created with views so please help someone asap
thanks in advance
Thanks!
Thanks!
you shouldn't run a mile when
you shouldn't run a mile when only ten yards is needed
just one field "title" does it
@sukant The reason why this
@sukant
The reason why this happens is because the paths that get reserved by views allow for arguments to be passed.
A workaround for this is to add an argument to the view in question, and then add some validation. One of the options in validating an argument is to return a 404 / Not Found error.
Hope that helps
This is fantastic thanks,
This is fantastic thanks, works a dream.
I have to echo my thanks.
I have to echo my thanks. The post is almost two years old and yet so valuable!
Hi! The big problem is when
Hi! The big problem is when you have to negate the term ID argument... how could that be possible??????????
One nice thing to call out
One nice thing to call out might be the 'Theme: Information' link which tells you which templates the styles will be using, and gives you a full list of names that you can choose from for your own template; and also will show you the default template so you don't even have to go and seek out the original .tpl.php file if you want to look at it.
Fantastic tutorial and
Fantastic tutorial and comments...what a lifesaver
I had a problem using gost_
I had a problem using gost_ "What if you want to show only" comment below for my site. The code worked great expect that the block I was using it for was isolated to a single Content Type.
Here is his original code:
$node = node_load(arg(1));
if ($node) {
$terms = taxonomy_node_get_terms_by_vocabulary($node, 6);
foreach ($terms as $tid => $term) {
$tids[] = $tid;
}
return implode ("+", $tids);
}
return false;
Now if I needed this on every page then I wouldn't have had any problem. But I needed it on only a single Content Type page. Now I already had the region isolated to that Content Type, but still it was producing an error. The problem I was having was it was producing this error on every other page that did not have a term.
"warning: implode() [function.implode]: Invalid arguments passed in /home/hpelive/public_html/sites/all/modules/views/plugins/views_plugin_argument_default_php.inc(48) : eval()'d code on line 6."
Now it was discussed below about fixing that by adding a term to each node but that is not really logical if you have many node as some describe.
So my fix was to isolate that in the Views Argument based on Content Type. So I replaced Line 2:
if ($node) {
with this:
if ($node->type == 'episode')
where "episode" is my Content Type. So my entire code looked as follows:
$node = node_load(arg(1));
if ($node->type == 'episode') {
$terms = taxonomy_node_get_terms_by_vocabulary($node, 3);
foreach ($terms as $tid => $term) {
$tids[] = $tid;
}
return implode ("+", $tids);
}
return false;
Not the most complicated of fixes but hopefully it will be able to help someone else.
Hi Great tutorial! How could
Hi Great tutorial!
How could I build a sort of related terms block using this method on taxonomy/term/x page (not on nodes pages) of "foreign" vocabulary?
Logic something like this:
1.Get the x out of the url (url= taxonomy/term/x)
2. Get the terms out of all the nodes shown on taxonomy/term/x page
3. Show the terms from a specific other vocabulary (not the one from the url).
Would this be doable using above method. What would be the phpcode please?
Thanks a lot in advance for your reply!
Greetings,
Martijn
Martijn, There is probably an
Martijn,
There is probably an easier way to do this with a contributed module, or possibly Panels context.
A quick Google search returned:
http://drupal.org/project/related_terms
http://groups.drupal.org/node/10829
http://davidherron.com/content/improving-navigability-drupal-taxonomy-h…
Thank you very much. Just a
Thank you very much. Just a question: how can I set the title of the block to something related to the view argument? I would like to set it as "Other nodes in category X". I tried to preprocess the block through template.php but I lost myself in the API. Thanks
Leonardo, When setting up an
Leonardo,
When setting up an Argument, there is an area called "Title". Type your text, but instead of "X", put the characters "%1". This is a placeholder for whatever the argument returns. In this case it would be "Other nodes in category Sheep", where you entered %1 in the place of Sheep.
Enter it on this screen, in the Title box.

Sorting problem and already
Sorting problem and already viewed node is displayed again in related content block :(
I'm comming back with the question from few earlier posts:
There is no way to dictate that the nodes with highest number of matches should come first?
I know module like 'similar terms' that make it perfect, but only displays the linked titles to the related node. Is any way to acomplish the same with the views, so I could dislpay other custom fields (ex. image) in the block of related nodes?
Thanks in advance for any helpfull answer.
Hello, I have created
Hello, I have created something similar as you, but I currently have:
A page (which gets the taxonomy-id from an argument, the taxonomy id represents the category of a product). I've created a relationship to get the seller of the product. But I want next to the product something like:
The seller is ..., they also sell ____ , ____ and ____. So what I'm trying to do here is making an attachment for this (I've managed to get the related products when you put the seller-id as an argument, but I want to get the argument directly from the above-lying page).
I really hope this makes some sense to you.
In a nutshell: How can I pass arguments from the page to an attachment, staying on the same page?
Sam, There is actually a
Sam,
There is actually a setting in the attachment (at the bottom of the left column while editing the attachment) that allows you to inherit arguments from the main view. This might be off by default, but it's easy to change.
Excellent tutorial, Ryan. You
Excellent tutorial, Ryan. You sure helped a lot of people (like me) out with this single post. We owe you countless beers.
Hello, I have successfully
Hello,
I have successfully followed your instructions in the past, but now I have another problem which is similar but not exactly the same you are talking about:
I want to show related nodes according to user interests (which are content taxonomy fields in a content profile).
That's what I want to achieve:
1. Determine the current user's taxonomy terms
2. Determine all other nodes that share taxonomy terms
3. Display the title (and link) to those pages in a block
That's what I did:
1. Install and configure Content Profile.
2. Create a vocabulary called "interests/targets"
3. Create a taxonomy field called "interests" (linked to vocabulary created before) in a content type using content profile that would be displayed in sign-up process.
4. Create custom content types with a taxonomy field called "target" which would share the same vocabulary ("interests/targets").
5. Create a block using views that would display current's user's content of interests, according to the taxonomy fields.
6. Provided that both content types and users share a content taxonomy field, I wanted to use it as an argument (it's the field called "Interessos" in the attached view) and as default value I chose "logged in user".
7. Since technically users don't have any taxonomy field (I had to use content Profile) I also used that field as a relationship and I made sure that the argument uses the relationship.
Unfortunately it didn't work.
Can you help me, please? Thank you very much
More details are provided in views' issue queue, but unfortunately I didn't get any reply: http://drupal.org/node/923834
Hi, Thank you for this
Hi,
Thank you for this tutorial !
Is it possible to display the view not in a block of the current page, but on a separate page, on demand (by clicking a button "see related content" for instance) ?
In other words : will the arguments from the current node be automatically transfered when I generate the view on another page ?
Or by extension, how to generate a block with content related to a page on another page ?
That would be awesome !
Many thanks,
Xavier
Hello, anyone tried this with
Hello,
anyone tried this with Views 6.x.3-dev? Can´t get it working there.
The SQL for a node with nid = 17 looks like this:
SELECT node.title AS node_title,
node.nid AS nid,
node.language AS node_language
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 = 17
WHERE (node.status = 1) AND (node.type in ('product')) AND (term_node_value_0.tid = 17)
It searches for nodes associated with the term id = 17 while the term associated with the actual node is 253 (17 is the nid as stated above).
Thanks!