CHAPTER 13

image

Theming Your Site Part 2: Creating a Custom Theme and Subtheme

Making your site look great is very important—to attract customers, to keep users engaged on your site, and more. This chapter dives down deep in how to knock your design out of the park, showing you how to properly approach theming in Drupal 8. In Drupal, the look of your site is referred to as the theme for your site, and you can easily switch between different Drupal themes to change the design of your site. This chapter teaches you how to create both themes and subthemes. You will create a custom subtheme using Bartik, which ships with Drupal 8, as the base theme.

Image Note  Actually, Bartik uses the Classy theme as its base theme; Bartik is just a subtheme itself. Although we’re using Bartik as the basis for our new subtheme, the true base theme of both the Bartik theme and our new theme will, in fact, be “classy.”

Creating a Subtheme

There are many Drupal 8 themes that can serve as a great base theme, from which you can then start creating subthemes. A Drupal subtheme allows you to declare an existing theme as the “base” theme. Then, by changing the subtheme, you can override certain aspects of the base theme. That means you can safely customize your theme to your heart’s delight to get the look your want for your web site. The base theme is helpful in not forcing you to re-create the wheel, while still allowing you to create a subtheme so you can get the exact final theme presentation you’re looking for.

Image Note  Technically speaking, you could just start hacking the base theme itself to your liking, but doing so means you will no longer be able to get updates to the base theme. And the base theme’s updates may contain security updates or other improvements you may want to adopt into your site. Therefore, when you want to customize a theme, it’s recommended that you work with a subtheme instead.

Let’s take a look at how to create a subtheme using the Bartik (classy) theme as the base. First, go to the ...core/themes directory and do an ls. You’ll see that out of the box Drupal 8 includes the Bartik, Classy, Seven, and Stark themes.

You need to make a copy of the Bartik theme to make it your new subtheme. Type the following at your Linux command prompt:

cp –r bartik ../../themes

You’ve now made a copy of the Bartik theme out of ...core/themes into the themes directory. Note that you can still also put themes in the ...sites/all/themes directory.

You’ll find a README.txt file in the themes directory, which says the following:

Place downloaded and custom themes that modify your site’s appearance in this directory to ensure clean separation from Drupal core and to facilitate safe, self-contained code updates. Contributed themes from the Drupal community may be downloaded at http://drupal.org/project/themes.

It is safe to organize themes into subdirectories and is recommended to use Drupal’s subtheme functionality to ensure easy maintenance and upgrades.

In multisite configuration, themes found in this directory are available to all sites. In addition to this directory, shared common themes may also be kept in the sites/all/themes directory and will take precedence over themes in this directory. Alternatively, the sites/your_site_name/themes directory pattern may be used to restrict themes to a specific site instance.

Refer to the “Appearance” section of the README.txt in the Drupal root directory for further information on theming.

You can see from this README.txt file that there are two places you can choose to put your themes: in the themes directory or in the ...sites/all/themes directory. In Drupal, one code base can service multiple web sites. This is known as a multisite Drupal instance. As the README.txt file says, you can employ a theme to be available for only one particular site within the multisite Drupal installation by placing your theme in the appropriately named directory, but by placing the theme in the ...sites/all/themes directory, the theme will be available for all Drupal sites even if within a multisite installation.

Image Note  You can read more about multisite installations at https://drupal.org/documentation/install/multi-site.

Once you copy the Bartik theme into the themes directory, you can start to modify it to become the Bartik subtheme. By creating the Bartik (classy) subtheme (shown in Figure 13-1), you’ll still be able to update Bartik (and Bartik’s base theme called Classy), which means you’ll still get all the fixes and updates—and, most important, all security updates. Doing so also keeps your subtheme modifications intact—that is, you won’t override your changes to the subtheme when you update the Bartik and Classy themes.

9781430264668_Fig13-01.jpg

Figure 13-1. The new Bartick (Classy) subtheme

Before you can customize the subtheme, you need to do a bit of housekeeping. I’ve copied all the files from Bartik in the . . . core/themes/bartik folder into a new folder I’ve called barnettechetJLB in the themes directory. This barnettechetJLB folder then houses my new Bartik subtheme. However, there are some filename changes that need to be made.

Every filename in the barnettechetJLB folder that has the word “bartik” in it needs to be changed to the new subtheme’s name: barnettechetJLB. (You can name your subtheme anything you like.) This means changing function names, which need to start with the theme’s name to be the new subtheme’s name (this occurs in the barnettechetJLB.theme file). That means that in the main barnettechetJLB.info.yml file, I declare the subtheme’s name as “barnettechetJLB.” Any file in this directory now belongs to the bartikJLB subtheme and not to the Bartik base theme.

