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 several 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 search 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, is a bilingual website, 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')); ?>
  <?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 about the relationship between views templates and preprocess functions: 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:

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

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:

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'));