User login

Drupal Tutorials

Drupal theme function overriding

1
Friday, August 1, 2008

For those new to Drupal the term Drupal theming can sound a little scary but really it really isn’t something you should fear!
Drupal theming in its simplest form in just a HTML/CSS layout with a bunch of PHP tags dropped in.

There seems to be a perception that Drupal theming is something really difficult but to be honest if your HTML and CSS skills are up to scratch and you’re open to learning some basic PHP you’ll have no problems.

Drupal can run on different theme engines but as of Drupal 4.7 the phptemplate theme engine became standard, so that’s what we’ll focus on in this tutorial.

What is a theme function?

A theme function is a PHP function withing Drupal that is prefixed with theme_. Theme functions display HTML, and which can be customized by themes.
This is how Drupal.org defines a theme function:

All functions that produce HTML for display should be themeable. This means that they should be named with the theme_ prefix, and invoked using theme() rather than being called directly. This allows themes to override the display of any Drupal object.

How do theme functions work?

Next we’ll need to understand how and when theme functions are executed. In every page load and number of theme functions can be executed by Drupal.

For example you may have a page listing all of the users on your site and this list would call the function theme_username (that we’ll look at more later) for every user in the list to output the users username as a link. This user list may then be passed to another theme function and then finally the content will be passed to the theme_page function which is automatically used by Drupal in order to display your page content within your themes page template.

Modules declare and generally execute theme functions although you can call a theme function from anywhere in your Drupal site (ie. From your theme) providing the module providing the theme function has been loaded.

The great thing is using our themes template.php file we can override any theme function we like without having to edit a single module and this is where using a template.php file becomes so powerful.

Let me briefly explain what I mean by override. By override I mean declaring a new version of a theme function (in template.php) and completely by passing the original theme function in order to alter its output.

An example

Let’s take a look at the theme_username function to explain how to do a theme function override.

Who's New block outputAs I mentioned previously the theme_username function outputs a given users username, so every time you want to display a users username rather than retype a load of code all you need to do is call this function. The "who’s new" block is a great example of where this function is used (see grab to the right). But let’s say you want to change the output of this function so that every time a username is displayed the users user ID is shown after the username, not hugely useful but should give you the idea. It’s fairly simple we just need to override the theme_username function like so:

  1. Open up your template.php file that can be found within your themes root folder or if you don’t have one simply make a PHP file and save it to your themes root folder as template.php. By root folder I mean where your page.tpl.php is located.
  2. Next open up the theme.inc file located in the includes folder with notepad or whatever text editor you use. This is the file that declares the function we want to override.
  3. Find the function theme_username within the theme.inc code then copy and paste the whole function into your template.php file. You can now also close the theme.inc file as we won’t need it again.
    <?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('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 ($object->homepage) {
         
    $output = l($object->name, $object->homepage);
        }
        else {
         
    $output = check_plain($object->name);
        }

       
    $output .= ' ('. t('not verified') .')';
      }
      else {
       
    $output = variable_get('anonymous', t('Anonymous'));
      }

      return
    $output;
    }
           
    ?>
    The theme_username function found in theme.inc

  4. In your template.php file rename the theme_username function to phptemplate_username and save the file. This puts our template.php file in control of the theme_username function and completely bypasses the theme.inc version of the function.

    Before
    <?php
    function theme_username($object) {
    ?>
    After
    <?php
    function phptemplate_username($object) {
    ?>
  5. We can now make any changes to the function we desire and all at theme level so we’re not messing with any modules or themes.
    So let’s go ahead and add the users user ID after their username by modifying the last line of the phptemplate_username function to look like so:
    <?php
      $output
    .= '('. $object->uid .')';
      return
    $output;
    }
    ?>

    So your final phptemplate_username function should look like this:
    <?php

    function phptemplate_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('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 ($object->homepage) {
         
    $output = l($object->name, $object->homepage);
        }
        else {
         
    $output = check_plain($object->name);
        }

       
    $output .= ' ('. t('not verified') .')';
      }
      else {
       
    $output = variable_get('anonymous', t('Anonymous'));
      }

     
    $output .= ' ('. $object->uid .')';
      return
    $output;
    }
    ?>
  6. Save the template.php file and as you should see something similar to the image below. Et viola you’ve just do your first theme override, pretty simple wasn’t it.
    Who's New block output after

