Views 3 Plugins

How would you describe the Views module for Drupal? At its most basic, Views is simply a way to query a data set and display the results of that query. I like to think of it as this: Views turns data into information. The problem is, there are an infinite number of ways to display that information and Views only provides you with a few: as a table, a list or a grid. These are known as styles in the Views UI. Luckily, Views provides ways to extend these styles or create a completely new one. This is where plugins come into play.

This article assumes a certain familiarity with developing modules that are dependent on Views. If you do not have much experience with Views, I recommend watching the Views for hackers presentation by Karim Ratib at Drupalcon Chicago.

I’m going to step through the process of creating a Views 3 sub-module with a display plugin. Although Views 3 is still in an alpha state in Drupal 6, all Drupal 7 Views development is with Views 3 rather than Views 2. If you are developing for Drupal 6, it makes sense to develop a Views sub-module within the Views 3 architecture since it is much more extensible, thus easier to port to Drupal 7.

Ok, let’s dive in. We’re going to create a plugin that extends the table style. The first thing we should cover is the overall layout of your module. You will need the usual .module, .info and .install files. You will also need a .views.inc file, which is where all of your views hooks will live. This will automatically be picked up by Views, so you do not need to provide an include to it in your .module file. Create the following folders: plugins and theme. It also doesn’t hurt to add a README file to explain how your module works.

your_module directory structure

The first thing we need to do is create our hook_views_plugins() in the .views.inc file. This is where we register our new plugin and tell Views where our plugin lives. It is also where we can register our theme for the new plugin.

function your_module_views_plugins() {
  $theme_path = drupal_get_path('module', 'your_module') . '/theme';
  return array(
    'module' => 'your_module',
    'style' => array(
      'new_table' => array(
        'path' => drupal_get_path('module', 'your_module') . '/plugins',
        'parent' => 'table',
        'title' => t('New Table'),
        'theme' => 'your_module_new_table_view',
        'theme path' => $theme_path,
        'help' => t('Adds a message after the table.'),
        'handler' => 'views_plugin_style_new_table',
        'uses row plugin' => TRUE,
        'uses fields' => TRUE,
        'uses options' => TRUE,
        'type' => 'normal',
      ),
    ),
  );
}

In the above code example, the ‘handler’ points us to our next file, the actual plugin. Within the plugins folder, we can now create a file with the value of the ‘handler’, views_plugin_style_new_table.inc. Since Views is designed with an object-oriented architecture, we will create a class for our new plugin in this file.

class views_plugin_style_new_table extends views_plugin_style_table {

Our plugin is extending from views_plugin_style_table which extends from views_plugin_style which extends from views_plugin. We get all of the functionality from the table display plugin for free and all we need to do is tweak it to our liking. For example, we get all of the style options defined by table, so if we wanted to add some additional options, we could override the option_definition() and options_form() methods. For the purposes of this tutorial, let’s say that we want to create an option to allow for natural sorting of our table. So if we have content with titles that begin with integers, we expect them to be sorted like integers and not like strings. For example, if we have titles that begin with 1, 2 and 10, we expect them to be sorted that way and not 1, 10 and 2.

function option_definition() {
  $options = parent::option_definition();
  $options['nat_sort'] = array('default'  => '');
  return $options;
}

function options_form(&$form, &$form_state) {
  parent::options_form($form, $form_state);
  $form['nat_sort'] = array(
    '#type' => 'checkbox',
    '#title' => t('Natural sorting'),
    '#default_value' => $this->options['nat_sort'],
  );
}

Notice that the first thing we need to do in each method is call the parent method, otherwise we’d completely override the options defined by the table style. Now, we need to add the functionality that this checkbox enables. We can manipulate the query by overriding the query() method in the plugin. In our case, we’re going to change the ORDER BY portion of the query so that we first sort the field as if it’s an integer, then sort the field as if it’s a string.

function query() {
  parent::query();
  $field = $_GET['order'];
  $sort = $_GET['sort'];
  if ($this->view->display_handler->display->display_options['style_options']['nat_sort'] && $field && $sort) {
    $base_table = $this->view->query->base_table;
    $this->view->query->orderby[0] = $base_table . '_' . $field . '+0 ' . $sort;
    $this->view->query->orderby[1] = $base_table . '_' . $field . ' ' . $sort;
  }
}

There are a number of other methods that can be overridden the same way in your plugin. I recommend going in and exploring the plugins defined in Views to get an idea of what they can do and how they are used.

Now that we have defined our new plugin and given it some very basic functionality, we should check to make sure it displays under the view styles in the UI.

view style settings

Click on the link next to Style: and you should see your new plugin listed. It uses the title defined in your_module_views_plugins().

your module's new style

After selecting your plugin, you will then be taken to the style options. Make sure that the form fields defined in your plugin are displayed there. In our example we have created a new checkbox called ‘Natural sorting’ and it should display below all of the parent options inherited from the table style.

your module's new style options

Next, we move on to the plugin theme. We won’t need to do any real theming for this plugin as we only changed the sorting of the table. Since this is a new plugin, however, we still need to create a template and preprocess function for the display. If we look back at your_module_views_plugins(), there is a new theme defined there. This theme needs to be registered properly in the .module file with hook_theme().

function your_module_theme() {
  return array(
    'your_module_new_table_view' => array(
      'arguments' => array('form' => NULL),
    ),
  );
}

We have set our ‘theme_path’ in your_module_views_plugins() to point to the theme folder in our module, so we can create a file there called views_plugin_style_new_table.tpl.php. In order to preserve the theming of the parent table plugin, we can copy the code in from views-view-table.tpl.php. We can do the same with the preprocess function and copy the code from template_preprocess_views_view_table(&$vars) into the function template_preprocess_your_module_new_table_view(&$vars) in our .module file.

If you are doing anything sufficiently complicated with your plugin, chances are you will need to do some additional work in your preprocess function before sending data to the theme. The view object will get passed in through &$vars, so any values that you need out of the view will be available to you to prepare data for your template.

This article doesn’t demonstrate the true power of plugins for the Views module, but I hope it gives you an idea of how to get started. If you’d like to see some powerful plugins in action, two of the most heavily used sub-modules are Views bulk operations and Views slideshow (which are so popular that they have THEIR own sub-modules). I have one of my own in review on drupal.org called Views taxonomy grid, the development of which provided me with much of the material for this article.

If you’ve ever caught yourself saying, “Why doesn’t Views do X?”, then get coding and contribute to the already rich ecosystem of modules available for Views.

2 Responses to Views 3 Plugins

  1. Pablo López says:

    Hello!
    Congratulations for your site. I was just finding how to extend a views plugin. However, I read your post and tried to follow it in my D7 installation with the .dev release of views and I wasn’t able to create theplugin. It appears in the list of plugins, but after choosing it, I can’t access tothe config plugin page and the selected plugin is the previously selected plugin.
    Any help?
    Thanks in advance!

    • Luca says:

      I had the same problem. Specify the plugin file in the [module].info (or module_load_include) like

      files[] = includes/my_plugin.inc

      Thanks for the article!