Views API in Drupal

There's a reason Views is an essential core module in Drupal. Its powerful UI is only a part of the story. Once you’ve realized the power of creating complex lists of nodes, users and other content via the Views UI, the next logical desire is to allow site builders and administrators to build queries with the content provided by your custom entities and database tables as well. In Views for Developers, we cover the ins and outs of the Views API. This series will take an in-depth look at Views' build and render cycle, altering a view before or after its rendered, altering a query, exposing your own database tables to the Views module, adding relationships, and exposing custom entities to Views.

After getting the basics out of the way we’ll also take a look at writing our own custom field handlers to expose our module’s data to views so that it can be sorted, filtered, and queried in new ways. We’ll also look at implementing views plugins to do things like add custom access control options to views and to add new output styles.

Once you understand a bit more about how views works under the hood and how easy it is to tie in to that system you'll re-imagine your solutions for all sorts of different problems.

Author, Anna Mykhailova

Anna, amykhailova on Drupal.org, is an Associate Director of Technology and certified Acquia Grand Master. She has extensive real-world experience using Layout Builder, and the various solutions that preceded it, to solve client's needs through her work as developer over the past 6 years.

Tutorials in this course
Categories
Drupal 8, 9, and 10
More information

The Views module is a query generator and render engine in Drupal core. It's typically used to create and output collections of items such as Drupal content entities. But it can also aggregate users, blocks, log records, and more. The output can be rendered many ways, including as a list, a grid, or an RSS feed. Views is commonly used in Drupal to create pages, blocks and other types of displays.

Through the Views API developers can expose new data to Views, add new configuration options, create new output plugins, field formatters, sort handlers, filter handlers, and more. By creating these customizations as extensions of Views instead of as stand alone queries, or hard-coded lists, you can empower site administrators to mix and match your customizations with the existing feature set in any way they might need.

In this tutorial we'll:

  • Get a high level overview of the Views API.
  • Discuss the functional parts of the Views API such as hooks, plugins, and data types.
  • Learn how to use the Views API in your project.

By the end of this tutorial you'll have a solid understanding of the parts of the Views API and some guidance on which to use for your goals.

More information

In the process of displaying the content of a view to an end user, every view goes through a common build cycle. As a developer it helps to understand the build and render cycle that a view goes through and how you can use it to alter the final result. It helps to know where things are in the cycle when your code is executed, and how that impacts what your code can and can't do. The Views module exposes hooks -- documented in views.api.php -- that allow developers to influence every step of the cycle. This includes altering the database query that gets executed, changing the configuration of filters, computing things based on raw results, and changing the rendered output of any field.

In this tutorial we'll:

  • Learn the steps of the Views build and render cycle.
  • Identify the hooks invoked during each step and provide examples of what types of things you might do with each hook.

By the end of this tutorial you should be able to list the hooks invoked by Views, when they get called during the build and render cycle, and explain the impact this has.

More information

Developers can implement hook_views_pre_render() to make changes to a ViewsExecutable object and change the render array that gets generated by the render phase of a view. By the time hook_views_pre_render() gets invoked, the data to display has already been collected, and things like field formatter configuration have been loaded. This hook gives you the opportunity to dynamically alter that configuration before it's passed to field handlers that will ultimately calculate and return a render array by combining the field configuration with the query results.

You might, for example, dynamically change the label used in a table depending on context that doesn't exist in the view itself. Another example, and the one we'll use here, is transforming a view's rows into a slider (or tabs, or an accordion). That requires that you alter the views object before rendering and attach a custom JavaScript library.

If the thing you want to change is the configuration of the display or any fields, or the contents of the results (versus the presentation of the results) of a view, than hook_views_pre_render() is the right place to do that. If you're looking to alter the generated render array than you'll likely want to use hook_views_post_render().

