Coding

Creating a custom theme in Drupal 8/9

Published by Alan Saunders on Tuesday, April 13, 2021 - 23:00

Reading Time: 7 minutes

Sections

Title
Introduction

Body

In this blog post, I will be talking about the basic elements of a Drupal 8/9 theme. 

For this blog post, I do assume that you have knowledge of css and html, as this blog post should allow you to get to the point in which you just need to add what templates, styling and html that you need. We will also look briefly at twig, but twig is quite a broad subject in itself.

First of all, we need to create a folder for our theme to sit in, the theme can sit inside the themes folder in the Drupal 8/9 installation, but I prefer to denote which themes are contrib and which themes are custom and create a folder for our custom theme inside the custom folder. For the purposes of this blog post, I created a folder called custom_theme.

One thing that we won't be looking at is using installing configuration relating to theme when the theme is installed.

Title
The info.yml file

Body

Just like creating a module, we need to tell Drupal that we have added a new theme, so we need to create a file inside our theme folder that we just created above, the file name should be in the format of: [theme name].info.yml, so in the case of this blog post, the file we have is called custom_theme.info.yml.

The file starts off in a similar manner as a .info.yml file for a module, in the sense that we specify a; name, optional description and a package, we also need to set the type, but whereas we specified module as a the type, we need to specify theme as the type for this, so that Drupal knows that we are adding a theme.

We also specify the core_version_requirement, so that we can enable the theme in Drupal 9, the core element is not needed if you don't want the theme to be installed on Drupal versions less than 8.7.7. Next thing to set is a library, this will bring in our css and js files, that we will setup later on, so don't worry too much about this just now, we can also attach a library to pages via other means, but we won't get into that in this blog post.

Next we set if the theme is sub theme of any one of the base themes, which can be one of the core themes or a contrib theme, equally you can set this key to false. The base theme key was optional in Drupal 8 but required in Drupal 9.

Finally we are going to setup a number of regions that we can use in our theme for adding blocks etc too. Drupal uses regions to allow developers to structure the pages of the site. There are lots of other elements that you can add, have a look at: https://www.drupal.org/node/2349827.

Below is the contents of our [theme name].info.yml that we created for this blog post.

name: Custom theme
type: theme
description: 'My Awesome theme'
package: Other
core: 8.x
core_version_requirement: ^8 || ^9
libraries:
  - custom_theme/global-styling

base theme: bootstrap

regions:
  navigation: Navigation
  navigation_collapsible: Navigation (Collapsible)
  header: Top Bar
  highlighted: Highlighted
  help: Help
  content: Content
  sidebar_first: Primary
  sidebar_second: Secondary
  footer: Footer
  page_top: Page top
  page_bottom: Page bottom

Title
[theme name].libraries.yml

Body

The next step is to tell Drupal where the custom styling and javascript files may be. This can be done in one of two ways, one is by using the hook hook_page_attachments. The other option is to create a yml file with the name of [theme name].libraries.yml and the syntax for defining the js and css can be seen below.

global-theme:
  css:
    theme:
      presentation/scss/css/style.css: {}

  js:
    js/theme.js: {}

Title
[theme name].breakpoints.yml

Body

You can use the [theme name].breakpoints.yml file to add extra breakpoints in for responsive website purposes, this is useful if you have some specific breakpoints that you need your theme to be able to work on.

The core breakpoint module reads the contents of the breakpoints yml files and adds them to the site's configuration. It is at this point that, other installed modules and themes can access this configuration and utilise it in their own functionality.

The core responsive image module utilises the breakpoint module. Lullabot has a nice blog post talking about this file, check it out here. However, it does seem a bit of work, when you can have the breakpoints set in your theme styling instead, but definitely useful if you want to tie your theme into some of the core functionality of Drupal.

Title
Twig Templates

Body

To make our pages output the markup/ content that we want, we need to create twig templates in our theme.

Twig was one of the other major changes that was brought in in Drupal 8, which saw the switching of the theme engine from PHP Template to Twig. Twig is a very established and quite popular templating engine, allowing for easier adoption and sharing some of maintenance/ improvement load onto a wider community.

The twig templates go inside a folder called templates inside theme folder, for ease and good practice you can also split up the different types of templates into folders. For example any node template files could sit in a folder called node.

