Notes on Drupal Theming

advertisement
Notes on Drupal Theming
Created 12/14/08
Updated 01/17/09, Updated 02/03/09, Updated 10/25/09, Updated 06/21/10, Updated 03/22/11, Updated 12/19/11
Updated 01/20/12, Updated 04/21/12, Updated 09/19/12, Updated 12/14/13, Updated 05/23/14
Introduction
These notes cover the “theming” aspects of Drupal. A theme allows you to change the appearance of an entire
site. It is also possible to "theme" only certain sections of a site, select types of content, or even individual pages.
For example, your theme could specify a different look for just the front page of your site.
Some other things that you can do with a theme are:
 Change layouts, images or fonts
 Hide or display fields dependent on user role
 Dynamically respond to changes in the content or to user input
 Modify or replace text (for example the labels) and variables generated by modules
Within the idea of “theming” is all of the final HTML generation for PHP arrays that contain the content generated
by the blocks. The theming system goes far beyond the definition of CSS style rules, it includes all of the
definition of a page, the regions on the page, the menu system, and the facilities to take the output of the blocks
and create HTML. For instance, a block might create a table as an array of arrays of strings in the PHP, and the
theme’s table processor will generate the TR, TD elements and have them reference the theme’s CSS rules for
tables. The theming system uses a PHP template system for of its behavior
This document is organized as: standard themes, starter themes, interesting themes, and theme development. This
document is focused on version 6. There may be new features in Drupal 7, but we are not using that yet.
Resources
http://www.apaddedcell.com/how-create-drupal-6-theme-scratch
Drupal theming guide: http://drupal.org/documentation/theme
“Drupal 6 Themes: Create new themes for your Drupal 6 site” by Ric Shreves. Packt Press, September 2008. List
price $39.99, Amazon price $36.35, used from $1.95. Rated 3.5 stars from Amazon.com, but the reviews were
high scattered, and low used price reflects this.
Standard Themes
The standard theme is Garland in Drupal 6. This looks like:
Page 1 of 10
Others include PushButton, Minnelli, and BlueMarine.
Starter Themes
Zen
The ultimate starting theme for Drupal. If you are building your own standards-compliant theme, you will find it
much easier to start with Zen than to start with Garland or Bluemarine. This theme has fantastic online
documentation and tons of code comments for both the PHP (template.php) and HTML (page.tpl.php,
node.tpl.php).
Foundation
This is a liquid layout theme that handles layout for one, two, and three columns based on which blocks are
enabled using CSS, not tables. There is not a lot of "pretty" in this theme as it is meant to be used as a starting
point for theme creators to customize with their own look and feel.
Hasn’t changed since 2008.
Finished Themes
Aquia Marina
One of the first distributed themes from Aquia, this looks quite clean and well-laid out, with very corporate blues
and greens.
Nitobe
Nitobe is a fixed-width, content-first theme based on the 960 Grid System. It supports two or three column layouts
in several configurations and a header image area that can be set to a fixed image or selected at random. In
addition to the column region, a four region area spanning the width of the layout is provided between the content
and footer regions.
Current version is from late 2010.
Baron
I used this during early 2008.
Insignia
I created this during early 2008.
Developing Themes in Drupal
The theme development process begins with the primary files in a theme, particularly template.php, style.css, and
page.tpl.php. As of release 6.0, there is a .info file which is also required.
The resulting output is created by using the different tpl files in combination. A diagram is shown below:
Page 2 of 10
The now-standard template engine is called PHPTemplate, and is described below. Earlier versions of Drupal
didn’t use a standard template engine, and so each template was a bit more complex and ad-hoc.
The .info file defines the metadata such as the theme name, author, version, features, regions, stylesheet(s), etc.
and use of the template engine. The internal name of the theme is also derived from this file. For example, if it is
named "drop.info", then Drupal will see the name of the theme as "drop". An example .info file would be:
name = Barron
description = XHTML & CSS based two column theme
core = 6.x
version = 1.0
engine = phptemplate
regions[sidebar] = Sidebar
regions[content_top] = Content Top
regions[content_bottom] = Content Bottom
regions[footer] = Footer
features[] = logo
features[] = favicon
features[] = name
features[] = slogan
features[] = mission
features[] = node_user_picture
features[] = comment_user_picture
features[] = primary_links
features[] = search
stylesheets[all][] = html.css
stylesheets[all][] = layout.css
stylesheets[all][] = style.css
stylesheets[print][] = print.css
This defines a theme named ‘Barron’ to be written for Drupal 6.x, be currently in version 1.0, use the phptemplate
engine, and have the additional regions Sidebar, Content Top, Content Bottom, and Footer. The features provided
include logo, name, slogan, mission, primary links, search, etc. There are a set of stylesheets used, which are
organized as:
 html.css – contains overrides for the basic HTML elements
 layout.css – defines positioning rules for the container and other geometric elements
 style.css – defines the font, text, color, and border information for visual elements
