Creating a custom filter in Drupal Views for yearly filtering

Components

This snippet provides a custom Views filter for Drupal, enabling users to filter nodes by the year of their publication date. It adds a user-friendly dropdown in the Views UI, allowing easy selection of a year to filter content.

The hook_views_data() hook in Drupal is used to define how a module exposes database tables to Views.

/**
 * Implements hook_views_data().
 */
function MY_MODULE_views_data() {
  $data = [];

  $data['views']['year_filter'] = [
    'title' => t('Year filter - Custom Filter'),
    'filter' => [
      'title' => t('Year filter - Custom Filter'),
      'field' => 'created',
      'id' => 'year_filter',
    ],
  ];

  return $data;
}

To correctly implement your custom filter plugin in Drupal, you should place the code in the MY_MODULE/src/Plugin/views/filter directory. Below is an example of how your plugin code might look:

<?php

namespace Drupal\MY_MODULE\Plugin\views\filter;

use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\filter\FilterPluginBase;

/**
 * Filters nodes by year of publish date.
 *
 * @ViewsFilter("year_filter")
 */
class YearFilter extends FilterPluginBase {

  /**
   * {@inheritdoc}
   */
  public function adminSummary() {
    return $this->t('Filters nodes by year of publish date.');
  }

  /**
   * {@inheritdoc}
   */
  protected function valueForm(&$form, FormStateInterface $form_state) {
    $current_year = date('Y');
    $options = [];

    for ($year = 2023; $year <= $current_year; $year++) {
      $options[$year] = $year;
    }

    $form['value'] = [
      '#type' => 'select',
      '#title' => $this->t('Year'),
      '#options' => $options,
      '#default_value' => $current_year,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function query() {
    $this->ensureMyTable();

    /** @var \Drupal\views\Plugin\views\query\Sql $query */
    $query = $this->query;

    if (!empty($this->value[0])) {
      $query->addWhereExpression(0, "EXTRACT(YEAR FROM FROM_UNIXTIME(node_field_data.created)) = :year", [':year' => $this->value[0]]);
    }
  }

}

Clear the caches after implementation, and then add the custom filter to a View used to display nodes.

About the Author

Goran Nikolovski is an experienced web and AI developer skilled in Drupal, React, and React Native. He founded this website and enjoys sharing his knowledge.