A couple weeks ago, Matt Tucker and I gave some folks at our local Drupal users group a preview of our recently contributed theme pack called Studio. We're announcing the official 1.0 version release of the theme and we felt it would be interesting to provide some background.
A bit of history
I began working with Drupal back in January 2007 as version 5 was just coming out. My comfort level and skills increased in the theming layer over the course of time. These experiences, married with community input, identified new elements that we thought beneficial to a base theme. This theme was contributed to the community as Hunchbaque.
Hunchbaque became pingVision's standard base theme through Drupal 5's life cycle. It provided the company with time savings by avoiding repetitive efforts on each project. There were, however, limitations. The most significant being development of a brand new version of the theme for every site.
As Drupal 6 approached a stable release, I began porting Hunchbaque. I approached this assuming I could leverage the relationship between base themes and sub-themes. However, as I continued development, I found I could do so much more. Early versions, in Drupal 6, illustrated new flexibility that didn't exist in Drupal 5.
I decided that to take full advantage, it would be best to start from scratch. The Studio theme pack was created. The theme has grown from a simple theme to a full pack of themes. They include Paint, a simple three-column layout; Workspace, an administrative theme; and, soon, a mobile theme.
After several months of maturation and help from co-themer Matt Tucker, we feel it is time to release it to the community. So with the history lesson over, it is time to tell a little more about what this theme contains.
The usefulness of base themes
The Studio set of themes is intended to provide a starting point to quickly begin work on your custom themes. It provides a theme called Canvas as a base that does not get altered and can be upgraded. It should provide a good foundation to quickly get started on a new and original look for a site. The other two (Paint and Workspace) are provided as examples of how to build off of it.
You may be wondering why one should even bother with a base theme. It is a simple matter of preserving reusable code. For many of the themes we have done at pingVision there was a common set of code that every theme contained. Previously this was handled by starting with our in-house theme and modifying it as needed. Unfortunately, this also meant we had to role any useful bits we devoloped in individual projects back into our base. Now that there is a base theme that is exactly the same from project to project, we can simply commit the code and not worry about conflicts.
Cleaning up the theme
The first thing that is possibly noticed is that the template files are now placed in a subdirectory. Not only that, but we have decided to break this up into "custom" and "overrides" directories. This is best illustrated by looking at the CVS repository. We found this made finding needed files easier for us and, best of all, does not require any extra declarations in the theme. This is a Drupal core functionality in version 6 and our arrangement is merely a matter of taste. Feel free to arrange these files as you wish in your subthemes.
Next on the list of generally messy parts of the theme is the template.php. Through the course of building any theme, this gets filled up with a lot of logic in preprocess and theme functions. The simplest way to get this file back to a managable state is to break up the file. We chose to do this a couple different ways.
The biggest culprits that were filling up the template.php file were the many preprocess functions. These got rather large when building out the base classes for the theme and most could justify being a file themselves. For this reason there is a folder named "preprocess" in canvas and the subthemes. In here are several .inc files named for their related hooks. We also wanted to automate the process of including these files so that we did not have to tell PHP to include each manually. The following snippet found in Canvas' template.php allows for this:
<?php
function canvas_preprocess(&$vars, $hook) {
if(is_file(drupal_get_path('theme', 'canvas') . '/preprocess/preprocess-' . str_replace('_', '-', $hook) . '.inc')) {
include('preprocess/preprocess-' . str_replace('_', '-', $hook) . '.inc');
}
}
?>This function is the generic preprocess function that can handle any hook in Drupal. The function checks in the preprocess folder for a file named after the hook. If that file exists, it is loaded into the system. Unfortunately this functionality does not translate to subthemes well. The plus is that it is easy to duplicate for your own themes by copying the above code into your own theme's template.php and changing the word "canvas" to the name of your theme.
The next step in cleaning up the theme is to offload the bulk of custom theme functions and overrides to separate files. Unlike preprocess functions, normal theme functions rarely justify having an individual file for each one. This is why we broke them up into custom theme functions and overrides similar to the tpl files. These files can be found in the folder names "functions".
We take what some would consider nonstandard ways to include these files and that is by overriding the definition of theme function in the theme registry. This is done by simply defining a "file" key in the hook_theme() function. For instance, we wanted to remove the containing <div /> from the theme_item_list(), so we re-register it like so in the Canvas theme:
<?php
funtion canvas_theme() {
return array(
'item_list' => array(
'arguments' => array(
'items' => array(),
'title' => NULL,
'type' => 'ul',
'attributes' => NULL,
),
'file' => 'functions/theme-overrides.inc',
),
)
}
?>Even though this is what some would consider overkill, we like this for a reason other than using the "file" declaration: it gives us a functional list of overridden functions.
Additional defining attributes
There are several ids and classes declared to accommodate many of the situations we have found to be needed in the majority of sites. Logged in status, section designators, types of nodes, etc. With the way these are all added, it should be very easy to add more of your own or even remove some. This system is also upgradeable to accommodate new versions of the Canvas core. Simply add the $attributes variable to the container to the containing element of your template.
In the process of providing all these classes and ids, We found the core drupal_attributes() function inadequate. We had to perform and extra step to format the array of classes into a string since drupal_attributes() only handles strings for the values. For this reason we created theme_render_attributes(). It is very close in functionality to the original function except that it can accept an array or a string for a value.
The value of this expands beyond simple classes and ids also. One example of this is RDFa support in a theme. Details on how this would work is beyond the scope of this post, but it is something we hope to cover in the future.
Stylesheets for Internet Explorer
There is also support for Internet Explorer specific stylesheets. There is a good example on how to use this in the Paint theme's preprocess-page.inc.
<?php
$vars['ie_styles'] = array(
'lte IE 6' => array(
'screen' => array(
path_to_theme() . '/css/lte-ie6.css',
),
),
);
$vars['styles'] .= theme('ie_styles', $vars['ie_styles']);
?>The above process is pretty straight forward. We are constructing an array consisting of a conditional, media type and the path based on the Drupal root. This will allow for multiple stylesheets with similar properties to be grouped together. To get the stylesheets into the page output, simply render them with theme_ie_styles() and append it to the end of the $styles variable.
Region theming
There is now a theme_region() function. This provides a region.tpl.php that you can use to customize and wrap your regions how you wish. No more need to put extra if statements in the page.tpl.php files in your theme. If you need different markup for a certain region, just add a region-[region name].tpl.php to your theme and wrap as needed.
As an example of how this can clean up a file, look no further than Canvas' page.tpl.php. There is less logic, but all the appropriate wrappers are in place. We feel this creates a file that is easier to parse for the themer.
Cutting the fat
In addition to all of this, we have overridden theme functions and template files to trim out as much of the markup as possible. Currently this is limited to major themes in core Drupal and there are many more on the docket to override. In time this will be expanded even further to cover popular modules like Views and CCK.
How do I use this?
To begin using the capabilities of this theme, all you have to do is add base theme = canvas to your theme's .info file. Simple as that. If you wanted to have more of a structured start, you can make a copy of the Paint or Workspace themes and change all instances of the themes name in the included files. As an example, this is the beginning of the Paint theme's .info file:
name = Paint
description = This is a starter derivative theme of Canvas. If you would like to make your own custom theme, copy this one and change the name of the folder and .info file then provide your own information in the .info file.
engine = phptemplate
base theme = canvas
version = 1.x-dev
core = 6.xNow, we must stress that making a duplicate is the proper method for this as we would hate for you to accidentally overwrite your hard work in an upgrade to the theme system.
Conclusion
One of the questions that will be asked is "How does this compare to the other base themes available?" This is a theme that grows and evolves with our company and it fits with what we do. This industry and technology is evolving at a fast pace. There are always new ways to implement various aspects of a site and we want a theme that can change as fast as we can. In the end there will be a lot of similarities between this and other themes out there in the wild. On the flip side, we feel there are enough differences to justify a new contribution to the community.
This concludes our not-so-brief rundown of the theme. In the future, we will be posting some more posts and videos on how to use it. There will also be more information on upcoming improvements later.
[edit] Studio was also presented at Design For Drupal in Boston and DrupalCamp Colorado in Denver. Slides from those presentations are available in pdf here
- Tags: contribution, Drupal, Drupal 6, theme









