Drupal Module Development

This series is a collection of all of our Drupal Module Development tutorials -- essential information for anyone developing Drupal modules or working on Drupal core. The various APIs and subsystems outlined below are critical systems and in most cases you'll need to know how some or all of these work in order to make use of Drupal's higher level developer APIs.

Note: If you're using Drupal 7, see Module Development for Drupal 7 or search using the Drupal 7 filter.

Topics covered include:

  • Altering and extending Drupal without hacking core through plugins, hooks, and events
  • Working with forms
  • Using the Render API to present content for display
  • Working with services, dependency injection, and the service container
  • Writing secure code
  • Debugging tips and tricks
  • Useful tools for developers
  • Adding different kinds of links
  • ...and more!

We recommend working through tutorials in this collection on an as-needed basis. You might also want to explore our guide for Drupal module developers: Develop Drupal Sites.

We'll continue to fill this collection out as we develop more tutorials for these critical components.

Tutorials in this course
More information

In this tutorial we're going to look at one the first files you will need in order to create a Drupal module: the info file. Each module is required to have a MODULE.info.yml file to help Drupal identify that a bundle of code is a unique module. This specially-formatted YAML file not only tells Drupal about the module, but also allows us to provide other useful metadata. In this tutorial, we'll walk through all of the metadata possibilities that can be included in an info file.

Drupal 8, 9, and 10
More information

Before you can create a path or link to another page on your site, you'll need to know the route (unless there is already a variable available for the URL you need). Finding a route can be a tricky task unless you have the right tools. In this tutorial, we'll show how tools like Webprofiler, Drush, and Grep can be used to get route information for a page, so that you can use functions that need a route as a function parameter.

In this tutorial we'll:

  • Learn how to determine the route or path of an internal page.
More information

Do you know some PHP and want to learn how to create a custom page at a custom URL in Drupal? You're in the right place.

Every web framework has the same job: provide a way for developers to map user-accessible URLs with code that builds the page. Routes, controllers, and responses are what module developers use to create pages at custom URLs in a Drupal site.

In this tutorial, we'll:

  • Define what routes, controllers, and responses are.
  • Explain the routing workflow that Drupal uses to match a URL to a route.
  • Define routing system-related terms like parameter and upcasting.

By the end of this tutorial, you should be able to explain how a developer uses routes, controllers, and responses to create custom pages in a module.

Categories
Drupal 8, 9, and 10
More information

If you want to define a new URL that a user can navigate to, and custom PHP code that will generate the content of the page, you need a route and a controller. Most of the time you'll want to do something more complex than hard code the content of the page. This will require using services in your controller. This can be accomplished in different ways.

In this tutorial we'll:

  • Provide the definition for a new route which maps a path to the callback method of a controller class.
  • Create a controller that returns a hard coded string.
  • Look at examples of using both ControllerBase and dependency injection to access services from a controller, and discuss the benefits of both approaches.

By the end of this tutorial, you should be able to define a new route that maps to a controller and displays content on the page as a result of your custom logic.

More information

The routing system can get dynamic values from the URL and pass them as arguments to the controller. This means a single route with a path of /node/{node} can be used to display any node entity. Route parameters can be validated, and upcast to complex data types via parameter conversion. If you ever want to pass arguments to the controller for a route, you'll use parameters to do so.

In this tutorial we'll:

  • Define what parameters (slugs, placeholders) are and what they are used for in a route definition.
  • Explain how URL parameters are passed to a controller.
  • Define parameter upcasting.

By the end of this tutorial, you should be able to explain how to define a route that uses parameters to pass dynamic values to the route controller, and explain how parameter upcasting works.

Categories
Drupal 8, 9, and 10
More information

Let's write some code that will allow us to see route parameters in action. We'll define a new route with a path like /journey/42/full but where 42 can be any node ID, and full can be any view mode. When a user accesses the path we'll pass the dynamic parameters from the URL to the controller. The controller will then load the corresponding node and render it using the provided view mode, and return that to display on the page.

By the end of this tutorial you should be able to:

  • Use dynamic slugs in a route to pass parameters to the route controller.
  • See how Drupal will upcast a value like the node ID, 42, to a Node object automatically.
  • Explain what happens when you visit a URL that matches a route but the parameters don't pass validation.

By the end of this tutorial, you should be able to pass dynamic values from the URL to a route's controller.

More information

When defining a route and subsequently displaying the page, often we need to calculate the page title based on route parameters or other logic. In these cases, we can't just hard code the value into the _title configuration of the route. To set a dynamic title for a page, we'll use the route's _title_callback option, and point to a PHP callback that contains the logic that computes the title of the page.

In this tutorial we'll:

  • Learn how to use the _title_callback route configuration option to dynamically set a page title
  • Explain how arguments are provided to the title callback method
  • Update the route and controller from a previous tutorial to use a dynamic title callback

By the end of this tutorial, you should be able to configure a route so that its title can be set dynamically using route parameters, instead of hard-coding the title with a static string of text.

More information

If you've ever built or administered a Drupal site, the permissions page (/admin/people/permissions) is probably quite familiar.

If you're new to module development, you may wonder where these permissions come from, and how you can specify your own permissions. In this tutorial we'll answer those questions.

First, we'll look at how to define permissions from within a custom module. We'll examine techniques that enable you to provide specific (static) permissions as well as dynamic permissions, which depend on another piece of data, such as the name of a content type. By the end of this tutorial you will understand how to add both static and dynamic permissions to a custom module.

Categories
Drupal 8, 9, and 10
More information

Every route should define its access control parameters. When you define routes in a module, you can limit who has access to those routes via different access control options. Route-level access control applies to the path. If your route defines a path like /journey/example, the access control configuration will determine whether to show the current user the page at the path defined by the route, or to have Drupal serve an "HTTP 403 Access Denied" message instead.

In this tutorial we'll look at different ways of adding access control to a route including:

  • Access based on the current user's roles and permissions
  • Access based on custom logic in a callback method
  • Logic in an access checker service

By the end of this tutorial, you should be able to add access control logic to your custom routes that will meet any requirement.

More information

Every web framework, including Drupal, has basically the same job: provide a way for developers to map URLs to the code that builds the corresponding pages. Drupal uses Symfony's HTTPKernel component. Kernel events are dispatched to coordinate the following tasks:

  • Process the incoming request
  • Figure out what to put on the page
  • Create a response
  • Deliver that response to the user's browser

