Yes, I’ve finally got around to digging my mitts into Drupal 8, and building custom themes for Drupal 8. I have this bare-bones starter theme called Clarus that I developed back in the day when I was theming Drupal 7 sites willy-nilly. I thought I’d keep it, and develop a Drupal 8 branch rather than start a new project.
Drupal 8 has undergone quite a significant revamp under-the-hood, and the folder structure has changed quite a bit. Instead of placing your themes in the sites/all/themes folder, all user-created themes go into the themes folder. Well, that’s an upgrade on the intuitive-ness front.
The documentation for theming Drupal 8 is really good, and you should read that before anything else if you’re planning to do this custom theming thing. I generally follow whatever the guide says with a couple tweaks to suit my personal preferences.
Folder structure
As mentioned, all non-core themes should be placed in the
Speaking of organisation, it's best to create some subfolders inside your custom theme folder as well. I use Sass as part of my workflow, so I have an
godzilla/
├── css
├── js
├── scss
└── templates
The .info.yml
file
A key difference from Drupal 7 is the extensive use of .yml
for a lot of configuration. Instead of the .info
file in Drupal 7, we now use a .info.yml
file, which serves the same purpose, just in a different format. This file goes into the root of your theme folder.
The theme folder and this file should have the same name. Theme names have to be unique, so check that you don’t clash with any modules you’ve installed. Theme names cannot have spaces in them. It’s a PHP function thing.
I’ve used a LOT of Jekyll over the years, so YAML is not a problem for me. But if you’re completely new to YAML, try reading some documentation first. Here’s a cheatsheet-style summary and a basic introduction. Remember that tabs are not allowed in YAML, only use spaces, and the rule of 2-space indentation must be strictly followed.
Every time you make a change to the .info.yml
file, you must also clear your cache to see the changes. There are seventeen key/value pairs that can be used to provide information and configuration options for your theme. Only three are required, though some of the optional ones are very useful to include as well.
name (required)
Defines the human-readable version of your theme name. This is the name that shows up on the Administration > Appearance screen. Because this serves as a label for your theme, you're allowed to use spaces, but put them in quotes if you do.
name: 'Godzilla is rox'
type (required)
For the purposes of theming, this should always be set to theme.
type: theme
description
Optional but recommended to have. This is a brief description of your theme, which shows up below your theme name on the Administration > Appearance screen.
description: 'A custom responsive Godzilla-based theme'
core (required)
Indicates what major version of Drupal the theme is compatible with. If this does not match the version of Drupal installed, the theme will be disabled.
core: 8.x
libraries
I don't really understand why this is optional, because it seems quite mandatory to me. Anyway, instead of defining stylesheets and scripts like we did in Drupal 7, these assets are now defined in a separate THEME_NAME.libraries.yml
file, and reference entries in that file here.
libraries:
- godzilla/global-styling
This concept of an asset library is based on the premise that CSS and JS for modules and themes are all loaded via the same system. Part of improving the performance of Drupal 8 is to have assets load only if you tell them to, so not everything is loaded on every page.
For this bit, I strongly recommend reading the documentation, because it goes really in-depth on how this new asset library system works. Here’s how a THEME_NAME.libraries.yml
file looks like:
global-styling:
version: 1.x
css:
theme:
css/styles.css: {}
js:
js/scripts.js: {}
regions
Optional and will default to the list below if not specified. Regions are what shows up in the Administration > Structure > Blocks screen. Refer to the official documentation for a comprehensive explanation on defining regions in your theme.
regions:
sidebar_first: 'Left sidebar'
sidebar_second: 'Right sidebar'
content: 'Content'
header: 'Header'
primary_menu: 'Primary menu'
secondary_menu: 'Secondary menu'
footer: 'Footer'
highlighted: 'Highlighted'
help: 'Help'
breadcrumb: 'Breadcrumb'
base theme
The documentation recommends using Classy or Stable as a base theme because then you get all the pre-defined CSS classes written into those themes. If you're a sucker for punishment, like me, and just want to have absolute control over all your CSS classes, you can always set this to false
, then your theme will have ZERO CSS classes. From there, you can add Twig templates to customise your CSS classes exactly the way you want to.
base theme: OTHER_THEME
The full list of all options available for the .info.yml
file can be found here. A sample .info.yml
file would look something like this:
name: 'Godzilla is rox'
type: theme
description: 'A custom responsive Godzilla-based theme.'
core: 8.x
base theme: false
libraries:
- godzilla/global-styling
regions:
header: Header
content: Content
footer: Footer
Twig template files
PHPTemplate has now been replaced by Twig, so instead of *.tpl.php
template files, they are now all *.html.twig
template files. But the underlying mechanism of overriding templates with increasing specificity (based on naming convention) still apply in the world of Drupal 8. How this works is covered right here.
I’m not going to repeat the documentation, but I have to mention the most useful feature my noob ass fell in love with. Twig debugging! But before that, I hope you have a settings.local.php
file already, because that’s good practice, folks. Drupal 8 has a pretty aggressive caching strategy, which is great for performance, but a bit of a hassle during development. But that’s what development settings are for.
First of all, we need Drupal to recognise your local development settings file. Check your settings.php
file for these lines, and make sure they are uncommented:
if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) {
include $app_root . '/' . $site_path . '/settings.local.php';
}
Now, check in your settings.local.php
file. If you made a copy from the example.settings.local.php
file in the sites folder, then you should see this line somewhere in there:
$settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.services.yml';
Make sure it’s uncommented. This tells Drupal to recognise the development services configuration. If you can’t find it, add it in there. The development.services.yml
file comes by default and should be in your sites folder, you shouldn’t have to create it.
The default development.services.yml
file 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
services:
cache.backend.null:
class: Drupal\Core\Cache\NullBackendFactory
You need to add some twig configuration to the parameters block like so:
# 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
This has activated twig debug mode, which means that if you check DevTools, there will be a bunch of comments that tell you which template is loaded as well as the file name suggestions you can use. This is pretty helpful for when you realise you need to add or change classes during the course of developing your theme.
Now you can start CSS-ing
Like I mentioned before, those of you who write plain vanilla CSS are free to start theming away. If you happen to use a workflow that involves Sass and gulp, I cover that bit on my updated theming Drupal with gulp post. Oh, and don’t forget to take a screenshot of your theme, name it screenshot.png
and place it in the root of your theme folder. Just makes things look nicer. Happy Drupal-ing!