Drupal Theme System (Part 2)
In this series I am going to explore the Drupal Theme System: how it works, how to override core functions, common hacks and code snippets, and how to build your Drupal site exactly how you want it. In this post we'll explore specifics of how to override core theme function.
In part 1 of this series we looked at what the Drupal theme system is and an overview of how to use the theme() function. In this post I'd like to look specifically at how to implement theme overrides and in the next post well look at how to implement your own theme_ functions.
Theme Overrides
We briefly looked at how theme overrides work in my last post so you should have a general idea of the concept of theme overrides at this point, what I'd like to show is how to find out what you are trying to override and where to implement that override.
1. Discovering The theme_*** function
A great resource for discovering the theming function used to render an object is to use the Theme Developer Module.
This module used to be packaged with the Devel module but is now it's own package on Drupal.org. Once enabled this module provides a little checkbox at the bottom of the page to turn it on. After turning it on you will find that any item you hover over will be highlighted with a red outline. Clicking upon any item will bring up the box seen on the right. As you can see in the screenshot it gives a lot of useful information about what function was called, the arguments passed to that function, the parent functions that were called, and possible candidate function names for overriding it. (Check out the Documentation for Theme Developer)
(NOTE: while there is technically nothing wrong with using the suggested phptemplate_ as an override, don't do it. Yes core themes sometimes do, I'm looking at you Garland, but it is much better practice to just use your theme/module name to reduce any chance of a conflict.)
2. Implementing your override
So now you've figured out what the function you want to override is and you've got an idea of the naming convention for your override, the next step is to implement the override. Within your theme you'll want to create a template.php file(if it doesn't already exist, which it most likely does if you are using any contributed theme). This file is a regular php file and should be set up as such. Next you'll want to grab the code for the theme function you are going to override, we'll use theme_username as before. Using one of the Drupal API sites, I prefer http://api.lullabot.com, look up and then copy and paste that function into your template.php file.
<?php
function theme_username($object) {
if ($object->uid && $object->name) {
// Shorten the name when it is too long or it will break many tables.
if (drupal_strlen($object->name) > 20) {
$name = drupal_substr($object->name, 0, 15) .'...';
}
else {
$name = $object->name;
}
if (user_access('access user profiles')) {
$output = l($name, 'user/'. $object->uid, array('attributes' => array('title' => t('View user profile.'))));
}
else {
$output = check_plain($name);
}
}
else if ($object->name) {
// Sometimes modules display content composed by people who are
// not registered members of the site (e.g. mailing list or news
// aggregator modules). This clause enables modules to display
// the true author of the content.
if (!empty($object->homepage)) {
$output = l($object->name, $object->homepage, array('attributes' => array('rel' => 'nofollow')));
}
else {
$output = check_plain($object->name);
}
$output .= ' ('. t('not verified') .')';
}
else {
$output = check_plain(variable_get('anonymous', t('Anonymous')));
}
return $output;
}
?>
The reason I suggest doing this is that you now have a starting block to work from. You can modify the existing code to fit your needs rather then trying to figure out what to do with a blank function. As you get more comfortable with Drupal, you may decide to just skip this step, but I generally will always at least copy the and paste the first line of the function so I make sure I'm getting the right variable set up in my override function.
The next thing you'll want to do is change the function name. As I mentioned above, the Theme Developer module will give a list of suggested override names, but I would suggest you throw out the phptemplate naming convention and just use your themes name. Let's assume out theme is called Super Awesome theme and we have it in a folder named sa and it's info file is called sa.info our theme name is sa.
<?php
function sa_username($object) {
//rest of the function
}
?>
Now our themes sa_username function will be called anytime theme('username') is called. (If you have completed these steps but your override function is not being called, you probably need to flush the theme registry. Admin Menu module provides a handy link for this and is my preferred way to accomplish this.) So now we want to actually edit our override function. I'll show a bit of code that I recently employed on this site.
<?php
function sa_username($object) {
if ($object->uid && $object->name) {
// Shorten the name when it is too long or it will break many tables.
if (drupal_strlen($object->name) > 20) {
$name = drupal_substr($object->name, 0, 15) .'...';
}
else {
$name = $object->name;
}
if (user_access('access user profiles')) {
$output = l($name, 'user/'. $object->uid, array('attributes' => array('title' => t('View user profile.'))));
}
else {
$output = check_plain($name);
}
}
else if ($object->name) {
// Sometimes modules display content composed by people who are
// not registered members of the site (e.g. mailing list or news
// aggregator modules). This clause enables modules to display
// the true author of the content.
if (!empty($object->homepage)) {
$output = l($object->name, $object->homepage, array('attributes' => array('rel' => 'nofollow','title'=>$object->homepage.' (opens in new window)','target'=>'_blank')));
}
else {
$output = check_plain($object->name);
}
//$output .= ' ('. t('not verified') .')';
}
else {
$output = check_plain(variable_get('anonymous', t('Anonymous')));
}
return $output;
}
?>"What's the difference between the two?", you may ask. Well it's that one line of code where I comment out the display of "not verified". I use this so that when non registered users, which is everyone except for me, post comments the username it displays doesn't show up with (not verified) next to it. It seems like a lot of work and code for a simple little fix like that, right? Well, yes and no.
You see that's the beauty of this whole system. Many CMS's wouldn't even allow you the ability to change something like that without hacking core files, Drupal was well thought out enough that the developers knew that changing one line of code can make all the difference in the world to a developer and so they made it available. I would have hated to have that line of text show up on my site, but I wouldn't have wanted to hack core to remove it, but luckily thanks to Drupal I don't have to hack anything.
Obviously this is a simple example but you can see that from here you could control much more then just one line of code. Here are some examples I have used from theme_username:
<?php
//I want to link usernames to a website provided in a profile field and not to the user/* page
//Replace these lines
if (user_access('access user profiles')) {
$output = l($name, 'user/'. $object->uid, array('attributes' => array('title' => t('View user profile.'))));
}
//With something like the following. (just use your profile field rather then the placeholder I used)
if ($object->profile_website) { //Check to see if they have filled out this feild
$output = l($name, $object->profile_website, array('attributes' => array('title' => t('View website.'))));
}
//I want to output all usernames as plain text
//replace the following peices of code
if (user_access('access user profiles')) {
$output = l($name, 'user/'. $object->uid, array('attributes' => array('title' => t('View user profile.'))));
}
else {
$output = check_plain($name);
}
//and
if (!empty($object->homepage)) {
$output = l($object->name, $object->homepage, array('attributes' => array('rel' => 'nofollow')));
}
else {
$output = check_plain($object->name);
}
//with this
$output = check_plain($name);
//and this respectively
$output = check_plain($object->name);
?>Those are some quick examples of other things you could do with theme_username. The possibilities are limited to the data at hand and you ability to code out a solution. So dig in and start customizing the output of theme() function to make you site look exactly the way you want.

Search Site
Latest Posts
Get In Touch
Feel free to contact me about how I can help with your next Web project.
Telephone: 910-808-1717
E-mail: info@adamagregory.com


Add Your Comment