Last updated November 6, 2010. Created by Senpai on June 21, 2006.
Edited by bekasu, xtfer, DyanneNova, webchick. Log in to edit this page.

In addition to the arguments that Views supplies natively, you can also insert your own custom argument handling code using PHP (provided you have the 'use PHP for block visibility' permission). Simply expand the Argument Handling Code fieldset and enter your code.

For example:

// Make the first argument 1 if not already set
if (!$args[0]) {
  $args[0] = 1;
}
return $args;

You can also make changes to the view directly here as well:

// Show full node view, rather than teaser, if an argument exists
if ($args[0]) {
  $view->page_type = 'node';
}
return $args;

A few notes:

  1. The code should not go between <?php and ?> delimiters; just typed in directly.
  2. The code should return an array of arguments to pass into the view.
  3. You have a number of variables available to you in this handling code: all of the arguments of the views_build_view function. For full details, please see the documentation above that function in views.module.

The following is a list of variables that are ready to use:

$type
The type of view, for example 'page' or 'block.'
$view
The current view object.
$args
an array of arguments being passed into the view (for example, in the URL http://www.example.com/view_url/1/foo, $args[0] is 1 and $args[1] is foo).
$use_pager
a boolean value indicating whether current view is using a pager.
$limit
the number of rows to retrieve; required if $use_pager is TRUE.
$page
a number which indicates what page of the view to start on; used when not using $use_pager but using $limit, to retrieve only a section of the view.

Recipe: CCK Node Reference as argument

Suppose you want to make a block to display on node pages (URL path node/n). The block should show all the items that have a CCK Node Reference field that link to the current node id. Here's a little recipe.

First, in the Arguments section of the view, select Node Reference:.

In the Argument Code section, enter:
$args[0] = arg(1);

arg(1) is a drupal function that grabs the second argument from the URL path, in this case the node id. The query that views will build will include a WHERE clause that require to equal $args[0].

For an example of the output, see http://si505.cms.si.umich.edu/node/2.

Setting Dynamic Filters

You can use this field to dynamically set filters with options that may not exist. For instance, you could combine with date module and create a filter to list x number dates after a certain day, which is generated from the URL. The real trick here is if you set dynamic filters, you MUST clear the query cache so views will regenerate it for you. Example code (minus the php tags):

<?php
// Create a timestamp for two days ago
$stamp = time() - (86000 * 2);
// Generate the date parts, using our stamp OR the arguments passed in to the view
$year = $args[0] ? $args[0] : date('Y', $stamp);
$month = $args[1] ? $args[1] : date('m', $stamp);
$day = $args[2] ? $args[2] : date('d', $stamp);
// Add a filter to include only dates later than two days ago
foreach (array('year', 'month', 'day') as $part) {
 
$view->filter[] = array(
   
'vid' => $view->vid,
   
'tablename' => '',
   
'field' => 'node_data_field_date.field_date_value_' . $part,
   
'value' => ${$part},
   
'operator' => '>=',
   
'options' => '',
   
'position' => count($view->filter),
   
'id' => 'node_data_field_date.field_date_value_' . $part,
  );
}
// IMPORTANT: Invalidate the cached query for this view, as it'll need to be regenerated on each request
$view->is_cacheable = 0;
?>

Dynamic filters within a panel with pathauto

I needed to so something similar to setting dynamic filters and I think I found a very easy way to do it. Also, it needed to work in combination with panels 2 and pathauto. Here is my solution, hopefully my code will help others.

Situation:
I am making a simple event calendar. I want a two-column panel with a list of this month's events in the left column and the description of the selected event in the right column. There is a content type called 'event' and pathauto is configured is configured to have a path like this (simpified explanation, not the actual pathauto code): agenda/[yyyy]/[m]/[d]/[title]. Of course the event content type has a cck date field to enter the event's date.

Next I created a view which displays a list with the event's title (as link) and its date. I added 4 filters:
[0] field_datum_value_year=now
[1] field_datum_value_month=now
[2] published=true
[3] node_type=event

My panel page is set up to override the event node, so when an event node is called, the panel is displayed with the event in it's right column. The panel loads the view in the left column. The path of this panel page was set to 'agenda'. The result so far is a panel which displays this month's events on the left and, when an event in this list is clicked, displays the event node on the right.

Here comes the dynamic filter part: I want to access the calendar of other months by passing arguments to the page. The path agenda/2008/4/ should show the calendar of april 2008. As you have seen, I already had the year and month filters in place. This means that I don't have to create the filters completely with the argument handling code; I can just override the 'value' variable when an argument is available. The code looks like this (without the php tags):

<?php
if ($args[0]) {
   
$view->filter[0]['value'] = $args[0]; // set the value of filter[0]
}
if (
$args[1]) {
   
$view->filter[1]['value'] = $args[1]; // set the value of filter[1]
}
$view->is_cacheable = 0;
?>

As you can see, I use much less code than quicksketch, because I only set the values that need to be changed.

This works perfectly, but there was one problem. When I was at agenda/2008/4/ (now = 2008/2) and clicked one of the events in the list (let's call it 'workshop'), the event node was displayed in the right column, but the view on the left was reset to the default, being the current month. The reason for this is, that the path changed to the path of the event node, which has no arguments. The actual path was 'node/21' while the path alias was 'agenda/2008/4/16/workshop'. That's why I had to add some more code: to make sure that the view didn't reset to the default month when an event was opened. Now the argument handling code looks like this (again without the php tags):

<?php
if (!$args[0]) { // if there are no arguments, we may be looking at an event node
   
$path = explode('/', drupal_get_path_alias($_GET['q'])); // get the current path, lookup the path_alias and turn the pieces it into an array
   
if (($path['0'] == 'agenda') && is_numeric($path['1']) && is_numeric($path['2'])) { // check if $path contains a year and month after 'agenda/'
       
$view->filter[0]['value'] = $path['1']; // set the value of filter[0]
       
$view->filter[1]['value'] = $path['2']; // set the value of filter[1]
   
}
}
if (
$args[0]) {
   
$view->filter[0]['value'] = $args[0]; // set the value of filter[0]
}
if (
$args[1]) {
   
$view->filter[1]['value'] = $args[1]; // set the value of filter[1]
}
$view->is_cacheable = 0;
?>

If the value you are passing is not an array() you can add this code in to the arguments field (without the php tags):

<?php
if(!$args[0]){
$view->filter[2]['value'] = array(12); // make sure that the value is an array
}else{
$view->filter[2]['value'] = array(); // make sure that the value is an array
}
$view->is_cacheable = 0;
?>

Content in block 'user whose profile's page is being looked at'

Put code below in Argument Handling Code section of view module.

  if (arg(0) == 'user' && is_numeric(arg(1))) {
    return array(arg(1));
  }

Details at:
http://drupal.org/node/111639

For the current node:

if (arg(0) == 'node' && is_numeric(arg(1))) {
  return array(arg(1));
}

Taxonomy Term as Block Argument

You can get the taxonomy term sent as an argument to a block on a taxonomy term page. E.g. /category/VOCAB/TERM.

Working with devel module's dpm() function you'll discover that:
1) There are no variables ($type, $args, etc.) to work with. Don't bother.
2) Though the path was as described above, the arg() function returned:
arg(0) => "taxonomy"
arg(1) => "term"
arg(2) => 1 (i.e. the term id)

