Skip to main content

From HTML mockup to a full Drupal site: a tutorial - Part III: Template Theming, Integration and Finishing Touches

March 5, 2008

Please note: this tutorial was written for Drupal 5.

Continuing from Part I and Part II in our 'From HTML mockup to a full Drupal site: a tutorial' series, this final part will focus on integrating our finished HTML / CSS mockup into our now final Drupal site. As I mentioned before, I'm omitting quite a bit of advanced (and some not-so-advanced) theming practices, intentionally. What were focusing on is making quick work of simpler clients' website needs.

So what've we got? We have a skeleton of a Drupal site fully built out, and an HTML / CSS mockup sitting around somewhere. Let's meld the two.

Administration menu

Back in part II, when I said we were done with all the setup and module bit'ness, I lied. That's because I forgot one module, the 'Administration Menu module'. Why do we need this module? Well, we don't, if you plan on truly building your theme to support all native Drupal functions (including multiple navigation slots).

Since our BeeEss mockup clearly only has one navigation, and that navigation is used for retail purposes, we don't really have an all-that-intuitive place to dump our 'admin' menu system. Well, the Administration Menu module takes care of that. What it does is place the 'admin' menu at the absolute top of each page, so you don't have to worry about integrating it into your site layout. So go ahead and upload and enable that module. Once enabled, you'll see the menu at the top. Sweet!

With the admin menu out of the way, we can focus on building the theme.

Theme directory structure

The first thing you need to do when beginning a new theme is to create the directory that will house your theme. We'll want our theme to live in '/sites/all/themes/custom/bellascena'. You'll need to create the 'custom' directory if this is a fresh Drupal install. Also, I would suggest naming your actual theme directory with no dashes or underscores. I seemed to have some questionable results with one or the other (can't remember specifically).

Within our newly created theme directory, we'll need the following files to start:

  • page.tpl.php (can be blank for now)
  • node.tpl.php (ditto)
  • screenshot.png (a 150x90 screenshot of your theme)
  • style.css (can also be blank for now)

We'll also want an 'images' directory within our theme's root directory as well. This isn't Drupal specific, it's just where I think images belong :). For our BeeEss theme, we also need to employ the IE PNG fix. Grab a copy and place it within our theme directory.

How theme processing works

Drupal's theme engine, in our case - PHPTemplate - looks for specific files to theme a page when it builds a certain page. The 'algorithm' is not complex, actually it's quite simple. If you're loading a 'blog' page in Drupal, the system will look for 'page-blog.tpl.php', and if it doesn't find it, will move on to 'page.tpl.php'. It's a hierarchical approach.

Since we've only got 'pages' and 'news entries', we can focus on just using 'page.tpl.php' to handle the core 'page', and 'node.tpl.php' to handle the news entries (well, pages, too - but we'll get into that later). Since 'news' is a content type in Drupal, the theme engine will look for 'news.tpl.php', and move on to 'node.tpl.php', since instances of the 'news' content type are essentially 'nodes'.

Bring in the HTML!

If you'd like to follow along with the actual BeeEss theme itself, you can grab the images to drop in the 'images' folder. Also, you can go ahead and copy the styles to your own style.css. Now, modify page.tpl.php to be the complete page mockup (straight HTML). If you're following along, copy the BeeEss mockup HTML into your page.tpl.php.

Bring in the PHP!

Now what we need to do is get some dynamic content (PHP vars) into our template. Pop open page.tpl.php. Here are the variables that we'll be putting into this template:

  • $language: The 'locale' of this Drupal site. For english, will be 'en'.
  • $head_title: The title of the current page being loaded.
  • $site_slogan: The site slogan. We'll use this for construction of the '<title>' as well.
  • $styles: The output of CSS styles as defined by modules, core system styles, as well as 'style.css'.
  • $site_name: The name of the site.
  • $head: Spits out some various things, like the link to the favicon, among others.
  • $feed_icons: URLs to RSS feeds provided by Views.
  • $scripts: JavaScript files needed by modules or Drupal core, such as jQuery.
  • $base_path: The base path to your website. This would be something like
  • $directory: The path to your theme directory. Useful for images and files residing within, in our case, /sites/all/themes/custom/bellascena.
  • $logo: The URL to the 'logo' if you've uploaded one.
  • $primary_links: An iterable list of menu items deemed 'Primary Links'. We'll use this for our nav.
  • $is_front: Either 'TRUE' or 'FALSE' depending on whether or not the page being loaded is the 'front page'.
  • $content: The good stuff! '$content' is the alpha and the omega. It carries the core 'content', ie. a page 'body', or a node 'body'.
  • $title: The 'title' of the node or page, or some other content type, such as a blog entry 'title', or a page 'title'.
  • $footer_message: The 'footer' content we filled out on the site info page.
  • $closure: Probably one of the most important vars to remember to include in your theme. This var carries output of things such as the admin_menu, google_analytics module, etc. Don't forget it!

