Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Themes and template overrides

A theme is responsible for the look of the site: page markup, styles and regions for blocks. A module decides what to output, and the theme decides how it looks. You create your own theme to change the templates of core and other modules without touching their files.

Where a theme lives

Your own themes live in web/themes/custom. A core script creates a skeleton. Run it from the web folder:

cd web
php core/scripts/drupal generate-theme blog_theme --path themes/custom
cd ..

The folder web/themes/custom/blog_theme appears — a copy of the core starter theme with ready templates and styles.

Enabling

vendor/bin/drush theme:install blog_theme
vendor/bin/drush config:set system.theme default blog_theme -y

The first command enables the theme, the second makes it the default one. The same is done in the panel, in the Appearance section. After that the site looks plain, almost without styles — that is expected for a skeleton.

What is inside

File or folderPurpose
blog_theme.info.ymlThe theme description: name, base theme, regions, libraries
blog_theme.libraries.ymlThe theme styles and scripts
blog_theme.themePHP functions: preparing variables for templates
templates/Twig templates
css/, js/Style and script files

In blog_theme.info.yml the theme has type: theme, and the base theme key names the theme whose templates are inherited. The regions key lists the regions blocks are placed into.

Overriding a template

To change markup, put a file with the same name as the original template into the templates folder of the theme. A node is output by the node.html.twig template. Let us make a separate template for articles only:

{# web/themes/custom/blog_theme/templates/content/node--article.html.twig #}
<article{{ attributes.addClass('article') }}>
  <h2><a href="{{ url }}">{{ label }}</a></h2>
  <div class="article__body">
    {{ content }}
  </div>
</article>

After drush cr articles are output with this markup and other content types with the old one. label is the title, url the address of the node, content its fields, attributes the tag attributes collected by Drupal and modules.

Name suggestions

Drupal goes through template names from the most specific to the general one and takes the first file it finds.

FileWhen it applies
node--5.html.twigOnly the node with number 5
node--article--teaser.html.twigAn article in teaser view
node--article.html.twigAny article
node.html.twigAny node
page--front.html.twigThe skeleton of the front page
block--system-branding-block.html.twigThe block with the logo

Which names fit a particular place on the page is shown by the Twig development mode from the installation lesson: the page source gets comments with the list of suggestions and the path of the file that was used.

The template of your own module is overridden the same way: a blog-card.html.twig file in the templates folder of the theme replaces the template from the blog module.

Preparing variables

A new variable for a template is added by a function in the blog_theme.theme file:

// web/themes/custom/blog_theme/blog_theme.theme
 
/**
 * Implements hook_preprocess_node().
 */
function blog_theme_preprocess_node(array &$variables): void
{
    $node = $variables['node'];
 
    $variables['created_date'] = date('d.m.Y', $node->getCreatedTime());
}

The node template gets a new variable: {{ created_date }} outputs the creation date. The function name is made of the theme name, the word preprocess and the template name.

Common mistake

Drupal notices a new template file only after drush cr: the list of templates is kept in the cache. Changes inside a file it has already found are visible at once if Twig development mode is on. And check the name: files use hyphens, and a double hyphen separates the refinement — node--article.html.twig, not node_article.html.twig.

Thanks for reading!

Donate to the site — we work hard for you.