The basic naming convention for a twig template is to end the file name in .html.twig, so that Drupal can recognise and use the file. Depending on what you are doing whether it be theming a node content type or a view, you can use templates that match your needs and you target specific elements like views or content types etc by naming the twig templates in a certain way. There are lots of useful information on this on drupal.org.

Twig is very broad topic and has a lot of different syntax to think about, so below are some links that can be used for further reading

The main thing is that instead of using php in the template file, you need to use the twig syntax. For example in Drupal 7, you may have a template that outputs a variable like:

<?php print $variable_name; ?>

But in twig, the same variable would be output like:

{{ variable_name }}

Another site with lots of useful information on twig is: https://www.ostraining.com/blog/drupal/twig/.

You can also create custom twig templates in your custom modules, further information can be found here. Plus with the various hooks that Drupal has, you can use the preprocess hooks to populate custom twig variables as well altering the naming of the twig templates.

Title
.theme

Body

In Drupal 7, you could create a file called template.php, the [theme name].theme is the Drupal 8 equivalent. The .theme is a php file essentially and the purpose of the .theme file is to store functions (hooks) that relate to the theme, mainly the pre process hooks that are used to affect the markup/ output of nodes/ taxonomy terms/ users or any other entities.

Title
Drupal console

Body

Below are the drupal console commands used to generate the skeleton theme files.

$ drupal gt

// Welcome to the Drupal theme generator

Enter the new theme name []:
> Custom theme

Enter the theme machine name [custom_theme]:
>

Enter the theme Path [themes/custom]:
>

Enter theme description [My Awesome theme]:
>

Enter package name [Other]:
>

Enter Drupal Core version [8.x]:
>

Base theme (i.e. classy, stable) [false]:
> bootstrap

Enter the global styling library name [global-styling]:
>

Do you want to add another library? (yes/no) [yes]:
> no

Do you want to generate the theme regions? (yes/no) [yes]:
>

Enter region name [Content]:
> Navigation

Enter region machine name [navigation]:
>

Do you want to add another region? (yes/no) [yes]:
>

Enter region name [Content]:
> Navigation (Collapsible)

Enter region machine name [navigation_collapsible]:
>

Do you want to add another region? (yes/no) [yes]:
>

Enter region name [Content]:
> Top Bar

Enter region machine name [top_bar]:
> header

Do you want to add another region? (yes/no) [yes]:
>

Enter region name [Content]:
> Highlighted

Enter region machine name [highlighted]:
>

Do you want to add another region? (yes/no) [yes]:
>

Enter region name [Content]:
> Help

Enter region machine name [help]:
>

Do you want to add another region? (yes/no) [yes]:
>

Enter region name [Content]:
>

Enter region machine name [content]:
>

Do you want to add another region? (yes/no) [yes]:
>

Enter region name [Content]:
> Primary

Enter region machine name [primary]:
> sidebar_first

Do you want to add another region? (yes/no) [yes]:
>

Enter region name [Content]:
> Secondary

Enter region machine name [secondary]:
> sidebar_second

Do you want to add another region? (yes/no) [yes]:
>

Enter region name [Content]:
> Footer

Enter region machine name [footer]:
>

Do you want to add another region? (yes/no) [yes]:
>

 Enter region name [Content]:
 > Page top

 Enter region machine name [page_top]:
 >

 Do you want to add another region? (yes/no) [yes]:
 >

 Enter region name [Content]:
 > Page bottom

 Enter region machine name [page_bottom]:
 >

Do you want to add another region? (yes/no) [yes]:
> no

Do you want to generate the theme breakpoints? (yes/no) [yes]:
> no

Do you want proceed with the operation? (yes/no) [yes]:
>

Generated or updated files
Generation path: /var/www/sandbox/web
 1 - /themes/custom/custom_theme/custom_theme.info.yml
 2 - /themes/custom/custom_theme/custom_theme.theme

Like mentioned in previous blog posts, Drupal console doesn't make the info.yml Drupal 9 ready, so you need to manually update the file to include the following new line:

core_version_requirement: ^8 || ^9
Categories:

Related blog posts

Kint

Authored by Alan Saunders on Sunday, May 16, 2021 - 19:00
Reading Time: 2 minutes

Creating custom content entities in Drupal 8/9

Authored by Alan Saunders on Wednesday, March 24, 2021 - 22:00
Reading Time: 7 minutes

Creating custom tokens in Drupal 8/9

Authored by Alan Saunders on Sunday, January 17, 2021 - 10:00
Reading Time: 8 minutes