Page 3 of 10

print.css (only for the printable representation of the site) – defines overrides for the printed output.
This splitting of CSS into html, layout, and style is a common recommendation in CSS design. Even if these rules
are all in one file, the file should be in sections that are organized this way.
The standard template files are:
page.tpl.php,
node.tpl.php
box.tpl.php
block.tpl.php
comment.tlp.php
There is also a separate style sheet for the printed version of a page, called print.css.
The process of defining a region for a theme is quite simple: just add it to the .info file, and then place a print of a
variable with the same name in the appropriate place of the theme’s page.tpl.php file.
Content is assigned to regions through the block system and also through drupal_set_content() calls. For
example, drupal_set_content('left', 'Hello there.') would assign the text 'Hello there.' to the left
region (usually implemented as a left sidebar). Any regions defined in the theme are available on the block
configuration page.
The file called “template.php” contains the implementation of PHP functions that are used by the theme, as well as
some initialization and parameter-defining scripts.
In general, the themes for Drupal seem less complex than the themes for WordPress. However, the themes are
better thought of as the wirework for a presentation, rather than having the detailed formatting guts of what
information is shown for a posting, what is done conditionally, how are single posts shown differently than
multiple posts/archives, etc.
Elements of the Foundation Theme
Page 4 of 10
Elements of the Zen Theme
Elements of the Nitobe theme
Header image size: 940x118
Template Files
page.tpl.php
page-front.tpl.php: can be used to specify a custom front page.
node.tpl.php
node-<nodetype>.tpl.php: optional template file to configure nodes of a specific type.
block.tpl.php
block-<region>.tpl.php: optional template file to configure blocks in a specific region.
The PHPTemplate Facility
This is used in most of the themes and is the standard template engine as of release 5.x and later.
A .tpl file is one that is run for each element of a set of objects, such as each node. It appears that the main code
handles the looping and runs the .tpl files. For instance, since a page has a collection of nodes, the code will run
the node.tpl php file over and over. The engine avoids having loop structures be visible in the PHP files.
Page 5 of 10
A template is a file designed to be friendly to the typical administrator. There is not supposed to be any complex
PHP code there, because that would scare off many a user. In fact the only PHP code that typically appears is “if”
statements. They're lightweight files used to generate the equivalent of what a theme_function does. Values can
be passed into the template through variables by use of a PHP function, template_preprocess_<template_name>().
The structure of a .tpl file is actually standard PHP. There is a context object provided in the global namespace.
For instance for block.tpl.php it is $block.
Structure of page.tpl.php
This paints the outer portion of the page, working from variables such as $head, $content, $site_name,
$site_slogan, $closure, $primary_links, and $language.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language ?>"
lang="<?php print $language->language ?>">
<head profile="http://gmpg.org/xfn/11">
<title><?php print $head_title ?></title>
<?php print $head ?>
<?php print $styles ?>
<?php print $scripts ?>
<style type="text/css" media="print">@import "<?php print base_path() . path_to_theme()
?>/print.css";</style>
</head>
<body>
<div id="page">
<div id="header">
<div id="headerimg">
<?php if ($logo) { ?>
<div style="float:left; margin: 5px;">
<img src="<?php print base_path() . path_to_theme() ?>/images/headericon.gif">
</div>
<?php } ?>
<div><h1><a href="<?php print check_url($base_path); ?>">
<?php print check_plain($site_name); ?>
</a></h1></div>
<div class="description" style="margin 5px;"><?php print check_plain($site_slogan);
?></div>
</div><!-- headerimg -->
<?php if (isset($primary_links)) : ?>
<?php print theme('links', $primary_links, array('class' => 'nav')) ?>
<?php endif; ?>
</div><!-- header -->
<div id="content">
<?php if ($breadcrumb): print $breadcrumb; endif; ?>
<?php if ($mission): print '<div id="mission">'. $mission .'</div>'; endif; ?>
<?php if ($tabs): print '<div id="tabs-wrapper" class="clear-block">'. $tabs .'</div>';
endif; ?>
<?php if (isset($tabs2)): print $tabs2; endif; ?>
<?php if ($help): print $help; endif; ?>
<?php if ($messages): print $messages; endif; ?>
<?php if ($title): print '<h2'. ($tabs ? ' class="with-tabs"' : '') .'>'. $title .'</h2>';
endif; ?>
<?php print $content ?>
<div class="navigation">
<span class="previous-entries"></span> <span class="next-entries"></span>
</div>
</div><!-- content -->
<div id="sidebar-right">
<ul>
<li>
<?php if ($search_box): ?>
Page 6 of 10
<div class="block block-theme"><?php print $search_box ?></div>
<?php endif; ?>
</li>
<?php if ($right): ?>
<?php print $right ?>
<?php endif; ?>
</ul>
</div><!-- sidebar -->
<hr class="clear" />
</div><!-- page -->
<div id="footer">
<php print $footer_message ?>
</div><!-- footer -->
<?php print $closure ?>
</body>
</html>
In this file, there is no block object to work from, but global vars are used. $content contains the result of
expanding all of the lower level objects using their template.
Structure of block.tpl.php
In this case the input block is $block, and the subcontent is located in $block->content.
<div id="block-<?php print $block->module .'-'. $block->delta; ?>"
class="clear-block block block-<?php print $block->module ?>">
<?php if ($block->subject): ?>
<h2><?php print $block->subject ?></h2>
<?php endif;?>
<div class="content"><?php print $block->content ?></div>
</div>
This basically just emits the block subject and the block content.
Structure of node.tpl.php
In this case, the input is $node, and the subcontent is $content.
<div class="node<?php if ($sticky) { print " sticky"; } ?><?php if (!$status) { print " nodeunpublished"; } ?>">
<?php if ($picture) {
print $picture;
}?>
<?php if ($page == 0) { ?><div class="nodeTitle"><a href="<?php print $node_url?>"><?php
print $title?></a></div><?php }; ?>
<span class="submitted"><?php print $submitted?></span>
<?php if ($terms) { ?><div class="taxonomy">Tagged: <?php print $terms?></div><?php }; ?>
<div class="content"><?php print $content?></div>
<?php if ($links) { ?><div class="nodeLinks"><?php print $links?></div><?php }; ?>
</div>
If there is a taxonomy, then the terms are listed before the content. If there are links, they are listed before the
content on page 0, but after the content on page 1.
$page is equal to 0 for all front-like pages (including nodes classified under a specific taxonomy term etc).
Otherwise it is equal to 1. Front-like pages display a list of nodes, while pages with $page == 1 are displaying a
single node. There is also a variable called $is_front that can be checked.
The way that the header and footer meta data for a node is rendered is that these are treated as links on the node
and are located in the global variable $links. Hence they are not specified through the node formatting (which was
Page 7 of 10
typical of the fine-grain decoration through a theme as used in WordPress) but are controlled through the variable
population function.
If you want more detail regarding the presentation of fields within a node (these include the dates, the image
attachments, etc.), see http://jodyhamilton.net/node-theming-field-deconstructing-node-content-drupal-5 Though
this was written for Drupal 5, it still applies (at least) to Drupal 6.
Using body_classes for dynamic layouts
Drupal 6 provides a new tool for dynamic layouts called $body_classes. This enables the CSS rules of your theme
to be told what sidebars are active, and hence you can have different layout rules for when there is one sidebar,
two sidebars, etc. The previous approach to handling this relied on tables that conditionally rendered content, etc.
To use this, just add $body_classes to the body tag of your page.tpl.php file, as in the following:
<body class=”<?php print $body_classes; ?>”>
The values of $body_classes include the following:
.
Condition
no sidebars
one sidebar
left sidebar visible
right sidebar visible
two sidebars
front page
not front page
logged in
not logged in
page visible
node visible
Class Available
.no-sidebar
.one-sidebar
.sidebar-left
.sidebar-right
.two-sidebars
.front
.not-front
.logged-in
.not-logged-in
.page-[page type]
.node-type-[name of type]
Note that this also enables you to have different layouts for front page and not front page, logged in and not, etc.
Using the template.php file
If you want to override a theme function not included in the basic list (block, box, comment, node, page), you need
to tell PHPTemplate about it.
To do this, you need to create a template.php file in your theme's directory. This file must start with a PHP
opening tag <?php but the close tag is not needed and it is recommended that you omit it. Also included in the file
are stubs for the theme overrides. These stubs instruct the engine what template file to use and which variables to
pass to it.
Using JavaScript in themes
Starting from a basic Drupal 6 installation, the Garland theme is used. That has the following headers/includes:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="shortcut icon" href="/dev/misc/favicon.ico" type="image/x-icon" />
<title>Themes | therisbergfamily.com</title>
<link type="text/css" rel="stylesheet" media="all" href="/dev/modules/node/node.css?i" />
<link type="text/css" rel="stylesheet" media="all" href="/dev/modules/system/admin.css?i" />
<link type="text/css" rel="stylesheet" media="all" href="/dev/modules/system/defaults.css?i" />
<link type="text/css" rel="stylesheet" media="all" href="/dev/modules/system/system.css?i" />
Page 8 of 10
<link
<link
<link
<link
type="text/css"
type="text/css"
type="text/css"
type="text/css"
rel="stylesheet"
rel="stylesheet"
rel="stylesheet"
rel="stylesheet"
media="all" href="/dev/modules/system/system-menus.css?i" />
media="all" href="/dev/modules/user/user.css?i" />
media="all" href="/dev/themes/garland/style.css?i" />
media="print" href="/dev/themes/garland/print.css?i" />
<script type="text/javascript" src="/dev/misc/jquery.js?i"></script>
<script type="text/javascript" src="/dev/misc/drupal.js?i"></script>
<script type="text/javascript" src="/dev/misc/tableheader.js?i"></script>
<script type="text/javascript">
<!--//--><![CDATA[//><!-jQuery.extend(Drupal.settings, { "basePath": "/dev/" });
//--><!]]>
</script>
<!--[if lt IE 7]>
<link type="text/css" rel="stylesheet" media="all" href="/dev/themes/garland/fix-ie.css" />
<![endif]-->
</head>
<body class="sidebar-left">
With the Foundation theme, it was similar.
The key is that there are two variables to be rendered in the theme $styles, and $scripts. These variables contain
the full list of styles and scripts registered with the Drupal environment. The registration is typically done by the
module. For instance suppose that module X wants a CSS file. The module would call
drupal_add_js(<pathname>) such as:
drupal_add_js('misc/collapse.js');
Through this approach, a module could request that the scripts and css generate referenced in the header of page,
not matter which theme is being used. The typical use is module-centric, since presumably only module
developers (not page content developers) know how to use jQuery, for instance.
The sources of the scripts or css can be in the modules or themes directories. Also, it can be in the “libraries”
directory, which was added more recently. Examples are the population of jQuery libraries, which can be referred
to by modules.
However, a theme could also make these calls. For instance our changed copy of Foundation, we have:
<?php
// $Id: template.php,v 1.3 2008/06/23 12:08:02 add1sun Exp $
drupal_add_js('sites/all/libraries/js/jquery-1.6.4.min.js');
drupal_add_js('sites/all/libraries/js/jquery-ui-1.8.16.custom.min.js');
drupal_add_css('sites/all/libraries/css/redmond/jquery-ui-1.8.16.custom.css');
Does this depend upon the JQuery UI module? Actually, no. That module was a way of understanding the above,
and is a helpful way for developers who don’t know the structure of jQuery UI as clearly to carry out the above. It
also provides a module name to mark as a dependency if you were writing a module that wanted to depend upon
jQuery UI being provided.
Hence, we have taken the jQuery UI module out of our Drupal 6 developer area. For Drupal 7, this is greatly
simplified, since a closer-to-current version of jQuery is provided in core (Drupal 6 has 1.2.6).
Responsive Theming
James Jonas just spun up another test website for a project called http://cafe.us. I was curious so I took another
look at responsive themes for mobile phone.
(1) Omega was the correct theme.
(2) It needed a subtheme: http://drupal.org/project/respond (7.x)
Page 9 of 10
This is still pretty ugly, and needs some work, but it does provide a little better look and feel inside a mobile
phone. Here is a screen shot:
Next test
- jQueryMobile
- Services 3.x against iOS5 (iPhone)
Page 10 of 10
Download