Drupal 7 Tutorial: Creating Custom Filters in Views

I love views. It makes my job easier, so I can focus on the more complex things, rather then having to hand-write queries, create forms for filtering data and it saves time debugging my typos. Every so often you will get a request that can't be accomplished out of the box.

If you are trying to customize the options in an exposed form, you may still need to do hook_form_alter(). Or, if you are trying to filter or sort your view by a field that doesn't appear in views, this short tutorial will show you how.

Say your module has a table that has a relationship to files, although it could be to nodes, users, taxonomy, etc. All your module needs to do is define two little functions hook_views_api() and hook_views_data(). The documentation there is pretty good, but lets take a look at a simple real-life example.

<?php 
/**
 * Implements hook_views_api()
 */
function my_video_views_api() {
  return array(
    'api' => 3,
  );
}
 
/**
 * Implements hook_views_data()
 * Exposes our playcount table to views
 */
function my_video_views_data() {
  // Basic table information.
  $data['my_video_playcount'] = array(
    'table' => array(
      'group' => t('File statistics'),
      'join' => array(
        'file_managed' => array(
          'left_field' => 'fid',
          'field' => 'file_fid',
        ),
      ),
    )
  );
 
  // Our fields
  $data['my_video_playcount']['playcount'] = array(
    'title' => t('Playcount'),
    'help' => t('The total number of times the video has been started.'),
  );
 
  // Adds our field in the "Fields" section of Views
  $data['my_video_playcount']['playcount']['field'] = array(
    'handler' => 'views_handler_field_numeric',
    'click sortable' => TRUE,
  );
 
  // Adds our field in the "Filters" section of Views
  $data['my_video_playcount']['playcount']['filter'] = array(
    'handler' => 'views_handler_filter_numeric',
  );
 
  // Adds our field in the "Sort" section of Views
  $data['my_video_playcount']['playcount']['sort'] = array(
    'handler' => 'views_handler_sort',
  );
 
  return $data;
}

I've tried to make the code comments self-explanatory, but let's break it down a bit. The hook_views_data() function expects an array. The first dimension is keyed by your table name.

// Basic table information.
  $data['my_video_playcount'] = array(
    'table' => array(
      'group' => t('File statistics'),
      'join' => array(
        'file_managed' => array(
          'left_field' => 'fid',
          'field' => 'file_fid',
        ),
      ),
    )
  );

This first section defines the 'group' the relationship will be displayed in, you could use an existing group, like 'Content' or define your own. The 'join' defines the relationship between your table and the primary table of the view, in our case, the file_managed table. The 'left_field' will be the column in the file_managed table, and the 'field' is the column in my_video_playcount table.

 // Our fields
  $data['my_video_playcount']['playcount'] = array(
    'title' => t('Playcount'),
    'help' => t('The total number of times the video has been started.'),
  );

Next you define the fields in your table, in our case we only have one field 'playcount'. The 'title' and 'help' are displayed in the Views admin pages when you add or edit your filters. You can then define how each field may be used in views.

// Adds our field in the "Fields" section of Views
  $data['my_video_playcount']['playcount']['field'] = array(
    'handler' => 'views_handler_field_numeric',
    'click sortable' => TRUE,
  );

Defining 'field' will make it appear in the "Fields" section, you will need to set the 'handler', which can be the name of any subclass of views_handler_field. You can set 'click sortable' to TRUE to make it sortable in the Table display.

 // Adds our field in the "Filters" section of Views
  $data['my_video_playcount']['playcount']['filter'] = array(
    'handler' => 'views_handler_filter_numeric',
  );

Similarly you can add 'filter' and 'sort' support for your field by defining the 'handler' that the field should use. Views provides some built in handlers, that should meet almost every use-case, but if not, all the handlers are extendable, so you can quickly write your own if necessary. I haven't needed to write my own handler, and couldn't think of one for the purpose of this blog post, but I'm sure there are. If you have one, I'd love to hear about it.

Ready to get started?