Adding Sort via Argument Handler & Visualizing $View Object

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
KentBye's picture

I'd be interested in any feedback about potential pitfalls or improvements for this, but I wanted to share a short Views Argument Handling code snippet that is able to control sorting behavior. It programatically changes the $view object when the second URL argument is "desc" (be sure to change the vid to your view id).

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;

I ran into trouble when I tried to cut and paste the views export code for the $view->sort array directly into the Argument Handling section because there were some differences in the schema. This led me to digging into the views.module code to see what the $view object actually looked like. Here's a photo of the $view object:
Only local images are allowed.

And here's how the Views Export maps to the Views $View Object...

Only local images are allowed.

Here's what the views export for the $view->sort looked like:

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

So doing a straight copy and paste of this into the Handler code section doesn't work.
If you want to alter the Fields, Arguments, Filters or Sort Criteria, then you should look into what the $view object array looks like. I'd be curious if there are any downsides to this or something that I'm overlooking.

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.

And for fun, here's another photo for how the Views UI maps to Views Export and Views $View Object

Comments

KentBye's picture

Just wanted to pass along a proof-of-concept, views argument handling code snippet that makes it possible to dynamically change the views $view object based upon arguments passed in the through the URL. I image that a brute force approach of cloning and creating multiple views is probably sufficient in most cases, but there may be cases where you need more sophisticated or dynamic control of a view.

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

<?php
if ($args[0]== "interview") {
 
$view->argument[0]['vid'] = 4;
 
$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.

This approach could be expanded to include other conditionals that dynamically add fields, arguments and filters to the $view->query based upon the URL arguments. Here's an example of adding a second filter that shows which nodes the logged in user has voted on when the third argument is "vote"

<?php
if ($args[2]== "vote") {
$view->filter[1]['vid'] = 7;
$view->filter[1]['tablename'] = '';
$view->filter[1]['field'] = 'votingapi_vote_vote_percent.uid';
$view->filter[1]['value'] = '***CURRENT_USER***';
$view->filter[1]['operator'] = 'IS NOT NULL';
$view->filter[1]['options'] = '';
$view->filter[1]['position'] = 1;
$view->filter[1]['id'] = 'votingapi_vote_vote_percent.uid';
}
$view->query ='';
return
$args;
?>

Hi, Can you help me

mixey's picture

Hi,

Can you help me please?
I'm trying to make simple search form for my website where user will enter price range (from 10 to 150, for example)

and then View should output just articles where CCK field price is in the range of 10-150.

I guess I should user arguments and Arguments handling code, but I can't figure out, how to set this "range" filter

any help is really appreciated

Step by step with your

mixey's picture

Step by step with your example I came with:

if ($args[0]) {
  drupal_set_message(arg(1));
  $view->sort[0]['vid'] = 7;
  $view->sort[0]['position'] = 0;
  $view->sort[0]['field'] = 'node_data_field_price.field_price_value';
  $view->sort[0]['sortorder'] = 'ASC';
  $view->sort[0]['options'] = '';
  $view->sort[0]['tablename'] = '';
  $view->sort[0]['id'] = 'node_data_field_price.field_price_value';
}
$view->is_cacheable = 0;
return $args;

It is working example for the CCK field price this code sorts nodes asc.
But I can't understand why it doesn't work when I'm modifying it to filter results instead of sorting:
if ($args[0]) {
  drupal_set_message(arg(1));
  $view->filter[0]['vid'] = 7;
  $view->filter[0]['tablename'] = '';
  $view->filter[0]['field'] = 'node_data_field_price.field_price_value';
  $view->filter[0]['value'] = '105';
  $view->filter[0]['operator'] = '>';
  $view->filter[0]['options'] = '';
  $view->filter[0]['position'] = 0;
  $view->filter[0]['id'] = 'node_data_field_price.field_price_value';
}
$view->is_cacheable = 0;
return $args;

Please help me out :)

Views Sort Ascending or Descending

davidwhthomas's picture

Here's the code for ascending and descending sort options, if anyone is looking.

<?php
if ($args[0]== "desc") {
  
$view->sort[0]['vid'] = $view->vid;
  
$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';
}elseif (
$args[0]== "asc") {
  
$view->sort[0]['vid'] = $view->vid;
  
$view->sort[0]['position'] = 0;
  
$view->sort[0]['field'] = 'node.nid';
  
$view->sort[0]['sortorder'] = 'ASC';
  
$view->sort[0]['options'] = '';
  
$view->sort[0]['tablename'] = '';
  
$view->sort[0]['id'] = 'node.nid';
}
return
$args;
?>

Browse content like on the YouTube site.

berend31's picture

Hi,

I want to be able to browse a large amount of links like you can browse the videos on youtube (http://youtube.com/browse?s=mp , on the left). There are three blocks where you can select 'Sort by', 'Time' and 'Category'. The thing is that you can select one item from each block at the same time; when you click a link in the second block, it remembers your choice of the first block.

For my site, I'd like something like this:

Browse
most recent
most hits
top rated
most comments

Time
today
this week
this month
all time

Category
games
internet
multimedia
system
...

Do you think this is possible with this method? If yes, how?
Sorry if this has nothing to do with this thread.

Thanks,
Bert

Have you solved it?? I would

aac's picture

Have you solved it??
I would be interested to know how to implement this functionality.
Thanks in advance!!

---~~~***~~~---
aac

Subscribe. How would his

bflora's picture

Subscribe. How would his filters be created?

This is such an awesome

light-blue-pdx's picture

This is such an awesome post! I have been lost countless times in Views doing just this sort of thing, and I've hunted through the views php code, export object, and dpr($view) as well (not fun), but you've done an absolutely wonderful job of presenting the pieces graphically. Cheers!

Also, I wanted to add two things:

  1. In D5 with panels, if your view uses widget-based arguments (i.e. not exclusively manipulating $view in the argument handling code), visit admin/panels/views for ADDITIONAL widget-based options. Those options are not available otherwise!

  2. With devel enabled, create a widget-based views argument (you can remove it later), then go to the argument handling code and issue the commands below to build a proper $view object.
    dpm(arg(0)); //especially for panels with only arg handling code (no argument handling widgets)
    dpm(arg(1));
    dpm(arg(2));
    dpm(arg(3));
    dpm(arg(4));
    dpm($args); //these are views argument, not drupal ones as above. subtle but critical difference
    dpm($view);

Views Developers

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: