Drupal Custom Contextual Filter

A custom contextual filter for Views in Drupal 8 is demonstrated using the Data project. Only a small amount of code is needed for the custom filter.

Set up Drupal

Begin by setting up Drupal and installing the Schema and Data projects.

composer create-project drupal-composer/drupal-project:8.x-dev contextual --no-interaction

Create a database and visit the website to install it. Now install a couple of contributed projects.

cd contextual
composer require 'drupal/data:1.x-dev'
composer require 'drupal/schema:1.x-dev'
composer require drupal/views_flipped_table

Currently the Data project needs a couple of patches to be applied for it to work.

composer require cweagans/composer-patches
mkdir patches
cd patches
wget https://www.drupal.org/files/issues/data-add_adopt_function-2874050-9.patch
wget https://www.drupal.org/files/issues/data-fix_views-2934560-2.patch
cd ..

Then edit the composer.json file to add the patches under the "extra" section.

    "extra": {
        "patches": {
            "drupal/data": {
                "Add adopt function functionality": "patches/data-add_adopt_function-2874050-9.patch",
                "Fix view creation": "patches/data-fix_views-2934560-2.patch"
            }
        },
        ...

Now patch the Data project. The update should be run twice to remove the project and then installed a patched project.

composer update drupal/data
composer update drupal/data

Login as the administrator and enable the Data, Data Search, Schema, and Views Flipped Tables modules. There may be an error but reload the website and verify these modules are installed.

A sample database table is needed. This article uses the city table from the world database. Import the table into the database for the website. Flush the Drupal cache and then go to Manage -> Structure -> Data Tables. Click on Adopt tables and then select the city table and adopt it.

Custom Views Contextual Filter

Now that everything is set up the next steps are to set up a view and create a custom module. The custom views filter will use the value in the URL to select the correct row of the database to display. Flush the Drupal cache to make sure the adopted table appears in Views. Start with Manage -> Structure -> Views and click on Add view. Select City and check Create a page. Enter city/% for the path. Under the display format select Flipped Table. Only display 1 item with no pager. Under the fields section of the view add the Name, CountryCode, District, and Population columns. Edit the ID column and mark it to not be displayed. Under no results behavior enter a global text area with "The city is not in the database." Now click the Advanced section and add a contextual filter. The Data project does not supply a contextual filter for filtering to the city ID in the URL so a custom filter needs to be created. Save the view and proceed to creating the custom contextual filter.

Create a custom module called "contextual." Create a contextual.info.yml file.

name: 'Contextual'
description: 'Custom Views contextual filter.'
core: 8.x
type: module

Now use a hook to add the custom contextual filter in the contextual.module file. It does not require much code.

<?php

/**
 * Implements hook_views_data_alter().
 */
function contextual_views_data_alter(&$data) {
  $data['city']['ID']['argument'] = [
    'id' => 'numeric',
    'help' => 'City ID',
  ];
}

In the data array, city refers to the name of the adopted table. ID is the column which is a key index. At the next level, field supplies the fields for the view. Adding argument supplies a contextual filter. The id refers to an argument plugin. In this case the integer plugin is used. There is also a string plugin and other possibilities the can be found in Drupal core in the views module (src/Plugin/views/argument/NumericArgument.php).  Enable the module.  Now go back to the view and click on add a contextual filter. Select a default of displaying the text in "no results found." Save the view.  To verify the view is set up correctly go to Manage -> Structure -> Views and click on the Settings tab.  Check the show the SQL query options and save the configuration.  Go back to the view and type an integer into the preview box.  Click on Update preview and verify the output has the following.

WHERE (city.ID = '24')

Now go to the website with a path of /city/<integer> where <integer> is an integer less than or equal to 4079.

Custom contextual filter example

Categories