Guidelines and instructions on separation.

Events happening in the community are now at Drupal community events on www.drupal.org.
You are viewing a wiki page. You are welcome to join the group and then edit it. Be bold!

If you haven't done so, please read this groups home page description for the general idea behind this group and the How to contribute page on contributing code. And please mark the Work in progress wiki for any sections your working on. All sections are grouped by either modules or .inc files and the Work in progress wiki is only a partial list.

This wiki will go into more detail, suggest a few guidelines and hint on how we should go about separating the code.

You don't have to follow the suggestions provided here but staying within them will flatten out the learning curve a lot faster for themers. Lets make it as easy as possible for theme designers by maintaining some consistency.

There will also be a few changes to the theming system in Drupal 6 (it has been committed!!) and some form of the work done here will eventually get into core. One of the new features is to have modules provide their own .tpl.php template files. Soon, it will be very easy to drop core template files right into your own themes.

Assessing the theme function

The first thing to do is to look through the function and understand how the output is constructed. Some will be easier than others to separate. If you see any HTML tags then it should be deconstructed and redone inside a .tpl.php file bearing the name of the original function minus the "theme_" prefix.

theme_book_export_html example

The original from "module/book.module":

<?php
function theme_book_export_html($title, $content) {
  global
$base_url;
 
$html = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
 
$html .= '<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">';
 
$html .= "<head>\n<title>". $title ."</title>\n";
 
$html .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
 
$html .= '<base href="'. $base_url .'/" />' . "\n";
 
$html .= "<style type=\"text/css\">\n@import url(misc/print.css);\n</style>\n";
 
$html .= "</head>\n<body>\n". $content ."\n</body>\n</html>\n";
  return
$html;
}
?>

All the HTML tags can be easily separated here. The variables in the next code block are setup to be fed into the callback function [diagram]. This is always done from the template.php file. Remember to rename the function prefix from theme_ to phptemplate_.

Each section (or module) gets its' own template.php file. This is so there are no conflicts in CVS.

following placed within "book/template.php":

<?php
function phptemplate_book_export_html($title, $content) {
  global
$base_url;
 
 
$variables = array(
   
'title'     =>  $title,
   
'content'   =>  $content,
   
'base_url'  =>  $base_url,
   
'language'  =>  $GLOBALS['locale'],
   
'head'      =>  drupal_get_html_head(),
  );
 
  return
_phptemplate_callback('book/book_export_html', $variables);
}
?>

Always pass the original arguments into the callback ($title & $content in this case). In other functions they may not be apparently useful from the .tpl.php file but it's still good practice to have them available. There's very little overhead on providing them and it gives the advanced themers more information to work with.

Notice how the $language and $head variables are set from a dynamic source -was originally hard coded html. It's not required but these little touches help the dynamic environment of the system. Look for bits like this that could stand some improvement.

Name the variables array "$variables". It's minor but it maintains consistency. Use descriptive names for each variable also (the keys in the $variables array).

This next bit are the contents of "book_export_html.tpl.php" residing within the "book" subfolder. Notice the hook parameter from from _phptemplate_callback() and how it's directed at the .tpl.php file.

following placed within "book/book_export_html.tpl.php":

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="<?php print $language ?>" xml:lang="<?php print $language ?>">

  <head>
    <title><?php print $title ?></title>
    <?php print $head ?>
    <base href="<?php print $base_url ?>" />
    <style type="text/css">@import <?php print url('misc/print.css') ?></style>
  </head>
 
  <body>
    <?php print $content ?>
  </body>
 
</html>

With the separation above, there are no changes from the default HTML markup. Lets keep it that way.

Other scenarios

You may run into situations where a single callback can't handle foreach loops. In these cases, create a separate callback and capture the results to be passed to the final output. The file names of these "sub-callbacks" are preceded with an underscore to make them clear that they are not from the main theme function.

Also, if there is no workable HTML in the output of the function, just return with no callback. -we may have to reconsider this. Even with no workable HTML, the themer may want to add in his/her own tags/content beyond what's already there.

from theme_book_admin_table():

<?php
function phptemplate_book_admin_table($form) {
 
$header = array(t('Title'), t('Weight'), array('data' => t('Operations'), 'colspan' => '3'));

 
$rows = array();
  foreach (
element_children($form) as $key) {
   
$nid = $form[$key]['nid']['#value'];
   
$pid = $form[0]['nid']['#value'];
   
$variables = array(
     
'pixel_depth'   =>  (25 * $form[$key]['depth']['#value']),
     
'depth'         =>  $form[$key]['depth']['#value'],
     
'title_input'   =>  drupal_render($form[$key]['title']),
    );
   
$rows[] = array(
     
_phptemplate_callback('book/_book_admin_row_title', $variables),
     
drupal_render($form[$key]['weight']),
     
l(t('view'), 'node/'. $nid),
     
l(t('edit'), 'node/'. $nid .'/edit'),
     
l(t('delete'), 'node/'. $nid .'/delete', NULL, 'destination=admin/content/book'. (arg(3) == 'orphan' ? '/orphan' : '') . ($pid != $nid ? '/'.$pid : ''))
    );
  }

  return
theme('table', $header, $rows);
}
?>

As you can see, the $variables is assembled within a foreach and passed as one of the cells in an array to be rendered from theme_table. The name of this "sub" .tpl.php file should be descriptive and have parts of the main theme function. (and don't forget the underscore.)

We have no direct control over the output in theme_table so there is no callback.

Commenting code

Have a look at Code style and other minor requirements. Those are really minor requirements but if you can, please also add in a list of variables and descriptions inside each .tpl.php file. It makes it easier to know what's going on inside the file and it's not shown in the rendered output.

For example:

<?php // $Id: book_navigation.tpl.php,v 1.5 2007/04/06 20:27:09 dvessel Exp $

/**
* Available variables:
*  $tree
*    Unordered list of child nodes.
*  $previous_link, $parent_link, $next_link
*    Relative links to nodes in the book outline.
*  $previous_id, $parent_id, $next_id
*    Relative node id's
*  $previous_title, $next_title
*    Relative node titles.
*  $has_links
*    Either true or false dependent on any of the links being present.
*  $node
*    Full node object in the current page.
*/
?>

   
<div class="book-navigation">
  <?php print $tree ?>
 
  <?php if ($has_links): ?>
    <div class="page-links clear-block">
      <?php print $previous_link ?>
      <?php print $parent_link ?>
      <?php print $next_link ?>
    </div>
  <?php endif; ?>
 
</div>

If your not sure what a variable does, then do this to observe it.

<?php
print var_dump($whats_this);
exit;
?>

Devel.module uses can also do a "print dprint_r($whats_this);". $whats_this being the variable your trying to observe.

AttachmentSize
callback_flow.png66.78 KB

Themer Pack Working Group

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: