With Views1.x I had some argument handling code that would change a view from a teaser view to a page view if an argument was present. This is the code i used:

if ($args[2]) {
  $view->page_type = 'node';
}
return $args;

Im developing a new site using Drupal6 and Views 2 and am at a loss for where I can add this code. In my views2 view I added 3 arguments:
Content: (a custom field)
Taxonomy: Term
Node: Title

Each argument has a section: "Action to take if argument not present" and "Validator options." Since I want something to happen if the argument is present I've tried inserting my new handling code above into the Validator (PHP Code):

if ($argument) {
  $view->page_type = 'node';
}
return $argument;

Any suggestions?

thanks
PP

Comments

ppmax’s picture

I forgot to mention that I added the new argument code to the Node: Title argument...

ppmax’s picture

For the searchers out there:

Adding argument handling code in views2 is different than views1. In views2 you have much more control and it's way more powerful.

For this explanation I'll use my original post as an example. I typically use the presence of a node title as the last argument as a way to trigger a node view as opposed to a teaser view. In views1 the code for this was:

if ($args[2]) {
  $view->page_type = 'node';
}
return $args;

As stated above doing this same thing in views2 is different; in essence you now enter views argument code per argument which is way cool (but has the drawback of requiring you to manage your views2 argument handling code per argument). In views2 I created two arguments:
taxonomy term
node title

Once you save your view with the arguments defined you can click on the argument to reveal many options for handling the argument if it doesnt exist and more options for validating the argument if it does exist. For my purposes I "Display all values" if the argument is not present. I then added some code in the "Validator options" to execute PHP Code (which then provides a text entry field). In the text entry field I added this code:

// Show full node view, rather than teaser, if an argument exists
if ($argument) {
  $view->display_handler->set_option('style_plugin', 'default');
  $view->display_handler->set_option('row_options', array(
  'teaser' => 0,
  'links' => 0,
  'comments' => 1,
));
}
return TRUE;

Compared to views1 argument handling code you now use $argument instead of arg() as the basis for your conditional. You also get to set options for the view if the argument exists which can be very powerful.

Hope this helps someone--
pp

summit’s picture

Subscribing, needing argument handling code for taxonomy term filtering (twice:)
So how can you get to $args[1] and $args[2] in views2? Do you need to add two arguments of the type taxonomy then. How do you then explain which one is the first, and which one is the second?
Thanks a lot for sharing your thoughts on this!
greetings,
Martijn

ppmax’s picture

>>So how can you get to $args[1] and $args[2] in views2?

The trick is that you dont use $args[n] anymore; for each argument you add you use $argument which returns that single argument that gets passed. So if you add 2 arguments to your view you would add argument validation code for each and do your conditional for each. Besides the small inconvenience of entering argument code for each argument this new technique seems to be far more powerful and flexible.

For example: if a user clicks a link with only one argument you could enter something in the Validator options for the first argument to change the view through the $view->display_handler->set_options method. If your user clicks a link with both arguments you'd add additional Validator options code for the 2nd argument.

>>Thanks a lot for sharing your thoughts on this!
No problems. It took me a while to figure it out and I haven't seen a post where anyone really explains how it works. In fact I havent really found any docs on the set_options possibilities; the only way I was able to figure out the set_options stuff was to export a view and dig through all the code it provides.
pp

summit’s picture

Hi ppmax,

Could you tell me how I can convert than this sort of code to views? What will be the resulting code then? And how can I tell with $argument which argument is the first taxonomy term?
(it is argument handling code in views1):