It’s easy enough to go through all the files and change “bartik” to “barnettechetJLB.” To find any instance of the word “bartik” within the files, go into the barnettechetJLB directory and type the following command:

grep –lri "bartik" *

This command will recursively search (through all directories) through all files, look for the word “bartik,” and print a list of all files that need to be edited.

You’ll notice that this grep command, which is a search command really, includes the arguments –lri. The l means “don’t show the context of where the match was found—just tell me the filenames.” You can omit this argument (omit the l) if you prefer to see the context where the match was found. The r in the argument list says to look recursively through all subdirectories. The last argument, i, says to make the search case insensitive, so even if there’s an instance of the word “Bartik” with a capital “B” or any other letter in “bartik” capitalized, it will still show a match. The dash (-) after the grep command signifies that the argument list follows. You will need to keep the dash in there to use any of the arguments, although you can omit the dash if you are going to omit all the arguments.

Image Note  You can find these files on Github: https://github.com/barnettech/drupal8_book/tree/subtheme. I’ve also uploaded this basic Bartik subtheme to drupal.org: www.drupal.org/project/barnettechetjlb. I decided to use the same Github repository to store the example subtheme that I used for the Hello World example module files. You can clone the branches of the repository with the Hello World module into your ...modules/custom directory and then also clone the same repository into your themes directory (or ...sites/all/themes directory). Then, to look at the barnettechetJLB theme, just make sure you change branches to the “subtheme” branch to get the theme, or any of the other branches you like to see that version of the Hello World module.

After copying the files from the Bartik theme to create the barnettechetJLB subtheme, you need to identify a few of the templates that you will most likely want to override (i.e., templates where you don’t want to use the default look and feel that the Bartik base theme provides). So in the templates directory, you need to copy over the following files (see Figure 13-2):

  • page.html.twig
  • node.html.twig
  • maintenance.html.twig
  • comment.html.twig

9781430264668_Fig13-02.jpg

Figure 13-2. The template files copied from the bartik theme into the barnettechetJLB theme. These new template files will override those in the Bartik base theme templates folder

Now, when you want to override the look and feel for your own subtheme, you can make my changes directly to the copied files. The templates in the subtheme will always take precedence over the base theme template files. So a subtheme can allow you to use a base theme for the look of non-overridden elements yet allow for customization with overridden elements.

You can also copy over CSS (Cascading Style Sheet) files and then list them in the barnettechetJLB.yml file. The copies of the CSS files in your subtheme will override the styles in the base theme’s CSS files with the same filename. To override any CSS files, you’ll need to have it look as follows:

# Override a CSS file:
stylesheets-override:
  - css/color.css

In this case I’m overriding the color.css file from the Bartik base theme with the contents of the color.css file in the barnettechetJLB/css/color.css file.

To add new CSS files to the subtheme, I can add them to the lists in the barnettechetJLB.libraries.yml file. The libraries.yml file described here allows you to add assets like CSS files to a theme. (For more information, see the drupal.org documentation: www.drupal.org/theme-guide/8/assets.)