So that's a good overview of what we'll be plugging into our now static HTML template. Crack open your page.tpl.php file, and make it look like this one: BeeEss mockup PHP + HTML. Take a look at the integration of the above vars within the template, and I'll step through some of the not-so-obvious pieces now.

Implementing the new theme

Go ahead and copy the PHP'd version of page.tpl.php to your server. Head over to /admin/build/themes, find the theme, enable, and set to 'default'. Click 'save configuration'. Woah! Our site is now using our theme. The first thing I notice is that the logo is missing. Back on the themes listing page, click 'configure' next to the theme we're using. Down the page a bit, you'll see the form for 'custom logo'. Uncheck the 'Use the default logo' checkbox, and download and upload this logo (it's also located within the images directory I linked to earlier). Much better. You can also upload your custom favicon here (grab it here). Win!

So for the most part, things are pretty self-explanatory. Let's run through a few of the not-so-obvious pieces now.

The homepage switcheroo

Well, there are a few different ways to theme separate 'pages' differently. For BeeEss, I took the approach of hardcoding a small conditional in page.tpl.php, and putting the HTML into a Drupal 'Page' for the actual content of the homepage. The switch in page.tpl.php looks like this (forgive my too-lazy-and-busy-to-do-my-own-blog-theme reasoning for no code highlighting):

<?php if ($is_front == true) { ?>
<div class="content-container-front clearfix">
<?php print $content ?>
<?php } else { ?>
<div class="content-container clearfix">
<h1 style="margin-bottom: 10px;"><?php print $title ?></h1><?php if ($tabs): print $tabs; endif; ?>
<?php print $content ?>
<?php } ?>

Clearly there are better ways to do this, but whatever.

So now that we've got that setup to just dump the unadulterated homepage HTML where we want it, we need to edit the 'homepage' page that we created earlier. Go edit the page, and put this as the body. Before you save it, be sure to set your input format to 'PHP Code'. You don't ever want to use this format unless you must, and in Drupal 6, it's not even there by default. But, in our case, we'd like to surface our mission statement on our homepage. Go ahead and save that puppy.

Now, right after you save it, you may notice it looks pretty whacky. That's because /home is not set to our 'homepage' yet, and our little conditional above isn't taking effect. Head to /admin/settings/site-information, and at the bottom you'll find 'Default front page'. Change that to 'home' without the qutoes. Click on 'Home' in your nav, and we're in damn good shape. You'll also notice the mission is being pulled in from the variable_get function. Score!


Our navigation is setup to use list items, which should be working just fine. This is the function we use in page.tpl.php to build the nav menu:

<div id="navigation">
<?php if (isset($primary_links)) : ?>
<?php print theme('links', $primary_links, array('class' => 'nav-links primary-nav-links')) ?>
<?php endif; ?>

Basically, we're saying, print out my primary_links, with the UL class of 'nav-links primary-nav-links'. Pretty straightforward. There are ways to modify the output of these links, and - well - everything in Drupal theming, but again this post is focusing on simplicity.

Almost... there...

So yeah, I forgot to tell you really anything about node.tpl.php. And, for some reason, nodes still seem to be appearing quite well. Well, almost. We need to really have a template that will tell a node how the hell to look on the page. Use this for your node.tpl.php. It should be pretty straightforward. Basically, this template is what gets called when any node is loaded, whether it be a teaser view of a node, full node itself, or even a page (since they're nodes, too, you know - have a little respect).

So yeah, moving forward...

I must admit, after being at Drupalcon all week, I've become a tad 'reserved' (as in, not motivated) with regards to this blog post, so it may or may not fulfill one's theming dreams. I actually had second thoughts about whether or not I should've really written this post, so tell me if I made a good choice or not. So why did I have second thoughts? Well - Drupal 6, and Theme Developer for devel.

So all things aside, I'm sure I left out a bunch of stuff, so feel free to publicly harass and embarrass me if you will.