Knowing a bit more about how Drupal handles the request-to-response workflow will help you better understand how to use routes and controllers to create your own custom pages or deal with authentication, access checking, and error handling in a Drupal module.

In this tutorial we'll:

  • Walk through the process that Drupal uses to convert an incoming request into HTML that a browser can read
  • See how the Symfony HTTPKernel helps orchestrate this process
  • Learn about how the output from a custom controller gets incorporated into the final page

By the end of this tutorial, you should be able to describe the process that Drupal goes through to convert an incoming request for a URL into an HTML response displayed by the browser.

More information

Sometimes we need the response returned from a controller to be something other than HTML content wrapped with the rest of a Drupal theme. Maybe we need to return plain text, or JSON structured data for an application to consume. Perhaps we need greater control over the HTTP headers sent in the response. This is possible by building on the fact that controllers can return generic Response objects instead of renderable arrays, allowing you to gain complete control over what is sent to the requesting agent.

In this tutorial we'll:

  • Look at how to return a plain text response, and JSON data
  • Show how to make your responses cacheable by adding cacheability metadata
  • Learn about how to use a generic Symfony Response to gain greater control over what gets returned

By the end of this tutorial, you should be able to return responses from a controller in a Drupal module that are not HTML content wrapped in a Drupal theme.

Categories
Drupal 8, 9, and 10
More information

Hooks allow modules to alter and extend the behavior of Drupal core, or another module. They are one of the various ways that code components in Drupal can communicate with one another. Using hooks a module developer can change how core or another module works -- without changing the existing code. As a Drupal developer, understanding how to implement and invoke hooks is essential.

In this tutorial we'll:

  • Define what hooks are and the types of hooks that exist
  • Understand the use case for hooks
Categories
Drupal 8, 9, and 10
More information

Hooks allow module developers to execute custom code at key moments during Drupal's request processing life cycle. They can be used to react to actions or conditions, alter forms and existing configuration, and extend Drupal in various ways. Knowing how to implement a hook is an essential skill for any Drupal developer.

In this tutorial we'll walk through the process of locating the documentation for a specific hook, and then implementing it. All hooks are implemented in the same way, so once you know how to implement one, you'll be able to implement any.

Categories
Drupal 8, 9, and 10
More information

How do you figure out what hooks are available to implement? How do you know which hook to implement to accomplish a task?

The list of hooks that are available to implement in your custom Drupal module varies depending on the modules enabled for a site. Each module can optionally invoke new hooks. There are also some hooks invoked by Drupal core subsystems like Form API that are always present. This can make it a little bit tricky sometimes to figure out what hooks are available, and which one to implement.

In this tutorial we'll look at:

  • Different ways to get a list of available hooks
  • Where to find the documentation for a hook so you can know if it's the one you want to implement

By the end of this tutorial you should be able to browse a list of hooks and their related documentation.

Categories
Drupal 8, 9, and 10
More information

As a module developer you should define and invoke new hooks in your module in order to allow other developers -- or even future you -- to extend your module's functionality without hacking your module's code. This requires:

  • Creating a new, unique, name for your hook
  • Providing documentation for your hook
  • Invoking the hook at critical points in your code

By the end of this tutorial you should have a better idea of when to define a new hook and know how to invoke a hook from your code.

Categories
Drupal 8, 9, and 10
More information

The Drupal plugin system allows a particular module or subsystem to provide functionality in an extensible, object-oriented way. The controlling module defines the basic framework (interface) for the functionality, and other modules can create plugins (implementing the interface) with particular behaviors. Plugins are grouped into plugin types. Each plugin type is managed by a plugin manager service, which uses a plugin discovery method to discover provided plugins of that type and instantiate them using a plugin factory.

The system aims to make it easy for developers to allow for management of these components via the user interface, giving more flexibility and control to site administrators.

In this tutorial we'll take a high-level look at the problem the Plugin API is solving and provide a starting point for diving deeper into the various components that make up the Plugin API.

Categories
Drupal 8, 9, and 10
More information

The term plugin type is used as a way to provide a generic name for all plugins managed by the same plugin manager. Example plugin types include block, field widget, and image effect. A plugin type doesn't consist of any code that provides specific functionality. Instead, it provides a way to refer to the system and it describes the central purpose of all plugins of that type.

In this tutorial, we'll cover what the term plugin type means and how it is used when talking about Drupal's plugin system. By the end of this tutorial, you'll understand what a plugin type is and be ready to learn how to define a plugin type in a module.

Categories
Drupal 8, 9, and 10
More information

Knowing how to define a new plugin type will allow you to write modules that are more extensible, and more configurable. In doing so you'll learn more about best practices in decoupling code within your module, and get an in-depth look at how the plugin system works. Even if you're not defining a new plugin type in your own module, understanding how the system works will give you more insight into how many parts of Drupal work. This is essential knowledge for anyone developing modules for Drupal.

By the end of this tutorial you should be able to determine if defining a new plugin type is the right solution to your problem, and then understand the steps involved in doing so.

Categories
Drupal 8, 9, and 10
More information

Knowing which plugin types exist and the use case for each is important when it comes to writing modules that extend Drupal's existing functionality. If you want to add additional functionality, you need to first know which plugin type provides that functionality.

In this tutorial, we'll list some of the more commonly-used plugin types and their use case, show where you can find a more complete list of plugin types provided by core, and provide several methods for discovering existing plugins in your Drupal codebase.

Categories
Drupal 8, 9, and 10
More information

Before you can create a new plugin of any type you'll need to figure out where the plugin implementation and its metadata should live in the code base so that the plugin manager can find plugins and examine what functionality instances of the plugin type are expected to provide.

This tutorial contains 2 parts:

  • A recipe and example of how to implement a plugin if you already know the plugin type.
  • How to figure out a specific plugin type's implementation details.

In this tutorial we'll:

  • Provide a recipe for implementing plugins of any type.
  • Demonstrate how to figure out where the code and metadata should live for PHP-based plugins.
  • Explain how to figure out where YAML plugin definitions should go, and what they should contain.

By the end of this tutorial you should have a recipe for getting started with implementing annotation-based plugins, and YAML-based plugins, and a better understanding of how to figure out the details required to implement any given plugin type.