So, "return(arg(2));" in the php code for the default-if-no-argument-provided section, where the argument type was term id, seems to work.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

You can use this field to dynamically set filters with options that may not exist. For instance, you could combine with date module and create a filter to list x number dates after a certain day, which is generated from the URL. The real trick here is if you set dynamic filters, you MUST clear the query cache so views will regenerate it for you. Example code (minus the php tags):

<?php
// Create a timestamp for two days ago
$stamp = time() - (86000 * 2);
// Generate the date parts, using our stamp OR the arguments passed in to the view
$year = $args[0] ? $args[0] : date('Y', $stamp);
$month = $args[1] ? $args[1] : date('m', $stamp);
$day = $args[2] ? $args[2] : date('d', $stamp);
// Add a filter to include only dates later than two days ago
foreach (array('year', 'month', 'day') as $part) {
 
$view->filter[] = array(
   
'vid' => $view->vid,
   
'tablename' => '',
   
'field' => 'node_data_field_date.field_date_value_' . $part,
   
'value' => ${$part},
   
'operator' => '>=',
   
'options' => '',
   
'position' => count($view->filter),
   
'id' => 'node_data_field_date.field_date_value_' . $part,
  );
}
// IMPORTANT: Invalidate the cached query for this view, as it'll need to be regenerated on each request
$view->query = '';
?>

Nathan Haug
creative graphic design        w: quicksketch.org
& software development       e: nate@quicksketch.org

The latest views.module uses

$view->is_cacheable = 0;

instead of the
$view->query = '';

I needed to so something similar to what quicksketch described (setting dynamic filters) and I think I found a very easy way to do it. Also, it needed to work in combination with panels 2 and pathauto. Here is my solution, hopefully my code will help others.

Situation:
I am making a simple event calendar. I want a two-column panel with a list of this month's events in the left column and the description of the selected event in the right column. There is a content type called 'event' and pathauto is configured is configured to have a path like this (simpified explanation, not the actual pathauto code): agenda/[yyyy]/[m]/[d]/[title]. Of course the event content type has a cck date field to enter the event's date.

Next I created a view which displays a list with the event's title (as link) and its date. I added 4 filters:
[0] field_datum_value_year=now
[1] field_datum_value_month=now
[2] published=true
[3] node_type=event

My panel page is set up to override the event node, so when an event node is called, the panel is displayed with the event in it's right column. The panel loads the view in the left column. The path of this panel page was set to 'agenda'. The result so far is a panel which displays this month's events on the left and, when an event in this list is clicked, displays the event node on the right.

Here comes the dynamic filter part: I want to access the calendar of other months by passing arguments to the page. The path agenda/2008/4/ should show the calendar of april 2008. As you have seen, I already had the year and month filters in place. This means that I don't have to create the filters completely with the argument handling code; I can just override the 'value' variable when an argument is available. The code looks like this (without the '<?php' of course):

<?php
if ($args[0]) {
   
$view->filter[0]['value'] = $args[0]; // set the value of filter[0]
}
if (
$args[1]) {
   
$view->filter[1]['value'] = $args[1]; // set the value of filter[1]
}
$view->is_cacheable = 0;
?>

As you can see, I use much less code than quicksketch, because I only set the values that need to be changed.

