Conditional Fields in Drupal Views

Views is an essential part of any Drupal site. It is very versatile and allows non-developers to set up all kinds of listings of their content. However, no matter how versatile it is, you will always find a scenario that is not feasible to set up on its user interface. But if you are a developer, you have even more ways of manipulating views. 

Making one field conditional on another field

One not so uncommon scenario is where you would like to make the display of one field conditional on some other field. Let's suppose you have a listing of recent content. The listing shows the content type, title, and author of the content. Let's suppose you would like to display the content type only if the author is not anonymous, and hide it otherwise. So in this case, the content of the content type field depends on the content of the author field. This is one condition that Views' configuration interface is not capable of setting up. To implement this, you will need to implement one of Views' hooks in your custom module, and manipulate the data on the code level. The hook we will need is hook_views_pre_render(). When this hook is invoked, the view has already been executed, and the results are available for manipulation. The results are available as a property of the giant $view variable that is passed in to your hook. To see how our data looks like, we can print it out by doing a dsm() in the hook. Assuming the custom module we would like to put the code into is called test_views, our hook will look as follows:

function test_views_views_pre_render(&$view) {
  dsm($view->result);
}

(dsm() is provided by Devel module, and displays the variable as a collapsible tree). Having set up a very simple view that lists recent content, I get the following when printing out the variable:

 

The view looks as follows:

 

So the two fields I am interested in are the content type and the author field. From the results dataset, I can see that I will need users_node_uid and node_type. With that in mind, my hook implementation will look like as follows. Let's suppose my view's name is tracker, and the page I am working on is called page.

 

function test_views_views_pre_render(&$view) {
  if ($view->name == 'tracker' && $view->current_display == 'page') {
    foreach ($view->result as $result) {
      if ($result->users_node_uid == 0) {
        $result->node_type = '';
      }
    }
  }
}
 

 

In the hook, I step through all the result items, and, if the user id is 0, that is, anonymous, I remove the content of the node type field. After adding the hook, the type field will be blank in the appropriate rows, as the figure below illustrates.

 

 

Conditionally hiding columns in a view

Another common scenario is where you want to hide columns under certain conditions. For instance, in a listing of recent content, you may want to hide the author's name if the user looking at the listing is not logged in. For this, I am using another Views hook, hook_views_pre_execute(). As opposed to the hook used previously, - as the name suggests - this one is invoked before the view has been executed. This gives us the opportunity to remove certain columns before they make their way to the result set. What I will need here is to look up the handler for the field, so to begin I implement the hook and just print out a part of the $views variable. 

 

function test_views_views_pre_execute(&$view) {
  dsm($view->display_handler->handlers);
}
 

Here is what we will get:

 

 

Under 'field', a list of available fields can be seen. I'll need the name field, since I would like to hide the author's name. Below is my final hook implementation.

 

function test_views_views_pre_execute(&$view) {
  global $user;
  if ($view->name == 'tracker' && $view->current_display == 'page') {
    if ($user->uid) {
      $view->display_handler->handlers['field']['name']->options['exclude'] = 1;
    }
  }
}
 

 

To hide the column in the view, one needs to set the exclude option to 1 in the appropriate handler object. We check the logged in user's id before we set the exclude variable here. This is another condition that is not available for setting up on the Views user interface. The resulting view looks as the picture below illustrates.

 

 

Comments

Have you ever had a scenario where you can hide a row in a view after a different user has manipulated the data? Here is the scenario we need help with: user a fills out questionnaire a. user b views user a's responses in the view and then can use user a's information in user b's form. user b submits user b's form and now no longer needs to see user a's responses in the view because user a is done. Does this make sense and do you think the hook option will work even though it is a completely different user submitting a different form?

Hi Meghann,
This depends on how you store user A's and B's responses. If each user's response is stored in a field in the same entity, this solution might work. You can use the method described above, but with your own conditions. If each user's response is a separate entity, (for example, this is the case if you are using webforms), then what you need to do is hide the whole row of user A's response. For that, you would need to use a different approach. For instance, using hook_views_query_alter might be needed.

Add new comment