if ($args[0]) {
   $tmpterms_0 = taxonomy_get_term_by_name($args[0]);
   $view->filter[2][value][0] = $tmpterms_0[0]->tid;  
   if ($args[1]) {
     $tmpterms_1 = taxonomy_get_term_by_name($args[1]);
     $view->filter[3][value][0] = $tmpterms_1[0]->tid;
     drupal_set_html_head('<title>'. $tmpterms_0[0]->name . ' ' . $tmpterms_1[0]->name . '</title>');
     drupal_set_html_head('<meta name="description" content="' . $tmpterms_0[0]->name . ' ' . $tmpterms_1[0]->name . '" />');
     drupal_set_html_head('<meta name="keywords" content="' . $tmpterms_0[0]->name . ' ' . $tmpterms_1[0]->name. '" />');
     }
   else {
     drupal_set_html_head('<title>'. $tmpterms_0[0]->name . '</title>');
     drupal_set_html_head('<meta name="description" content="' . $tmpterms_0[0]->name . '" />');
     drupal_set_html_head('<meta name="keywords" content="' . $tmpterms_0[0]->name . '" />');
     }
   }
return $args;

Thanks a lot in advance!

Greetings,
Martijn

ppmax’s picture

You'll have to break this code up and paste it into two different places. Some of this is guesswork because I don't know what you're doing ;)

For the first argument you created in your views2 UI do this:
Click on your first argument
Select PHP Code from the Validator drop down in Validator options
Enter this in the PHP validate code text box:

if($argument) {
  $tmpterms_0 = taxonomy_get_term_by_name($argument);
  $view->filter[2][value][0] = $tmpterms_0[0]->tid;
}
return TRUE;

Be sure to click the Update (default?) display button

Now click on the 2nd taxonomy term you created in your views2 UI
Select PHP Code from the Validator drop down in Validator options
Enter this in the PHP validate code text box:

if ($argument) {
  $tmpterms_1 = taxonomy_get_term_by_name($argument);
  $view->filter[3][value][0] = $tmpterms_1[0]->tid;
  drupal_set_html_head('<title>'. $tmpterms_0[0]->name . ' ' . $tmpterms_1[0]->name . '</title>');
  drupal_set_html_head('<meta name="description" content="' . $tmpterms_0[0]->name . ' ' . $tmpterms_1[0]->name . '" />');
  drupal_set_html_head('<meta name="keywords" content="' . $tmpterms_0[0]->name . ' ' . $tmpterms_1[0]->name. '" />');
     }
  else {
    drupal_set_html_head('<title>'. $tmpterms_0[0]->name . '</title>');
    drupal_set_html_head('<meta name="description" content="' . $tmpterms_0[0]->name . '" />');
    drupal_set_html_head('<meta name="keywords" content="' . $tmpterms_0[0]->name . '" />');
  }
}
return TRUE;

Click Update display
Save

Regarding lines like:
$view->filter[3][value][0] = $tmpterms_1[0]->tid;
...you'll probably have to export a view and poke around to find the appropriate $view->display_handler->set_option method that's appropriate

HTH
pp

summit’s picture

Hi,

Thanks for helping till now!
My goal is to have a view showing the results of the nodes belonging to two taxonomy terms. Say all nodes which have christmas in holland(and nodes belonging to terms under christmas and underneath holland, like amsterdam. So the url will be www.example.com/about/christmas/holland (the view will be "about" and then all nodes with depth 3 will need to popup with terms christmas and holland or terms underneath chrismas and holland with dept of 3.
Does this give you more to help with?

I was wondering, is it true that the second taxonomy term, still knows about the first arrays.
So that: $tmpterms_0[0]->name is valid code in the second $argument.
EDIT: I am trying to get this to work, but I am not able to get the arguments working...any taxonomy_term I fill in gives no results when I build the view from scratch from taxonomy/term view.
EDIT2: Trying to convert, I got with importing the views1 view:

Field handler node.body is not available. 
Filter handler node.distinct is not available. 
Field handler node.body is not available. 
Filter handler node.distinct is not available. 
Field handler node.body is not available. 
Filter handler node.distinct is not available. 
Unable to import view. 

I am still confused about how to get this working in views2, because I need to seperate things now..and then somehow integrate again..

ppmax, can I PM you? Or you contact me to get this working. I can email you then my views1 view, and my fabricated views2 view. Thanks!
greetings,
Martijn

summit’s picture

Hi,

I think this is the filter put on the view (trying for ages to get this working...) could you help me out please?
What will be the code of:

$view->filter[3][value][0] = $tmpterms_1[0]->tid;

This is what the export of the view about filtering says:

$handler->override_option('filters', array(
  'status_extra' => array(
    'id' => 'status_extra',
    'table' => 'node',
    'field' => 'status_extra',
    'operator' => '=',
    'value' => '',
    'group' => 0,
    'exposed' => FALSE,
    'expose' => array(
      'operator' => FALSE,
      'label' => '',
    ),
    'relationship' => 'none',
  ),
  'term_node_tid_depth' => array(
    'operator' => 'or',
    'value' => array(
      '1904' => '1904',
      '1916' => '1916',
    ),
    'group' => '0',
    'exposed' => FALSE,
    'expose' => array(
      'operator' => FALSE,
      'label' => '',
    ),
    'type' => 'select',
    'limit' => TRUE,
    'vid' => '2',
    'depth' => '2',
    'id' => 'term_node_tid_depth',
    'table' => 'node',
    'field' => 'term_node_tid_depth',
    'hierarchy' => 1,
    'override' => array(
      'button' => 'Use default',
    ),
    'relationship' => 'none',
    'reduce_duplicates' => 0,
  ),
));

What would be the resulting code please for php in argument handling?

$view->display_handler->override_option('term_node_tid_depth' array( ...

1904 and 1916 are taxonomy term ID's. In the arguments will be the taxonomy term names.
Will it be something like:

// Show only filtered taxonomy term through $argument
if ($argument) {
  $tmpterms_0 = taxonomy_get_term_by_name($argument);
  $view->display_handler->override_option('term_node_tid_depth' array(
     'value' => $tmpterms_0[0]->tid,
     ));
  }
return TRUE;

Thanks a lot in advance for your help!
Greetings,
Martijn

tommytom’s picture

thanks a lot for that info. somebody really should do a good documentation.

icstars’s picture

i was and remain completely confused by this new approach. i have a regular pattern of using block views to display related content based on node reference fields. the pattern was nice and simple and always the same in views 1.x - in the argument handler we put the code:

if ($view->build_type == 'block' && arg(0) == 'node' && is_numeric(arg(1))) {
  $args[0] = arg(1);
}
return $args;

worked flawlessly every time. and when no content was related, the block simply disappeared.

trying to get this same pattern to work in views 2. i am stumped. i have tried just the following three approaches, all of which give correct and expected results in the views previewer when i provide the argument, but do not work in the actual site block context, nothing shows up.

  1. basic validation + hide view - i call this the black box - i assume since this is the only argument that it does the old code above without any extra work and just verifies a number is there.
  2. php code
    $handler->argument = $argument;
    return TRUE;

    - don't ask why i thought this would be right. seems completely redundant.

  3. node validator - most intuitive - choose the node type that should be getting sent in as the node reference. no code required

i have cleared the views cache and verified multiple times that the view works as designed within the edit view page with correct and incorrect arguments. still the block view does not show up on the actual page.

icstars’s picture

the reason it works in the preview and not the site is that viewing a node passes two args on the url: node + the id (e.g. node/1199 - where 'node' is arg(0) and 1199 is arg(1)). the reason the preview worked is because i was just passing in 1199. if i simulate the real world context where the view is actually getting node/1199 passed to it. the view says my argument was not present. so, now i can finally frame the question: if you cannot reference arg(0)/arg(1) directly via array anymore, and you want to ignore arg(0) and just focus on the id in arg(1), how do you accomplish that? i can't imagine i have to define a dummy argument in the first position to ignore the 'node' in arg(0), right?

WorldFallz’s picture

I'm not sure I understand your question completely-- but if you're trying to use the node id as an argument to a block in views2 do this:

  1. add an argument of "Node: nid" to arguments
  2. select 'Provide default argument'
  3. select 'php code'
  4. add the following:
    if (arg(0) == 'node' && is_numeric(arg(1))) {
      return arg(1);
    }
    else {
      return FALSE;
    }
    

===
"Give a man a fish and you feed him for a day. Teach a man to fish and you feed him for a lifetime." - Lao Tzu
"God helps those who help themselves." - Ben Franklin
"Search is your best friend." - Worldfallz

icstars’s picture

Here's how I did it:

1) Added an argument: Content: Node reference: (NAME OF FIELD I WANT TO USE TO GET RELATED CONTENT) (same as views1)

2) Action to take if argument is not present: Provide default argument (new)

3) Default argument type: Node ID from URL (new)

4) Validator: Basic Validation (new)

5) Action to take if argument does not validate: Hide View/Page not Found (new)

This works both in the view preview and in the real site and does not require extra code to be eval'd - SWEET!!

Its not clear why in step 2 we are specifying what to do if the argument is NOT present, this seems counter-intuitive - the argument is there, and i'm telling it to get the argument from the url.

WorldFallz’s picture

Excellent-- thanks for the info, it's good to know.

As for step 2, it's my understanding that is necessary because blocks, unlike pages, no not have the concept of "argument" so technically, for block views, the argument is not present for the block though it is there in the url. There's an issue in the views issue queue somewhere where merlin explains this a bit more.

===
"Give a man a fish and you feed him for a day. Teach a man to fish and you feed him for a lifetime." - Lao Tzu
"God helps those who help themselves." - Ben Franklin
"Search is your best friend." - Worldfallz

jonahan’s picture

icstars - thanks much! Your info here helped me greatly in figuring out the new Views 2.

Drupal is so great, but it fails in actually explaining how to use the powerful features. I spent like 2 hours figuring it out. More documentation by the developers and planning for ease-of-use would go a long way towards Drupal's acceptance by the mainstream.

Anyway, just a big thank you to icstars and everyone else who posted useful info here!

WorldFallz’s picture

Developers develop-- that's what they're good at, that's how they should maximize their precious time. It's very rare that a developer will also be a good documenter-- and even if they are, it's not the best use of their skillset (there are far more people with the skills to contribute documentation then the skills to contribute code). It's up to the rest of us in the community to help out with documentation (which anyone can contribute). Merlin has asked for help with documentation more then once.

Glad it was helpful though. ;-)

doublejosh’s picture

This does work, but why can't you accomplish the same thing by setting $handler->argument in the "Use empty Text" validation through PHP option.

I couldn't seem to get it to work. I would be great to see how that approach can also succeed.

916Designs’s picture

After endless googling, I found some decent documentation from the Views Developers group.

dzaus’s picture

I believe that I have something very similar to the other questions, and I'm sure the answer is floating there just out of my grasp (particularly the answer from ppmax). I feel like I'm missing something really obvious, too.

I have two node types - 'news' and 'events' (not from the event module) shown in my calendar. Really the only difference between the two is that 'events' has a specific date range. The calendar is filtered on types 'news' and 'events'.

The calendar came configured with the settings for "show on post date". This takes care of 'news' postings. I then set it up to also show on the content dates, which takes care of the 'events' postings. However, the 'events' posts are also showing on their post days in the calendar. I would like it to decide "if this is node.type 'events', then only look at the argument 'Content: - value' instead of 'Node: Post date' ".

Right now, the arguments are set to "Date: Date Content: - value OR Node: Post date" (configure / Date field(s): / 'Content: - value' & 'Node: Post date' are checked). I tried separating it into two arguments, one for each, so I could try a PHP validation filter (which is actually my main question - how?), but the weird thing is that separating it into two arguments makes it fail to show anything with the corresponding post date -- even though the SQL statements at the bottom of the preview are identical.

--- Modules ---
Calendar 6.x-2.0
Views 6.x-2.3
Date 6.x-2.0

paganwinter’s picture

Thanks so much for that!
Spent such a long time trying to get it work on Views 2.
Had done this in D5 + Views1.

Didn't expect the validator to do this piece of functionality. It's really a misnomer!

Anyone wanting to use pathauto alias as arguments, here is how I did it:

I have a content type movie - path setting: movie/my-movie-name
I wanted a view like movie/my-movie-name/news listing all news content types referring a particular movie (my-movie-name in this case)
Here is what I did for it:

Set the views path as movie/%/news

Added this in validator:

$normal_path = drupal_get_normal_path("movie/".arg(1));  // to get node id from alias
preg_match('/node\/(\d+)/', $normal_path, $matches);

$handler->argument = $matches[1];

return TRUE;

Of course this is not "validation" per se... but you can add some more validation code here...

Radiating Gnome’s picture

Stuck - Please help! I'm using Views2 and CCK, trying to filter a view of sections down to those with a certain value in a text field (an identifier).

It's a display of courses and the available sections. I have a view that displays all available sections; I would like to filter them down to just those for this particular course. Because of the way I'm getting the data, node references aren't really working for me, but the parent node has a Catalog ID Code (something like CS101) and then the sections also have the catalog ID code.

When the page loads, I have "$field_cid[0][value]", which will output the code I need. I can filter the results with that code in the preview, but I'm missing something -- how do I use the argument settings and what snip of php (in which of the two php areas, the default or validation) do I need to make this work.

I've beat my head into this all day - - I think I'm running around in circles. Help!

Radiating Gnome’s picture

Found out what I *think* was my problem, and a solution that was not quite what I was hoping for at first. So, for anyone else having the same problems:

My issue, I think, was that I was trying to pass a variable from the node to a block displaying on the page -- but I was not successful trying to get the argument into the view. I tried a bunch of different ways, but in the end I think that the blocks must be rendered BEFORE the node on the page is -- so the variable I'm looking for isn't available. The ugly solution would probably involve some sort of node_load() stuff, but . . . well, it just seems like it might be a little goofy to load the node an extra time for each page load.

But, working on that assumption, I've created a variation on the node template for my course node type. I went there because I *know* that when I'm in the node template area that I have the variables I need without calling up the node an extra time.

There's a function we can call -- views_embed_view(). I added this line of code in the appropriate part of the template:

<?php
print views_embed_view('viewname','displayname',$field_something[0][nid],$field_somethingelse[0][value]);
?>

The function requires two parameters:

viewname = the name of the view
displayname = the name of the display

The additional parameters provided are passed into the view as arguments:

$field_something[0][nid] = the variable that will display the CCK field data I want to display, in this case a node reference
$field_somethingelse[0][value] = another variable, in this cases a simple text field

(If you're not sure what variable to call, install the devel module, take a look at the dev-load and dev-render versions of a sample node)

I hope that helps someone!

WorldFallz’s picture

FYI node_load is frequently used in views argument handling code to get at the info you need-- the node is being displayed so it's cached and any performance impact should be negligible.

That said, the method you use is also quite common. However, since you're not displaying the results in a block but the node itself, you could also have used the views_attach module as well.

deg’s picture

I would like to use argument handling code to filter a view's output based on the argument given to the view. Depending on the argument, a filter's value will be different. The arguments are in one taxonomy vocab, the filters are in another vocab.

Example: site.com/news should only display content from within "Story Type > News" and "Story Source > World" and site.com/entertainment should only display content from within "Story Type > Entertainment" and "Story Source > Lithuania"

In Views 1, I achieved this by appending to the current argument with the other argument I would like to filter by. How is this manipulation (or the manipulation via filters suggested earlier in this post) done? Thanks for the help.

Views 1 code:

if($args[0] == 123 || $args[0] == 456){ // If "Entertainment" or "Edutainment"
     $args[0] .= ",789";  // Limit to only Lithuania
izmeez’s picture

Thanks for all the ideas in this thread.

I am now realizing that I will need some php for the argument to do what I am trying to do. Unfortunately my php skills are somewhat limited and I could use some help.

I would like to display a list of users but only in a specific group type. I have more than one group type.
Any suggestions on how to do this would be appreciated. Thanks,

Izzy