Last updated October 29, 2018
Theming8.6.x

Making Drupal fast by default implies having caching layers and CSS and JavaScript aggregation utilities enabled out-of-the-box. As a theme developer this can be annoying, because you must clear these various caches in order to preview any changes. In addition, inspecting variables with debugging tools often produces PHP errors. We'll make some recommendations for PHP settings on your local environment that can prevent these errors from happening so often.

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

  • Set up your local Drupal site for theme development
  • Prepare your local development environment for working on and debugging themes

Goal

Access theme information in HTML comments for every template on a page and output variable debugging information for any active template file.

Prerequisites

  • None

Configure Your Environment for Theme Development

Before enabling the Twig engine's debug mode you'll probably want to start with disabling Drupal's render cache. The first time Drupal renders an element, it uses the Twig template, and caches the resulting HTML output. Any subsequent request for the rendered version of that element is filled from the cached data, until the cache is invalidated. Disable render caching in order to bypass this cache and use the theme layer every time an element is rendered. If you don't, changes to the Twig template associated with an element will not be displayed until the cache has been cleared.

Flow chart showing how render api and themes find template files

The above diagram shows the process used to determine where HTML is retrieved from when rendering an #element.

Disable render caching and JavaScript/CSS aggregation

Both render caching, and JavaScript/CSS aggregation can be disabled by making modifications to configuration variables in your settings.php file.

In addition, aggregation can be turned off in the UI by navigating to Configuration > Performance (admin/config/development/performance).

When setting up a development environment, change these settings directly in your settings.php file. (This is the preferred method.) The best way to do this is to enable the use of a settings.local.php file. Then put your environment-specific settings into this local file. From there, you can also include the development.services.yml file that comes with core, and use that as a location for your environment-specific services settings.

Follow these steps to disable render caching and CSS/JavaScript aggregation:

Edit your settings.php file

Edit your sites/default/settings.php file and un-comment the code that includes an optional settings.local.php file. Make sure this code is at the bottom of your settings.php file so that local settings can override default settings.

The code at the bottom of your sites/default/settings.php file should look like this:

if (file_exists(__DIR__ . '/settings.local.php')) {
  include __DIR__ . '/settings.local.php';
}

Copy example.settings.local.php

Copy copy sites/example.settings.local.php to sites/default/settings.local.php, and clear the cache.

Use settings.local.php

Drupal will now locate your sites/default/settings.local.php file, if it exists, when sites/default/settings.php is loaded. Since the local settings file is loaded last, any variables set there will override settings in the default file.

Use development.services.yml

Using the sites/default/settings.local.php file will also include and use sites/development.services.yml.

Uncomment lines in settings.local.php

Ensure that the following lines are uncommented by removing the # character from the beginning of the line.

This first set disables the CSS and JavaScript aggregation features.

$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;

And uncommenting this line effectively disables, or rather, bypasses the Render API cache:

$settings['cache']['bins']['render'] = 'cache.backend.null';

This disables Drupal's Render API caching by telling Drupal to use the cache.backend.null cache service instead of the default. This new service is defined in the sites/development.services.yml and essentially returns a MISS for every cache request, thus bypassing the Render API cache.

Note: One point of possible confusion is that on the admin/config/development/performance page, in the Bandwidth Optimization settings, the checkboxes to enable CSS and JavaScript aggregation remain checked, even if you have turned these values off in sites/default/settings.local.php. So how do you know if your development settings are working? View source on your site's home page and if you see a long list of CSS files with recognizable names, aggregation is turned off. If you only see a few CSS files with filenames consisting of a bunch of random characters, then aggregation is on. Same goes for JavaScript files.

Enable Twig debugging options

Enabling Twig debugging involves locating the twig.config[debug] settings in your services.yml file and changing their values.

These variables can be edited either directly in sites/default/services.yml or added to the sites/development.services.yml file if you followed the steps above to use a settings.local.php file.

Edit the following variables under the twig.config: section:

debug: true
auto_reload: true
cache: false

If you're placing this into your sites/development.services.yml file, add the twig.config configuration indented under the parameters: line. Ensure that your code additions are appropriately indented with 2 spaces, not the tab character (or an error will result).

parameters:
  twig.config:
    debug: true
    auto_reload: true
    cache: false

From a fresh install of Drupal and with the twig.config additions, the sites/development.services.yml file now looks like this:

# Local development services.
#
# To activate this feature, follow the instructions at the top of the
# 'example.settings.local.php' file, which sits next to this file.
parameters:
  http.response.debug_cacheability_headers: true
  twig.config:
    debug: true
    auto_reload: true
    cache: false
