Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll

Creating image style for Views in Drupal

13/04/2025, by Ivan

Creating a Views display style plugin may seem like a daunting task, but it's easier than it looks. Here's a step-by-step guide on how to do it, complete with source code.

You can download the ready-made code here: TARDIS (although it's still in dev). And if you need an introduction to Drupal 8 modules, here's a practical guide to creating basic Drupal 8 modules.

.info.yml

Start by creating a folder named tardis for your module inside /modules/custom. Place a file named tardis.info.yml in it with the following code:

name: TARDIS
type: module
description: 'Provides a View display style that renders a list of year and month links to content in reverse chronological order.'
package: Views
core: '8.x'
dependencies:
  - drupal:views

Classy

Now it's time to create the plugin class. Create a file named Tardis.php inside src/Plugin/views/style and insert the following code:

<?php

namespace Drupal\tardis\Plugin\views\style;

use Drupal\core\form\FormStateInterface;
use Drupal\views\Plugin\views\style\StylePluginBase;

/**
 * Style plugin to render a list of years and months
 * in reverse chronological order linked to content.
 *
 * @ingroup views_style_plugins
 *
 * @ViewsStyle(
 *   id = "tardis",
 *   title = @Translation("TARDIS"),
 *   help = @Translation("Render a list of years and months in reverse chronological order linked to content."),
 *   theme = "views_view_tardis",
 *   display_types = { "normal" }
 * )
 */
class Tardis extends StylePluginBase {
  ...
}

Let’s go over some of these:

 * @ViewsStyle(
 *   id = "tardis",
 *   title = @Translation("TARDIS"),
 *   help = @Translation("Render a list of years and months in reverse chronological order linked to content."),
 *   theme = "views_view_tardis",
 *   display_types = { "normal" }
 * )

These comments are crucial. They lay the foundation for our plugin. If you forget to add them, the code won't function correctly.

class Tardis extends StylePluginBase {

The basic definition of the plugin. Again, this is necessary.

  protected function defineOptions() {
    $options = parent::defineOptions();
    $options['path'] = array('default' => 'tardis');
    return $options;
  }

This defines the default options, including a crucial default value for our plugin. This is needed because the plugin is meant to be configurable.

  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);

Moving forward, we build the actual options form with fields, much like regular configuration forms. For more information, refer to the Forms API Reference.

.module file

The .module file isn't mandatory in Drupal 8, but this is where theme information should go:

<?php

/**
 * @file
 * TARDIS Views module help and theme functions.
 */

/**
 * Implements hook_theme().
 */
function tardis_theme($existing, $type, $theme, $path) {
  // Store TARDIS preprocess theme functions in a separate .inc file.
  \Drupal::moduleHandler()->loadInclude('tardis', 'inc', 'tardis.theme');

  return array(
    'tardis' => array(
      'file' => 'tardis.theme.inc',
    ),
  );
}

Essentially, we delegate the preprocess function to a separate file for better organization.

.theme.inc file

Create a file named tardis.theme.inc in your module’s directory and include the following code:

<?php

/**
 * @file
 * Theme for TARDIS views.
 */
function template_preprocess_views_view_tardis(&$variables) {
  ...
}

This code mainly gathers all created dates from nodes and builds an associative array that gets passed into the Twig template for final rendering, along with other form-defined options that remain unchanged.

Twig it out

To display the module output, create a file views-view-tardis.html.twig inside a templates folder. But why this name? Remember the comments at the beginning of this lesson?

* theme = "views_view_tardis",

This means the template should be found in the default location (/templates) with that name, using dashes instead of underscores and ending in .html.twig.

{#
/**
 * Default theme implementation for Views to output a TARDIS archive.
 *
 * Available variables:
 * - options: View plugin style options:
 *   - classes: CSS classes.
 *   - nesting: Whether months should be nested inside years.
 *   - path: Link path. Eg.: example.com/TARDIS/2016/03
 *   - time_pool: Two-dimension array containing years and months with content.
 *
 * @see template_preprocess_views_view_tardis()
 *
 * @ingroup themeable
 */
#}
{%
  set classes = [
    'views-view-tardis',
    options.classes
  ]
%}
<div{{ attributes.addClass(classes) }}>
  <ul>
    {% for key, item in options.time_pool %}
      {% if options.nesting == 1 %}
        <li><a href="/{{ options.path }}/{{ key }}">{{ key }}</a><ul>
        {% for subkey, subitem in item %}
          <li><a href="/{{ options.path }}/{{ key }}/{{ subkey }}">{{ subitem }}</a></li>
        {% endfor %}
        </ul></li>
      {% else %}
        {% for subkey, subitem in item %}
          <li><a href="/{{ options.path }}/{{ key }}/{{ subkey }}">{{ subitem }}</a></li>
        {% endfor %}
      {% endif %}
    {% endfor %}
  </ul>
</div>

It’s best to extract all the variables passed via the $variables associative array at the beginning of the file. They're neatly stored in $variable['options'] — or in Twig, variables.options.

Then we define some classes for our view, as configured in the options form:

{%
  set classes = [
    'views-view-tardis',
    options.classes
  ]
%}

And recall them:

<div{{ attributes.addClass(classes) }}>

The rest of the code loops through the years and months that contain entries and displays the HTML list. The important part is the for loop:

{% for key, item in options.time_pool %}

Which renders each link properly. For example:

<li><a href="/{{ options.path }}/{{ key }}/{{ subkey }}">{{ subitem }}</a></li>

One more thing

Last but not least, we should create a default View and export it to make it easier for users. You'll notice that in /config/install/views.view.tardis.yml there’s already a default View. This default View is available as soon as users enable the module.

I created and exported it through the single export form at admin/config/development/configuration/single/export, following Subhojit Paul's excellent tutorial.

That’s it!

Now you’ll be able to write your own Views display plugin for Drupal 8! Leave a comment below. Happy coding!

Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.