Categories
Drupal 8, 9, and 10
More information

A plugin manager is responsible for both the definition of a new plugin type, and for listing and instantiating instances of plugins of the defined type.

In this tutorial we'll:

  • Define what a plugin manager is
  • Create a list of all plugins of a specific type
  • Load and instantiate specific plugin instances so we can use them in our code
Categories
Drupal 8, 9, and 10
More information

In order for a plugin manager to locate instances of individual plugins within the Drupal code base it needs to know where to look, and how to interpret the data that it finds. This process is called plugin discovery and can be accomplished in a few different ways.

In this tutorial we'll look at what plugin discovery is doing at a high level, and then talk about the various plugin discovery methods you can choose from when defining a new plugin type.

Categories
Drupal 8, 9, and 10
More information

Learn how the Plugin API takes a given plugin ID and uses it to instantiate and return a fully configured plugin object. In this tutorial we'll look at:

  • What factories are, and the role they serve in the Plugin API
  • The factories available in core
  • Using mappers to dynamically load a plugin when you don't know the ID of the specific plugin you need.
Categories
Drupal 8, 9, and 10
More information

Plugin derivatives allow a single plugin to act in place of many. This is useful for situations where user-entered data, or other dynamic configuration, might have an impact on available plugins. Or, put another way, any time you need to be able to dynamically generate plugin definitions.

In this tutorial we'll:

  • Define what plugin derivatives are
  • Understand the use case for derivatives
  • Examine how core uses derivatives in order to demonstrate how you could write your own plugin deriver class
Categories
Drupal 8, 9, and 10
More information

Drupal uses events to allow modules and various subsystems to communicate with one another in an object-oriented manner. Understanding how the Event API works is critical knowledge for all module developers. In this tutorial we'll:

  • Explain what events are
  • Discuss the use case for subscribing to events
  • Give an example use case for dispatching events

By the end of this tutorial you should be able to explain what events are, understand when to use them in your own code, and know where to learn more about how to do so.

Categories
Drupal 8, 9, and 10
More information

Some events are dispatched by Drupal core, some by underlying Symfony components, and some by contributed modules. The list of events that you can subscribe to depends on the modules you've got installed. This can make it tricky to get a complete list.

In this tutorial, we'll look at different ways you can get a complete list of the available events for your Drupal application, and where to find documentation for those events.

Categories
Drupal 8, 9, and 10
More information

Modules can declare their interest in being notified when a specific event, or events, are triggered by implementing an event subscriber. This can be used to react to events in order to add your own logic, or to alter Drupal's existing functionality.

In this tutorial we'll cover how to subscribe to an event from your own module. After completing this tutorial you should be able to subscribe to any event and ensure that your custom code is executed when the specific event is triggered.

Categories
Drupal 8, 9, and 10
More information

Modules or subsystems can dispatch events in order to allow another developer to subscribe to those events and react to what's happening within the application. As a module developer you'll learn how to:

  • Define and document new events
  • Define new event objects
  • Use the event dispatcher service to alert event subscribers when specific conditions are met in your own code.

By the end of this tutorial, you should be able to explain the use case for dispatching events, and be able to trigger one more events from within your own code.

More information

It's best practice to access any of the services provided by Drupal via the service container to ensure the decoupled nature of these systems is respected. In order to do so, you need to know what services exists, and then, where possible, use dependency injection to use them in your code.

This tutorial walks through the process of:

  • Discovering existing services and learn their machine name
  • Using the machine name of service to request a copy from the service container
Categories
Drupal 8, 9, and 10
More information

Annotations are specially-formatted PHP docblock comments that are used for class discovery and metadata description. While it is technically possible to use annotations for other purposes, at the moment Drupal only uses them for the plugin system.

In this tutorial we'll look at:

  • What annotations are
  • The use case for annotations
  • How to figure out what you can put into an annotation

By the end of this tutorial you should understand how annotations are used in Drupal and how to write them in your own code.

Drupal 8, 9
More information

The Drupal Console is a suite of tools run from a command line interface (CLI) to generate boilerplate code and interact with a Drupal installation.

Note: This project is no longer actively maintained. See the Drush topic for alternative solutions.

More information

Themes and modules can alter the list of theme hook suggestions in order to add new ones, remove existing ones, or reorder the list. This powerful feature allows for the definition of custom logic in your application that can tell Drupal to use different templates based on your own unique needs. You might for example; use a different page template for authenticated users, or a custom block template for someone's birthday.

In this tutorial we'll cover:

  • Adding new theme hook suggestions from a theme using hook_theme_suggestions_HOOK_alter()
  • Altering the list of theme hook suggestions
  • Removing theme hook suggestions
  • Reordering the list of theme hook suggestions
Drupal 8, 9, and 10
More information

Any text that will be displayed to user as part of your application's user interface should be passed through the t() function, or an equivalent, so that it can be translated into other languages as needed. This tutorial will look at how to use the t() function.

This tutorial contains information that applies to anyone writing modules or themes. And many of the tutorials you read on this site and on the web in general will expect that you understand how basic string translation works.

In this tutorial we'll look at:

  • Passing strings through the t() function or equivalent so they are available for translation
  • Using placeholders for dynamic content in translatable strings
  • Tips for making your code's interface strings easier to translate
Categories
Drupal 8, 9, and 10
More information

Drupal provides module developers several different methods for creating the different types of links we see on a typical page. In this tutorial we'll see how these different types of links relate to each other, and when you might want to make use of them.

Link types illustrated

In this tutorial we'll provide an overview of the following concepts:

  • Menu links
  • Action links
  • Local tasks
  • Contextual links
Categories
Drupal 8, 9, and 10
More information

In this tutorial we will learn how to add menu links using a custom Drupal module. We will also look at the options available for configuring our new menu link. Lastly, we'll learn about using hook_menu_links_discovered_alter() that can be used to add new menu links, or alter the behavior of existing ones.

Categories
Drupal 8, 9, and 10
More information

Modules can provide action links to make common operations more readily available within a particular context. For example, a site administrator visiting the content management page may be interested in adding content. If you've ever noticed the Add content button on this page, that's an example of an action link. In this tutorial we'll take a look at how custom modules can provide these action links to make it easier for users to interact with our site.

More information

Contextual links provide yet another method for Drupal module developers to add helpful links for site administrators to quickly navigate to commonly used tasks. In this tutorial we'll learn how to implement and render contextual links from a custom module. We will also look at a pair of alter hooks that can be used to tweak existing contextual links.

More information

Local task links are the tabs you see when logged in as an administrator viewing a node on a Drupal site. In this tutorial we'll take a look at how local tasks are added within a custom module. We'll also see how to alter local tasks provided by other modules via hook_menu_local_tasks_alter().

Drupal 8, 9, and 10
More information

The Render API consists of two parts: structured arrays that provide data and hints about how that data should be rendered, and a rendering pipeline that can be used to render these arrays into various output formats. Understanding at least the basics of how the Render API works, the difference between elements and properties, and the concept of callback functions is an integral part of learning Drupal.

In this tutorial we'll:

  • Look at the fundamentals of the Drupal Render API
  • Point to additional material to provide more detail about the inner workings of the Render API and how content is output in Drupal
Drupal 8, 9, and 10
More information

The core structure of Drupal's Render API is the render array, which is a hierarchical associative array containing data to be rendered and properties describing how the data should be rendered. As a module developer you'll use render arrays to describe the content your module controls in order to output it on a page as HTML, or as part of a response in another format like JSON. As a theme developer, you'll manipulate render arrays in order to affect the way content is output on the page.

In this tutorial we'll learn:

  • What render arrays are and why they exist
  • The basic format of a render array
  • What "properties" and "elements" signify in the context of a render array
  • Where to find more information about how to create a render array to describe your own content

By the end of this tutorial you should be able to understand when you need to use a render array, recognize one when you see it, and know where to get more detailed information about render array formatting specifics.

Drupal 8, 9, and 10
More information

One of the central components of Drupal's Render API is render elements. You can think of them as prepackaged render arrays or shortcuts you can use to describe common things, like tables, links, and form elements, in a consistent way. In this tutorial we'll take a more in-depth look at the use of the #type property in render arrays in order to answer questions like:

  • What are render elements, and what is their use case?
  • Where can I find more information about available element types?

By the end of this tutorial you should be able to identify individual render element types within a larger render array, find the relevant documentation for specific types of render elements, and explain the use case for render elements.

More information

Strings of simple HTML and plain text can be defined in a render array using the #markup and #plain_text element types. In this tutorial we'll look at:

  • Adding simple strings to a render array so they appear as HTML on the page
  • When to use #markup and #plain_text in your code

By the end of this tutorial, you should be able to add simple strings of HTML and plain text to a render array.

More information

We often need to add code to an alter hook or preprocess function that adds additional HTML attributes to items in a render array. Maybe you're developing a module that adds conditional classes to elements on the page under certain circumstances. Or perhaps your theme needs to add some data attributes to certain links, or form elements, in order to enable some custom JavaScript functionality.

Adding HTML attributes like class, id, or data-* to render array elements involves:

  • Adding the desired values to the element in a render array as an array of key/value pairs
  • Converting the values in the render array to an Attribute object
  • Outputting the Attribute object inside a template file

In this tutorial, we'll cover all of these steps. By the end of this tutorial, you should be able to add new HTML attributes to elements in a render array and discover which property those values should be added to, depending on the element in question.

Categories
Drupal 8, 9, and 10
More information

Drupal makes it easy to convert an array of strings to an ordered or unordered HTML list using '#theme' => 'item_list' elements in a render array. This is commonly done by module developers to display a list such as links to content, the values of settings in a module, or the names of everyone who has viewed a page. Displaying lists is a super common task for a content management system.

In this tutorial we'll look at:

  • Outputting an array of items as an unordered <ul> list
  • Properties specific to '#theme' => 'item_list' in a render array

By the end of this tutorial you should be able to output unordered lists.

Categories
Drupal 8, 9, and 10
More information

The #table render element type is a powerful way to output an array of rows and columns as an HTML table. It supports all the features of a standard HTML <table> element like headers, captions, and column groups. Data to be displayed in the table can be an array of simple string values, or an array of render arrays where each sub element is a row with columns as child elements. In addition, when used in the context of a form, tables can be made into a multiple select widget, or have drag-and-drop reordering of rows enabled. Whether you just want to display a set of tabular data, or you provide your users with a complex form element for reordering and nesting items inside a menu tree, it can all be done with the #table element.

In this tutorial we'll:

  • Look at outputting simple strings as a table
  • Provide definitions for all the various properties that can be used to define a table element
  • Demonstrate how to use the #tableselect and #tabledrag options to create complex form widgets

By the end of this tutorial you should be able to create HTML tables in all their various permutations as part of a render array.

More information

#prefix and #suffix are two commonly used examples of standard properties. That is, they are available for use on any element in a render array regardless of the element #type or #theme property's value. They are a great way to add additional layout markup to an element in a theme-agnostic way.

In this tutorial we'll:

  • Use the #prefix and #suffix Render API properties to wrap an element
  • Look at some possible use cases for using #prefix and #suffix in your own code

By the end of this tutorial you should know how, and when, to use the #prefix and #suffix properties in a render array.

More information

In this tutorial we'll look at how you can use the #theme property of a render array to define custom HTML. With this information, module developers can use render arrays to define content, and theme developers can understand how elements in a render array are converted to HTML and which templates they can override to change the output for a specific element.

Learn how to:

  • Use hook_theme() to define a new theme hook and define default values for variables
  • Create a corresponding Twig template file that outputs the variables and any custom HTML markup
  • Use a preprocess function to add additional variables for the Twig template file you created
  • Use the new theme hook in conjunction with a #theme property in a render array to link your Twig template file to actual content

By the end of this tutorial you should know how to define new templates to output content as HTML. You should also have a better understanding of how Twig template files are linked to elements in a render array.

More information

There are a bunch of existing render elements, most commonly Form API elements. You need to know how to discover and make use of existing elements. In this tutorial, we'll learn how to:

  • Locate a list of elements provided by Drupal core
  • Figure out what properties apply to each element
  • Use any render element type when defining content or forms in our code

By the end of this tutorial you should know what render element types are available for you to use, and how to find the details you'll need in order to implement them in your own render arrays.

More information