In this tutorial we'll:

  • Alter a ViewsExecutable object using hook_views_pre_render() before the view is rendered.
  • Attach custom JavaScript (or CSS) to a view.
  • Transform a view of article nodes into an interactive slider using the Slick Slider JavaScript library and some custom JavaScript code.

By the end of this tutorial, you should know how to alter the render array of a view and attach custom and third-party asset libraries in a Drupal site.

More information

Using hook_views_post_render() Drupal module developers can change the render array representation of a View before it gets displayed. You can use this to modify the computed HTML of a view just before it gets printed. This hook is similar to using a preprocess function for a template file, but in this case you have access to the whole render tree, not just the specific leaf covered by the template file you're preprocessing.

This hooks gets called after the Views object has been through the render process, and all the different configured displays and formatters have been applied, producing a render array representation of the results of the view. This hook receives an $output parameter which contains the render array, and only changes made directly to the $ouput variable will have any effect. This hook is the last chance to make changes to the render array before it is converted to markup.

You can use hook_views_post_render() to change #cache properties for the View, and to do things like add CSS classes to rows, and change the page title.

In this tutorial we'll:

  • Learn how to alter a view's rendered output right after the Views object completes the render phase of the build cycle.
  • Use hook_views_post_render() to change the title of the view's display

By the end of this tutorial you should know how to alter the render array generated by a View prior to it being passed to the theme layer and converted to HTML.

More information

At its core, Views is a query generator. It provides a way for site builders and developers to construct queries for Drupal content using an intuitive user interface. The UI allows you to configure the fields, filters, sorting, and relationships in the generated query using common conditions. In most cases, this is sufficient. However, there are situations where you need to dynamically alter the constructed query using hook_views_query_alter() prior to its execution.

One example use case is adding sort parameters to a search view if no search terms have been entered. You can use hook_views_query_alter() to check if a search term was entered. If so, sort the result by relevance; and if there are no search terms, sort the results by date. Or maybe you need to dynamically set the value of a filter condition based on a calculation performed by your custom code.

Using hook_views_query_alter() in a custom module, you can alter the query that is generated by a view before the query is performed. In most cases this alters the SQL query used. This same technique will work regardless of the storage system Views is querying.

In this tutorial we'll:

  • Learn how to alter a view's query using the hook_views_query_alter() hook in Drupal
  • Use hook_views_query_alter() to dynamically add a new sort condition that could not be achieved using the UI

By the end of this tutorial you should know how to alter the database query used to retrieve the results for a view.

More information

Any Drupal module that provides custom database tables should implement hook_views_data() to describe the schema of those tables to Views. This hook is used to provide information to Views about the fields in a table, their human-readable names, and the types of data (string, integer, date, etc.) stored in each column. You can also tell Views how it should handle sorting, filtering, and formatting the data. Implementations of hook_views_data() can also be used to describe relationships between tables.

If you're creating a module that implements hook_schema() and adds new tables to the database it's a good idea to also add support for Views. Among other things, it'll allow administrators to create any user-facing displays of data from your table using Views. Then, they can be edited without having to write code. Once you've described your table to Views via hook_views_data() Views will be able to provide a way for administrators to construct queries against your data via the UI.

In this tutorial we'll:

  • Use hook_views_data() to expose a custom table defined in a Drupal module to Views.
  • Learn how to describe different types of data to Views.
  • Demonstrate the relationship between hook_views_data() and what a site administrator has access to in the Views UI.

By the end of this tutorial you should know how to describe custom database tables and their fields to the Views module.

More information

In Expose a Custom Database Table to Views we learned how to let Views know about custom tables created by a Drupal module. In that example, the custom table was a stand-alone one, without any connections to the other tables in the database. However, it's common for data in one table to relate to data in another.

For example, you might have TableA with the columns first_name, last_name, email and TableB with the columns email, score. TableA.email and TableB.email can be used to join the two tables together.

