Building a Views Style Plugin in Drupal 8

Drupal 8 is just around the corner, and it has reached an important milestone: beta-to-beta updates will be provided for each beta release going forward. That gives me some confidence that no major re-works are to be expected if I start building with Drupal 8. That said, we are still facing a sizable documentation gap regarding the changes in the API. My first encounter with this problem was when I was building a custom style plugin for Views. This post discusses how this is done in the new version of everyone's favorite CMS.

In Drupal 7, we had hook_views_plugins(), which let us register new plugins. Drupal 8, on the other hand, relies on autoloading and annotations to discover plugins. Autoloading allows us to simply put a plugin file in a predefined directory, and Views will discover it as needed. The metadata of the plugin can be specified inside the plugin's file using specially crafted comment blocks, that is, annotations.

To let Views find our style plugin, we will need to place it in src/Plugin/views/style inside a custom module's directory. For the sake of example, let’s say we wish to build a style plugin that displays nodes in a card-based style. The skeleton of the style plugin for this might look like the following.

<?php
namespace Drupal\mymodule\Plugin\views\style;

use Drupal\views\Plugin\views\style\StylePluginBase;

/**
 * Style plugin for the cards view.
 *
 * @ViewsStyle(
 *   id = "cards_style",
 *   title = @Translation("Cards Style"),
 *   help = @Translation("Displays content in cards."),
 *   theme = "mymodule_cards_style",
 *   display_types = {"normal"}
 * )
 */
class CardsStyle extends StylePluginBase {

  /**
   * Specifies if the plugin uses row plugins.
   *
   * @var bool
   */
  protected $usesRowPlugin = TRUE;

  // Class methods…
}

The class needs to inherit from StylePluginBase, and therefore we need to reference that class using the use keyword. Due to the facts that this file is in the correct location and it has the annotation above the class definition, Views will find it, and it will be available for selection in the Views' settings. The $usesRowPlugin property is necessary to retain the option that lets you select whether you'd like to display fields or rendered content in the view.

The presentation logic will live in the template file. The template file will need to be placed at templates/mymodule-cards-style.html.twig inside the module. There is no need to implement hook_theme(); the theme will be automatically registered based on the fact that we specified the theme name in the annotation. The template file name is derived from the theme name by replacing underscores with hyphens. The following is an example template file that could be used for the style plugin.

{#
/**
* @file
* Template for the cards style.
*/
#}

{% for row in rows %}
  <div class="card-container">
   {{ row }}
  </div>
{% endfor %}

This is a very simple template file that just prints out all the rows in a card container that we can use for styling. The actual styling of the cards will be omitted in this post.

The rows variable in the template is provided by Views. If you need other variables in the template file, you can implement template_preprocess_mymodule_cards_style() in the .module file to prepare other variables needed by the template.

So far, the only benefit of having our own style plugin is that we can provide our own template for it. This in itself could be achieved by overriding the template of an existing style in most cases. To make the style plugin more practical, we will take a look at how to offer configuration options to the user in the next blog post. Stay tuned!