The #access property can be used with any element in a render array, including form elements, to control the visibility of that element and its children. This is an effective way to limit access to specific parts of a page's content to only those users with the required permissions, and to show or hide material based on other conditional logic.

In this tutorial we'll:

  • Review the #access Render API property
  • Demonstrate using the #access property to show/hide a field on a node depending on the current user's permissions

By the end of this tutorial you should be able to limit access to any element on the page via logic that returns a Boolean value.

Categories
Drupal 8, 9, and 10
More information

Some Render API properties, like #pre_render, #element_validate, and #lazy_builder are considered callable. Rather than receiving a static value, they contain a pointer to code that should be called at a specific time during the process of rendering a render element. Callbacks are used in some cases to return a value that can be substituted into the render array, and in other cases given the opportunity to manipulate the current element in the array directly.

In this tutorial, we'll:

  • Look at what callbacks are
  • List some common callback properties
  • Show various ways that callback code can be defined
  • Discuss how to choose which method to use

By the end of this tutorial, you should be able to define an appropriate value for any Render API property that expects a callback, and define the logic that is executed when the callback is triggered.

More information

The Render API is capable of detecting poorly-cacheable (highly dynamic) parts of a page and rendering them later using a process called auto-placeholdering. This works by using #lazy_builder callbacks to lazy load certain very dynamic subtrees of a render array. The place in the array where that very dynamic content would appear is first assigned a placeholder. At the very last moment it is replaced with the actual content.

This allows Drupal to do things like cache the overall page in the Dynamic Page Cache despite parts of the page being too dynamic to be worth caching. It also allows the Render API to assemble a page using cache fragments combined with non-cacheable elements.

In this tutorial we'll:

  • Discuss what lazy builders are and how they work in conjunction with placeholders to speed up the rendering pipeline
  • Cover some common gotchas for lazy builders
  • Look at some example code that implements a lazy builder callback

By the end of this tutorial, you should know how and when to use the #lazy_builder property of a render array and how Drupal uses placeholders to increase the cacheability of content and speed up the rendering process.

Categories
Drupal 8, 9, and 10
More information

This tutorial looks at the steps that Drupal goes through to obtain a render array for an incoming HTTP request, transform the render array into HTML, and then return it to your browser. We provide an outline of the process and links to resources for more in-depth information. We also take a more thorough look at the HtmlRenderer which converts a render array into HTML. Knowing how the render arrays you write in your code are ultimately used can help you optimize Drupal's Render API to describe your module's content.

More information

Modules can provide new render element types -- a powerful way to encapsulate complex logic into a reusable component. This can help to cut down on code repetition, and allow other module developers to build on your work. In this tutorial we'll:

  • Define a recipe for creating a new render element type
  • Look at the code for the marquee element type from the render_example module in the Examples for Developers project.

By the end of this tutorial you should be able to implement a new render element type in your own module and make use of it when defining content as part of a render array.

Categories
Drupal 8, 9, and 10
More information

Linking to things is probably one of the first things you learned how to do as a web developer. Anchor tags are the framework of how the world wide web works. So it's important to know how to create them in Drupal. Chances are you'll be doing a lot of it.

Creating links to things in Drupal, however, is a bit more complicated than just typing out an HTML anchor tag. It requires understanding how URLs are generated from routes, and how to define links as renderable arrays. It can also be tricky because of the multitude of deprecated, but still functioning, ways of creating links.

In this tutorial we'll:

  • Use the \Drupal\Core\Url class to generate URL objects from routes and external URIs.
  • Use the \Drupal\Core\Link class to create HTML links within a Drupal module.
  • Examine best practices for working with URLs and links in a Drupal module in order to ensure that your code continues to work into the future.

By the end of this tutorial you should be able to link to anything, either internal to your application or external, using Drupal best practices.

Categories
Drupal 8, 9, and 10
More information

Renderers are the services that take a render array and convert it to HTML (or JSON, or any other format). As a module developer, understanding how they work will help you gain a better understanding of what happens behind the scenes when Drupal links an incoming request to your custom controller and then handles the data you return.

In this tutorial we'll:

  • Define renderers
  • List the renderers available in Drupal core
  • Demonstrate how you can create a link that forces the use of a different renderer

By the end of this tutorial, you should understand the role that renderers play in the Drupal render pipeline and when you might want to use one other than the default.

Categories
Drupal 8, 9, and 10
More information

If you've ever created or edited a piece of content on a Drupal site you have already interacted with the Field API. The Field module (along with its user interface counterpart) is responsible for providing the forms and data components used to build up the content model that make up a Drupal site. Understanding how Drupal fields work and how they're constructed via the Field API is an important part of understanding how Drupal works.

In this tutorial, we're going to look at the main components that make up the Field API at a high level. We'll see how the Field UI module exposes the field types included in core. We'll also look at the three main pieces that compose fields: types, widgets and formatters.

Categories
Drupal 8, 9, and 10
More information

Drupal's field system provides us with a flexible system of adding different types of discrete data to content types. This enables us to create rich content models. The Field API allows us to define these distinct field types by creating a new plugin. These plugins specify a FieldType annotation. In this tutorial, we'll look at these annotations in detail. We'll look at the implementations of field types from Drupal core. Also, we'll see what a new custom field type would look like.

By the end of this tutorial, you should be able to:

  • Understand how field type definitions are created and exposed to Drupal
  • Identify the various field types provided by Drupal core
  • Understand the requirements for providing a specification for a new field type
Categories
Drupal 8, 9, and 10
More information

Once we've explored the various field types provided by Drupal core, the next component of the Field API to explore is field widgets. Field widgets define how the data structure of the field is displayed on an edit form. When content editors interact with your field type they will be doing so via the field widget you provide. In this tutorial, we'll take a look at the field widgets provided by Drupal core, the plugin type required to define our own custom widget and how we can define multiple widget options for a single field type.

By the end of this tutorial, you should be able to:

  • Understand where field widgets fit into the overall Field API
  • Implement a custom field widget to support a particular field type
Categories
Drupal 8, 9, and 10
More information

Of the 3 main components of the field system -- types, widgets and formatters -- only 1 has an impact on the actual display of content for end users: field formatters. Field formatters are responsible for taking the data stored by a field and transforming it into the markup that is sent to the browser when an end user views your site.