For the barnettechetJLB subtheme, I copied over some templates for later use, as stated earlier, but I did not yet modify them (https://github.com/barnettech/drupal8_book/tree/subtheme). I also copied over some CSS files, which I did modify. I added a background image to every page of the site to add some color, to liven up the theme a bit (see Figure 13-3).

9781430264668_Fig13-03.jpg

Figure 13-3. The barnettechetJLB.info.yml file marked up to show the changes I needed to make to the copied bartik.info.yml file I copied over from the ...core/themes/bartik folder while I was creating the barnettechetJLB subtheme

9781430264668_Fig13-04.jpg

Figure 13-4. The CSS file that I changed in the barnettechetJLB theme, making the new subtheme VERY unique!

I also added a background image to the header id in the colors.css file, as shown in Figure 13-5.

#header {
  #background-image:url('../images/sky-top-banner.jpg');
  background-image:url('../images/nature_wallpaper-normal-
  greyscale.jpg');
  background-repeat: repeat-x;
}

9781430264668_Fig13-05.jpg

Figure 13-5. Using Firebug to show the change in the CSS for the barnettechJLB subtheme

The id "main-wrapper" now has a background image, and the background image’s file is ../images/css-background-image-sky.jpg.

It’s possible, of course, to continue customizing the barnettechJLB theme, and eventually it could look much different from the base Bartik theme. By using a base theme that you like, you get to use Drupal again to provide much of the look and feel you like, and then the subtheme allows you to tailor the theme to better fit your needs and tastes.

Now that this section has laid the groundwork, you should be able to create and customize a new subtheme (using any base theme) without limiting your creativity.

Creating a New Base Theme

Creating a new base theme is similar to creating a new subtheme—assuming you choose to start by copying an existing base theme. By copying another base theme, you really are jumpstarting your efforts because you can use an existing theme as boilerplate code (as a template). Then, just as with a subtheme, you can customize it as you wish. The only difference is that you will not be overriding templates, CSS, and so on. Instead, your new base theme will become the primary code for the theme. Of course, you can still choose to create subthemes off of your own base theme if you like. The primary bit of code that decides if a theme is a base theme or a subtheme is within the themename.info.yml file. Figure 13-6 shows the Bartik theme’s bartik.info.yml file.

9781430264668_Fig13-06.jpg

Figure 13-6. The bartik.info.yml file shown in the MVIM editor (my favorite code editor on a MAC; it’s not user friendly, but it’s very developer friendly)

By comparison, Figure 13-7 shows the extra line in the barnettechetJLB.info.yml file:

base theme: classy

9781430264668_Fig13-07.jpg

Figure 13-7. The barnettechetJLB.info.yml file with the extra line declaring itself a subtheme of Bartik

This one line tells Drupal to look to “classy” to be the base theme, which then makes the “barnettechetJLB” a subtheme of the base theme. (Remember that Bartik also uses Classy as its base theme; Bartik is itself just a subtheme of Classy.)

So far, this chapter has explained the mysteries of theming in Drupal. You’ve learned about base themes and subthemes. Just knowing about creating themes can take you quite far on your road toward creating a great-looking web site. The next section speaks about what theme functions are and how to override them.

Overriding Existing Theme Functions

Now that you have your own custom subtheme, we can continue with the discussion about overriding theme functions. Overriding theme functions is usually done within the theme, and because you don’t want to hack a base theme, it’s better to start overriding theme functions in a subtheme that you’ve created. You created your own theme function in Chapter 12, which others can override without having to hack your module when they would like to customize the look of your module’s output.

Drupal core ships with lots of theme functions, and community-contributed modules (known as contrib modules in Drupal circles) typically have theme functions. How do we override them? You will first learn to override a theme function in your theme’s your_theme_name.theme file (in Drupal 7 and prior versions this was the template.php file).

Image Note  The template.php file is no longer in Drupal 8; it is now the your_theme_name.theme file. For all intents and purposes, it works exactly the same; only the filename is different.

All you do is make a function in your your_theme_name.theme file. But instead of saying theme_username($variable), which is the original name of the username theme function (as you can see defined here: https://api.drupal.org/api/drupal/core%21modules%21user%21user.module/function/theme_username/8), you name your function instead in your your_theme_name.theme file: your_theme_name_username($variables).

You will have the same $variables available to you, but you can override the look of usernames throughout your site in this manner (remember, we are overriding theme_username). So go and find your custom subtheme within the ...sites/all/themes directory or themes directory. I’ll continue to use the bartikJLB subtheme I created earlier in this chapter. Within the bartikJLB subtheme, I find my bartikJLB.theme file. Go to the bottom of the bartikJLB.theme file and paste in the following code:

use DrupalComponentUtilityString;
use DrupalComponentUtilityXss;
use DrupalCoreTemplateAttribute;
use DrupalCoreUrl;

function barnettechetJLB_username($variables) {
  if (isset($variables['link_path'])) {
    // We have a link path, so we should generate a link
    // using l().
    // Additional classes may be added as array elements like
    // $variables['link_options']['attributes']['class'][] =
'myclass';
    $output = Drupal::l($variables['name'] . ' is awesome ' .
$variables['extra'], Url::fromUri('base://' . $variables
['link_path']));
  }
  else {
    // Modules may have added important attributes so they must
    // be included in the output. Additional classes may be
    // added as array elements like
    // $variables['attributes']['class'][] = 'myclass';
    $output = '<span' . new Attribute($variables['attributes']) .
'>' . $variables['name'] . $variables['extra'] . '</span>';
  }
  return $output;
}

Notice this is the same code as you find on the drupal.org page documenting theme_username (see Figure 13-8): https://api.drupal.org/api/drupal/core%21modules%21user%21user.module/function/theme_username/8. This code is actually defined in your Drupal installation in the user module. The only difference is I’ve added the “is awesome” text, so every user is declared as awesome anytime his or her username shows in the web site.

9781430264668_Fig13-08.jpg

Figure 13-8. Documentation on drupal.org for theme_username. I copied the code from this drupal.org page into the barnettechetJLB.theme file and modified it a tiny bit

Image Note  This is a simplistic example, but in real life knowing how to override theme_username can prove very useful. In a current site I’m working on, for example, we’ve overridden theme_username to show a chat bubble next to everyone’s name. We also have some great JavaScript from the strophe.js JavaScript library and we use the jabber module (which I’ve written) helping us to show if a user is online or offline in Google’s gtalk service.

So now with the new barnettechetJLB_username function in the barnettechetJLB.theme file, the page of a node I just created looks like Figure 13-9. You can see that every time a username is printed to the screen, it instead adds that the user “is awesome”!

9781430264668_Fig13-09.jpg

Figure 13-9. With the customized theme_username function, the output of all usernames on the page is altered with “is awesome”

You can find a list of theme functions in Drupal 8: https://api.drupal.org/api/drupal/core%21modules%21system%21theme.api.php/group/themeable/8. Remember, every downloaded contrib module will likely have its own theme functions as well. I encourage you to not hack modules and Drupal core but to instead override theme functions in your custom theme or subtheme, whenever possible. I find it almost never necessary, and it is not encouraged because you will find yourself overwriting your hacks when you update your modules and Drupal core. If you do need to hack Drupal and you’re absolutely sure it’s necessary, others may find the same problem you have. When that’s the case, you should submit your “hack” as a patch to drupal.org as a suggested update for all to enjoy (www.drupal.org/patch).

Exploring Other Options for Overriding Theme Functions

Another thing you often might do to override the output of another module’s theme function is to copy the template file from that module’s directory, if there is one, into your own theme’s templates directory. By making the copy of the template in your templates directory, your copy in your theme will now take precedence over the template file in the downloaded contrib module that came as the default.

Also, you can override a theme function in a module. Many prefer to override a theme function in a module so that the theme file (in my case, barnettechetJLB.theme) doesn’t get enormous. To override a theme function in a module, you will need to use the hook_theme_registry_alter function, as defined at https://api.drupal.org/api/drupal/core%21modules%21system%21system.api.php/function/hook_theme_registry_alter/8) and shown in Figure 13-10.

9781430264668_Fig13-10.jpg

Figure 13-10. Documentation on drupal.org for hook_theme_registry_alter to override theme functions from other modules in your own custom module

At Babson College we have some code that uses that function to override the theming of the forums, which is a centerpiece of one of our web sites. We basically throw out the theme function that ships with a module, and we completely replace it with the look and feel that our faculty and students prefer. You can see the code in Figure 13-11, which I’ll soon be porting over to Drupal 8 from Drupal 7.

9781430264668_Fig13-11.jpg

Figure 13-11. The hook_theme_registry_alter function in use in a site at Babson College

The babson_forums_theme_registry_alter function you see in Figure 13-11 overrides the theme function sts_commons_forum_view_topic. It first tells the system the path to find the new theme function being used instead.

$path = drupal_get_path('module', 'babson_forums');
$theme_registry['sts_commons_forum_view_topic']['theme path'] =
$path;

Then, the next bit of code defines the theme function that will be called instead of the one that shipped with the module.

$theme_registry['sts_commons_forum_view_topic']['function'] =
    'babson_forums_hold_the_bloat';

The function name that will be called instead to form the output of this theme function will be babson_forums_hold_the_bloat. The function has a funny name because at the time the code was created, this one page on our site was loading up very slowly in a browser. This function was created to override the default one that came with the module. The new function was called “hold the bloat” to try to right the wrongs of the overridden code, which had a lot of bloat and was causing major slowdowns to the site.

Overriding theme functions can be essential in succeeding to make your employer or client happy, and it can mean the difference between having just a canned Drupal site and having a site that really is tailored to the site audience’s needs and makes for a really great user experience (UX).

Summary

This chapter showed you how to create a custom theme and how to create a subtheme in Drupal. The drupal.org community recommends creating subthemes rather than hacking any existing downloaded theme, and it holds the same for overriding module code. Doing things the right way means that when you update Drupal or a module or theme within Drupal your changes won’t be overwritten. You’ll be able to customize and extend Drupal to your heart’s content, without missing out on the new great updates to code you’ve been enjoying through drupal.org.

This chapter also spoke about creating your own base theme. After establishing how to create a theme or subtheme, I showed you how to override theme functions. Overriding theme functions in your theme or in a custom module is the proper way to override the output from a module to make it your own, to customize the look and feel, and to get things exactly as you need them to create a great user experience.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset