Building Drupal 5Themes
From ThemesWiki
| Official Page |
| Project Documentation |
| Download |
|
Building a New Theme
This tutorial takes us into the world of building Drupal themes from scratch. While many people may begin their theme project by copying and modifying an existing theme, in this tutorial, we cater to the purists who want to do it all themselves.
To follow fully the examples in this tutorial, you will need your favorite web editor (Dreamweaver or another similar program) and, preferably, access to a development server on which to preview your work. In the section dealing with pure PHP themes, we will be using as our example the Chameleon theme from the default Drupal distro.
Planning the Build
How you go about building a theme is largely framed by your intentions for the theme. If you intend to release the theme for the use of others, then it is best to follow certain (albeit largely unwritten) conventions that make the resulting theme more "standard" and therefore, easier for others to use. In contrast, if use by others is not a factor, then you can proceed in a fashion that tailors the code more narrowly to your needs.
In terms of features, our goal here is to create a theme with the following attributes:
- Employs PHPTemplate
- Valid XHTML, pure CSS
- Supports one to three columns
- Supports theme configuration options native to PHPTemplate (e.g., logo, search box, site slogan, etc.)
Represented visually, the structure of our page.tpl.php file will be as follows:
In terms of the layout that we will impose on the functionality, we will set up a standard three-column layout with a header and a footer, and then create the following structure to hold our functionality:
Regions are the primary key to placement of content and the functionality. By default, PHPTemplate provides for the following Regions:
- Header
- Content
- Sidebar Left
- Sidebar Right
- Footer
You are not restricted to the default Regions. You can use all or only some of the Regions and you can also define new Regions if you so desire. For the example in this tutorial, we will employ all the default Regions. If you are designing themes for others, it is best to include all the default Regions, as the system will show all the default Regions as options in the Block manager, regardless of whether they are present in the page.tpl.php file. Given the system's default display of these Regions in the Block manager, failing to include all the default Regions in your theme may lead to confusion for the site administrator.
Now let's put this all together here's a graphical representation of how our new theme will place the functional elements, including the Regions, relative to the CSS page divisions.
Diagram of the position of the elements relative to the principal divisions of the CSS layout and the main document divisions. Note that the ordering of the elements within the CSS is done alphabetically here, as the final ordering of the elements will be up to the individual developer.
Build a New PHPTemplate Theme
To create a new PHPTemplate-powered theme, we need to create the following files:
- page.tpl.php'
- style.css'
We'll also need a directory to hold them, so create a new directory and name it Bluewater; this will be the home directory and the name of our new theme.
Testing during theme development is easiest if you have access to a development server. Unlike straight HTML, it is difficult to preview the PHP files. If you have access to a development server, go ahead and place the Bluewater directory into the sites/all/themes directory. Next, copy into that directory a sample logo file we can work with and name it logo.png the default Drupal logo used in the themes included in the distro will work just fine.
Note- You can grab a copy from any of the default themes in the distro. Typically, the logo can be found inside the theme directory and is named logo.png, for example, themes/garland/logo.png.
Place the directory and basic files for our new theme, Bluewater, inside sites/all/themes.
Building a page.tpl.php File
The page.tpl.php file is the key to creating a PHPTemplate theme. This essential file handles the placement of all the major page elements and the final HTML output. Accordingly, we will place in this file a mix of HTML and PHP. The PHP supplies the logic and the functionality, and the HTML supplies the formatting.
Take note of the ordering of the tags and the relationship between the PHP and the HTML. In this theme, we will typically place the HTML formatting inside the PHP conditional statements, rather than wrapping the PHP with HTML.
For example, we will typically want to order the tags like this (HTML inside the PHP):
<?php if ($site_slogan): ?> <div class="slogan"> <?php print $site_slogan; ?> </div> <?php endif; ?>
We generally don't want to do it like this (PHP inside the HTML):
<div class="slogan"> <?php if ($site_slogan): ?> <?php print $site_slogan; ?> <?php endif; ?> </div>
The reasoning behind the preference for the first ordering of tags is quite simple: if we place the HTML outside the PHP, then the appearance of the HTML will occur even when the condition contained in the PHP statement is not true, thereby clogging our page with unnecessary code and more importantly, creating unnecessary complexities in dealing with the styling of the page as a whole.
Again by way of example, compare the impact of the different orderings on the resulting source code. First, let's look at what happens when the HTML is placed inside the PHP.
Here's the source code with the site slogan functionality enabled by the administrator:
<!-- slogan --> <div id="slogan"> this is the slogan </div>
Compare that with the source code that results when the site slogan function is disabled:
<!-- slogan -->
In this case, the PHP conditional statement is false (site slogan disabled by the administrator) and, as a result, neither the site slogan nor its accompanying HTML formatting is displayed; the only thing that remains in the resulting source code is the comment tag.
Now, let's compare the source code that is produced when the PHP is wrapped with the HTML.
With site slogan enabled, you will see no difference:
<!-- slogan --> <div id="slogan"> this is the slogan </div>
But, when the site slogan is disabled, you do see a difference:
<!-- slogan --> <div id="slogan"> </div>
In the latter example, the HTML is visible even though the conditional statement is false. The formatting remains despite the fact that the element the HTML is intended to format is not present. With this ordering of tags, we're always stuck with the presence of styles in the resulting code, regardless of whether the function it is supposed to format appears or not.
The example above makes another point as well, that is, how the use of the PHP conditional statements delivers benefits at run time. With the conditional statements in place, unneeded code is removed at run time. Without the conditional statements, the code remains for the browser to render, regardless of whether it is needed.
As a result of the interaction between the PHP conditional statements and the HTML tags, you will need to make decisions about whether you wish the styles to remain active in the absence of the element that the styling is intended to affect. In some cases, your layout integrity is maintained better by leaving the styling in place, regardless of whether the underlying element is active. In other cases, you will want the formatting to fold away when the element is not active for example, a sidebar that collapses when no Blocks are assigned to a Region and will therefore, want to use the PHP to control the visibility of the HTML.
With that background behind us, let's create a new file, name it page.tpl.php, and get started on the code for our new theme.
Insert DocType and Head
Start by declaring the appropriate DocType. XHTML Strict is appropriate for this usage:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
Next, place the opening HTML tag and name space. Note that this code also includes the PHP statements that call the appropriate language settings for your site, and should not be altered.
<html xmlns="http://www.w3.org/1999/xhtml" lang="<?php print $language ?>" xml:lang="<?php print $language ?>">
As the opening tag is an HTML declaration, go ahead and add the closing HTML tag now.
</html>
The rest of the code, discussed below, will be placed inside these two HTML tags.
Next, let's set up the head of the document. The various statements that compose the head of the document, including the metadata, the links to the style sheets, and any scripts, are produced by the following lines of code:
<head> <title> <?php print $head_title; ?> </title> <?php print $head; ?> <?php print $styles; ?> <?php print $scripts; ?> </head>
Here,
-
$head_titleproduces the site (not the page) title. -
$headincludes the Drupal head code. -
$stylesincludes the various stylesheets. -
$scriptsincludes any necessary scripts.
There is no need to alter any of these, unless you have special needs (e.g., excluding the default Drupal style sheets).
Insert Body Tags
Immediately after the </head> tag, open the <body> tag:
<body>
Then add a closing </body> tag:
</body>
All the code discussed in the section below will be placed inside the body tag.
Taken together, at this stage, you should now have the template's bare skeleton, like this:
<!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" lang="<?php print $language ?>" xml:lang="<?php print $language ?>"> <head> <title> <?php print $head_title; ?> </title> <?php print $head; ?> <?php print $styles; ?> <?php print $scripts; ?> <script type="text/javascript"> </script> </head> <body> </body> </html>
Into this document outline, we will now place the basic HTML that defines the layout of the output on the page. Once we have the basic HTML in place, we will insert the functional elements into the appropriate areas.
Lay Out the Page Divisions
The next step is to outline the general divisions that will define the layout of the page.tpl.php output. Between the <body> tags, add the following:
<div id="page-wrapper"> <div id="header-wrapper"> <div id="header-region"> </div> </div> <div id="primary-links"> </div> <div id="main-wrapper"> <div id="sidebar-left-region"> </div> <div id="content-region-<?php print $layout ?>"> </div> <div id="sidebar-right-region"> </div> </div> <div id="footer-region"> </div> </div>
Before we get started with placing the functional flesh on this HTML formatting skeleton, note that the organization of divs, above, wraps the entire body section inside <div id="page-wrapper">. Within that primary div, we create separate styling for the header, the primary links, the main content area, and finally, the footer. We have also set up dedicated styling for each of the five Regions all nested inside the primary div.
Now, let's look at this in more detail as we add the functionality.
Place the Functional Elements
With our framework in place, we can now go back and place the functional elements where we want them to appear inside the layout.
Insert the Secondary Links
For this theme, I have placed the secondary links at the very top right-hand side of the page, before the header area. The placement is a subjective decision and here, instead of treating the secondary links as subnavigation to the primary links (which some templates do), I have separated them from the primary links, in order to create a second distinct area in which navigation can be positioned.
Here, the secondary links ($secondary_links), are placed with a conditional statement that allows this area of the layout to compress and disappear from view if the secondary links are not enabled.
<!-- secondary links -->
<?php if ($secondary_links): ?>
<div id="secondary-links">
<?php print theme('menu_links', $secondary_links); ?>
</div>
<?php endif; ?>
Inside the Header Wrapper
The first section of our page layout is designated Header. Inside this page division, which will appear at the top of our final page, we will place a number of elements related to the site's identity as well as some basic functionality.
Logo
The following snippet includes the logo ($logo), with a hyperlink to the homepage. Note that the title and alt attributes are set by the code below. In this snippet, the image attributes are set to 'Click to return to the Homepage', but you can change this to whatever wording you wish. Note also the t function, which enables the translation feature of Drupal.
Wrap the logo inside a div with the id logo. In this case, I have placed the div outside the PHP. By wrapping the PHP with the styling, instead of placing the styling inside the conditional statement, we maintain the integrity of the size of the header area of our layout; we want this area of the layout to be stable and not changing size in response to the logo settings.
<!-- logo -->
<div id="logo">
<?php if ($logo): ?>
<a href="<?php print $base_path; ?>" title="<?php print t('Click to return to the Homepage'); ?>">
<img src="<?php print $logo; ?>" alt="<?php print t('Click to return to the Homepage '); ?>" /></a>
<?php endif; ?>
</div>
Note- The logo code in the example calls the system default logo image. The logo setting is controlled by the administrator in the theme and global configuration settings. If you intend to distribute your theme to others, you must place a logo file in the proper location (inside the directory), with the proper name (i.e., logo.png) and include it with your theme files. The Drupal logo is commonly used for this purpose.
Site Name
To include the site name ($site_name) on the page, together with a hyperlink to the homepage, add the code below. The title attribute of the a tag is set dynamically and tied to the translate functions (t). You can change the text from "Home" to whatever you wish.
A div named sitename is used to wrap the functionality. Unlike the logo, previously, the formatting here is inside the PHP conditional statement, so that the formatting is disabled if the site name is disabled.
<!-- site name -->
<?php if ($site_name): ?>
<div id="sitename">
<h1><a href="<?php print $base_path ?>" title="<?php print t('Home') ?>"><?php print $site_name; ?></a></h1>
</div>
<?php endif; ?>
Theme Search Box
The theme search box is inserted with the following snippet. Wrap this in a div with the id searchbox.
<!-- theme search box --> <?php if ($search_box): ?> <div id="searchbox"> <?php print $search_box; ?> </div> <?php endif; ?>
Site Slogan
Here's the site slogan wrapped with a div with the id site-slogan:
<!-- slogan --> <?php if ($site_slogan): ?> <div id="site-slogan"> <?php print $site_slogan; ?> </div> <?php endif; ?>
Site Mission
The site mission statement is included with $mission. Wrap it in a div with the id mission:
<!-- mission statement --> <?php if ($mission): ?> <div id="mission"> <?php print $mission; ?> </div> <?php endif; ?>
Header Region
Despite the confusing name, this has nothing to do with the header of the HTML page this is the Region used for the placement of blocks.
$header prints the Region to the page. Note that this employs a conditional statement allowing the space for the Region to compress if nothing is assigned to the Region.
I have wrapped the Region with a div. The id here is header-region.
<!-- Region: header --> <?php if ($header): ?> <div id="header-region"> <?php print $header; ?> </div> <?php endif; ?> </div>
Insert the Primary Links
I am going to place the primary links in the space between the header wrapper and the main wrapper. In this fashion, it is easy for me to control the formatting of this area, which will span the width of the design.
The primary links for the site are included by the following. Note that the div is inside the conditional statement so if the user decides not to use the primary links, then the area compresses and is hidden from sight.
<?php if ($primary_links): ?>
<div id="primary-links">
<?php print theme('menu_links', $primary_links); ?>
</div>
<?php endif; ?>
Inside the Main Wrapper
There is a bit more styling involved here, given that three columns and a wide range of functionality will be included in this critical area of the page. For this theme, in addition to the main content Region, we're placing the breadcrumb trail, title, tabs, help, messages, and feed icons inside the area between the two sidebars. To control all this, we will wrap the entire set of tags with one div (with the id main-content-wrapper), and then create formatting inside of that for each column and its constituent elements.
Sidebar Left
Let's place first the left sidebar ($sidebar_left), using a conditional statement to wrap the entire thing. We want this to compress and fold up if nothing is assigned to this Region, thereby allowing us to create a one- or two-column layout. Note the div controlling this Region has been named sidebar-left-region.
<?php if ($sidebar_left): ?> <div id="sidebar-left-region"> <?php print $sidebar_left; ?> </div> <?php endif; ?>
The Main Content Area
For the main content area of this design, I've created a div with a dynamic id. The div is used to wrap all the following elements. In a three-column layout, the area inside this div would be the center column. Regardless of how many columns are used, this area will hold the main content of the site by default.
Breadcrumb Trail
The breadcrumb functionality is placed on the screen with $breadcrumb. Note that while you can style this from within the page.tpl.php file, the creation of the breadcrumb trail is controlled by a themeable function. You can obtain the best control over the display and formatting settings by overriding the themeable function, rather than by styling this PHP statement.
<!-- breadcrumb trail --> <?php if ($breadcrumb): ?> <?php print $breadcrumb; ?> <?php endif; ?>
Title
Insert the following conditional statement to place the page title on the screen. Style the title with the H2 tag and a dedicated class, content-title.
<!-- title --> <?php if ($title): ?> <h2 class="content-title"> ?php print $title; ?> </h2> <?php endif; ?>
Tabs
$tabs controls the placement of the tabs-based navigation. Note that while the default front-end settings do not employ tabs, the default administration interface does; omitting this can cause you problems in the administration interface. Wrap the PHP print statement with a div and a class, tabs.
<!-- tabs --> <?php if ($tabs): ?> <div class="tabs"> <?php print $tabs; ?> </div> <?php endif; ?>
Help
$help controls the output of the context-sensitive help information. The help link typically only appears in the admin interface. Note that you can style this statement if you choose. In this example, I have added no extra styling and left it to the system to provide the default styling.
<!-- help --> <?php print $help; ?>
Messages
Insert $messages wherever you wish the system status and alerts messages to appear on your page. Note that you can style this statement if you choose. In this example, I have added no extra styling and left it to the system to provide the default styling.
<!-- messages --> <?php print $messages; ?>
Content Region
The content Region ($content) is the primary Region used by the Drupal system to hold a variety of information, including nodes, the administration interface, and more. There is no conditional statement attached to this Region, because the system does not give the user the option to omit output to this Region. The formatting for this is covered by the div we've used to wrap the entire column; in our example, no additional styling is needed.
<!-- Region: content --> <?php print $content; ?> </div>
Sidebar Right
Let's close out this section of our page layout by including the right sidebar ($sidebar_right). Wrap this with a conditional statement so it will compress out of sight in the event nothing is assigned to the right sidebar. The div sidebar-right-Region is used to wrap the Region itself.
<?php if ($sidebar_right): ?> <div id="sidebar-right-region"> <?php print $sidebar_right; ?> </div> <?php endif; ?>
Inside the Footer
Last, at the bottom of our layout, is the footer Region. Let's wrap this with a div and name it appropriately. Inside the div, we will place the feed icons and the footer message.
<div id="footer-region">
Feed Icons
Place the RSS feed icon ($feed_icons) inside the div for the footer and wrap it in a div named feed-icons:
<!-- feed icons --> <div id="feed-icons"> <?php print $feed_icons; ?> </div>
Footer Region
The Footer Region statement shows a variation in nomenclature the string is named "footer_message" instead of simply "footer" (the latter would be more consistent with the names given to other Regions). The name, however, does not restrict the Region in any way. $footer_message provides both the footer Region and the output of the footer message, set by the administrator. Wrap $footer_message in a div so you can style it easily.
<!-- footer text --> <div id="footer-text"> <?php print $footer_message; ?> </div> </div>
Insert the Template Closing Tag
A final snippet produces no output but is required by the Drupal system to close the logic of the template. Add this statement immediately before the closing body tag. No styling is needed.
<?php print $closure; ?>
The Final page.tpl.php File
At this stage, we've assembled all the necessary pieces of a fully functional PHPTemplate theme. All the elements you need are in place, though the styling is lacking. Let's stop here for a moment and get the Big Picture. Below is our raw page.tpl.php file, with only comment tags to enhance readability:
<!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" lang="<?php print $language ?>" xml:lang="<?php print $language ?>">
<head>
<title>
<?php print $head_title; ?>
</title>
<?php print $head; ?>
<?php print $styles; ?>
<?php print $scripts; ?>
<script type="text/javascript"> </script>
</head>
<body>
<div id="page-wrapper">
<!-- secondary links -->
<?php if ($secondary_links): ?>
<div id="secondary-links">
<?php print theme('menu_links', $secondary_links); ?>
</div>
<?php endif; ?>
<!-- BEGIN Header -->
<div id="header-wrapper">
<!-- logo -->
<div id="logo">
<?php if ($logo): ?>
<a href="<?php print $base_path; ?>" title="<?php print t('Click to return to the Home page'); ?>">
<img src="<?php print $logo; ?>" alt="<?php print t('Click to return to the Home page '); ?>" /></a>
<?php endif; ?>
</div>
<!-- site name -->
<?php if ($site_name): ?>
<div id="sitename">
<h1><a href="<?php print $base_path ?>" title="<?php print t('Home') ?>"><?php print $site_name; ?></a></h1>
</div>
<?php endif; ?>
<!-- theme search box -->
<?php if ($search_box): ?>
<div id="searchbox">
<?php print $search_box; ?>
</div>
<?php endif; ?>
<!-- slogan -->
<?php if ($site_slogan): ?>
<div id="site-slogan">
<?php print $site_slogan; ?>
</div>
<?php endif; ?>
<!-- site mission -->
<?php if ($mission): ?>
<div id="mission">
<?php print $mission; ?>
</div>
<?php endif; ?>
<!-- Region: header -->
<?php if ($header): ?>
<div id="header-region">
<?php print $header; ?>
</div>
<?php endif; ?>
</div>
<!-- END Header -->
<!-- primary links -->
<?php if ($primary_links): ?>
<div id="primary-links">
<?php print theme('menu_links', $primary_links); ?>
</div>
<?php endif; ?>
<!-- BEGIN Center Content -->
<div id="main-wrapper">
<!-- Region: sidebar left -->
<?php if ($sidebar_left): ?>
<div id="sidebar-left-region">
<?php print $sidebar_left; ?>
</div>
<?php endif; ?>
<div id="content-region-<?php print $layout ?>">
<!-- breadcrumb trail -->
<?php if ($breadcrumb): ?>
<?php print $breadcrumb; ?>
<?php endif; ?>
<!-- title -->
<?php if ($title): ?>
<h2 class="content-title"><?php print $title; ?></h2>
<?php endif; ?>
<!-- tabs -->
<?php if ($tabs): ?>
<div class="tabs">
<?php print $tabs; ?>
</div>
<?php endif; ?>
<!-- help -->
<?php print $help; ?>
<!-- messages -->
<?php print $messages; ?>
<!-- Region: content -->
<?php print $content; ?>
</div>
<!-- Region: sidebar right -->
<?php if ($sidebar_right): ?>
<div id="sidebar-right-region">
<?php print $sidebar_right; ?>
</div>
<?php endif; ?>
</div>
<!-- END Content Area -->
<!-- BEGIN Footer -->
<!-- Region: footer -->
<div id="footer-region">
<!-- feed icons -->
<div id="feed-icons">
<?php print $feed_icons; ?>
</div>
<!-- footer text -->
<div id="footer-text">
<?php print $footer_message; ?>
</div>
</div>
<!-- END Footer -->
<!-- theme closing tag -->
<?php print $closure; ?>
</div>
</body>
</html>
The style.css File
Let's go back now and open up the style.css file we created at the beginning of this tutorial. Use this file to define the various selectors we've placed in the page.tpl.php file. In addition to the selectors we've used to control the placement of the functionality, you will need to define various tags, classes, and IDs to specify fonts and style the information hierarchy. You may also wish to add decorative touches via some creative CSS. All the theme-specific styles should be defined in this document, along with any overrides of existing selectors.
Because an exhaustive CSS tutorial is beyond the scope of this text, we're not going to go through all the various styling. The file is included, below, for your review:
/** global styles **/
body {
font: 13px/16px Verdana, Arial, Helvetica, sans-serif;
color: #CCCCCC;
background-color: #CCCCCC;
}
#page-wrapper {
position:relative;
width:974px;
text-align:left;
background-color: #336699;
border: solid 12px #FFFFFF;
margin-top: 0;
margin-right: auto;
margin-bottom: 0;
margin-left: auto;
}
a, a:link, a:visited {
color: #FFFFFF;
text-decoration: none;
}
a:hover, a:focus {
color: #6191C5;
text-decoration: underline;
}
a:active, a.active {
color: #89A3E4;
}
h1.title, h1.title a, h1.title a:hover {
font-family: Trebuchet MS , Arial, Helvetica, sans-serif;
font-weight: normal;
color: #6191C5;
font-size: 200%;
margin:0;
margin-bottom:0px;
line-height:normal;
}
h1, h1 a, h1 a:hover {
font: 20px/20px Arial, Helvetica, sans-serif;
color: #FFFFFF;
margin: 0;
}
h2, h3 {
font: 18px/18px Arial, Helvetica, sans-serif;
color: #FFFFFF;
margin: 2px 0 0 0;
padding: 2px 5px;
border: dashed 1px #FFFFFF;
}
h2 a, h2 a:hover, .block h3, .block h3 a {
font: 18px/22x Arial, Helvetica, sans-serif;
color: #FFFFFF !important;
margin: 0;
padding: 0;
}
#sidebar-left-region h2,
#sidebar-left-region h3,
#sidebar-right-region h2,
#sidebar-right-region h3 {
font: 16px/16px Arial, Helvetica, sans-serif;
color: #FFFFFF;
margin: 0;
padding: 20px 0 0 0;
border: none;
}
h4, h5, h6 {
font-weight: bold;
font-family: Arial, Helvetica, sans-serif;
}
/** header styles **/
#header-wrapper {
position: relative;
display: block;
background-color: #336699;
height: 120px;
}
#header-region {
}
#logo {
float: left;
width: 50px;
margin: 12px 0 0 12px;
padding: 8px 12px;
border: solid 10px #FFFFFF;
background-color: #6699CC;
}
#sitename {
float: left;
margin-top: 30px;
}
#sitename h1 a{
font: 28px/28px Arial, Century Gothic , Verdana;
color: #FFFFFF;
margin-left: 7px;
text-decoration: none;
}
#searchbox {
float:right;
width:210px;
height: 20px;
margin-top:85px;
margin-right:0px;
}
#search .form-text {
width: 137px;
vertical-align: middle;
border: 1px solid #6699CC;
}
#search .form-submit {
padding: 0 3px;
vertical-align: middle;
border-top: 1px solid #FFFFFF;
border-right: 1px solid #666666;
border-bottom: 1px solid #666666;
border-left: 1px solid #FFFFFF;
}
.submitted {
color: #333333;
}
.submitted a{
color: #000000;
}
#primary-links {
position: relative;
display: block;
height:20px;
width:974px;
border-top: solid 12px #FFFFFF;
background-color: #666666;
}
#primary-links ul {
padding:0;
margin:0;
list-style:none;
}
#primary-links ul li {
display:inline;
}
#primary-links ul li a, #primary-links ul li a:visited {
padding: 3px 10px 0 10px;
font: 10px/13px Verdana, Arial, Helvetica, sans-serif;
color: #FFFFFF;
float: right;
}
#primary-links ul li a:hover {
color: #000000;
}
#secondary-links {
position: relative;
display: block;
height:20px;
width:974px;
margin-top: -12px;
border-bottom: solid 12px #FFFFFF;
background-color: #666666;
}
#secondary-links ul {
list-style: none;
}
#secondary-links ul li {
display: inline;
}
#secondary-links ul li a, #secondary-links ul li a:visited {
padding: 3px 10px 0 10px;
font: 10px/13px Verdana, Arial, Helvetica, sans-serif;
color: #FFFFFF;
float: right;
}
#secondary-links ul li a:hover {
color: #000000;
}
#mission {
position: absolute;
left: 113px;
top: 60px;
}
#site-slogan {
position: absolute;
left: 113px;
top: 73px;
}
/** content area styles **/
#main-wrapper{
position: relative;
width:auto;
height: 100%;
border-top: solid 12px #FFFFFF;
background-color: #336699;
}
#content-region-none {
padding: 12px 10px 10px 10px;
position: relative;
}
#content-region-left {
width: 743px;
padding:12px 0px 10px 10px;
position: relative;
float:left;
}
#content-region-right {
width: 743px;
padding:12px 10px 10px 10px;
position: relative;
float:left;
}
#content-region-both {
width: 533px;
padding:12px 10px 10px 10px;
position: relative;
float:left;
}
#tabs {
}
.content-title {
}
/** sidebar styles **/
#sidebar-left-region{
position:relative;
float:left;
width:200px;
padding: 0px 0 0 10px;
}
#sidebar-right-region{
position:relative;
float:right;
width:200px;
padding: 0px 10px 0 0;
}
/** footer styles **/
#footer-region {
position:relative;
width: auto;
height:40px;
margin:0 auto;
clear:both;
border-top:12px solid #FFFFFF;
}
#feed-icons {
float:right;
padding: 8px;
}
#footer-text {
position:relative;
display: block;
height: 30px;
float:left;
color: #FFFFFF;
font-size: 10px;
line-height: 35px;
left: 10px;
}
/** Admin Style **/
/* Tabs */
ul.primary {
border-bottom: solid 1px #18324B;
}
ul.secondary {
border-bottom: solid 1px #18324B;
}
ul.primary li.active a.active {
background-color:#2B5986;
border: solid 1px #18324B;
}
ul.primary li a {
background-color:#6699CC;
}
ul.secondary li {
margin-bottom: 5px;
}
/* Region: content */
#content-region-both table {
width: 530px;
}
table thead {
color: #FFFFFF;
}
table tbody tr.odd,
table tbody tr.odd td.menu-disabled{
background: #2B5986;
border-bottom: solid 1px #336699;
}
table tbody tr.even,
table tbody tr.even td.menu-disabled{
background: #2D5E8D;
border-bottom: solid 1px #336699;
}
table tr td.region{
font-weight: normal;
color:#FFFFFF;
background: #6699CC;
}
ul.secondary li.active a.active {
border-bottom: solid 1px #18324B;
}
While the vast majority of the selectors defined in our style.css are basic (we used a bare minimum for this example), you should note the following, which relate to the implementation of the three-column layout:
#content-region-none {
padding: 12px 10px 10px 10px;
position: relative;
}
#content-region-left {
width: 743px;
padding:12px 0px 10px 10px;
position: relative;
float: left;
}
#content-region-right {
width: 743px;
padding:12px 10px 10px 10px;
position: relative;
float: left;
}
#content-region-both {
width: 533px;
padding:12px 10px 10px 10px;
position: relative;
float: left;
}
These selectors work together with the dynamic styling we applied to the main content column (<div id="content-region-<?php print $layout ?>">) to create a center column that expands to fill either the right or left column when either of the sidebars carry no blocks. The styles, in other words, are critical to creating a template that can support a one-, two- or three-column layout.
The technique used to create the fluid columns structure is discussed below, in the section on Creating Dynamic CSS Styling.
A Look at Our New Theme
With the completion of the style.css file, the new theme is ready for use.
Our new theme in action. Note that this screenshot shows sample content and dummy text in position for testing the primary links, the main content area, the site slogan, site mission, and footer message. The Who's Online block has also been assigned to the Left Region.
Extending Your PHPTemplate Theme
Working with Template Variables
Drupal produces variables that can be used to enhance the functionality of themes. Typically, a function is placed in a template file. The function returns values reflecting the state of the template. A function may indicate, for example, whether the page is the front page of the site, or whether there are one, two, or three active columns. Tapping into this information is a convenient way for a theme developer to style a site dynamically.
The default Drupal variables cover the most common (and essential) functions, including creating unique identifiers for items. Some of the Drupal variables are unique to particular templates, others are common to all. In addition to the default variables, you can also define your own variables.
Let's look first at the default Drupal variables, then at intercepting and overriding the default variables, and finally, at creating your own variables.
Variables Available in block.tpl.php
The system provides the following variables for the block.tpl.php template:
The $block object includes the following standard fields:
| Variable | Function |
|---|---|
$block->content
| The HTML content for the block. |
$block->delta
| The number of the block. |
$block->module
| The name of the module that generated the block. |
$block->region
| The Region name (can be any Region defined by system or user). |
$block->status
| The status of the block (either 0 or 1). |
$block->subject
| The block's title. |
$block->throttle
| The throttle setting. |
Other variables available in the block template include:
| Variable | Function | |
|---|---|---|
$block_id
| Unique to the block. | |
$block_zebra
| Odd/even label created for each block, unique to each sidebar. | |
$directory
| The directory in which the theme is located. | |
$id
| Sequential ID of the block (first block is 1; second block is 2, etc.). | |
$is_front
| True if the front page is currently being displayed, false if not. | |
$zebra
| Creates alternating label for blocks (odd or even). |
Variables Available in box.tpl.php
The system provides the following variables for the box.tpl.php template.
| Variable | Function |
|---|---|
$content
| The content of the box. |
$region
| The name of the Region in which the box is displayed. |
$title
| The title of the box. |
Variables Available in comment.tpl.php
The system provides the following variables for the comment.tpl.php template.
| Variable | Function |
|---|---|
$author
| Name of comment's author with a link to the author profile. |
$comment (object)
| The comment object. |
$content
| The body of the comment. |
$date
| Formatted creation date of the post. |
$directory
| The relative path to the directory in which the theme is located. |
$id
| Sequential ID of the comment displayed (first comment is 1, second comment is 2, etc.). |
$is_front
| True if the front page is currently being displayed, false if not. |
$links
| The links below the comment. |
$new
| Text for 'new' (where the comment is new). |
$picture
| HTML for user's picture. |
$submitted
| The Submitted by text. |
$title
| Link to the comment title. |
$zebra
| Creates alternating label for comments ('odd' and 'even'). |
Variables Available in node.tpl.php
The system provides the following variables for the node.tpl.php template.
| Variable | Function |
|---|---|
$content
| Node content (teaser if it is a summary). |
$date
| Formatted creation date of the node. |
$directory
| The relative path to the directory in which the theme is located. |
$id
| The sequential ID of the node displayed in a list. |
$is_front
| True if the front page is currently being displayed, false if not. |
$links
| The links associated with the node (e.g., read more, add comment). |
$name
| The formatted name of the user who authored the page. |
$node (object)
| The node object. |
$node_url
| The permanent URL to the node. |
$page
| True if the node is being displayed by itself as a page. |
$picture
| HTML for user's picture. |
$sticky
| True if the node is sticky. |
$submitted
| The Submitted by text. |
$taxonomy (array)
| An array of HTML links for the taxonomy terms. |
$teaser
| Whether the teaser is displayed (true or false). |
$terms
| HTML for the taxonomy terms associated with this node. |
$title
| The title of the node. |
$zebra
| Creates alternating label for nodes ('odd' and 'even'). |
Variables Available in page.tpl.php
In additional to the basic variables included in the example page.tpl.php file we built earlier in this tutorial, there are a number of other variables that are available for your use:
| Variable | Function |
|---|---|
$base_path
| The base URL path of the Drupal installation. |
$breadcrumb
| HTML for displaying the breadcrumb trail. |
$closure
| Placed at bottom of page to provide closure for any dynamic JavaScripts that need to be called once the page has
been displayed. |
$content
| The HTML content generated by Drupal. |
$css
| An array of all the CSS files for the page. |
$directory
| The relative path to the directory in which the theme is located. |
$feed_icons
| The links to the RSS feeds for the page. |
$footer_message
| The footer, including the footer message set by the admin. |
$head
| The HTML that will appear inside the <head></head> tags.
|
$head_title
| The text displayed in the page title (between the <title> and </title> tags).
|
$help
| The dynamic help text. |
$is_front
| True if the front page is currently displayed, false if not. |
$language
| The site's language setting. |
$layout
| Set different types of layout, depending on how many sidebars are enabled (values include none,
|
$logo
| Sets path to logo image (as defined in admin). |
$messages
| HTML for status and error messages. |
$mission
The text of the site mission, as defined in admin. | |
$node
| Available when displaying a node in full page view. |
$primary_links (array)
| An array containing the links designated as primary by admin. |
$scripts
| Loads the <script> tags into the page.
|
$search_box
| The HTML for the theme search box. |
$secondary_links (array)
| An array containing the links designated as secondary by the admin. |
$sidebar_left
| The HTML for the left sidebar Region. |
$sidebar_right
| The HTML for the right sidebar Region. |
$site_name
| The site name, as defined by admin. |
$site_slogan
| The site slogan, as defined by admin. |
$styles
| Includes the style sheets. |
$tabs
| HTML for displaying the tabs. |
$title
| The main content title, typically the node title. |
Intercepting and Overriding Variables
You can intercept and override the system's existing variables. Intercepting a variable is no different in practice from intercepting a themeable function: you simply restate it in the template.php file and make your modifications there, leaving the original code in the core intact. In this fashion, you are able to maintain your modifications inside the theme directory, rather than by modifying the core files.
To intercept an existing variable and override it with your new variable, you need to use the function _phptemplate_variables(), which is added to the template.php file with the following syntax:
<?php
function _phptemplate_variables($hook, $vars = array()) {
switch ($hook) {
// add your code here...
}
return $vars;
}
?>
Let's take an example and apply this. Assume you wish to substitute a new value for $title in page.tpl.php. To accomplish this task, add the following code to the template.php file:
<?php
function _phptemplate_variables($hook, $vars = array()) {
switch ($hook) {
case 'page' :
$vars['title'] = 'override title';
break;
}
return $vars;
}
?>
With this change made and the file saved to your theme, the string "override title" will appear, substituted for the original $title value. Note that the function specifies 'page'; this points our function to the page theme hook.
Making New Variables Available
PHPTemplate also allows you to define additional custom variables in your theme. To create a new variable, you must declare the function _phptemplate_variables() in the template.php file. The syntax is the same as that just used for intercepting and overriding a variable:
<?php
function _phptemplate_variables($hook, $vars = array()) {
switch ($hook) {
// add your code here...
}
return $vars;
}
?>
In this case, we will add a new variable, 'newvar' to the page theme hook:
<?php
function _phptemplate_variables($hook, $vars = array()) {
switch ($hook) {
case 'page' :
$vars['newvar'] = 'new variable';
break;
}
return $vars;
}
?>
The ability to add new variables to the system is a powerful tool and gives you the ability to add more complex logic to your template, for example, to set variables to track user status (logged in or not).
Dynamically Styling Modules and Blocks
In this tutorial, we want to look at how to control the formatting of a site's Blocks, regardless of their contents.
Block output is controlled by the block.tpl.php template. As we have seen in other areas, PHPTemplate will look to the names given multiple template files to determine which template to display. The order of precedence used for the Block template is consistent with that used elsewhere:
The naming convention determines what is displayed. At the most specific, you can provide a template to apply to the Blocks of a specific module of a specific delta (block-modulename-delta.tpl.php). You can also attach a template to Blocks of a module by module name (block-modulename.tpl.php), or to the Blocks of a particular Region (block-regionname.tpl.php). Failing the presence of any of the above, the system applies the default block.tpl.php template.
Note that the order of precedence includes the module name, that is, the name of the module that produces the output being displayed in the Block. Delta is a system-generated value that provides a unique identifier.
If you are not certain of the provenance of your Block, that is, the name of the module that produces it or its delta, try the following, which will give you information on all Blocks on a particular page:
- Open your theme's block.tpl.php file (or create it if it does not exist).
- Add the following at the top of the file:
<?php print_r($block); ?>
- Save.
- Load the page in a browser.
When you view the page, the information will appear for each Block active on that page. Here's the information that would appear for our theme Bluewater, when the Who's Online Block is placed in the left sidebar:
stdClass Object ( [module] => user [delta] => 3 [theme] => bluewater [status] => 1 [weight] => 0 [region] => left [custom] => 0 [throttle] => 0 [visibility] => 0 [pages] => [title] => [subject] => Who's online [content] => There are currently...
Note we are given the name of the module that produces the output in this Block (User), the delta (3), as well as other information like the weight, the Region, etc.
With this information, we can then assemble the following example showing the order of precedence relative to this Block:
| Template | Will apply to... |
|---|---|
block-user-3.tpl.php
| the Who's Online block |
block-user.tpl.php
| All blocks output by the User module |
block-left.tpl.php
| All blocks in the sidebar-left region |
block.tpl.php
| All blocks |
Build a New Pure PHP Theme
Given the popularity of the PHPTemplate engine, and the extent that it eases the difficulties attendant to theming, it is probably no surprise that few people choose to build their themes without the use of the theme engine. Moreover, pure PHP themes tend to be more difficult to maintain over time and there are fewer help resources available in the Drupal community (as most people employ one of the theme engines). Given the advantages of PHPTemplate, and the drawbacks of building without it, it is very hard to recommend that you build a pure PHP theme; indeed, without some special circumstance, I would recommend against it.
That said, it is possible to build pure PHP templates, without the use of PHPTemplate (or any other theme engine) and in this section we will look at the basics behind this approach to theming, and give you the information you need to get started, should you decide this is how you want to proceed.
Building a theme in pure PHP requires a slightly different approach to theming. A number of the functions that would normally be handled by the PHPTemplate engine must be coded into your PHP theme. Open up the file chameleon.engine (inside the Chameleon theme) with your editor. When you examine the code, it will be immediately apparent that this is radically different from what we've seen so far in this tutorial.
The learning process associated with building PHP themes for Drupal can be challenging unless you have strong PHP skills. For most people, the correct first step will be to crack open the Chameleon directory and copy the elements you need. Copying the code from the Chameleon theme and modifying it to fit your needs is not only a great way to learn but also a huge time saver, as it cuts down dramatically on the chance for errors.
Required Elements
The only required file you need for a pure PHP theme is the themename.engine file. This is a plain PHP file and will be placed into the sites/all/themes/themename directory. For development purposes, you should also copy into that directory a sample logo; the Drupal logo will work just fine.
The themename.engine file begins with the declaration of two functions: themename_features() and themename_regions().
The first function is necessary to specify which of the optional theme configuration settings are enabled, the second to enable the Regions. Both of these functions are required.
Let's use the Chameleon theme as our example. The theme configuration options enabled in chameleon.engine are: logo, favicon, name, and slogan. Here's the code that sets that up:
<?php
function chameleon_features() {
return array(
'toggle_logo', 'toggle_favicon',
'toggle_name',
'toggle_slogan');
}
?>
This tells the system to enable the logo, favicon, site name, and site slogan options in the theme configuration settings. You can add others, or delete from this list.
The features available to function themename_features() include:
| Feature | Functionality |
|---|---|
logo
| Logo can be used. |
toggle_comment_user_picture
| Optional display of user picture next to comments. |
toggle_logo
| Logo can be toggled on or off by administrator. |
toggle_mission
| Site mission can be toggled on or off by administrator. |
toggle_name
| Site name can be toggled on or off by administrator. |
toggle_node_user_picture
| Optional display of user picture next to nodes. |
toggle_search
| Theme search box can be toggled on or off by administrator. |
toggle_slogan
| Site slogan can be toggled on or off by administrator. |
The second required element is the themename_regions() function, which enables the Regions for the theme's Block placement. Turning to the Chameleon theme once again, you will see that the theme only enables two Regions for Block placement: left and right.
<?php
function chameleon_regions() {
return array(
'left' => t('left sidebar'),
'right' => t('right sidebar')
);
}
?>
You can establish whatever Regions you wish to use for the Blocks in your theme by expanding on this, using the same syntax.
Once these functions have been declared, you can begin to place the page elements and the layout.
Note that the Chameleon author also handles a couple of housekeeping matters at the top of the file. First, $title is defined in order to incorporate the Drupal site name and $blocks_left and $blocks_right are provided for use in placing the themed blocks.
HTML Headers
Placing the necessary HTML headers is done with two $output statements, as below:
$output = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"; $output .= "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"$language\" xml:lang=\"$language\">\n";
Head of Document
The header of the resulting web page needs to incorporate the Drupal head elements, along with the various style sheets and scripts. The code below does this, as well as invoking $title (set earlier in the document), the site name, and the site slogan.
$output .= "<head>\n";
$output .= " <title>". ($title ? strip_tags($title) ." | ". variable_get("site_name", "Drupal") :
variable_get("site_name", "Drupal") ." | ". variable_get("site_slogan", "")) ."</title>\n";
$output .= drupal_get_html_head();
$output .= drupal_get_css();
$output .= drupal_get_js();
$output .= "</head>";
Implementing the Features
At the top of the document, the author declared the function chameleon_features(). In addition to declaring the features you must also insert the code to implement the conditions attached to those features and display the resulting output.
Favicon
The author deals with the setting of the Favicon early in the document, prior to the output of the head of the document, and thereby makes the <link rel> tag available to the document head when it is output. All the other features, below, are placed in the body of the page where they will appear in the layout.
if (theme_get_setting('toggle_favicon')) { drupal_set_html_head('<link rel="shortcut icon" href="'. check_url(theme_get_setting('favicon')) .'" type="image/x-icon" />'); }
Logo
The following conditional statement enables the logo to be toggled on or off, wraps the image in an <a> tag and also sets the title and alt attributes.
if ($logo = theme_get_setting('logo')) {
$output .= " <a href=\"". base_path() ."\" title=\"". t('Home') ."\"><img src=\"$logo\" alt=\"". t('Home') ."\" /></a>";
}
Site Name
This snippet enables the site name to be toggled on or off, and wraps it with an H1 tag and a class.
if (theme_get_setting('toggle_name')) {
$output .= " <h1 class=\"site-name title\">". l(variable_get('site_name', 'drupal'), ""). "</h1>";
}
Note- You have probably noticed by now the recurrence of the l() function. This function is the key to tying into Drupal's language system and enables the system to support multiple languages. Preserve the l() function in your overrides and code to be able to maintain the system's support for multi-lingual labels, error messages, and alerts.
Site Slogan
The following statement enables the site slogan to be toggled on or off, and wraps it with a div and a class for styling.
if (theme_get_setting('toggle_slogan')) {
$output .= " <div class=\"site-slogan\">". variable_get( 'site_slogan', '') ."</div>";
}
Primary and Secondary Links
Chameleon combines the placement of the primary and secondary links, basically locking the secondary links into a subnavigation role. You don't have to group these two items together in this fashion, but it is one logical option.
Note the snippet below. In both cases, the display of the links is conditional (depending on what is enabled by the administrator). If either one is enabled, then it will appear inside a div with the class navlinks. Additionally, to be able to style each set of links individually, both $primary_links and $secondary_links are provided with a unique class and id.
$primary_links = theme('links', menu_primary_links(), array('class' => 'links', 'id' => 'navlist'));
$secondary_links = theme('links', menu_secondary_links(), array('class' => 'links', 'id' => 'subnavlist'));
if (isset($primary_links) || isset($secondary_links)) {
$output .= ' <div class="navlinks">';
if (isset($primary_links)) {
$output .= $primary_links; }
if (isset($secondary_links)) {
$output .= $secondary_links; }
$output .= " </div>\n";
}
Sidebars
The placement of the sidebars is split in the code (reflecting the placement within the table structure) with the left sidebar appearing first, followed by the main content area (discussed below), then the footer (see, below) and finally the right sidebar. The author only declared two Regions for this theme, left and right; as you might expect, those two Regions are placed in the left and right sidebars, respectively.
Sidebar Left
The following places the blocks designated for the left Region into a table cell. Note the conditional statement; this allows the output to be hidden in the event that no blocks are assigned to the Region. For styling, the table cell (td) is given an id named to reflect the placement (sidebar-left).
if ($show_blocks && !empty($blocks_left)) {
$output .= " <td id=\"sidebar-left\">$blocks_left</td>\n";
}
Source
The source of this content is Chapter 7: Building a New Theme of Drupal 5 Themes by Ric Shreves (Packt Publishing, 2007).
Executive Editor Sean Lopez own : SEO Company and provider of Link Building Services and SEO Services
And Like Costumes and Halloween Costumes and criar sites and desenvolvimento de site and Unhas and Tokio Hotel and Escola de Surf
And Like The Global Information Network and Global Information Network
And Like Scholarship for Moms and
Pearl Necklace and Pearl Necklaces and
Iphone App Developers and Fine Jewelry and Affordable Web Design and Email Marketing and
Adoption.
Main Content Area
The author of Chameleon has set up a number of critical elements to appear inside the main content area. The section will appear as the middle column where there are blocks assigned to both left and right sidebars. The entire set of elements is placed inside a table cell and styled with the id main:
$output .= " <td id=\"main\">\n";
Source
The source of this content is Chapter 7: Building a New Theme of Drupal 5 Themes by Ric Shreves (Packt Publishing, 2007).
Executive Editor Sean Lopez own : SEO Company and provider of Link Building Services and SEO Services
And Like Costumes and Halloween Costumes
And Like The Global Information Network and Global Information Network
And Like Scholarship for Moms and Pearl Necklace and Pearl Necklaces and Iphone App Developers and Fine Jewelry and Affordable Web Design and Email Marketing and Adoption.
Source
The source of this content is Chapter 7: Building a New Theme of Drupal 5 Themes by Ric Shreves (Packt Publishing, 2007).
Executive Editor Sean Lopez own : SEO Company and provider of Link Building Services and SEO Services
And Like Costumes and Halloween Costumes
And Like The Global Information Network and Global Information Network Logo Design & ""Website Design"" by ThemesWiki.org Kevin Josh 2010
And Like Scholarship for Moms and
Pearl Necklace and Pearl Necklaces and
Iphone App Developers and Fine Jewelry and and Email Marketing and
Adoption and Pearls and Ceramic Mills
Source
The source of this content is Chapter 7: Building a New Theme of Drupal 5 Themes by Ric Shreves (Packt Publishing, 2007).
Executive Editor Sean Lopez own : SEO Company and provider of Link Building Services and SEO Services
And Like Costumes and Halloween Costumes
And Like The Global Information Network and Global Information Network
And Like Scholarship for Moms and
Pearl Necklace and Pearl Necklaces and
Iphone App Developers and Fine Jewelry and Affordable Web Design and Email Marketing and
Adoption.
Source
The source of this content is Chapter 7: Building a New Theme of Drupal 5 Themes by Ric Shreves (Packt Publishing, 2007).logo design by Kevin Josh 2010
Additional References
- For instructions on Customizing Drupal 6 Themes, click here
- For instructions on installing Drupal, click here
- For instructions on Theming Drupal, click here
- For instructions on Advanced Theming on Drupal Multimedia, click here
- For instructions on Customizing Drupal Theme- CSS , click here
- For instructions on Troubleshooting Drupa, click here
- For instructions on Setting Up The Development Environment for Drupal 6, click here
- For instructions on Creating and Customizing Drupal 6 Themes, click here
- For instructions on Theming Drupal6, click here
- For instructions on Theming Drupal 5 Views Recipes, click here
- For instructions on Setting up Drupal for web services, click here
- For instructions on Installing Drupal Views Module , click here
Source
The source of this content is Chapter 7: Building a New Theme of Drupal 5 Themes by Ric Shreves (Packt Publishing, 2007).
Executive Editor Sean Lopez own : SEO Company and provider of Link Building Services and SEO Services
And Like The Global Information Network and Global Information Network Logo Design & ""Website Design"" by ThemesWiki.org Kevin Josh 2010