This works perfectly, but there was one problem. When I was at agenda/2008/4/ (now = 2008/2) and clicked one of the events in the list (let's call it 'workshop'), the event node was displayed in the right column, but the view on the left was reset to the default, being the current month. The reason for this is, that the path changed to the path of the event node, which has no arguments. The actual path was 'node/21' while the path alias was 'agenda/2008/4/16/workshop'. That's why I had to add some more code: to make sure that the view didn't reset to the default month when an event was opened. Now the argument handling code looks like this (again without the '<?php'):

<?php
if (!$args[0]) { // if there are no arguments, we may be looking at an event node
   
$path = explode('/', drupal_get_path_alias($_GET['q'])); // get the current path, lookup the path_alias and turn the pieces it into an array
   
if (($path['0'] == 'agenda') && is_numeric($path['1']) && is_numeric($path['2'])) { // check if $path contains a year and month after 'agenda/'
       
$view->filter[0]['value'] = $path['1']; // set the value of filter[0]
       
$view->filter[1]['value'] = $path['2']; // set the value of filter[1]
   
}
}
if (
$args[0]) {
   
$view->filter[0]['value'] = $args[0]; // set the value of filter[0]
}
if (
$args[1]) {
   
$view->filter[1]['value'] = $args[1]; // set the value of filter[1]
}
$view->is_cacheable = 0;
?>

Well, that's it! I would like to hear your opinions (positive and negative) about my solution. I'm quite pleased with it myself, but maybe I just didn't discover the disadvantages of this method yet... Thanks for reading, anyway!

Thanks for this code but I had to make some modifications to it to get it to work for me:

I created a view to show all nodes by term. I used the default "taxonomy_term" view that ships with the views module and then I added a filter to it. I wanted it to be dynamic like this:
Add this code in the arguments field (without the <?php )

<?php
if(!$args[0]){
$view->filter[2]['value'] = array(12); // make sure that the value is an array
}else{
$view->filter[2]['value'] = array(); // make sure that the value is an array
}
$view->is_cacheable = 0;
?>

This means that when there is no arguments, views will filter out the nodes that belong to term 12.
For some reason, marcvangend's code didn't work for me because the value I was passing was not an array(), so I just put the value inside an array() and worked just fine.

drush cc all

Is there a way to get all nodes with null taxonomy when no argument is given?

hi quicksketch and everyone,

first, thanks a lot for the inspiration. i'm on a project right now where i have to set dynamic filters defined by $_POST-variables, and this seems THE approach to it.

second, i stumbled upon a problem which i just can´t figure out. maybe you guys can. here´s my code:

if ($_POST['text_type'])
{
// get my data
$data1 = taxonomy_get_vocabulary($_POST['text_type']);
// prepare new filter
$filter = array();
if($data1->name) {
$filter[] = array(
    'vid' => $view->vid,
    'tablename' => '',
    'field' => 'node_type.type' ,
    'value' => array($data1->name),
    'operator' => '=',
    'options' => '',
    'position' => count($view->filter),
    'id' => 'node_type.type' ,
  );
}
//make $_POST-data the new filter (i use [1] because [0] is the 'equals published'-one)
  $view->filter[1] = $filter;
}
$view->query = '';

but this leads to 2 mysql-errors:

* user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''')' at line 1 query: SELECT count( DISTINCT(node.nid)) FROM node node WHERE (node.status = '1') AND (. '') in /homepages/my/installation/path/drupal/includes/database.mysql.inc on line 174.
* user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''') LIMIT 0, 10' at line 1 query: SELECT DISTINCT(node.nid) FROM node node WHERE (node.status = '1') AND (. '') LIMIT 0, 10 in /homepages/my/installation/path/drupal/includes/database.mysql.inc on line 174.

looks like my $view->filter[field] or [id] are not passed correctly...

any ideas what´s wrong here? i'm using D5...
help would be warmly appreciated!

peace,
bonzo

Problem is views isn't finding your field name in the database, so it's dropping it completely. That's why you see "AND (.'')" . It's not the most intuitive interface and definitely deserves more documentation. I would recommend trying

<?php
   
'field' => 'node.type' ,
?>

If that doesn't help, fiddle with it some more to see if you can get the right combo that views will accept.

Tried this code in views argument validation using php code

but the filter value was not overriden...

my php code was:

if ($argument) {
    $view->filter[1]['value'] = $argument; // set the value of filter[1]
$view->is_cacheable = 0;
$handler->argument='all';
return true;
}

here the sql request

SELECT node.nid AS nid, node.title AS node_title, node.language AS node_language FROM node node  LEFT JOIN content_type_mytype node_data_myfield ON node.vid = node_data_field_myfield.vid WHERE (node.type in ('some name')) AND <strong>(UPPER(node_data_field_myfield.field_myfield_value) LIKE UPPER('%%'))</strong>

there is the LIKE UPPER('%%') which shows there was no argument (default blank) so not overriden :/

hello drupal world!
my drupal site: Reprodukcje, obrazy

I was able to add sorting behavior to a view by adding a URL argument that programatically changed the view within the Views Argument Handling Code.

For example, when the second URL argument is "desc," then it sorts the nodes according to descending order when this code is entered as the argument handling code.

if ($args[1]== "desc") {
  $view->sort[0]['vid'] = 4;
  $view->sort[0]['position'] = 0;
  $view->sort[0]['field'] = 'node.nid';
  $view->sort[0]['sortorder'] = 'DESC';
  $view->sort[0]['options'] = '';
  $view->sort[0]['tablename'] = '';
  $view->sort[0]['id'] = 'node.nid';
}
return $args;

