fromMarch 2011
Feature:

PSD to Drupal 7 Theme

Part 1
3

The problem with creating a Drupal theme is —once you know how—it becomes intuitive. Themers spontaneously transform design files into complete Drupal themes without realizing all of the little steps their brain takes to achieve the final solution. It's sort of like those “learn to draw a cat” books where it takes you from a basic circle to a cat with beautiful fur in four simple steps. It's never four complete simple steps though. It's two steps of making circles and then some kind of crazy artist voodoo that makes a complete cat by the last step.

There are five key concepts you need to know before you can start making Drupal themes effortlessly:

  1. Web pages are an assembly of page elements.
  2. Default markup is provided for every page element.
  3. Your theme should include only what you want to change from the default markup provided by the modules you've installed.
  4. Base themes provide “better” default markup.
  5. CSS Grid Frameworks make theme building a lot easier.

Simple, right? Let's take a closer look.

Drupal modules create a series of HTML snippets which are combined (or “rendered”) into a finished Web page. When creating themes you change the markup and the placement of PHP variables within template files to alter the fragments of a Drupal Web page. Every time a Drupal Web page is requested, programmatic functions burst into action and create fragments of HTML that we see as Web page elements. Each theme-related function is responsible for either creating the HTML of a different page element or gluing together the fragments to create a whole Web page.

The module functions responsible for each of the bits of HTML provide suggested markup as well as a a set of tools a theme can use to create alternate markup.

Design files depict Web pages, not page elements. You cannot convert a Web page into a page element without first breaking it apart into its component pieces. Expert themers look at design files and see the page elements they will need to create in order to replicate the design in Drupal.

The scope of Drupal page elements varies. When theming you may need to deal with single elements such as a page title, or a group of elements such as a region which contains many blocks. To be successful at creating Drupal themes you need to “see” these elements in your design files and relate them to the rendered HTML fragments that make up a Drupal page.

For more help with this concept, refer to the tutorial at:
http://www.designtotheme.com/tutorials/seeing-drupal-template-variables

Your theme's job is to override any Drupal module markup that you don't like. Well-written modules allow themes to easily alter the markup through the use of template files (tpl.php). Themes can only redecorate page elements created by modules by changing the HTML and adding CSS—they don't inject new data into the database—that's a module's job.

A theme uses template files to override the snippets of HTML you see on a rendered page. Each template file has a very specific responsibility and can only change the page elements it is responsible for. This means you cannot alter the formatting for the the primary links in the template file for blocks. Nor can you alter the layout of a node from within the page template file.

A watershed is similar to a Drupal theme: lots of tiny creeks tumble into rivers which flow into oceans. The fish and the frogs and the lily pads have access only to their own creek and each creek is home to a different set of page elements. It's where they live. But the water flows downstream and gets bigger and broader and eventually tumbles into the ocean—the rendered HTML page a Web site visitors sees.

Like in a watershed, the following diagram has several branches of page elements all leading into the ocean that is the “rendered page.” See how some elements are made of lots of parts but others aren't? Find the “node” and work upstream. Can you get to the Login
Block from the Node? No, you can't.

When you are building themes you may change as much, or as little, as you'd like from this watershed picture. Do you want to change only the layout of the page? No problem. Your theme can contain one simple template file responsible for the the revised layout. Do you want to change the markup for the search block as well? No problem. Just add a new template file.

Your theme is finished when you've added as many template files as are necessary to change the default behavior of each of the page elements you want to change. No more, and no less.

Planning the Theme

Whether you scratch them out on paper, or create gorgeous and formal-looking diagrams with Illustrator, you must decide how your page elements fit together before you start wasting time decorating a page in your favorite graphics program. And let's face it—if you don't have a plan you aren't designing a site—you are just decorating.

If you already have a finished design that you're just trying to convert, do not skip this step. It's cheap and easy to make changes at this stage. It gets exponentially more expensive to make changes the further you get into the process. This little brainstorming session is going to ensure you can build a successful Drupal theme. If, at this stage, you find out that things are laid out in an “impossible” manner you can tweak your design to reflect how the data is actually stored in your site, or change the way you're building your site so that the theme can look the way you want.

Web Site Specifications

To create a Drupal theme you will need to know what “stuff” is going to appear on your site. To do this you need to do a site inventory of the features your site has and the modules that are used to build these features. From there you can isolate page elements which you will theme. That's a lot of italics. I know it looks scary—but stay with me.

Open up a spreadsheet. Down the left hand side write every single feature your site is going to have. For example: Events calendar, Gallery, Forum, Directory of Member Organizations, User profiles, and Embedded videos. In the middle column write down the name of the Drupal modules needed to build the feature. Finally, in the right-hand column write down all the elements that will be displayed by your feature:

Feature Module(s) Page elements
News page Blog List of recent news item. Individual items has only: Title, date, story
Gallery CCK, ImageField, ImageCache, ImageAPI, Views, Views Slideshow Page of thumbnails which links to larger image. Full image has title, image, photographer's name.

If you're not sure which modules are being used, and you're working on a team, ask your teammates to help out!
Only after you can match your features to their composite page elements and you know what modules will be responsible for outputting the content can you create your wireframes.

Wireframes

This is where you get to be all loose and sketchy. Start with the “inside” of your Web site. Draw all of the things that need to go on the page.