In this tutorial we'll:

  • Look at the role field formatters play in the Field API
  • Identify the main components that make up a field formatter

By the end of this tutorial you should be able to define the role of a field formatter plugin.

More information

Field formatters are responsible for taking the data stored by a field and transforming it into what a vistor sees. We can define new field formatters to output data for new field types or to provide alternative formatting options for existing field types. Creating a field formatter plugin is a common task for Drupal developers.

In this tutorial we'll:

  • Define a new background color field formatter that uses the string stored by our field_example_rgb field type as the background color of the output.
  • Make it possible for site builders to toggle on or off a feature that automatically adjusts the foreground text color of the output.

By the end of this tutorial you should be able to define a new custom field formatter plugin with settings that a site administrator can configure.

Categories
Drupal 8, 9, and 10
More information

Drupal's Field API specifies the implementation details for field types, widgets and formatters. It also provides several hooks that allow custom code to alter these implementation details. In this tutorial we'll take a look at these Field API hooks and see how they can be used to change field types, widgets and formatters.

By the end of this lesson, you should be able to:

  • Idenfity existing Field API hooks for manipulating field behavior
  • Understand the proper method for changing the behavior of a field type, widget or formatter
  • Know where to find the documentation for these API functions, and how to find their implementations
Categories
Drupal 8, 9, and 10
More information

Many of the processes that Drupal performs when responding to a request are cached in order to increase performance. Creating the HTML for the page that a user sees or the JSON response to a REST request can require thousands of operations. Some operations are time consuming, memory heavy, CPU intense, or all 3. By performing the operation once, and then caching the result for next time, subsequent requests can be fulfilled faster. In order to make it easier to store, retrieve, and invalidate cached data, Drupal provides cache-related services you can use in your code. Drupal also enables you to provide information about the cacheability of data to the Render API to improve the performance of page rendering.

In this tutorial we'll:

  • Cover the terms and concepts you should be familiar with when working with the Cache API
  • Point to additional resources for more information about how to perform specific tasks with the Cache API

By the end of this tutorial, you should be able to define the concepts of bubbling and cache invalidation, and know how cache keys, tags, context, and max-age are used to provide cacheability metadata for items.

More information

The individual items that make up the content of a page impact the cacheability of that page. In order for Drupal's cache and external caches to better understand how the content varies on a page, module developers use the #cache render element property. The #cache property defines cacheability metadata for individual elements in a render array.

Additionally, these Render API elements can become fairly complex. The calculation of what the final HTML output should look like often involves looking up content in the database, checking multiple conditions, maybe querying an external API, and various other tasks. This can cause turning a render array into HTML to become quite expensive. In order to speed up this process, the Render API will cache the generated HTML for each element and reuse it on future requests whenever possible -- but only if you tell it to do so.

In this tutorial, we'll look at:

  • How render caching impacts the performance of a page
  • Defining the cacheability of an item with cache tags, cache contexts, and cache max-age
  • Examples of using the #cache property in a render array

By the end of this tutorial you should know how, and when, to use the #cache property when defining render arrays.

More information

Want to know if the person that's viewing your custom block is authenticated? Need to change the elements visible on the page based on a user's permissions or roles? Want to display a welcome message for users returning to your site?

All of these things require knowing who the user is that's currently accessing a page. This can be accomplished by using the current_user service to load an object that contains information about the current user as well as methods for checking permissions, and retrieving additional information.

In this tutorial we'll:

  • Define what "current user" means
  • Use the current_user service to retrieve an implementation of \Drupal\Core\Session\AccountInterface
  • Retrieve information about, and check the permissions of, the current user

By the end of this tutorial you should be able to retrieve and make use of information about the applications current user in order to perform logic in your code that customizes the response for different users.

Categories
Drupal 8, 9, and 10
More information

Drupal's Form API is a set of interfaces, utility classes, and conventions that when combined together allow module developers to create forms that collect, validate, and process user-submitted data. The Form API is closely related to the Render API. It uses Render Arrays to define forms, and adds an additional level of workflow and processing to enhance the Render API with some features specific to handling forms.

Given that forms are one of the primary means of interacting with a Drupal site via the UI, understanding how the Form API works is a critical part of learning to develop modules for Drupal. While you may not need to know all the nitty-gritty details, every Drupal module developer is likely to encounter aspects of the Form API at some point. Understanding the basics should be considered required knowledge.

Theme developers are also likely to encounter some aspects of the Form API, as forms are inherently part of the look and feel of a site. Knowing how to make changes to the UX of a form is an important skill.

In this tutorial we'll:

  • Describe what forms are and how they are used in Drupal
  • Explain the relationship between Form API and the Render API
  • List some of the benefits of using the Form API over generic HTML forms

By the end of this tutorial you should have a solid understanding of the role of the Form API in Drupal.

Categories
Drupal 8, 9, and 10
More information

Understanding the flow--or life cycle--of a Drupal form will help you better understand how to build new forms or influence existing ones. This tutorial will help you understand the complete life cycle of a Drupal form: receiving the request from a browser, displaying a page with a form, rendering the form as HTML, handling the submitted form, validating input, handling errors, and processing data. We'll point out the common places that module developers might want to inject additional functionality into the process and link to tutorials with more details about how to do so.

In this tutorial, we'll:

  • List the major steps in the life cycle of a Drupal form in the order that they are encountered
  • Describe how Drupal determines which form to display, and/or which form handles an HTTP POST request
  • Understand the role of FormStateInterface in the life cycle of a form

By the end of this tutorial, you should have a solid understanding of the life cycle of a form within Drupal.

More information

Each form is defined by a controller, a class that implements the \Drupal\Core\Form\FormInterface. Form controllers declare the unique ID of the form, the $form array that describes the content of the form, how to validate the form, and what to do with the data collected.

In this tutorial we'll:

  • Define a new form controller class
  • Implement the required methods to describe a form
  • Add a route that can be used to access our form

By the end of this tutorial you should be able to define a form that adheres to the FormInterface requirements and know where to find more information about how to further customize your form controller.

Categories
Drupal 8, 9, and 10
More information

Module developers can add new elements to a form by adding their definition to the $form array in the buildForm() method of their controller or via an implementation of hook_form_alter(). Doing so requires knowing the element #type, and details about any element-type-specific properties.

In this tutorial we'll:

  • Determine the element type to use for the HTML input element we want to use
  • Consult the documentation for the two form element types we're using
  • Add a checkbox and a select list to our form via the buildForm() method of our form controller

By the end of this tutorial you'll know how to add new elements to an existing $form array in order to collect additional data from users.

Categories
Drupal 8, 9, and 10
More information

Drupal core provides a couple dozen different input #type elements that can be added to forms. This includes one for every standard HTML5 input element, and some Drupal-specific ones that encapsulate more complex interactions like uploading files. But how can you know what elements exist? Where do you find information about what Render API properties each element uses?

In this tutorial we'll:

  • Define what FormElements are and how they relate to the Render API
  • Find a list of all available input element types, additional documentation and usage examples
  • See examples of the most common element types

By the end of this tutorial you should be able to discover the different types of elements you can add to a $form array and find usage examples for each.

Categories
Drupal 8, 9, and 10
More information

When a form is submitted you'll need to check the data input by the user to ensure that it matches certain constraints, and to raise errors when necessary. Is the email address in the proper format? Is the title field long enough? Does the ASIN ID entered match a valid Amazon product? This process is called validation and is handled by a combination of the validateForm() method of a form controller, and validation callbacks.

In this tutorial we'll:

  • Explain the use case for both the validateForm() method of a form controller, and validation callbacks
  • Discuss additional uses for validation handlers beyond just checking the length of a text field, or format of a phone number field

By the end of this tutorial you should know how to start adding custom validation logic to any form in Drupal.

More information

When your module defines the form and the form controller, you can add your validation logic as part of the form controller. This is done via the implementation of a validateForm() method. The FormBuilder service will automatically invoke this method at the appropriate time during the process of submitting a form. While the validateForm() method is required by \Drupal\Core\Form\FormInterface, an empty method will fulfill that requirement. It's up to you to provide appropriate validation code inside the method.

In this tutorial we'll:

  • Use the validateForm() method of a form controller to verify user input
  • Demonstrate how to raise errors on a form element when it doesn't pass validation

By the end of this tutorial you should know how to validate your custom forms.

More information

When working with forms that are not created by your code, where you're not implementing the form controller but rather interacting with the form via implementations of hook_form_alter(), you can use the #validate property of the root form element to add additional validation logic in the form of a callback function or method.

In this tutorial we'll:

  • Implement a #validate callback that raises an error if specific conditions are not met

By the end of this tutorial you should know how to add custom validation logic to any form in Drupal by using a #validate callback.

Categories
Drupal 8, 9, and 10
More information

When defining a new FormElement plugin, or if your constraints are only relevant for a single element, you can use the #element_validate property of an individual element to specify additional validation callbacks.

In this tutorial we'll:

  • Add an #element_validate callback to a single element in a form to perform validation of just that element.

By the end of this tutorial you should know how to add #element_validate callbacks to any form element in Drupal.

Categories
Drupal 8, 9, and 10
More information

You probably created a form with the intent of collecting user input and then doing something with that input. Using the submitForm() method of our form class we can access the validated, and sanitized, user input data and make use of it for our own needs. We might do things like save the collected data as configuration, update an entity, or use it as part of a search query.

In this tutorial we'll:

  • Demonstrate how to add a submitForm() method to a form controller class
  • Access the value(s) of form input elements via the $form_state object
  • Set a redirect after performing processing in a form submission handler
  • Look at alternative ways to affect the submission handling of a form like #submit callbacks

By the end of this tutorial you should know how to access the values of a submitted form, and how to write custom processing code that gets invoked when the form passes validation.

More information

Sometimes you need to add additional processing of input to forms where your module doesn't implement the form controller. In order to do this you can use the #submit property of the root level $form element, or of a specific button on a form, to add one or more callbacks. These functions, or methods, will be automatically called when the Form API is processing a submitted form and give your custom code an opportunity to do whatever it needs to do.

In this tutorial we'll:

  • Look at alternative ways to affect the submission handling of a form like #submit callbacks

By the end of this tutorial you should know how to add a #submit callback to an entire form, or a specific button in a form.

More information

When you create a custom form for Drupal and your module defines the form controller, the best way to handle processing of submitted data is via the submitForm() method of your controller. This method is called automatically by the Form API during the process of handling a user-submitted form. It can be used to save incoming data to the database, trigger a workflow based on user input, and instruct the Form API where to send the user after form processing has completed.

In this tutorial we'll:

  • Demonstrate how to add a submitForm() method to a form controller class
  • Access the value(s) of form input elements via the $form_state object
  • Set a redirect after performing processing in a form submission handler

By the end of this tutorial you should know how to access the values of a submitted form, and how to write custom processing code inside of the submitForm() method of a form controller.

More information

Eventually you'll want to do something with the information your form collects beyond just printing it to the screen. It's generally considered a best practice to keep business logic out of your form controller so that it can be reused. In order to accomplish that you'll generally define your business logic in a service, and then call out to that service from your form controller. Or, you can make use of one of the existing services provided by Drupal core to save data.

In this tutorial we'll:

  • Use dependency injection to inject a service into a form controller
  • Make use of a service injected into a form controller from within the buildForm() and submitForm() methods

By the end of this tutorial you'll understand how to inject one or more services into your form controller and then make use of them.

More information

Forms are used for both collecting new data, and editing existing data. In order to allow users to modify existing data you need to pre-populate the elements on the form with the data you previously stored.

In this tutorial we'll look at the ways in which forms can be pre-populated with existing data, including:

  • Providing default values for form elements which a user can edit with the #default_value property
  • The differences between the #value and #default_value properties

By the end of this tutorial you should know how to populate forms using existing data.

More information

You'll often need to make minor, or major, alterations to an existing form provided by another module. The Form API allows you to alter any existing form through a series of hooks without having to change the existing module's code at all. This is probably one of the most powerful features of the Drupal Form API. Knowing how to implement and leverage hook_form_alter() and its variations is an essential skill for any module developer.

In this tutorial we'll:

  • Learn how to implement hook_form_alter() and hook_form_FORM_ID_alter() in a module
  • Modify existing elements, or add new elements, to a form provided by another module
  • Understand how to add new validation and submission handlers when altering an existing form

By the end of this tutorial you should know how to alter almost everything about the way any form in Drupal works without having to hack the module that provides the form.