Be sure to change the view id (vid) to match your view (i.e. the last argument seen here "admin/build/views/edit/4")
If you export your view, you can start to see some details of the $view object array, but copying and pasting this into the argument handler only works with the strings and not arrays. For example, the same sorting array looks like this when you do a views export:

  $view->sort = array (
    array (
      'tablename' => 'node',
      'field' => 'nid',
      'sortorder' => 'DESC',
      'options' => '',
    ),

And doing a straight copy and paste of this into the Handler code section doesn't work.
That's because the actual $view object has a slightly different data schema for the information that's stored as arrays.
So if you want to alter the Fields, Arguments, Filters or Sort Criteria, then you should look into what the $view object array looks like.

How do you do that? Well, I did it with a debugger and took some screenshots to share what the Views $view object looks like, how it maps to the Views export, and how they are both related to the Views UI layout:
* Photo of Drupal Views.Module $View Object
* Mapping Views Export to Views $View Object
* Mapping Views UI to Views Export and Views $View Object

If you're interested in digging into the views.module code, then the Views Argument Handler Code get processed in the views_build_view() function in this section of the code:

  if ($view->view_args_php) {
    ob_start();
    $result = eval($view->view_args_php);
    if (is_array($result)) {
      $args = $result;
    }
    ob_end_clean();
  }

I set a break point in Komodo debugger after this line in order to verify that the code in $views->view_args_php was accurately altering the $view object.

$result = eval($view->view_args_php);

I'm going to play around with altering the $view object by using URL arguments, but I'd be interested in any code improvements, better ways or any pitfalls to doing this.

Here's a views argument handling code snippet makes it possible to dynamically change the views $view object based upon arguments passed in the through the URL.

Given a URL of "example.com/soundbite/interview/argument_input" where
* "soundbite" is the views Page URL
* $args[0] triggers the Views Argument Handling Code when equal to "interview"
* And $args[1] is the input to the views argument query that is generated within the Views Argument Handling Code

if ($args[0]== "interview") {
  $view->argument[0]['vid'] = $view->vid;
  $view->argument[0]['type'] = 'content: field_interview';
  $view->argument[0]['argdefault'] = '1';
  $view->argument[0]['title'] = '';
  $view->argument[0]['options'] = '';
  $view->argument[0]['position'] = 0;
  $view->argument[0]['wildcard'] = '';
  $view->argument[0]['wildcard_substitution'] = '';
  $view->argument[0]['id'] = 'content: field_interview';
}
$args[0] = $args[1];
$args[1] = '';
$view->query ='';
return $args;

Note that $args[1] replaces $args[0], and that the $view->query is cleared out so that _views_build_query() is triggered to rebuild and modify the query.

There could be other conditionals that can be used to dynamically change the fields, arguments and filters of the view based upon the arguments.

A brute force approach of cloning and creating multiple views is probably sufficient in most cases, but there may be a case where you want more sophisticated control. See the comment above for more details on how to format the data in the views $view object since it'll be different from what you see from a views export.

... $view->query is cleared out so that _views_build_query() is triggered to rebuild and modify the query.

This did not work for me, but I found I could turn off caching for the view which did the trick:

$view->is_cacheable = 0;

--
Mark Matuschka
www.glodigital.com.au

Great tip! I'm trying to add some custom sorts to teaser lists on a 5.x site, but I was having problems getting this to work with pathauto. When I had a built-out alias for a taxonomy/term/ page in the form of [vocab-raw]/[term-name-raw] and tried adding an argument it would result in a 404. This is because the argument was essentially telling drupal to look for a different page.

My current solution is to check for two get parameters (sort and order) instead of the args. This keeps the alias working, but also let's me sort. Additionally, it keeps me from breaking my feed arguments and aliases. My code looks like this:

Views:

if ($_GET['sort']== "title") {
  $view->sort[0]['vid'] = 10;
  $view->sort[0]['position'] = 0;
  $view->sort[0]['field'] = 'node.title';
  $view->sort[0]['sortorder'] = $_GET['order'];
  $view->sort[0]['options'] = '';
  $view->sort[0]['tablename'] = '';
  $view->sort[0]['id'] = 'node.title';
}
else if ($_GET['sort']== "date") {
  $view->sort[0]['vid'] = 10;
  $view->sort[0]['position'] = 0;
  $view->sort[0]['field'] = 'node.created';
  $view->sort[0]['sortorder'] = $_GET['order'];
  $view->sort[0]['options'] = '';
  $view->sort[0]['tablename'] = '';
  $view->sort[0]['id'] = 'node.created';
}
return $args;

And I have code in my theme to add the links, which looks like this:

  // Set up basic variables
  $sort = trim($_GET['sort']) ? $_GET['sort'] : 'date';
  $order = ($_GET['order'] == 'asc') ? 'asc' : 'desc';
  $reorder = ($order == 'asc') ? 'desc' : 'asc';
  $output = '<div>';
  // sort by title
  $title_link = ($sort == 'title') ? t('TITLE') .' '. theme_tablesort_indicator($order) : t('TITLE');
  $output .= l($title_link, $_GET['q'], array(), '&sort=title&order='.$reorder, NULL, FALSE, TRUE);
  // sort by date
  $date_link = ($sort == 'date') ? t('DATE') .' '. theme_tablesort_indicator($order) : t('DATE');
  $output .= ' | '. l($date_link, $_GET['q'], array(), '&sort=date&order='.$reorder, NULL, FALSE, TRUE);
  // wrap it up and return
  $output .= '</div>';
  return $output;

Seems to work so far. I'll report back if I run into anything.

--------------------
Sean B. Fuller
www.seanbfuller.com

--------------------
Sean B. Fuller
www.seanbfuller.com

I can't seem to get the below code to work. Basically, I'm using the events module. I want to sort the nodes by the event start time, then sort them alphabetically using the CCK fields value.

I can sort them by date and by price but not at the same time.

<?php
if ($_GET['sort'] == "price") {
 
$view->sort[0]['vid'] = 10;
 
$view->sort[0]['position'] = 0;
 
$view->sort[0]['type'] = 'content: event_start';
 
$view->sort[0]['sortorder'] = 'asc';
 
$view->sort[1]['type'] = 'content: field_price';
 
$view->sort[1]['sortorder'] = $_GET['order'];
 
$view->sort[0]['options'] = '';
 
$view->sort[0]['tablename'] = '';
 
$view->sort[0]['id'] = 'content: event_start';
 
$view->sort[1]['id'] = 'content: field_price';
}
return
$args;
?>

Any help much appreciated!

I wanted to add a filter to select songs with a certain metadata tag. This is my code.

<?php
if (isset($args[0])) {
 
views_view_add_filter($view, 'audio_metadata_genre', 'clean', '=', $args[0], '');
 
views_sanitize_view($view);
}
return
$args;
?>

For this to work you have to make sure that views knows about the table you are selecting from. At the moment I'm not really sure how to do this. The audio-module did this for me automatically in this case.

I created a custom node type with CCK in Drupal 5.1 and turned on the Pathauto module to generate SEO-friendly URLs based on its title, like "http://www.example.com/title_of_node".

I also wanted to create a view of the node using just a subset of its fields, while still keeping the custom path name, like "http://www.example.com/teaser_view/title_of_node".

The views module doesn't allow you to add arguments based on a node's URL path setting, just on its title which can include spaces that make for some ugly URLs.

To get around this limitation, I added an argument based on the Node: ID to my view and pasted the following php into the Argument Handling Code field to lookup the ID based on the path alias:

$result = db_query("SELECT src FROM {url_alias} WHERE dst LIKE '%s'", $args[0]);
$nodeid= array();
while ($nodepath = db_fetch_array($result)) {
  $nodeid[] = substr(strrchr($nodepath['src'], "/"), 1);
  return $nodeid;
}

This works great, except for the fact that if I put a random title in after the view URL, I'm getting a SQL error instead the usual Permission Denied screen. Any idea how to make this fail gracefully?

I've seen this code and it took me a while to get it working (ages, in fact) because there was a bit missing - there should be two ampersands each side of the %s, inside the single quotes. Maybe the code filter pulled them out, which is why they're not there. I will post my code here and see :)