services:
  cache.backend.null:
    class: Drupal\Core\Cache\NullBackendFactory

Note: This can also be done via the Drupal console command: drupal site:mode dev. Running this command will toggle all the Twig settings outlined above to their debugging state. However, this will make changes directly to your sites/default/services.yml file, and not the development.services.yml which is arguably a better place for these settings.

Check to make sure twig debug mode is on

View source of any page on a local install of your Drupal site and you should see new HTML comments with information about template names and theme debugging information. For example:

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'html' -->
<!-- FILE NAME SUGGESTIONS:
   * html--node--2.html.twig
   * html--node--%.html.twig
   * html--node.html.twig
   x html.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/classy/templates/layout/html.html.twig' -->

Try clearing/rebuilding the cache if you've completed the above steps but don't see these theme debugging HTML comments yet.

Twig debug settings

twig.config:
  debug: true
  auto_reload: true
  cache: false

This is what each of the Twig debug settings is used for:

debug
(boolean) Enable various debugging features in the Twig engine.
auto_reload
(boolean) When set to true, Twig will automatically recompile all templates when their source code changes.
cache
(boolean) Disabling the Twig cache by setting this to false will recompile the templates from source each time they are used. In most cases the auto_reload setting above should be enabled rather than disabling the Twig cache.

With Twig debugging enabled, changes you make to your theme should show up the first time you refresh the page.

PHP settings

Inspecting variables in a template file is often a PHP-memory-intensive task. You may encounter a white screen with no helpful information when trying to access a page containing a template with debugging information. This white screen often indicates a fatal PHP memory limit error or maximum execution time limit if you're inspecting many variables in a template file at once with Twig {{ dump() }}. Variables, especially with Drupal's render arrays, often contain extensively nested arrays and objects. You can view these errors (instead of a white screen) by adding or changing some configuration in your local environment's php.ini file.

Recommendations:

  • Increase the PHP memory_limit value on your localhost to at least 128M.
  • Increase the PHP max_execution_time value to at least 60 (seconds).
  • Set error_reporting to E_ALL so that all errors are caught.
  • Set display_errors to TRUE so that PHP errors are displayed, instead of a white screen.
  • Set display_startup_errors to display any errors during PHP's startup sequence.
  • Set html_errors to 1 so that errors contain HTML tags and contain clickable links, making errors more readable and useful.

Your localhost php.ini would then contain the following values:

memory_limit = 128M
max_execution_time = 60
error_reporting = E_ALL
display_errors = TRUE
display_startup_errors = TRUE
html_errors = 1

You may need to increase the memory_limit (trying increasing by 128M at a time) or max_execution_time (trying increasing by 30 seconds at a time) if you're still running into memory limit errors.

To learn more about the implications of increasing the memory limit and the trade-off it has with concurrent processes, see this page on Drupal.org: Changing PHP memory limits.

Tip: If {{ dump() }} or its alternatives are producing memory limit errors, try {{ dump(_context|keys) }} instead to discover the variable keys. Then inspect the keys one at a time with {{ dump(variable_key) }}.

Debugging tools

There are several Drupal modules available for theme debugging.

  • Devel project, which provides Kint (and other modules)
  • Twig Vardumper, an alternative to Kint

Download and install the Devel module which provides some additional options, including a replacement for the Twig {{ dump() }} allowing you to use {{ kint() }} and {{ kint(var) }} for variable inspection.

An alternative to Kint is Twig Vardumper, a module which, when installed and enabled, replaces Twig's {{ dump() }} output and also provides a {{ vardumper() }} function to inspect variables.

Learn more about installing and using these tools to inspect variables in this tutorial:

XDebug

We also recommend enabling XDebug on your localhost and using it for debugging a theme or module. To install XDebug, see the documentation. Your local PHP installation may already have XDebug installed. Learn how to use XDebug to inspect variables here or learn more about how XDebug displays PHP variable information here.

Recap

In this tutorial, you learned how to configure your local environment for theme development and template debugging. There were several facets to this configuration including enabling Twig debugging and turning off various caches in your local Drupal site's settings and services configuration files, editing some PHP variables to show errors, optimize variable inspection, and increase memory limit and max execution time, and installing various tools such as Devel, Kint, Twig Vardumper, and XDebug.

With these tools and the above configuration in place, you are ready to discover theme hook suggestions and inspect variables available in a template file.

Further your understanding

  • Why should you use a settings.local.php file instead of just editing settings.php directly?
  • In which file do I change the settings that enables the Twig engines debugging output?
  • Enable theme debugging for your own development environment and poke around a bit. What changed?

Additional resources