Categories
Drupal 8, 9, and 10
More information

Forms can be displayed as the main content of a route or by using the form_builder service to retrieve and display a form directly. Which one you choose will depend on where on the page you want the form to appear.

In this tutorial we'll:

  • Go over the two different ways a form can be retrieved and displayed
  • Demonstrate how to display a form inside a custom block using the form_builder service

By the end of this tutorial you'll know how to retrieve a form and have it rendered anywhere on the page.

More information

By default, individual forms in Drupal are not output using Twig template files. It's possible to associate a form with a Twig template file by creating a new theme hook, and then referencing that theme hook from the $form array that defines the form. Doing so allows theme developers to customize the layout of the elements in the form using HTML and CSS.

This is useful when you want to change the layout of the entire form. For example, putting the elements into 2 columns. If you want to change individual elements in the form, you can often do so by overriding element specific Twig template files.

In this tutorial, we'll:

  • Learn how to create a new theme hook that can be used to theme an element in a render array.
  • Associate the $form we want to theme with the new theme hook we created.
  • Create a Twig template file for the theme hook that will allow us to lay out the form elements using custom HTML.

By the end of this tutorial, you should be able to associate a Twig template file with any form in Drupal, so that you can customize its layout using HTML and CSS.

Categories
Drupal 8, 9, and 10
More information

Asynchronous JavaScript And XML (Ajax) is a programming practice for building more complex, dynamic webpages using a technology known as XMLHttpRequest. It allows you to asynchronously perform server-side operations without requiring a refresh, thus allowing for more complex user interaction and, in some cases, improved user experience.

In this tutorial we'll:

  • Define what Ajax is
  • Look at how Ajax is implemented in the Drupal Form API
  • Provide links to additional resources to learn more about implementing Ajax in your own forms

By the end of this tutorial you should be able to explain what Ajax is, when you might want to use it, and how to get started doing so with Drupal's Form API.

More information

A common use of Ajax is to alter a form by adding, removing, or updating parts of the form in response to actions taken by the user. The resulting altered form is still eventually submitted with a traditional HTTP POST request. For example, one might update the options available in a city dropdown field after someone has chosen a value in the country dropdown, or add an additional textfield for collecting a person's name when the user clicks an "Add another person" button.

In this tutorial we'll:

  • Understand why certain types of modifications to a form require the use of Ajax
  • Use #ajax in conjunction with a <select> field to demonstrate how to update a form with Ajax
  • Learn about responding to user interaction with #ajax

By the end of this tutorial you should be able to use the #ajax attribute on any form element to respond to user actions and update the form displayed to the user with new content and options.

Categories
Drupal 8, 9, and 10
More information

Using Ajax allows you to create forms that are submitted to the server, and processed, without requiring a page reload.

In this tutorial we'll:

  • Use #ajax with a '#type' => 'submit' button in order to submit a form via Ajax
  • Look at how form build, validation, and processing are used when submitting a form via Ajax
  • Use the form's internal storage to track data across multiple requests
  • Discuss some best practices to keep in mind when using Ajax for form submissions

By the end of this tutorial you should know how to update an existing form so that it is submitted via Ajax and no longer requires a page refresh to work.

Categories
Drupal 8, 9, and 10
More information

Deprecated code is any code flagged for future removal, but which has not yet been removed to ensure that existing code which relies on the to-be-removed code will continue to work. When an API, or feature, becomes deprecated it's a warning to all developers that at some point in the future this thing they are relying on will not exist, and they'll need to update their custom code to a new approach. Preferably before the existing one gets removed.

In this tutorial well:

  • Learn about why, and when, code is deprecated in Drupal
  • How to identify custom code that is using deprecated features
  • How to determine an appropriate upgrade path to the new API

By the end of this tutorial you should be able to explain what code deprecation is, and why it's important for Drupal's continue innovation, as well as how to update your own code when an API you rely on becomes deprecated.

More information

There’s no one-size-fits-all path to upgrade from Drupal 8 to Drupal 9, but there is a set of common tasks that everyone will need to complete.

In this tutorial we’ll:

  • Explain the differences between Drupal 8 and Drupal 9 that affect the upgrade path.
  • Walk through the high-level steps required to upgrade from Drupal 8 to Drupal 9.
  • Provide resources to help you create an upgrade checklist and start checking items off the list.

By the end of this tutorial you should be able to explain the major differences between Drupal 8 and 9, audit your existing Drupal 8 projects for Drupal 9 readiness, estimate the level of effort involved, and start the process of upgrading.

More information

As new major versions of Drupal are released, contributed modules need to be updated for compatibility. As of right now (October 2021) there are a lot of contributed modules with a Drupal 8 release and a patch in the queue to make them work with Drupal 9. However, there's no official Drupal 9 compatible release for the module, so the module can't be installed with Composer. This creates a circular problem where you can't composer require the module if you don't patch it, but you can't patch it until after it's been downloaded by Composer.

To help solve this common issue, Drupal.org provides a lenient Composer endpoint that publishes all modules as compatible with Drupal 9 regardless of whether that's true or not. By using it, you can composer require the module and then use cweagans/composer-patches to apply any necessary patches.

In this tutorial we'll:

  • Add the lenient Composer endpoint to our project's composer.json file
  • composer require a non-Drupal 9 compatible module
  • Use Composer to download and apply a patch that makes the module Drupal 9 compatible

By the end of this tutorial you should be able to use contributed modules that require a patch to be compatible with Drupal 9.

More information

There’s no one-size-fits-all path to upgrade from Drupal 9 to Drupal 10, but there is a set of common tasks that everyone will need to complete.

In this tutorial we’ll:

  • Explain the differences between Drupal 9 and Drupal 10 that affect the upgrade path.
  • Walk through the high-level steps required to upgrade from Drupal 9 to Drupal 10.
  • Provide resources to help you create an upgrade checklist and start checking items off the list.

By the end of this tutorial you should be able to explain the major differences between Drupal 9 and 10, audit your existing Drupal 9 projects for Drupal 10 readiness, estimate the level of effort involved, and start the process of upgrading.

This course appears in the following guides:
Categories
Module Development, Backend and Infrastructure
Drupal 9
Categories
Module Development, Backend and Infrastructure
Drupal 7, 8, 9, and 10