As for degradation, I was told about maybe cheekily using drupal_not_found(), but it didn't seem to work. Also, I have wrapped my while() in a test, but without a meaningful else {} at the bottom, it's useless.

$result = db_query("SELECT src FROM {url_alias} WHERE dst LIKE '%%%s%%'", $args[0]);
if (isset($result)) {
  $nodeid= array();
  while ($nodepath = db_fetch_array($result)) {
    $nodeid[] = substr(strrchr($nodepath['src'], "/"), 1);
    return $nodeid;
  }
}

I hope this helps someone, cos it took me ages to sort out.

The current (1.0) version of panels passes the '%1' (or whatever) into the view directly as a string, if that argument is not present.

You can easily correct this using some code like:

<?php
if ($args[0] == '%1') {
 
$args[0] = 'all';
}
return
$args;
?>

If you want to differ view type depending on vocabulary.
Example:
You have one view which responds to "taxonomy/term/$arg" URL.
You have selected "Argument" Field as "Taxonomy: Term ID" and set it to "Display all values"
You have specified the view to be "Bonus Grid" view for Page and/or Block and this view works perfectly to show your products (may be other content type) depending on term from taxonomy tree. Now, as you may expand your taxonomy to use different vocabularies and assign terms from them to different content types (page, for example), you will face the problem that clicking a term may display your "Pages" in "Bonus Grid" view - which is not what you want.

Here's a solution how to use "Argument Handling Code" to separate view type depending on vocabulary:
In the example I am using vocabulary ID (vid) as 2:

$Product = FALSE;
$args[0] = arg(2);
$tid = $args[0];
$query = db_query("SELECT d.vid from {term_data} d WHERE d.tid  = '%d'", $tid);
$vocab = db_fetch_array($query);
$nodeterm = array();
foreach ($vocab as $term) {
  $nodeterm[$i] = $term;
}
if(in_array(2, $nodeterm)) // This is where you specify your required vocabulary ID - which is 2 in my example and/or specify multiple id's if you like
{
  $view->page_type = 'bonus_grid'; // for vid = 2 we are showing Bonus Grid view
} else {$view->page_type = 'teaser';} // for any other vocabulary we show Teaser view.
return $args;

This code works for me perfectly and I hope will be in use to some of you, guys.

Thanks for the code ivan.g!

I used it to solve a similar problem. If you want a specific view type only for terms from a specific vocabulary, you can use this argument handling code.

Make a view with an url taxonomy/term

Give it the argument Taxonomy term ID. Provide page view and use pager should be 'on'.

Let your view provide the default type of view, usually Teaser list.

Argument handling code:

$tid = $args[0];
$vid = db_result(db_query("SELECT vid FROM {term_data} WHERE tid = '%d'", $tid));
// replace with your own $vid values
if ($vid == 12)
{
$view->page_type = 'panels_threecol'; // replace with your desired view type
}

Explanation:
$tid = $args[0]; this grabs the tid from the url.

The next line querries the database to find out what is the term's vocabulary id.

if ($vid is equal to the vocabulary id for the following view) - in my example I want to use the panels three column teaser view for terms from two vocabularies. You can add as many vids as you want by adding the following code :
|| $vid == SOME_VID

Example

if ($vid == 12 || $vid == 9 || $vid == 1)
{
$view->page_type = 'panels_threecol'; // replace with your desired view type
}

If you are not sure what to write for the view type here :
$view->page_type = 'panels_threecol';

You can get the view type name from the export tab in your view.

Using taxonomy fields in certain views is quite common. But having their IDs only in the URL is ugly.

Taxonomy terms could be filtered by Name from arg or via ID.
But if i have a specific vocabulary to be used only, i did not found a way to limit terms to. And still there where things unclear: What with special chars, ...

I decided for my ugly hack: A View with Filter by Taxonomy ID

And pass some Argument Code to lookup from $args[0] Taxonomy name to Taxonomy ID.
In this hack i use description field for URL naming ;-) ... at least for the moment!

if(isset($args[0])) {
  $query = db_query("SELECT d.tid tid from {term_data} d WHERE d.description  = '%s' AND d.vid=1", $args[0]);
  // Replace vid=1 with your Vocabulary ID!
  if(db_num_rows($query)) {
    $term = db_fetch_array($query);
    $args[0] = $term['tid'];
    #watchdog('content', 'TOPIC FROM '.arg(1).' TO '.$args[0]);
  }
}
return $args;

