Add a 'related nodes' block that links to a taxonomy-based view
Page views can easily accept arguments, but often it would be nice for the same view to provide a sidebar block that links to the full page. For example, a 'related nodes' block that links to other nodes in a taxonomy term, and also links to the full Page View for that taxonomy term.
This can be done using the 'Argument Handling Code' field in your view. Code pasted into that field can reshuffle the arguments that a view uses to build itself, depending on the mode the view is in (page, block, etc). It's for experienced users only, but can be very handy. Here's an example to list other nodes with the same terms within a vocabulary:
$tids = '';
if($type == 'block' && arg(0) == 'node' && is_numeric(arg(1) ) ){
$vid = 2; // this is the vocabulary id to search through...
$terms = taxonomy_node_get_terms_by_vocabulary(arg(1), $vid);
foreach($terms as $term){
$tids[] = $term->tid;
}
$tids = implode('+', $tids);
}
return array($tids);On node view pages, where the 'arguments' would normally be 'node' and the node's id, this rewrites the view argument to contain a comma separated list of taxonomy term IDs terms for that node. Then your view should be set up to accept taxonomy term(s) as arguments. This way you could list the latest nodes containing taxonomy terms common to the current node.

Show all related posts EXCEPT the current node
It works greatly, except I need to show all the related posts EXCEPT the current node?
Here is the solution:
1. Add two arguments, the first one is NODE:Node_id with 'not equal' option and the second one is TAXONOMY:taxonomy_term_id (with no special options).
2. Add the following argument handling code:
<?php
$retArgs = array ();
if($type == 'block' && arg(0) == 'node' && is_numeric(arg(1) ) ){
$nid = arg(1);
//$node = node_load($nid);
$retArgs[] = $nid;
$tids = '';
$vid = 2; // this is the vocabulary id to search through...
$terms = taxonomy_node_get_terms_by_vocabulary($nid, $vid);
foreach($terms as $term){
$tids[] = $term->tid;
}
if ($terms) $tids = implode('+', $tids);
$retArgs[] = $tids;
}
return $retArgs;
?>
3. Add filter node: distinct.
4. Add a sort criteria to sort it by decending node update time.
5. Of course, display the field node:title.
Amnon
-
Drupal Focused Search Engine | Drupal Israel | Organic Web Strategy Consulting
The missing manual
I have struggled myself with the argument handling code for a little while. I guess this is because there is some part "missing" in the manual of the views argument handling code that was definitively not intentional by the great "views" guys (the views module absolutely rocks and gives Drupal an enormous boost setting it apart from any other CMS I know by lightyears of technology!). Most likely they as well as many advanced views people just were a little too deep into their own material as to step back a bit and return to the level of a novice! ;-)
Let me help explain to those who have problems making the views argument handling code work!
First of you need a view. And you want to use the argument handling code because this provides some filtering not available by the included arguments. THIS is exactly the point where many, like me, make the most important error: I have seen it as either-or, and not as in-combination-of with regards to the argument handling code, which, if you do think a little further, certainly is stupid, but never mind, I was on the wrong track for about a day or so myself.
So, to make a long story short: whenever you use the argument handling code, you must also use a "normal" argument from the list of build in arguments! I first thought that if you entered anything in the argument handling code box, this would already work!
So if your argument handling code generates an array node IDs, you must certainly also pull down Node: Node ID from the list of built in Arguments!
So the Argument Handling Code does not work on its own, it provides an existing Argument "filter" with additional information.
Anyway: this might have been absolutely obvious to most of you, I just thought it would be helpful to include in the handbook just for making the point clear to everyone ;-)
Steve
The Missing Manual is still missing :-)
Steve,
i'm glad you were as confused as i am now :-). i'm getting comfortable with most aspects of drupal and views etc. However, the one thing that makes no sense no matter how many times i reread the section in views is the use of arguments. i know WHAT its supposed to do and the benefit it brings - it functions as a "real-time" dynamic filter based on the path typed in the browser bar.
BUT i still don't understand how to practically tie what's typed in the browser bar URL to the view args. i think part of the problem is that you actually tell the view what it's own URL path should be which means you can create it "out of thin air". And i think you can makeup whatever other arguments you want to append to the "base" View URL itself. In that sense VIEW args don't really exist at all either. Of course they have to represent something physical in the db somewhere like a nid or term but it's up to you to play with that as you want. You simply anticipate what you want your pseudo path to look like and then as long as you handle it in the args section of the views any user can type that new FAKE PATH into the browser bar.
does that make sense? If it does, then i might be starting to understand this.
I can't find a concrete example that shows the relationship between the view name, the view URL path (and any args it may have) and how that specifically relates to the args in the argument text block in the view. working examples always help.
Not sure if you followed any of this or not but if you have time to expound on my thoughts or add a better example of actually USING ARGS to your missing manual post, i'd be greatly appreciative
thanks in advance
spent my weekend looking for the manual
Here's a note that users of Pathauto should read:
When using the above code arg(n) function returns the values in the original path not the alias path.
-phil
How to finish making it work in 5.x
Here's what I did to make this work.
1 - I have created a basic view. It has only a block defined. (This code would work oddly on a page, if at all.) The view type is list view, with 10 nodes per block.
2 - The fields included are only the Node: Title.
3 - Then, for Arguments, I have Taxonomy: Term ID with Display All Values as the parameter.
4 - Paste the snippet above into Argument Handling Code. Make sure the $vid value is the right one for the vocabulary you want to use. (To find the VID of a vocabulary, go to edit that vocabulary and look for the number at the end of the URL on the edit page.)
You could add more filters if you wanted to further limit the results, e.g. only to specific node types, and/or a sort order.
Note that you will want to show this block only on pages which have taxonomy items defined; an error will be generated otherwise. I'm not sure yet what code you need to put in the Page Specific Visibility Settings section of the block configuration. I'll post here if I figure it out.
Edit: You can also use
$nid = (int)arg(1);$terms = taxonomy_node_get_terms($nid);
//$vid = 2; // this is the vocabulary id to search through...//$terms = taxonomy_node_get_terms_by_vocabulary(arg(1), $vid);
Getting an error; I think it comes from here
Hi,
I implemented the code above (first post of this thread) and it works very well for Drupal 5.1. I am filtering for CCK nodes.
However, on the "Page" (non-CCK) nodes I am getting the following problem:
warning: implode() [function.implode]: Bad arguments. in /home/misumisu/public_html/mywebsite/modules/views/views.module(538) : eval()'d code on line 8.This started right after installing the code on this thread; which by the way works very well except for this warning.
Thank you
http://www.faunapolis.org/
Ok, this error code is what
Ok, this error code is what emdalton was referring to.
Found the solution in a drupal related site (also somewhere here in the forums):
Configure the block containing your related products so that its visibility is PHP (advanced); in my case the name of the node is 'kid', replace this with the name of your node type.
Block > Configure > Page specific visibility settings > Show if the following PHP code returns TRUE (PHP-mode, experts only).
and then put the following code in the "Pages" text field (remember to change 'kid' for your node type):
<?php$bresval = false;
if (arg(0) == 'node' && ctype_digit(arg(1))) {
$node = node_load(arg(1));
if ($node->type == 'kid') {
$bresval = true;
}
}
return $bresval;
?>
Instructions here: http://www.freshblurbs.com/drupal-display-block-only-specific-node-type
http://www.faunapolis.org/
This version doesn't generate the implode error:
This goes in the Argument Handling Code:
$tids = '';if($type == 'block' && arg(0) == 'node' && is_numeric(arg(1) ) ){
//$vid = 2; // this is the vocabulary id to search through...
//$terms = taxonomy_node_get_terms_by_vocabulary(arg(1), $vid);
$nid = (int)arg(1);
$terms = taxonomy_node_get_terms($nid);
if ($terms) {
foreach($terms as $term){
$tids[] = $term->tid;
}
$tids = implode('+', $tids);
}
}
return array($tids);
Note the if statement bracketing the foreach loop and the implode line.
Show related nodes, viewing either a node or taxonomy view
To get related content displayed in a block view, whether watching a node or a taxonomy, you could do something like this:
<?php
$retArgs = array();
if(arg(0) == 'node' && is_numeric(arg(1) ) ) {
$nid = arg(1);
$retArgs[] = $nid;
$tids = array();
foreach(taxonomy_node_get_terms($nid) as $term) {
$tids[] = $term->tid;
}
if ($tids) {
$tids = implode('+', $tids);
}
$retArgs[] = $tids;
} elseif (arg(0) == 'taxonomy' && arg(1) == 'term' && is_numeric(arg(2))) {
$retArgs[] = 0;
$term = (taxonomy_get_term(arg(2)));
if ($term) {
$retArgs[] = $term->tid;
}
}
return $retArgs;
?>
Arguments should be node id and taxonomy term id, in that order. And yes, arguments and argument code is a mess, perhaps if things were named differently it would be easier to grasp
If you use this code..
If you use this code.. remember to have the "Node ID" 'Option' set to "not equal"
other then that... it works great
Drupal 5.x Related Links on Node Pages - Performance Optimized
I simplified the argument code for performance.
Views Argument Code
taxonomy_node_get_terms() is more database 'expensive' than a tailored single query.
Argument: Taxonomy: Term ID - Display All Values
Argument Code:
//return args key 0 as + separated string of tidsif(arg(0) == 'node' && is_numeric(arg(1))){
$nid = arg(1); //node id
$tids = db_fetch_array(db_query("SELECT tid FROM {term_node} WHERE nid = %d", $nid)); //simplest query for node tids
if($tids){
return array(implode('+', $tids));
}
}
Block Visibility PHP Code:
Note: don't load the entire node object as that is an expensive DB operation to add to every page load, checking the node path will suffice:
<?php//show block on node view pages but not on edit page
$show = false;
if (arg(0) == 'node' && ctype_digit(arg(1)) && arg(2) !== 'edit') {
$show = true;
}
return $show
?>
P.S About arg()
arg() is a function that returns parts of the non-url-aliased Drupal path (the true path)
e.g: node/123/edit
arg(0) = 'node'
arg(1) = '123'
arg(2) = 'edit'
more information is here:
http://api.drupal.org/api/function/arg/5
About Views Arguments
Views arguments ($args) are different from arg().
$args = the array of returned values from the argument handling code
arg() is a function to get parts of the non-aliased url path
AFAIK:
In terms of Views arguments, the argument handling code should return an array.
The array keys (0,1,2 etc...) correspond to each view argument, in order
The array key's value corresponds to the value to pass to that argument for the view
e.g:
$arg[0] = '{term ids}'
$arg[1] = '{second view argument parameters}'
etc...
Exported Related Headlines View
$view = new stdClass();$view->name = '1_related_headlines';
$view->description = 'Related headlines block';
$view->access = array (
);
$view->view_args_php = 'if(arg(0) == \'node\' && is_numeric(arg(1))){
$nid = arg(1); //node id
$tids = db_fetch_array(db_query("SELECT tid FROM {term_node} WHERE nid = %d", $nid)); //simplest query for node tids
if($tids){
return array(implode(\'+\', $tids));
}
}';
$view->page = FALSE;
$view->page_title = '';
$view->page_header = '';
$view->page_header_format = '1';
$view->page_footer = '';
$view->page_footer_format = '1';
$view->page_empty = '';
$view->page_empty_format = '1';
$view->page_type = 'node';
$view->url = '';
$view->use_pager = TRUE;
$view->nodes_per_page = '10';
$view->block = TRUE;
$view->block_title = 'Related Headlines';
$view->block_header = '';
$view->block_header_format = '1';
$view->block_footer = '';
$view->block_footer_format = '1';
$view->block_empty = 'There are currently no related links.';
$view->block_empty_format = '1';
$view->block_type = 'list';
$view->nodes_per_block = '10';
$view->block_more = FALSE;
$view->block_use_page_header = FALSE;
$view->block_use_page_footer = FALSE;
$view->block_use_page_empty = FALSE;
$view->sort = array (
array (
'tablename' => 'node',
'field' => 'changed',
'sortorder' => 'DESC',
'options' => 'normal',
),
);
$view->argument = array (
array (
'type' => 'taxid',
'argdefault' => '2',
'title' => '',
'options' => '0',
'wildcard' => '',
'wildcard_substitution' => '',
),
);
$view->field = array (
array (
'tablename' => 'node',
'field' => 'title',
'label' => '',
'handler' => 'views_handler_field_nodelink_with_mark',
'options' => 'link',
),
);
$view->filter = array (
array (
'tablename' => 'node',
'field' => 'status',
'operator' => '=',
'options' => '',
'value' => '1',
),
array (
'tablename' => 'node',
'field' => 'type',
'operator' => 'OR',
'options' => '',
'value' => array (
0 => 'story',
),
),
);
$view->exposed_filter = array (
);
$view->requires = array(node);
$views[$view->name] = $view;
Hope that helps :-)
Improvement: Skipping current node
Awesome post! However, it still returns the current node! I want to see Related Links, not including the one I'm seeing right now. To fix that...
<?php//return args key 0 as + separated string of tids
if(arg(0) == 'node' && is_numeric(arg(1))){
$nid = arg(1); //node id
$result = db_query("SELECT tid FROM {term_node} WHERE nid = %d", $nid); //simplest query for node tids
while ($row=db_fetch_array($result)){ //allows multiple rows for term1+term2+term3 (previous post used db_fetch_array(), which only returns a single row (i.e. first term from db)
$tids[]=$row['tid'];
}
if($tids){
return array($nid,implode('+', $tids)); //include current node, so we can skip it
}
}
?>
Also, be sure to follow the first posts describing two arguments (first is node:id with option of not equal, second is taxonomy Term ID: Display all Values)
With this code, the first argument returned to views will be the node id (second is your list of taxonomy terms with the + indicating an or operation, as per taxonomy), which will be excluded due to argument 1, as defined on the views GUI.
Or this new module...
Been upgrading my site and I used to use a php snippet for this functionality but I found this new module that does this:
http://drupal.org/project/similarterms
marcopolo ---
Blog Marco | Share Trading |
add multiple "related nodes" blocks
How to add for every term a new block, each of them displaying "related nodes" to respective terms associated with the displayed node:
1. Make a view as described above, but with argument handling code:
<?php$tids = '';
if($type == 'block' && arg(0) == 'node' && is_numeric(arg(1) ) ){
//$vid = 2; // this is the vocabulary id to search through...
//$terms = taxonomy_node_get_terms_by_vocabulary(arg(1), $vid);
$nid = (int)arg(1);
$terms = taxonomy_node_get_terms($nid);
if ($terms) {
foreach($terms as $term){
$tids[] = $term->tid;
}
$tids = $tids[0];
}
}
return array($tids);
?>
2. Set the title to:
articles about %1"%1" will be substituted by your term
3. Repeat steps 1 and 2, but in the argument handling code, replace
$tids = $tids[0];with
$tids = $tids[1];This will add a block with nodes related to the second term of the displayed node.