Theming Views in Drupal with Templates and Preprocess Functions

If you're building a large website in Drupal, you're likely to have a long list of views that you're using. Often, views require some custom configuration to match a given design or to provide the user with additional information. Sometimes you want to add dynamic text above or below the view, such as the number of results, or want to create a dynamic title beyond what views lets you configure through the user interface.

For example, on the McGill University Health Centre website, we decided to replace the standard "Read More" link on serveral block views with a link to a filtered search page.

A simplistic solution would be to insert a link in the footer of each view to the serach page in question. It's easy enough to add a link to the footer field:

Views Footer Edit Screenshot

However, the views in question were sometimes appearing within an organic group and they filtered content based on that group. So the search page being linked to also had to filter by organic group, and the link had to reflect that. In addition, muhc.ca is a bilingual webiste, so hardcoding a string in the views configuration didn't make sense. It's messy to put a lot fo PHP or HTML in your views configuration, so although it's easy to turn on a PHP input filter, it's not the best way to override your views.

The next solution that comes to mind is a bit more sophisticated. Views comes with a whole set of template files that can be overriden. For example, the template for the overrall views display is located at views/theme/views-view.tpl.php. You can override views-view.tpl.php by copying it into your theme's directory and renaming it based on the view you want to override.

When you're configuring a view, you can click on Theme: Information under "Basic Settings" to get a list of filenames that will override the original views-view.tpl.php file. They're listed in order from more general to more specific. In this case, I would rename the file views-view--events--block-1.tpl.php to override only the block_1 display of the events view.

You'll also see template files for views fields and views rows that you can override. The template name in bold is the one being used by the current theme, so you can see at a glance which template files have already been overriden. You need to clear the cache before a new theme file that you've added is recognized by the Drupal theming registry.

Views Theme Information

Once you've created your template and cleared the cache, you can override the more link by replacing $more with a link to the search page.


  <?php if ($more): ?>
    <div class="more-link">
      <?php print l(t('Search All Events'), 'search/apachesolr_search', array('query' =>'filters=type:event')); ?>
    </div>
  <?php endif; ?>

Because we wanted a similar behaviour on a whole set of views, overriding the more link in this way would have resulted in a lot of template files. A cleaner solution is to add a views preprocess function to override $more without overridng the entire template. There's a useful thread on drupal.org about the relationship between views templates and preprocess functions: http://drupal.org/node/258089. The outcome of this thread is that you can add a helper function to your template.php which will enable you to add preprocess functions to individual views on the fly.

To use this method, you'll need to override template_preprocess_views in your template.php file like this:

<?php
function mytheme_preprocess_views_view(&$vars) {
  if (isset(
$vars['view']->name)) {
    
$function 'mytheme_preprocess_views_view__'.$vars['view']->name
    if (
function_exists($function)) {
     
$function($vars);
    }
  }

?>

To preprocess a particular view, you just need to add a preprocess function appending the name of the view. You can also check for the display_id of the view to ensure that you're only overriding a single display of that view, in this case block_1. This function replaces the more link with a link to search all events:

<?php
function mytheme_preprocess_views_view__events(&$vars) {
  if(
$vars['display_id'] == 'block_1') {
   
$vars['more'] = l(t('Search All Events'), 'search/apachesolr_search', array('query' => 'filters=type:event'));
  }
}
?>

Comments

Hi Suzanne,

There are a few syntax errors in the "mytheme_preprocess_views_view" snippet...missing dollar signs, unbalanced parentheses, that sort of thing. Hard to see, hopefully I got them all...might save someone a headache.

Thanks for the tutorial - a nice clean approach.

Nic

function mytheme_preprocess_views_view(&$vars) {
if (isset($vars['view']->name)) {
$function = 'mytheme_preprocess_views_view__' . $vars['view']->name;
if(function_exits($function)) {
$function($vars);
}
}
}

Hmm, it's an interesting method you've devised.

You could also use the Views hooks, look hook_views_pre_render(), to alter what the View is going to display. For example:

function MYMODULE_views_pre_render(&$view) {
$view->attachment_after = my_fancy_link_here();
}

@Nic: Thanks for the correction! The code snippet in the post should now be correct.

Hi there,

got still one issue with the spelling of function_exits($function). Maybe this part was right before Nic corrected it? :)

And I tested the preprocess function for named views like mytheme_preprocess_views_view__events and it's working without the function mytheme_preprocess_views_view even existing.

But what I'm really looking for is a preprocess before rows are going to be rendered. I wonder if there is a function like mytheme_preprocess_views_view_fields__events()? I'll try...

Yes, mytheme_preprocess_views_view_fields__events(&$vars) is a valid function!

Yay! This is exactly the information that I've been trying to figure out! I'm using a module that uses views for its output, but my preprocess functions where never getting registered. I couldn't figure out why. Once I put the [mytheme]_preprocess_views_view function into my template.php file... Voila! It's working as I need it!
Thank you for writing this up. I was able to find this via a web search. Not sure how long it would have taken me to uncover this info otherwise.

Thanks @aaki, the spelling of function_exists has been fixed.

Hi All, thanks for this great post! I was able to implement the functionality to customize my views using preprocess function. The function is triggered but if I make any changes in the views like assigning some data in the $vars variable like shown below they are not reflected when the views are being displayed

$vars['view']->result[0]->term_data_name = "test";

Please can anyone help me in this..

Am really clueless not able to find any tutorial in the web to make this work....