Example:
View URL: /yourview/the-term-name
Taxonomy Term: Name: The Term Name, Description: the-term-name
Leading to correct identification :-)

----
EDIT: For those who like it more pro style
Add Table:

CREATE TABLE `term_data_url` (
  `tid` int(10) unsigned NOT NULL,
  `url` varchar(255) NOT NULL,
  PRIMARY KEY  (`tid`),
  KEY `url` (`url`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

Add the url names you like to the table to map to terms (tid from {term_data}) and use handling code:

#args[0] is arg(1)
if(isset($args[0])) {
  $query = db_query(
    "SELECT td.tid tid"
    ."\n FROM {term_data_url} tdu"
    ."\n INNER JOIN {term_data} td"
    ."\n  ON td.tid=tdu.tid"
    ."\n WHERE tdu.url = '%s'"
    ."\n AND td.vid=1" // replace it with your own vocabulary id!
    , $args[0]);
  if(db_num_rows($query)) {
    $term = db_fetch_array($query);
    $args[0] = $term['tid'];
    #watchdog('content', 'TOPIC FROM '.arg(1).' TO '.$args[0]);
  }
}
return $args;

Enjoy!

Hi,

I used the code below to prevent the need to provide a description field containing the path.
The code bellow goes to Argument Handling Code

<?php
//gets the aliased path
$pathAliasedArray = explode('/', drupal_get_path_alias($_GET['q']));
//I need the third element (bar) in my case (ex : domain.com/foo/bar) only if there is a second one "foo"
if(isset($pathAliasedArray[1]) && $pathAliasedArray[1] == 'foo' ) {
  
//get real url from alias
 
$query = db_query("SELECT d.src src from {url_alias} d WHERE d.dst  = '%s'", $pathAliasedArray[0]."/".$pathAliasedArray[1]);
  if(
db_num_rows($query)) {
   
$term = db_fetch_array($query);
   
$pathReal = explode('/', $term['src']);
   
//I need the third element wich is the term id (tid)
   
if(isset($pathReal[2])){
   
$args[0] = $pathReal[2]; //taxonomy term id
   
}
  }
}
return
$args;
?>

Ciprian M.

-

I have the above solution and it dosen't works for me. My code is the following for "Taxonomy: Term ID" argument:

if ( isset($args[0]) )  {
$sql = "SELECT src FROM {url_alias} WHERE dst = 'video/". $args[0]."'";
$result = db_query($sql);
if (isset($result)) {
  $termid= array();
  while ($termpath = db_fetch_array($result)) {
    $termid[] = substr(strrchr($termpath['src'], "/"), 1);
  }
  $args[0] = $termid[0];
}
}
return $args;

I have the names of the terms set up with Pathauto and it is like 'video/speedflying'. If i request the video/speedflying page i get the default taxonomy term listing interface, not my view. Am I missing something? How can I disable the default for taxonomy terms?

I believe you need another module for this. I believe Taxonomy redirect is what you want, you need to specify your vocabulary to use a view instead of the default taxonomy page. so that when you go to example.com/video/speedflying it uses your custom view, not drupals default.

Taxonomy redirect: http://drupal.org/project/taxonomy_redirect

A more sustainable solution may be to keep argument handling code reserved for arguments, and not messing with filters, fields, and sorts.

The alternative is to use hook_views_pre_query(&$view) to modify the $view object.

If you need arguments for hook_views_pre_query(), then add them to your view object using the argument handling code:

<?php
  $view
->view_args_php = '
    $view->args = $args;
    return $args;
    '
;
?>

In addition to being conceptually cleaner and keeping argument handling domain-specific, this method reduces potential frustrations with views caching.

Here's some sample code to create a 'related links' block

Views Argument Code

View: Provides Block
Type: List
Field: Node Title - link
Argument: Taxonomy: Term ID - Display All Values
Argument Code:

//return args key 0 as + separated string of tids
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));
  }
}

Block Visibility PHP Code:

<?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

P.S 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...

Appendix: 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 :-)

Also available are the exposed filters in $filters[]. You can override the user generated ones.. You can use a combination of this and the $limit to dynamically change the number of rows to retrieve.

  1. Create a dummy content type in CCK and add 1 field called 'Number of Results" or something similar to it. Make this is a numeric select field. Give it a select list of the set results you need. e.g. 10,25,50,100
  2. In your view - select this field as a filter and expose it. Select all the available values in the list box
  3. In the exposed filter mark this as optional (this will add in a '' field and also allow you to make views ignore this filter)
  4. Enable Lock operator in the exposed filter
  5. Enable Single Select in the exposed filter.
  6. Edit the Argument PHP code and insert the following code

Replace N with the number of the filter "Number of Results". for example - if this is the 3rd exposed filter then N=2.

<?php
if( !$_GET['filterN'] ) { /* replace "N" with the filter location of the exposed filter "Number of Results". */
  /* set to default of 10 or whatever you have - this will load the filter with the default value..
   * make sure that this value exists in the list of valid values for the CCK field you created above.
   */
 
$_GET['filterN'] = $limit;
}
else if (
is_numeric($_GET['filterN'])) {
 
$limit = $_GET['filterN'];
}
else {
 
$limit = 1000; /* the maximum number of values you may wish to return for 'All' */
}
unset(
$filters[N]); /* unset the filter so it does not get applied to the query. */
?>

I needed to build a view for a node reference field that filtered content by a term of the node being edited. You cannot use arg(1) since the view is being called via the autocomplete function. You can figure out the nid from the variable $_SERVER['HTTP_REFERER']. Here is the code I used.

<?php
  $matches
= array();
 
// get node ID from node being edited
 
preg_match('`node/(.*)/edit`',$_SERVER['HTTP_REFERER'],$matches);
 
$nid = $matches[1];
 
// get term(s) from vocabulary #5 of this node
 
$term = taxonomy_node_get_terms_by_vocabulary($nid, 5);
 
// set tid as argument for node reference view
 
$view_args[0] = key($term);
  return
$view_args[0];
?>

For anyone trying to dynamically add a filter to parse nodes based on uid/author, hopefully I can save you some time. I had a cck type that had a node reference field, and I wanted the following to happen:

- If the user was of a particular role, show ALL nodes in the node reference field
- If the user was not of a particular role, ONLY show nodes that they authored

So in the node reference field settings, I wanted to use a view.

I tried to get a filter working for this via views arguments to dynamically add it with 0 luck. But I finally stumbled on this page which will do exactly what I've said: http://drupal.org/node/162679

Hope that helps someone. Could'a saved me 3 hours!

I'll document the whole hack on http://design-crasseu.joblo.serveblog.net/anglais/awesome-drupal-hack as soon as I punch out of my job, but this stuff enable you to put a view on multiple columns, using panels. There is work to do on it (so it take second argument), but it is a good base.

/* Les arguments qu'on assume reçu ici sont: $arg[0] = numéro de colonne, et $arg[1] numéro de page */
    $numpercol = 3;
    $numcol = 2;
/* On fait la query un premier coup (quelle perte de temps) pour calculer le nombre de
   résultat */
    if ($args[0] == '4') {
          $limit = 0;
          $page = 0;
          $use_pager = false;
          return $args;
    }
    $a = views_build_view('items', $view, array(4,0), null, false);
    $count = count($a["items"]);
    /* Si on a moins de post que le nombre total de post par colonne multiplié par le nombre total de colonne, on met des limites au nombre de post, et on utilise pas pager. */
    $mod = $count % $numcol;
    $div = ($count - $mod) / $numcol;
    $div = $div % $numpercol;
    if ($count < $numpercol * $numcol) {
        if ($mod >= $args[0]) {
            $use_pager = false;
            $limit = $div + 1;
            $page = $args[0];
        } else {
            $use_pager = false;
            $limit = $div;
            $page = $args[0];
        }
    } else {
        $use_pager = false;
        $limit = $numpercol;
        $page = $args[0];
    }
    return $args;

I have a content type called "games" that has 2 particular fields: 'home team" & "away team". I am trying to create a view so that when the user goes to a particular team node [teams are also a content type] that a block appears in the content region display the teams "games". Using the views admin tool, I can create an argument and display either "home games" or "away games" but I don't know how to do an "OR" statement to get the view/block to show ALL the teams games in one block. Help appreciated. Thanks. http://holbrooktoday.com/team/holbrook-boys-soccer

I'm like Schultz, "I know Nutting!" about Drupal development........yet.

I've also run into a similar situation where I need to be able to OR the arguments together. The only answer I've come up with is to have an argument for the node's ID and then set "Default argument type" to "PHP Code" and have a query return all the IDs for the nodes I need. This doesn't seem like the best solution though. Does anyone know of a different or better solution? Thanks

So I had this problem,

I have a view http://www.mysite.com/view_name/ which is a view of news nodes. I wanted to pass it the year and month as arguments so that it worked in an archive like way

http://www.mysite.com/view_name/2007

This would give you a list as follows (View argument of "Node: Posted Year" with Default set to "Display All Values" and Wildcard set to *)

* December (24)
* November (59)
* October (30)
* September (34)
* August (19)
* July (13)
* June (20)
* May (26)
* April (23)
* March (21)
* February (19)
* January (14)

When you pass it a month as a URL it gives you a full node list http://www.mysite.com/view_name/2007/10 (View argument of "Node: Posted Month" with Default set to "Summary: sorted descending" and Wildcard set to *)

However this screwed up the default view http://www.mysite.com/view_name/ by causing a list like the above to appear.

The solution was to reset the Default to "Display All Values" if no argument was passed by placing the following in the Argument handling code area, minus the php tags of course

if(!$args[0] && !$args[1] ){
  //If there are no arguments - set the Default to "Display All Values"
  $view->argument[0]['argdefault'] = '2';
  $view->argument[1]['argdefault'] = '2';
}
return $args;

Sorry for the cross post but this question is relevant to this discussion.

In views1.x you would add this in the Argument handling code field:

// Show full node view, rather than teaser, if an argument exists
if ($args[0]) {
  $view->page_type = 'node';
}
return $args;

In views2 each argument you define has it's own argument handling code field. Where would you add this code in views2?

Link to previous post: http://drupal.org/node/343533

here's something that might help out someone, for views 1 with drupal 5
argument code for displaying only nodes in a block view with the same taxonomy term as page

if ($view->build_type == 'block' && arg(0) == 'node' && is_numeric(arg(1))) {
$node=node_load(arg(1));
  $term = taxonomy_node_get_terms_by_vocabulary($node->nid, 1); //change the 1 for the vocab id
$args[0] = key($term);
}
return $args;

Hi,

does anyone know how to implement this code with views 2 and drupal 6? I'm trying to create a block that would show the last 6 nodes from every term and would use arguments to filter them automatically.

For example:

term name: drupal 6
a block would show the following articles: views 2, cck 2, drupal 6 menus, drupal 6 blocks, drupal 6 nodes, seo for drupal 6...
it would be displayed on: www.example.com/drupal/drupal6

term name: drupal 5
a block would show the following articles: views 1, cck 1, drupal 5 menus, drupal 5 blocks, drupal 5 nodes, seo for drupal 5...
it would be displayed on: www.example.com/drupal/drupal5

Thanks for help.

hi,

this is the code for drual 6 and Views 2

if (arg(0) == 'node' && is_numeric(arg(1))) {
$node=node_load(arg(1));
$term = taxonomy_node_get_terms_by_vocabulary($node, 6);
$args[0] = key($term);
}
return $args[0];