It's useful to define these relationships for Views so that when TableA is used as the base table the fields from TableB are also available in the view. When the fields from a related table are automatically loaded, this is known as an implicit relationship. Our earlier example could benefit from the relationship with the users_field_data. This relationship will allow us to associate First Name and Last Name fields from the subscriptions table with the users on the site.

In this tutorial we'll:

  • Define the difference between implicit and explicit relationships in Views.
  • Learn how to create an implicit relationship between 2 tables using hook_views_data.

By the end of this tutorial you should know how to describe custom implicit relationships in a view, making data from one or more secondary tables available to the Views query builder.

More information

Drupal's Entity API allows developers to expose custom entities to the Views module, and takes care of many common features. It can handle exposing the fields associated with fieldable entity types for use as fields, filters, sorts, and arguments. It provides a way to customize any aspect of the Views integration, and makes it possible to create explicit relationships between 2 different entity types.

In this tutorial we'll:

  • Expose a custom Subscriber content entity type and all of its data to Views.
  • Create an explicit relationship between the custom content entity and Drupal core User entities.
  • Build a view of Subscriber entities.

By the end of this tutorial you should know how to expose custom entities to Views.

Categories
Drupal 8, 9, and 10
More information

The Drupal core Views module architecture is built on top of the Drupal Plugin API. This allows site administrators to pick and choose from a list of options (plugins) to handle all the different parts of a view -- including what to display, what style to display it in, how to order the results, who has access, and more. In the Views UI, any time you're presented with the option to choose something from a list of options you're likely dealing with some type of plugin.

The advantage of a plugin-based design is that all functional parts of the Views module are provided in an extensible object-oriented way. The Views module defines the basic framework, and provides interfaces for other modules to implement, extend, and customize via plugins. Customizations to filters, fields, area handlers, sorts, and relationship handlers start with plugins.

In this tutorial we'll:

  • Learn about Views plugins and the role they play
  • Explore the different plugin types and their underlying classes
  • Get a high level overview of the steps for creating a custom Views plugin

By the end of this tutorial you'll have a solid understanding of the different Views plugin types, what they are used for, and where to start if you'd like to define your own.

More information

Views field handler plugins handle retrieving and displaying data within a view. The Drupal core Views module provides field plugins for all of the core field types, and these work well for many situations where you need to describe custom data sets to Views. For situations where an existing plugin doesn't match your requirements, you can define a custom field handler plugin and alter both the query that gets executed and the rendered output of the data.

This is common for contributed modules that define new field types, or any module using hook_views_data() to define a dataset to Views where the data contained in a database column may need special handling in order to be displayed as part of a view.

In this tutorial we'll:

  • Implement a custom Views field handler plugin
  • Extend the default date field plugin and modify the way that it displays a timestamp so that instead of a specific date we get a relative value

By the end of this tutorial you should know how to define a custom field handler plugin and use it in a view.

More information

By default the Views module can display data contained in any field attached to an entity that is exposed in Views, and the content of any database column exposed to Views via an implementation of hook_views_data(). It's also possible to create pseudo fields. These appear in the Views UI like any other field, but don't map directly to the data stored in a database column and instead allow the data to be preprocessed. This could be performing a calculation, combining multiple fields into one, and much more.

A common example in core is the fields that allow you to perform edit or delete operations on a node. These don't correspond to a specific database column. And they can't be hard-coded because they require dynamic content specific to the node in question. Instead, they are the result of taking the entity ID and combining it with knowledge about the appropriate route for someone to edit the entity and outputting that as a link.

Another example: Imagine a cooking website where you collect cook time and preparation time (prep time) for recipes and want to also display the full time to prepare. In this case cook time and prep time could be fields on the recipe content type and total time could be handled as a calculated output of both fields, added together and converted into hours and minutes. To achieve this, you can create a custom Views pseudo field and specify the calculation and processing logic in the render function.

In this tutorial we'll:

  • Learn how to define a custom Views field plugin for a pseudo field
  • Attach the created field to node entities, and expose it to display in a view

