When the logic of a command depends on user input, it's useful to set up an interactive questionnaire inside the command code. This allows you to provide the user with more context about the input they're providing, and ensure that you collect all the necessary values. This is especially useful when the command uses a pre-defined list of options and the values require memorization. An example of this is the drush cache-clear command that comes with Drush core. It requires an argument indicating which cache to clear, which you can specify at the command line; however, if you invoke the command with no arguments it will present you with a list of cache bins to choose from and a UI for selecting one.
Drush 9+ can access the Input/Output (I/O) object via the $this->io() method. This object -- an instance of \Drush\Style\DrushStyle -- holds information about user-provided input, and utilities for manipulating that input. To ask a user a question, use an io() object in the command callback method. It can take over the execution flow of the command as needed to stop and gather additional input. The I/O system has various methods for asking confirmation or choice questions such as confirm() and select().
In addition to prompting for input, the I/O object can be used to provide other styling to the command, like progress bars.
In this tutorial we'll:
- Learn how to prompt the user for additional input
- Process the user's answer as part of the command execution flow
By the end of this tutorial you should understand how to prompt a user for additional input for a custom Drush command.
While Drush empowers all Drupal users with its commands, it's even more powerful when used in combination with scripting solutions such as Composer and Bash. Scripts can be used to power post-deployment tasks like importing new configuration or clearing the cache, as part of CI processes to sync a database from one environment to another, to run background processes on the server such as imports and migrations, search indexing, running cron, and much more. If you want to write Bash (or any other scripts) that interact with a Drupal site, then Drush is the tool for you.
In this tutorial we'll:
- Learn how to use Drush commands within Composer and Bash scripts
- Learn how to chain multiple Drush commands together in a script
By the end of this tutorial you'll know how to use Drush as part of a script that automates common or tedious tasks.
When you manage many Drupal websites, you may perform repetitive tasks that are common across all of your sites. In our experience, this usually relates to having a personal preference for how certain tasks are accomplished. For example, maybe you like to make backups of the database and files in a specific way before testing upgrades, or you have a set of scripts for running scans of core web vitals. Although these tasks can be bundled into a custom module, it could be useful to create a site-wide Drush command instead. Site-wide commands can be installed with Composer, managed in a separate Git repository, and act as a project dependency. This way they are easy to maintain through a separate upstream. Changes to this code will be reflected on all the sites where it's used.
In this tutorial we'll:
- Declare a custom site-wide Drush command
- Demonstrate how to use Composer to manage a package that contains a Drush command
By the end of this tutorial you'll be able to create a site-wide Drush command and manage the code with Git and Composer.
The Drupal Entity API makes it easy to define new custom content entity types. And in most cases, whenever you want to store custom content in Drupal, you should use the Entity API instead of making CRUD queries directly to the database. This ensures your code is more consistent and allows you to take advantage of all the features of the Entity API, like access control, Views module integration, and automatic JSON:API support. As well as making it easier for others to extend your custom content by ensuring all the proper hooks and lifecycle events get invoked when new content items get created, updated, and deleted.
In this tutorial, we'll:
- Walk through the process of creating a custom content entity
By the end of this tutorial, you'll be able to create your own custom content entity contained in a module.
One of Drupal's strengths is its fine-grained permission and access system. The Entity API enables this by providing interfaces that let us define access control rules.
In this tutorial we'll:
- Look at how access control is handled, using Drupal core as an example.
- Demonstrate how to implement access control in a custom module.
- Learn about the hooks that allow developers to modify access control for entities provided by another module.
By the end of this tutorial you should have a better understanding of the entity access control system and how to work with it.
Entities are the core data structures that provide the building blocks for nearly everything on a Drupal site. Whether an entity provides configuration or content, it plays a key role in how Drupal stores and manages data. Entities provide a consistent, developer-friendly, and Drupal-aware abstraction to data stored in the database.
In this tutorial, we will:
- Explore how different entity types relate.
- Compare configuration and content entities to understand the purpose and implementation of both.
- Review how (at a high level) an entity type is defined.
By the end of this tutorial, you'll understand the relationship between configuration and content entities and be able to identify the parts of code that define a custom entity type.
Often when building a site in Drupal you'll find yourself wanting to display a list of nodes, or find entities created by a particular author, or locate some content based on a particular set of criteria. Rather than querying the database directly, Drupal provides a helper class, EntityQuery, to make things a bit easier. The EntityQuery class will probably look very familiar to you if you're familiar with the Database API, or the EntityFieldQuery class in Drupal 7.
In this tutorial we'll:
- Go through several examples of using
EntityQueryto find subsets of content. - Demonstrate how to iterate over the results of an
EntityQueryquery.
By the end of this tutorial, you should understand how to use entity queries to create custom sets of data from entities.
Entity API Overview
FreeWhen learning Drupal development, it won't be long before you encounter the word "entity" and the Entity API. But what are entities in Drupal? How can you use them to build your site? When should you use the Entity API?
This tutorial will explain Drupal's Entity system from a high level. We'll look at:
- The main problems the Entity system solves
- Key terms you should know
- Key concepts we'll explore as we dive into Drupal's Entity API
By the end of this tutorial, you should be able to explain the problems that the Entity API solves, and when you should use it in your own code.
Drupal includes the Symfony Validator component, and provides an Entity Validation API to assist in validating the values of fields on an entity. By using the Entity Validation API you can ensure that you're validation logic is applied to Entity CRUD operations regardless of how they are triggered. Whether editing an Entity via a Form API form, or creating a new Entity via the REST API, the same validation code will be used.
Using the Entity Validation API in order to validate the value of a field on an entity requires:
- Defining (or choosing) a constraint plugin
- Defining (or choosing) a validation plugin
- Adding the constraint to the field definition
In this tutorial, we'll look at how this Validation API works and how it can be used in custom code to ensure our entities have properly constructed values. We'll look at how this validation works in Drupal core and how we can add our own additional constraints. We'll also see how to work with the error messages returned from the validator when our entity doesn't pass validation.
Drupal's Entity system provides several hooks that allow custom code to interact with various parts of the entity life cycle.
In this tutorial we'll:
- Examine the available hooks
- Learn how to make use of them to act on several different types of operations on individual entities
By the end if this tutorial you should have a better understanding of the hooks available to developers who want to respond to entity lifecycle operations and how to use them to customize the way specific entity types work.
Getting Drupal to run in Docker requires a lot of moving parts. After installing Docker and Docker Compose, we need to select a collection of containers from Docker Hub and create a new docker-compose.yml file. Once we have environment variables and volumes configured, this only gives us the capability of running a Drupal site in Docker.
What if we already have a Drupal site we want to develop using Docker? In this tutorial, we'll show how to modify an existing project to minimize the setup time necessary for switching to a Docker-based environment.
In this tutorial, we'll:
- Describe the best practices for project organization.
- Use an environment file to configure containers.
- Add a Docker-specific settings.php file.
Planning for a migration is essential. In our collective experience we've never once seen someone sit down and execute a migration flawlessly on their first attempt. Migrations involve preparing and analyzing your source data, building a new website that data can be migrated into, and lots of testing, rolling back, and testing again, in order to get everything right. By the end of this tutorial you should be ready to start planning for your own Drupal migration project, and have a better understanding of the challenges of migrating from one system to another.
Preprocess functions are specially-named functions that can be used to add new variables to a Twig template file. They are commonly used by themes to add new variables based on custom PHP logic and simplify accessing the data contained in complex entity structures. For example: adding a variable to all node.html.twig template files that contains the combined content a couple of specific fields under a meaningful name like {{ call_to_action }}. Modules use preprocess functions to expose the dynamic data they manage to Twig template files, or to alter data provided by another module based on custom logic.
In this tutorial we'll learn how to:
- Use PHP to perform some complex logic in our theme.
- Store the resulting calculation in a variable.
- Make that variable available to a Twig template file.
Example use cases for adding variables with preprocess functions include:
- Anytime calculating the value to output in a template requires logic more complex than an if/else statement.
- Anytime the desired value requires additional string manipulation beyond what can be easily accomplished using an existing Twig filter or function.
By the end of this tutorial you should be able to expose new variables to a Twig template file by defining a preprocess function in either a module or a theme.
Twig has a special syntax for accessing array keys and objects, also known in Twig as variable attributes. In this tutorial, we'll cover the period or dot (.) operator to access a variable attribute, as well as subscript or square-bracket syntax, useful for when the key of the array contains special characters, like a dash (-) or pound sign (#). We'll also look at the logic Twig uses to find the matching attribute in an array or object.
Once you've defined an asset library you'll need to tell Drupal when you want to add the CSS and JavaScript that it includes to the page. Ideally you'll do so in a way that allows Drupal to only add the corresponding assets on pages where they are needed.
You can attach a library to all pages, a subset of pages, or to elements in a render array. This allows you to have some assets that are global, and others that get loaded on an as-needed basis. To attach a library you'll need to know both its name and prefix, and then use one of the techniques outlined below to let Drupal know when to include it.
In this tutorial, we'll look at attaching asset libraries:
- Globally, via your THEMENAME.info.yml file
- Conditionally, via a preprocess function using the
#attachedrender array property - Inside of a Twig template file
By the end of this tutorial you should be able to attach asset libraries in various different ways depending on your use case.
Drupal's Breakpoint module defines a "breakpoint" plugin type that modules or themes can implement via a breakpoints configuration file. So, in order to make their breakpoints discoverable, themes and modules define their breakpoints in a THEME-OR-MODULE.breakpoints.yml file located in the root of their directory.
In this tutorial, you'll learn about the structure of a breakpoints configuration file and why you would want to use one. We’ll cover the kinds of metadata you can include in a breakpoint file, including key, label, mediaQuery, weight, multipliers, and breakpoint group. Throughout, we'll look at some examples of breakpoint configuration files available in Drupal themes and modules.
You've got a slick responsive theme for your Drupal site that's been implemented in CSS using media queries. But the content and images on your site will regularly be updated and you want to use the Responsive Images module to create responsive image style field formatters that you can apply to image field display settings.
In this lesson, we'll review the concepts of breakpoints and media queries so that you can better understand what's going on when you encounter them in non-CSS file contexts like configuration forms for responsive image styles or breakpoint YAML files.
By the end of this tutorial, you should have an understanding of what breakpoints are, how they are expressed in media queries, and how they are relevant in the context of Drupal.
Some, but not all, themes come with administrator-configurable settings that you can change through the UI. These might allow you to upload your own logo, choose between a couple of different pre-defined layouts, or turn features of a theme on or off. In this tutorial we’ll look at where you can find these theme settings if they exist, and how to go about changing them.
Preprocess functions are specially-named PHP functions that allow themes and modules to modify the variables passed to a Twig template file. They are commonly used by themes to alter existing variables before they are passed to the relevant template files. For example; Changing the makeup of render array so that it renders an <ol> list instead of a <ul> list. Or appending data to the label of a node depending on custom logic.
In this tutorial we'll:
- Define a new preprocess function in our theme's .theme file
- Use the preprocess functions to modify the content of an existing variable before it's used in Twig
By the end of this tutorial you should be able to define new preprocess functions in a theme (or module) that manipulate the variables for a specific Twig template file.
Theme developers often need to add or remove classes and other attributes from an HTML tag. Template files handle this with a special Attributes object that contains the attributes and their values, as well as a handful of powerful methods to help manage these attributes.
In this tutorial we’ll cover:
- Adding/removing classes from elements in a Twig template
- The attributes object
- Examples of common tasks using various helper methods on the attributes object