Drupal site performance relies heavily on caching. Optimal caching (and invalidation) requires that each page is rendered with the correct cacheable metadata. This metadata allows for intelligent caching -- but when something isn't working correctly, it can be tricky to figure out where exactly the metadata was generated from.
When debugging Drupal cache issues, you're usually trying to answer 1 of 2 primary questions:
- Why is this cached? If the information gets stale, why isn’t it updated?
- Why is this not cached? And why is our cache hit rate low?
The Drupal cache system consists of many layers, each of which may contribute to the problem. This tutorial focuses on debugging the Drupal application cache layer, and strategies for debugging Varnish. Given that most external to Drupal layers rely on the use of HTTP headers for caching, you should be able to use similar techniques to those used for debugging Varnish.
In this tutorial, we'll:
- Learn strategies for debugging the Drupal application cache and render cache
- Share strategies for debugging low hit rates when using Varnish
By the end of this tutorial, you should know how to enable and use various cache debugging mechanisms in Drupal to help identify problems in your site performance and resolve them.
Server scaling is the process of adding more resources (CPU, memory, disk space, etc.) to a server (or servers) to help with performance. This might be a single server, or a cluster of different machines. When we talk about server scaling, think more about the resources and less about the specific hardware. Modern servers may not always resemble a physical machine that you can open up and insert additional RAM into. But the theory is the same: more memory means the server can handle more concurrent requests.
Sometimes your Drupal site is optimized, but traffic is still high and takes most of the server’s resources. In order to sustain that load you'll need to scale your server up.
Sometimes you don’t have the resources or expertise to implement caching optimizations, refactoring code, and modifying slow queries -- all of which would improve Drupal's performance. In these cases, you may consider server scaling.
Server scaling can be done in two ways: horizontally or vertically.
In this tutorial we'll:
- Learn what server scaling is
- Discuss examples of both horizontal and vertical server scaling
- Talk about when to choose horizontal versus vertical scaling strategies
By the end of this tutorial, you should understand the concept of server scaling and how it applies to a Drupal application.
No one likes to wait for a slow site to load. Not me, not you, and definitely not search engines. And the effect of site load times on things like SEO, user bounce rates, purchase intent, and overall satisfaction are only going to become more pronounced over time.
Drupal is a modern web framework that is capable of serving millions of users. But every site is unique, and while Drupal tries hard to be fast out of the box, you'll need to develop a performance profile, caching strategy, and scaling plan that are specific to your use case in order to be truly blazing fast.
Drupal site performance depends on multiple components, from hardware setup and caching system configuration to contributed modules, front-end page weight, and CDNs. Experienced Drupal developers looking to optimize their applications know where to start looking for potential savings. They can manipulate settings and combinations of these components to achieve the desired results. Our goal with this set of tutorials is to help explain the process and provide you with the insight that comes with experience.
In this tutorial we'll:
- Introduce high-level performance concepts for Drupal that we'll then cover in more detail elsewhere
- Provide an overview of the main Drupal performance components.
By the end of this tutorial, you should understand what components around your Drupal application are responsible for site performance.
When it's time to start a custom Drupal theme from scratch (especially if you're new to Drupal theming), we recommend using Starterkit. Starterkit helps you get a new theme up and running by scaffolding a set of theme files with sensible defaults, saving you from a bunch of repetitive work.
In this tutorial we'll:
- Learn what Starterkit is
- Discuss when you should--and should not--use Starterkit
- Walk through how to use Starterkit to generate a new Drupal theme
By the end of this tutorial you should be able to explain the use case for Starterkit and understand how to use it to start a new custom theme.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Tools like PHP_Codesniffer (phpcs) can be used to help ensure your code adheres to Drupal's coding standards. As a module developer, you should use phpcs and its Drupal-specific rule sets on all custom module code.
In this tutorial, we'll:
- Learn about PHP_Codesniffer (phpcs).
- Install PHP_Codesniffer and the Drupal-specific rules.
- Use phpcs to lint our custom code.
By the end of this tutorial, you should be able to use PHP_Codesniffer to help automate the process of adhering to Drupal's coding standards.
Coding standards are vital in collaborative environments like Drupal. These guidelines ensure consistency, readability, and maintainability of the codebase. Drupal has its own coding standards that outline best practices and formatting guidelines, promote code quality, simplify code reviews, and enhance the project's overall health.
In this tutorial, we'll:
- Explore the use of coding standards in Drupal.
- Highlight basic practices and sources for detailed information.
By the end of this tutorial you should be able to explain why coding standards are important and where to find more info about Drupal's coding standards.
To use a hook in a Drupal module, we need to add a class with a method for each hook we want to implement and a #[Hook]
attribute that declares which specific hook we're implementing. Each hook has unique arguments and an expected return value. In this tutorial, we'll walk through the process of implementing a hook by adding end-user help text for the anytown module, which Drupal's administrative UI will display. The process we'll use here applies to any hook implementation.
In this tutorial, we'll:
- Locate the documentation for
hook_help()
. - Implement the hook in the anytown module.
- Verify our hook implementation.
By the end, you'll have implemented hook_help()
to display help text in the Drupal UI.
Update hooks in Drupal are used for executing database updates or applying configuration changes during module updates. They ensure these changes occur once and in the correct order.
In this tutorial, we'll:
- Explore the purpose of update hooks.
- Learn how to implement update hooks for database updates or configuration changes.
By the end of this tutorial, you should be able to understand the use case for update hooks and know how to get started implementing one.
It's a Drupal best practice to always use Drupal's internationalization utilities for any user interface strings in your code. This includes the PHP t()
function and StringTranslationTrait
trait, the Twig t
filter, and the JavaScript Drupal.t()
function. This makes it possible for our module's interface to be localized.
In this tutorial, we'll:
- Edit the
WeatherPage
controller and use thet()
method from theStringTranslationTrait
trait for all UI strings. - Update the weather-page.html.twig template file to use the Twig
t
filter. - Modify the JavaScript in our forecast.js code to use the
Drupal.t()
function for UI strings.
By the end of this tutorial you should be able to update the PHP, Twig, and JavaScript code in your module to ensure that any user interface strings they output are translatable.
Entities are the building blocks of Drupal's data structures. As module developers, the Entity API provides a way to manage custom data with minimal code. You'll use it when altering or enhancing existing content or when managing custom data sets. Instead of writing SQL, you'll be using the Entity API to manage data within a Drupal application.
In this tutorial, we'll:
- Define entities and their significance in Drupal.
- Distinguish between content entities and configuration entities.
- Explore entity-related terminology such as bundles, fields, annotations, plugins, and handlers.
By the end of this tutorial, you'll have a foundational understanding of the Entity API and how it's used for data management in Drupal.
Validation happens whenever an entity is created or updated, ensuring data integrity across form submissions, JSON:API requests, and direct entity object manipulation. Drupal's Entity Validation API, consists of constraints, validators, and their integration. As module developer, we'll use this API to enforce custom rules about what constitutes valid data.
In this tutorial, we'll:
- Learn about the roles of constraints and validators within Drupal's validation system.
- See how to create and integrate custom validation rules.
- Apply custom validation to an entity type that enforces specific data integrity rules.
By the end of this tutorial, you should be able to define new constraints and validators, and associate them with entity types.