Comments
Anonymous writes:
Excellent article. I just downloaded the them to play around with it. I do look forward to additional information and the screencast around this particular theme.
dvessel writes:
Nice work. It's interesting to see how others approach the theming layer in a systematic way. I've always strived for this and often failed. My latest I believe is a lot more solid and I solved most of the sub-theming inheritance problems by tapping into the global $theme and $base_themes variable. Pull them from a custom function, merge into the proper order and call it from many places where each layer needs to know the right cascading order. This can be done to include your preprocess files for sub-themes.
Al Steffen writes:
Thanks for the tip on that. I will have to play around with that for one of the next versions. Getting the preprocess file system to be inherited by the subthemes would be near the top of the list of the things I want to get functioning.
sun writes:
http://drupal.org/node/399702
Matt Tucker writes:
Nice link sun. Although I find that discussion interesting, I feel that the process in which .inc files are included in the method described in that issue is not structured enough. The reason we implemented the inclusion of "preprocess files" the way that we did is that it is extremely structured. A single preprocess file for a single template file, it just seems logical. It is easy to find where the preprocess stuff is, and it is easier to add and remove files than it is to search through an un-structured, un-standarized method. While in no way, is what we have done perfect, it strives towards consistency and organization within a theme. Themes are becoming more and more complex and with that, we need organization and consistency.
Jacine writes:
I've personally been hating the mess that D6 themes can become. Even though the new D6 features for theming are great, the lack of any real structure and massive increase in tpl files has been disappointing. I was silently wishing I could go back to Drupal 5 for a while, because IMO, having all the overrides in template.php was better than a mess of files in the theme just thrown in there.
So... I really love this. You guys have done an great job here. It's very logical to me, and I like the structure.
I like the preprocess inc files and the separation of custom function and overrides. I'm sure it really makes remembering what you did in a given theme months later a piece of cake, and also lets someone else come in and easily see what was done, which is key. I hardly have to look in the files to know what's going on, and that is very nice.
Thanks for sharing this with the community!
Jim writes:
Added to DrupalSightings.com
peach - ADT drupal themes writes:
I'm very impressed.
I've been playing with systems that make complex themes more structured but you guys seem to be much better at it.
Also, I never liked the structure of zen subthemes, it still had too much code mixed together, but I love how you took a separation of functionality so far as to separate preprocess, functions and template.php from eachother, as well as separating custom functions from overrides.
To some users this may seem like making the theme much more complicated than it needs to be, but this really is more useful for very complex themes.
I think I'm going to adopt your theme as a basetheme, and end the days of 2000+ lines of template.php :p
By the way you left a dpl($vars) in /studio/canvas/preprocess/preprocess-comment.inc.
Al Steffen writes:
We are glad you all like the structure. The fact I could place .tpl files inside of subfolders was the one thing I was most excited about when I started making the move to D6. I then decided to take things to the next logical conclusion with the preprocess files.
Even if people do not use the theme directly, I hope they can at least use it for an example of what can be done.
Also, thank you for the bug report and the issue cue post. It is much appreciated. There will be a fix in 1.1 when it comes out later today.