Inside pages are typically the easiest to deal with from a Drupal point of view—but the hardest to diagram because you have to know exactly how all of the navigation elements are going to fit together.
Even if you were handed a complete design and told to convert it to a theme—make wireframes first. These little sketches give you permission to be messy. They give you permission to think about how your site is being built. They allow you to “touch” (even if it's virtually) and name every element on the page. As you create the wireframe talk yourself through the elements, “This is the site navigation. I will make it with the primary links variable in the page template file.”

A complete list of variables for each of these template files is available from:

Site specifications and wire frames help you to map your site's design to Drupal modules. A module is responsible for storing and retrieving content from the database. A theme is responsible for wrapping that content in HTML tags which are in turn styled by CSS. Modules provide database output wrapped in HTML. Your job at the theme layer is to alter the HTML that is wrapped around the database output.

Using the wireframe, identify the modules responsible for the output of each page element.

With this done, it's time to start adding personality to your site.

Identify Page Elements

This is the part of the article where most experienced themers wave their hands to invoke some kind of weird voodoo magic and complete themes pop out the other end.

You must be able to identify the module (or template variable) responsible for creating every page element in your design before proceeding.

Let's start with a simple list:

  • News Block
  • Events Block
  • Programs Block
  • Site Logo
  • Search
  • Primary navigation
  • Utility (secondary) navigation
  • Footer message

Point to each of the page elements on the right and say out loud, “This is the ____.”

Yes. You'll feel stupid. Get over it. I promise it will help.
Don't cheat. Get back up there and say the names for those page elements!

Now that you've labeled each page element I want you to pretend you were going to build only that page element as an HTML snippet.

For example: let's say you were going to build the News Block. What can you tell me about just this piece of the puzzle? Here's what I see:

  • “custom” font headline
  • thick border across only the top
  • default font
  • little bit of padding on all sides
  • it's six columns wide
  • it has a different background texture

We've already learned that blocks have their own template file and there are two variables that will output content: $block->subject and $content.

The template file block.tpl.php contains, by default, the following HTML and PHP:

<div id="<?php print $block_html_id; ?>" class="<?php print $classes; ?>"<?php print $attributes; ?>>
  <?php print render($title_prefix); ?>
<?php if ($block->subject): ?>
  <h2<?php print $title_attributes; ?>><?php print $block->subject ?></h2>
<?php endif;?>
  <?php print render($title_suffix); ?>
  <div class="content"<?php print $content_attributes; ?>>
    <?php print $content ?>
  </div>
</div>

Let's assume the News block is a custom block made by clicking the “Add new block” button from Toolbar » Structure » Blocks. In rendered HTML that same snippet for our News block would look something like this:

<div class="block block-block contextual-links-region" id="block-block-3">
  <div class="content">
    <h2>News</h2>
    <p>Blah, blah, blah, lorem ipsum, blah blah blah.</p>
 </div>
</div>

Now I want you to really look at that HTML snippet. Other than the barf of CSS classes there's nothing hard about that snippet, is there. (See how I don't have a question mark there? You know that snippet is not scary.)

In this case if you wanted to make a News block on your site look exactly like the one I've got what would you need to do? Let's do things the “long” way. By this I mean you're going to end up with more tpl.php files than you need; however, there won't be any fancy PHP magic either.

  • Create a CSS file to deal with the block characteristics that are common to all blocks. This would include everything except the width. Most of the blocks are three columns wide. The selector in your CSS file would be div.block.
  • Look up the the template suggestions for blocks. The formula for block templates is:
      block-[region|[module|-delta]].tpl.php.

    The square brackets group options. The | symbol separates options. In “English” this says: block-region.tpl.php OR block-module.tpl.php OR block-module-delta.tpl.php. We don't know what region this block is in but take a look at the ID from the sample output. It's block-block-3. That pattern matches one of the template file suggestions!

  • Create a copy of the default block.tpl.php file and name it block-block-3.tpl.php.
  • Make changes to the new block template file to assign a six-column class appropriate for your grid framework. It might look something like this (only the big bold text has changed):
<div id="<?php print $block_html_id; ?>" class="<?php print $classes; ?> grid-6"<?php print $attributes; ?>>

Now do you see why it's so important that you be able to name those page elements in your design file? By naming the page elements you will be able to quickly locate and adjust the appropriate template file(s) and CSS to make Drupal look like your design file. If you need to you can slice and dice your design file and then copy that raw HTML into your template files, replacing the Lorum ipsum dummy text with the appropriate Drupal variables.

Now that you understand the strategy I'm going to use to build the Drupal theme.

Optimize your design files

If you've inherited a design file from someone else, take some time to clean up the files. It's worth the effort. Here are the changes I typically need to make to a design file:

  • Sort layers into element-related folders.
  • Use the “right” fonts so that you can see what you need to create in your Drupal theme. Yes, this means using crappy Web fonts (unless of course you're using TypeKit or some kind of CSS awesomesauce...in which case go ahead and use those Web fonts right in your design files).
  • Use the 960.gs grid templates.
  • Create colour palettes with the CSS-friendly (hex or RGB) numbering that you plan to use in your CSS files. Once they're in code it's hard to remember what shade #98aab7 is.
  • (Create and) use a style guide to identify patterns across common elements (for example: the blocks all had similar characteristics except for the width).

This is the first in a two-part series teaching how to create a Drupal 7 theme, starting with a PSD image.

Comments

Nice writeup. You mentioned CSS grid frameworks, which ones specifically do you like/use?

Thanks.

Thanks for the great article!
I didn't follow the 'formula for block templates' exactly. Is the '|' symbol an 'or'? Based on the 'English' examples should the formula be:
block-[region|module|module-delta].tpl.php
Some of those terms are variables, correct? Could the formula then be termed:
block-[$region|$module|$module-$delta].tpl.php
Does that ID 'block-block-3' correspond to 'block-$module-$delta'?
Is 'delta' basically a counter to keep these various IDs unique?

Nice article!

FYI -- path to page displaying block variables doesn't work: try
https://api.drupal.org/api/drupal/modules%21block%21block.tpl.php/7