Make your custom Drush command more flexible by allowing users to pass command line arguments into it. For example, rather than hard-coding that the command lists users with a specific status, allow the desired status to be specified at run-time. This allows the command's logic to be more generic, and to return different results, or operate on different data, based on the provided parameters.
Parameters are variables that are passed from user input at the command line into the Drush command method. Typically, they are either single string values, or comma-delimited strings of values. Parameters are typically used to provide input for the command related to what the command should work on, in contrast to options, which are typically used to configure how the command works.
In this tutorial we'll:
- Declare parameters for a custom Drush command in its annotation
- Use the parameter input inside the custom Drush command method
By the end of this tutorial you should understand how to work with parameters inside custom Drush commands.
When you create a custom Drush command it might be useful to allow users to pass options (predefined values) that change the way a command works. You can think of options as being flags, or variables, that affect the command's internal logic. As an example, consider the Drush core user:login
command which by default returns a one-time login link for the root account. The command also accepts an optional --name
option which allows the internal logic to create a link for a specified user instead of only being able to create links for the root user. This makes the command useful in a wider variety of situations. Another common option is the --format
option which allows a user to specify that they want the command to return its output in a format (CSV, JSON, Table, etc.) other than the default.
Options are defined in the Drush command's annotation. Their values are passed as part of an associative array to the command method. Unlike parameters, options are not ordered, so you can specify them in any order, and they are called with two dashes like --my-option
. Options are always optional, not required, and can be set up to accept a value --name=John
or as a boolean flag without a value --translate
.
In this tutorial we'll:
- Declare options for a custom Drush command in its annotation
- Learn how to use these options inside the custom Drush command method
By the end of this tutorial you should be able to add options to your own custom Drush commands.
Drush commands are commonly run in the Drupal docroot, the directory where Drupal's files live. This is a relatively simple task on your local development environment. But if you're working on multiple sites and each of those sites has one or more remote environments that you connect to via SSH, workflows quickly become complicated. Creating and using Drush site aliases allows you to run Drush commands on any site, local or remote, that you have credentials to access, from any location on your computer that has access to a Drush executable.
Imagine you've got a Drupal project with dev, test, and live environments in the cloud somewhere. And you need to clear the cache on the dev environment. You could SSH to that environment, and execute drush cr
there. Or, after configuring a site alias you could do something like:
drush @provider.dev cr -y
And Drush will connect to the remote environment and clear the cache.
Site aliases allow bundling the configuration options (--uri
, --root
, etc.) for a specific remote server under an alias. This reduces the amount of typing required. Even more importantly, it helps teams agree on a common definition for environments like @dev
, @test
, and @live
by committing their configurations to version control.
In this tutorial we'll:
- Define what a Drush site alias is
- Understand the use case for aliases
- Learn how to configure and use Drush site aliases
By the end of this tutorial, you should understand how Drush site aliases work, how to create Drush site aliases, and how to use them in a Drush command.
The Drush executable can be configured through the use of YAML configuration files and environment variables. This configuration can help cut down on typing lengthy frequently-used commands. You can tell Drush to look for command files in project-specific locations. Configuration can also set the value(s) of a specific command's options, instead of having to type them at the command line every time.
In this tutorial we'll:
- Explore different Drush configuration options
- Learn how to configure Drush for your project
By the end of this tutorial, you'll know how to provide project specific, and global, configuration that helps customize Drush and improve your own efficiency.
Creating a custom Drush command requires creating a PHP class that Drush can find with annotated methods and metadata about each custom command. You'll create a drush.services.yml file that tells Drush where to find the command class and any services to inject into it. You'll also modify the project's composer.json to tell Drush what versions of Drush the command is compatible with.
Custom Drush commands are a great way to expose your custom module's features to help automate these tasks and allow users to perform them as background processes. They can also provide a more efficient way to execute PHP code that takes a long time and is prone to timing out when run via the web server.
Depending on your use-case it can also be more efficient to create a custom Drush command to execute your logic instead of coding a complete UI. For example, if all the command needs to do is generate a CSV list it might take less effort to write a Drush command and pipe the output to a file than to create a UI that generates a file and prompts the user to download it.
In this tutorial we'll:
- Declare a new custom Drush command inside a custom module
- Make our custom Drush command output a list of all the blocked users on the site
- Verify our new command is working
By the end of this tutorial you should understand how to create a custom Drush command that returns a list of blocked users.
Developers can implement the Drush command API to write their own custom Drush commands. This allows you to include Drush commands with your modules to allow the module's features to be used via the CLI. You can also create project-specific Drush commands that help with the development, deployment, and maintenance of your particular application.
We've written Drush commands to help generate reports, make it easier for new team members to get up and running, compile custom theme assets, and more. Any time we need to write PHP code that interacts with our Drupal site where we're worried the code might time out because it takes too long to execute we'll reach for Drush. Custom Drush commands are also useful to combine background processes that can be executed on cron, such as nightly imports, data synchronization, bulk database manipulation, custom queues processing, and so much more.
In this tutorial we'll:
- Learn about different types of custom Drush commands
- Review the anatomy of a Drush command
- See how the Drush bootstrap process relates to commands
By the end of this tutorial, you'll be able to identify the parts of a custom Drush command and start writing your own.
In addition to using one of the existing generators, developers can write their own Drush generator commands. This can help speed up repetitive tasks and reduce the use of boilerplate code that is prone to human error.
Generators are provided through Drush's integration with the Drupal Code Generator project. Writing new generators isn't specific to Drush, though if you're creating generators for Drupal it is definitely easiest with Drush as a wrapper.
Similar to Drush commands, generators can be supplied by a Drupal module or declared globally. If you have a feature-specific functionality, it's best to ship your custom generator within the custom module. Otherwise, a global generator can be declared and used.
In this tutorial we'll:
- Explain the anatomy of a Drush generator
- Write a custom Drush generator for handling a site's development.services.yml file, and use it in a project
By the end of this tutorial you should understand how to create, or customize, a Drush code generator and use it in your project.
One of the problems that Drush solves for developers is the automation and optimization of routine tasks. Drush commands attempt to speed up workflows and tasks that developers and site maintainers would otherwise have to do manually through the UI, or run one-by-one via the command line. One of those tasks is the process of deploying changes to a Drupal application from one environment to another.
The typical Drupal deployment process consists of repeatable steps such as importing configuration changes, applying database updates, and clearing the cache. Drush comes with the handy drush deploy
command that allows you to automate the execution of all of these tasks post code deployment.
In this tutorial we'll:
- Learn about the
drush deploy
command - Discuss when you would use the
deploy
command
By the end of this tutorial you'll know how to use the drush deploy
command in conjunction with other useful deployment-related commands to help automate the task of deploying changes to a Drupal site's configuration and code.
Code generators are great productivity boosters that allow generating scaffolds for common development tasks in Drupal. One of the most common use cases for generators is scaffolding the code required for a custom entity type. Custom entities require many files and complicated annotations in order to function properly. There is a lot of boilerplate code that is more-or-less the same for every entity type. Creating all the files is repetitive, time-consuming, and prone to human error. Generators can help automate this task and make creating your own custom entity types quicker.
In this tutorial we'll:
- Learn how to generate the code for a custom entity with Drush
- Learn about the options that generators provide for custom entities
By the end of this tutorial you should know how to generate custom entities with Drush.
Some Drush commands return a lot of information -- lists of modules, generators, and status reports, for example. It might be hard to find a property you need in the small command window output. Luckily, the output of Drush commands can be piped to other commands, used as a source for imports, settings for CI, and other DevOps tasks.
In order to accommodate all these different use cases, Drush comes with a formatting system that allows you to format and filter output to meet your needs. This system allows to you specify what fields you want returned when the output contains more than one field. It also allows Drush command output to be formatted as JSON, XML, raw PHP, a table, and more.
In this tutorial we'll:
- Learn how to specify the output format -- and what formats are available
- Limit the fields that are returned in a report
- Learn to filter the output to only the data we're interested in
By the end of this tutorial you'll know how to format a Drush command's output to fit your needs.
If you want to change the way an existing Drush command works you use hooks. Hooks are useful for altering command parameters, options, annotation data, and adding custom logic during particular stages of the command execution process. Drush hooks are conceptually similar to Drupal hooks.
Hooks are methods on a Drush command class with an annotation indicating what hook is being implemented, and thus when the code should be invoked. The code in the methods is executed during specific stages of the command cycle. Developers can use core hooks -- predefined methods that come with Drush core -- or declare a custom hook that other commands can use.
In this tutorial we'll:
- Explore the different core Drush hooks
- Learn which hooks are called at what stage of the command cycle
- View example hook annotations and method implementations
By the end of this tutorial you'll know what types of core hooks are available to you and when they are called.
Adding logging and error handling are an important part of authoring Drush commands. Logs allow developers to get timely feedback from a command and inform users about potential alterations and flags, events to monitor, and the progress of long-running commands. Correct error handling allows for clean exits, meaningful error descriptions, and provides a path forward for developers to fix the errors and accomplish their goals.
In this tutorial we'll:
- Explore the different types of logging messages Drush commands can output
- Learn how to handle errors from within a Drush command
By the end of this tutorial you'll know what types of log messages you can use; how to log success messages, errors, or debug statements from a custom Drush command; and how to handle errors and exceptions.
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 choice()
.
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.
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.
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 has robust Cache API, and various caching layers (both internal and external to Drupal), that work together to decrease application load and boost performance. Drupal's APIs allow developers to declare the cacheability of data. How long can this be stored before it becomes stale? And under what conditions should it be invalidated? Drupal uses that information during the process of building a page to cache as much of the work it does as is possible so that it won't need to do it again. Additionally, Drupal bubbles up the cacheability data from everything required to build a page into HTTP response headers that caching layers external to Drupal can also use to cache the rendered HTML.
When these APIs are combined (and used appropriately), Drupal can be extremely fast for both anonymous and authenticated traffic. But doing so requires understanding the various caching layers, their roles, and their interconnections.
In this tutorial, we'll:
- Review the caching layers and systems behind them
- Learn about components of the Drupal cache system
By the end of this tutorial, you should have a broad understanding of the Drupal caching system, its layers, and a better understanding of where in the stack you should look to optimize for different scenarios.
Note: This tutorial is specific to Drupal sites hosted on the Acquia platform and covers integrating its features to improve performance.
The Acquia platform includes Memcache, Varnish, and Content Delivery Network (CDN) integration. In order for these to be as effective as possible, they should be configured and tuned for your specific use case. This tutorial provides an introduction to these utilities and common configuration. For more detail, you should consult the Acquia documentation.
In this tutorial, we'll:
- Learn what caching utilities are included in the Acquia platform
- Set up and tune different parts of Acquia's application caching level including Memcache and Varnish
By the end of this tutorial, you'll know what application-level caching options exist on Acquia's platform. And how to configure it, and your Drupal application, for better performance.
WebPageTest (webpagetest.org) is a free open source resource that runs performance tests on a site, provides educational reports about what it finds, and suggests optimizations you can make. The tests performed via the WebPageTest interface include Lighthouse tests, performance-specific tests, Core Web Vitals, visual comparisons, and traceroute tests. The tool also allows saving a history of tests if you sign up for a free account. This tool won't make your site faster on its own, but it will give you some good ideas about where to focus your efforts.
In this tutorial we'll:
- Learn how to run performance tests via the WebPageTest web interface
- Learn how to read and interpret the results
By the end of this tutorial, you should know how to use the WebPageTest online interface to analyze a Drupal site's performance.