Hi,

Here's the code for taking into account multiple taxonomy terms

1. add the argument Taxonomy: Term ID
2.Action to take if argument is not present : Provide Default Argument
3. Default Argument Type: php Code
4. PHP Argument code:

if (arg(0) == 'node' && is_numeric(arg(1))) {
$node=node_load(arg(1));
$term = taxonomy_node_get_terms_by_vocabulary($node, 4); // 4 being the vocabulary id
$terms = array_keys($term);
$args[0] = $terms[0];
for($i=1; $i<count($terms); $i++)
$args[0] = $args[0] ."+" .$terms[$i]; // replace the + with / if you want and "And" action instead of "or"
}
return $args[0];

5. Check allow multiple arguments
Hope this helps.

Idan

Here's the code for D7 views 3

1. add the argument Taxonomy: Term Id
2. Action to take if argument is not present: Provide Default Argument
3. Default Argument Type: php code
4. php Argument code:

if (arg(0) == 'node' && is_numeric(arg(1))) {
$terms = array();
$node=node_load(arg(1));
foreach($node->field_category['he'] as $term) {
        $terms[] = $term['tid'];
}
$args[0] = implode("+", $terms);
}
return $args[0];

5. Check allow multiple arguments

replace field_category with the term reference field on your content type.
[he] is I assume hebrew (since i'm working on a hebrew site so this should either be removed or changed to ['en'] - not sure, the best ways to find out is to install the devel module, and dpm($node) right after the if, this will show you structure of the node object and you'll see what ['he'] should be replaced with.
replace the "+" with "," for an "And" operator for the arguments, instead of "Or"

I also recommend adding another argument to hide the current node from the list
1. argument: node:id
2. Action to take if argument is not present: Provide Default Argument
3. node id from url
4. check exclude the argument

Idan

Followed to the letter and it works. I'm using it for taxonomy terms displayed as geo-coded (lat, long) OpenLayers maps, the maps of which appear in blocks on node page associated with locations of that node. The lat-lon function as ordinary fields

Using auto-complete multiple tagging of U.S. States and countries. Also tried drop-downs, same problem. Associated country/state appears marked on map for appropriate node if only ONE location per node... funny inconsistent things start to occur when using multiple locations. Played around with Views for ages (using distinct values, validating in different ways, filters etc). If mapped for US and Japan (for instance) on a single node, if just one of these two values (US or Japan) is set as a single value on a node, it often is accompanied by the other, an undesirable behavior.

Works just fine if only 1 taxonomy term per node, however, but I need 1, 2 or sometimes 3 per node. In my case, some nodes need US and Japan, some need just Japan, and some need just US. I tried changing the + to / etc, also, and just about every other option within Views 2 latest (I'm on D6 latest).

Your code up to now saved me. Any chance you might save me again? Thanks in advance!

Arbel, Thanks for the code, I have been looking for this everywhere.

I just want to confirm that we are doing the same thing:
I have created a Page content type with no body data to act as container page. I have created blocks to appear on certain pages and want to use the container pages taxonomy term as arguments used for the blocks.

I applied this to my site and managed to pull the right content from the live preview when I enter the taxonomy value in Arguments but it doesn't seem to work on the container pages. Is the code still the same for Drupal 6 or are there slight changes?

BTW, many thanks, Arbel

I have a view that takes the uid as an argument (eg., /articles/2 shows all the nodes by user 2). I want to set the title of the view based on the uid (eg., "All articles by John Smith").

Concept: Get the uid from the arg(), load the user account to get the username, set the view title using the username. If no uid is supplied in the args, then default to a generic title.

Use this code in the views argument handling box (without the <?php ?>).

<?php
$view
->page_title = 'All posts'// set the default title
if (is_numeric(arg(1))) {
 
$uid = arg(1);
 
$author = user_load(array('uid'=>$uid));
  if (
$author->name) {
   
$view->page_title = check_plain('All Posts by ' . $author->name);  // if we got the username, use that in the title
 
}
}
?>

I was setting the page title successfully with this:

<?php
  $title
= 'whatever... %1';
 
$handler->options['title'] = $title;
?>

I wish there was some documentation or best practices for this stuff. Views Developers documentation has some nice stuff, but it seems to assume you are working from outside views, and not from the argument handling code, trying to modify the view on the fly while its running.

I wanted to provide an argument that lets you say 'give me all terms from this taxonomy EXCEPT for this one. Couldn't find an easy way to do negative arguments, so I ended up with some cusrtom PHP in my argument validation:

<?php
$arg
=array();
$vid = 40; // vid of vocabulary we are interested in.
$terms = taxonomy_get_tree($vid, $parent = 0, $depth = -1, $max_depth = NULL); // load all the terms
foreach ($terms as $term) {
  if (
$term->tid != $argument) { // build up a new list, excluding the term provided as an argument
   
$arg[] = $term->tid;
  }
}
$handler->argument = join('+',$arg); // build the actual argument
return TRUE;
?>

--
Tom
www.systemseed.com - drupal development. drupal training. drupal support.

Большое спасибо за дельную информацию, столько интересного узнал для себя. Кое-где хотелось бы больше конкретики, но в вообщем информация подана очень доступно.

Thank you! I liked the part Recipe: CCK Node Reference as argument though it didn't work for me on Drupal 6 :-)

My views path is: /quotes/auhors/%, where % is for example albert_einstein. This view lists all the quotes for author. From the author node I could access first name, last name etc.

So I'd like to do something like this:
$handler->validated_title = $first_name . ' ' . $last_name . ' quotations';

Never mind, I wrote a module where I can detect url, use drupal_set_title, meta tags, keywords and call views programmitacally. Seems nice although it's not the Drupal way :)