I know that was a very simple example of Drupal theme overriding but hopefully you can see how this same principle can be used to override any theme function with Drupal allowing you to change the appearance of your site without ever having to edit a core file.

In future tutorials I’ll show you how to override the default user profile layout to create a Facebook type user profile layout.

Thanks for reading and please leave any comments below.

Comments (8)


Login or register to post comments
Francois's picture

"where your page.tpl.php is

"where your page.tpl.php is located"

Jumping straight in there:

  1. Which files are required in your themes folder when you start on a new theme?
  2. Are these files the same accross all themes, or are they custom?

The reason I'm asking is I'm a designer with HTML & CSS knowledge trying to learn Drupal theming - my PHP knowledge is very limited for now. Even though it might not be complicated the basic step 1, step 2 of starting out a theme is not well documented - IMHO.

*Hmm. Drupal Theme Guide might help. |(

Save the template.php file


Save the template.php file and as you should see something similar to the image below. Et viola you’ve just do your first theme override, pretty simple wasn’t it.

You only need to put the code in a file called template.php in your theme folder.

amedjones's picture

im trying to change the text

im trying to change the text link of "read more" for the teaser. I grabbed the function from node.module and placed it in template.php but i cant see the changes. But when i did the function directly in node.module, the modification are reflected .. of course this article advices otherwise.

Here the function that i copied and edited

function phptemplate_node_link($type, $node = NULL, $teaser = FALSE) {
$links = array();

if ($type == 'node') {
if ($teaser == 1 && $node->teaser && $node->readmore) {
$links['node_read_more'] = array(
'title' => t('Endelea'),
'href' => "node/$node->nid",
'attributes' => array('title' => t('Endelea.'))
);
}
}

return $links;
}

the above code is placed in template.php. Im trying to change "Read more" to "Endelea" ( swahili way of saying read more Smiling )

admin's picture

Hi, You can't override none

Hi,

You can't override none theme functions and i don't think theme_node_link exists, so the above code you mention won't work.

If you want to translate a string check out:
http://drupal.org/project/Translations
http://drupal.org/project/stringoverrides

Hope that helps
Tom

amedjones's picture

hi thanks for the reply. no

hi thanks for the reply. no theme_node_link does not exist. This function is in node.module which im guessing cannot overriden because its a core module?

thanks for the link, Translations is not supported anymore but stringoverrides worked great Smiling

xbaez's picture

Hi is a good tutorial. I did

Hi is a good tutorial.
I did that and works but just with buddylist, it still appearing the username in navigate block and on the title of BuddyList
How can i make that in all drupal override the username with real name ?

Thanks

xbaez's picture

I follow the instructions

I follow the instructions and there is a problem in administrator section, if you go to users
Drupal not shows the username ...
What happen with that ?

admin's picture

Hi, You are overriding the

Hi, You are overriding the function theme_username() which is used throughout Drupal including the admin pages, so any changes you make to the function will be reflected throughout your Drupal site!

As for showing the users real name, you'd need to setup the profile module with a user "real name" field and make it a required field on your registration page. Then at the top of the theme_username function change the $object->name variable:

<?php
function phptemplate_username($object) {
 
$object->name = $object->profile_real_name;
 
  if (
$object->uid && $object->name) {.........
?>
That assumes you have a profile field called "Real Name".

A useful debug you can use to see what variables you have available to you in $object is:
<?php
print_r
($object);
?>
Which will print onscreen all the available variables so you can see what you have to work with.

Hope that helps Tom