By the end of this tutorial you should know how to define a Views pseudo field plugin, attach it to the node entity type via hook_views_data_alter(), and display it in a view.

More information

Filter plugins provide the logic for determining what items to include in a view. They are the equivalent of a WHERE clause in an SQL statement. Filters can be exposed to the end user, allowing the viewer to enter a value, or select from a list of options, that are used to filter a list. For example, the options at the top of the Content list at /admin/content allow you to limit the list by content type.

Drupal's Views module provides filter plugins that can handle filtering for all core defined field types, as well as generic data types like numbers and strings. In situations where these filters don't meet your functional requirements, or you need a filter for a custom field, you may want to define a custom Views filter plugin. A common real-world scenario is defining a new filter plugin that extends an existing one and adds new possible values or options. For example, providing a relative date filter that allows a user to choose options like Last week or Last month.

In this tutorial we'll:

  • Learn how to create a Views filter plugin
  • Associate our new custom filter with data exposed to Views so it can be used
  • Learn how to use it in a view as an exposed filter

By the end of this tutorial you should know how to create a custom filter plugin and use it in Views.

More information

Sort plugins are responsible for determining how the data in a list created with Views is sorted. Sort plugins are applied to fields. For example, a field might contain numbers and the sort plugin can handle putting the values into ascending or descending order. Typically, sort plugins work by adding to the ORDER BY clause of an SQL query.

The Views module provides sort plugins for all core field types. This includes handling for most primitive data types like strings and numbers. A typical use case for creating a custom sort plugin is extending an existing sort plugin with new conditions or custom sorting logic. For example, you might need to create an alphabetical title sort that excludes articles like a, an, and the. Or a sort based on combining the values in multiple fields.

In this tutorial we'll:

  • Learn how to create a custom Views sort plugin
  • Associate our custom sort plugin with a field exposed to Views
  • Use the sort plugin in a view to sort a list of Article nodes

By the end of this tutorial you should know how to create a custom sort plugin for the title field.

More information

Area handler plugins are used to determine what is displayed in areas such as the header, footer, and empty text sections of a view. The handlers provided by core cover displaying result summaries, and allowing users to enter in HTML to display. They are already pretty versatile. However, they may require code knowledge to accomplish some specific tasks. If you'd like to have a more specialized area handler that can be reused across multiple views, you may want to look into defining a custom area handler plugin.

In this tutorial we'll:

  • Create a custom area handler plugin with settings that can be updated through the Views UI.
  • Use the new area handler plugin in a view.

By the end of this tutorial you should know how to define a custom area handler with settings and use it in Views.

More information

When a user creates a view, they can set access rules, and restrict who can see the view. The core Views module allows you to limit access by a user's permissions, or roles. If your project requires custom access rules you can define a custom Views access plugin. This will allow you to determine a user's access based on any custom logic you might have.

In this tutorial we'll:

  • Define a custom Views access plugin that determines access based on data stored in a field on the user entity type.
  • Learn the difference between access checks for routes and access checks for Views displays, and how to use each of them.
  • Use our new custom access handler when defining a view.

By the end of this tutorial you should know how to define a custom Views access plugin and use it to grant access to a view.

More information

Style plugins are responsible for determining how to output a set of rows. Individual rows are rendered by row plugins. Drupal core provides style plugins that include grid, HTML list, table, and unordered list styles. If you need to render the results in a different way, for example as tabs or accordions, or have special markup based on your project requirements, you may want to write a custom style plugin for Views. The advantage of this approach versus overriding the templates in a theme is that you may reuse this plugin in different views throughout the site, or even on different sites.

In this tutorial we'll:

  • Learn how to create a custom Views style plugin and render output in the form of an accordion using the HTML5 <details> element.
  • Demonstrate how to use a custom style plugin when building a view.

By the end of this tutorial you should know how to declare custom Views style plugins.

This course appears in the following guides:
Site Building
Learn how to query, list, and display your content using Views UI and Views API.

Views in Drupal