Converting 4.7.x themes to 5.x

Overview of Drupal API changes in 5.x

  1. changed $primary_links and $secondary_links now return structured links
  2. drupal_add_css() - the proper way to add CSS files
  3. theme_get_styles() has been replaced by drupal_get_css()
  4. New $feed_icons
  5. New clearing class
  6. theme_links() now returns list of links
  7. drupal_add_js()
  8. _phptemplate_callback signature change
  9. id='pager' is now class='pager'
  10. theme_form_element parameters changed

4.7.x themes:

<?php
print '<ul>';
foreach (
$primary_links as $link) {
   print
'<li>'. $link .'</li>';
}
print
'</ul>';
?>

5.x themes:

<?php
print theme('links', $primary_links);
?>

theme_links() now returns a list of links.

Additionally, the keys for each link are of the form 'moduleName-linkName', for example: menu-1-3-4 or node-read-more or comment-add-new.

For more info on this change, please see the Converting 4.7.x modules to 5.x docs.

drupal_add_css() - the proper way to add CSS

In 4.7.x, you would use theme('stylesheet_import', base_path() . path_to_theme() . '/extra_stylesheet.css') or theme_add_style($themes[$theme]->filename)

In 5.x, this is now changed to drupal_add_css($path = NULL, $type = 'module', $media = 'all')

This makes it very easy and consistent to add CSS in a proper cascading manner (with core CSS first, then module CSS, then theme CSS).

There is also a new variable available in phpTemplate now, $css, which is an array of all the CSS files for the current page. $styles still holds the actual HTML to load the CSS files, but if at the theme level you want to swap out certain CSS files (like drupal.css for example), this is very easy.

<?php
 
// print $styles;
  // we don't need to print out $styles since we want to take out drupal.css

 
unset($css['core']['misc/drupal.css']);
  print
drupal_get_css($css);
?>

Remember that $css gets it's value before the code in page.tpl.php is run. So trying to call drupal_add_css() from within page.tpl.php doesn't change the value of $css.

Usually, one would only call drupal_add_css() within template.php or within a module.

If you really want to add a CSS file from within page.tpl.php, you will either need to reset the value of $css or don't use it at all:

// page.tpl.php code:
<?php
drupal_add_css
(path_to_theme().'/override-defaults.css', 'core', 'all'); // consider 'theme' instead of 'core'

print drupal_get_css(); // don't add $css to the params

// equivalent, but longer code here:
$css = drupal_add_css();  // reset the value of $css (will now contain "override-defaults.css")
print drupal_get_css($css);  // add $css to the params
?>

References:
- Simplify adding CSS in Drupal (issue)
- How to properly add CSS files (Lullabot) (previous, 4.7.x and lower versions of Drupal)

theme_get_styles() has been replaced by drupal_get_css()

Related to the above there is a new drupal_get_css function which calls drupal_add_css. It loads the CSS in order, with 'core' CSS first, then 'module' CSS, then 'theme' CSS files. This ensures proper cascading of styles for easy overriding in modules and themes.

New $feed_icons

There is a new $feed_icons available to phpTemplate themes. This variable is a string of *all* feed icons for the current page. You can freely put this anywhere you want on your page--no longer are the icons tied to the body of the page.

For more details, read updating your modules.

New clearing class

In previous versions of Drupal, the bundled clearing class was:

<br class="clear" />

However, the problem with this is it that it adds unessecary breaks all over the page, just to clear floats.

This has been changed to now use a proper clearing class, as outlined at Position is Everything.

This clearing class is completely CSS based and requires no additional markup. It does have a 2 small hacks in there, but they are safe hacks, one simply makes it work in IE6 and the other hides it from IE5 on Mac. As browsers change and grow, altering the CSS in one central place will make it easier to maintain this.

To properly use this, you add the clearing class to the *containing* element at top, instead of the bottom:

Old way:

<div>
Some text here.
<br class="clear" />
</div>

New way:

<div class="clear-block">
Some text here.
</div>

theme_links() now correctly returns a list of links. It also adds in useful classes as well, including "first" and "last".

New usage:

<?php
print theme('links', $primary_links);
?>

Will print out a list of the primary links as follows:

<ul class="links">
 
<li class="first menu-1-1-52"><a href="/drupalCVS/?q=test" title="" class="menu-1-1-52">test</a></li>

<li class="menu-1-2-52"><a href="/drupalCVS/?q=test2" title="" class="menu-1-2-52">test2</a></li>

<li class="last menu-1-3-52"><a href="/drupalCVS/?q=test3" title="" class="menu-1-3-52">test3</a></li>

</ul>

Additionally, you can send in parameters to theme_links() to add in classes an IDs as follows:

<?php

print theme('links', $primary_links, array('class' =>'links', 'id' => 'navlist'));
?>

Which creates the same structure but with the class and ID added to the parent UL:

<ul class="links" id="navlist">

<li class="first menu-1-1-52"><a href="/drupalCVS/?q=test" title="" class="menu-1-1-52">test</a></li>

<li class="menu-1-2-52"><a href="/drupalCVS/?q=test2" title="" class="menu-1-2-52">test2</a></li>

<li class="last menu-1-3-52"><a href="/drupalCVS/?q=test3" title="" class="menu-1-3-52">test3</a></li>

</ul>

drupal_add_js()

In 4.7.x, JavaScript files were added to the page header by calling drupal_set_html_head().

In 5.x, JavaScript files and settings are added with drupal_add_js($data = NULL, $type = 'module', $scope = 'header', $defer = FALSE, $cache = TRUE).

JavaScript file inclusions, settings and plain code are now inserted by calling drupal_get_js(). The best place to call this function in your theme is right below the drupal_get_css() call in the HTML-head of your theme.

There is also a new variable available in phpTemplate now, $scripts, which holds the actual HTML to load the JavaScript files and make the JS settings available. This variable is necessary for JavaScript to run in the theme. If you want to swap out certain JavaScript files at the theme level (like autocomplete.js with your custom file for example), this is very easy.

<?php
 
// we don't need to print out $scripts since we want to take out autocomplete.js
  // print $scripts;
 
  // this returns the array of JavaScript files for the header
 
$js = drupal_add_js(NULL, NULL, 'header');
  unset(
$js['module']['misc/autocomplete.js']);
  print
drupal_get_js('header', $js);
?>

References:
- Streamline JavaScript addition and add settings storage (issue)

_phptemplate_callback signature change

The function _phptemplate_callback in the phptemplate theme engine, used to externalize theme functions to *.tpl.php files, has become more flexible in the way it finds and associates *.tpl.php files with theme function invocations. In Drupal 4.7, one had to specify the name of the external file, wheras in 5.0, one can specify a list of suggestions. Phptemplate will then look through all of the suggested filenames and look for each one. In practice, this makes the third parameter to the function an array instead of a string:

Drupal 4.7

<?php
function _phptemplate_callback($hook, $variables = array(), $file = NULL) {
?>

Drupal 5.0

<?php
/**
* Execute a template engine call.
*
* Each call to the template engine has two parts. Namely preparing
* the variables, and then doing something with them.
*
* The first step is done by all template engines / themes, the second
* step is dependent on the engine used.
*
* @param $hook
*   The name of the theme function being executed.
* @param $variables
*   A sequential array of variables passed to the theme function.
* @param $suggestions
*   An array of suggested template files to use. If none of the files are found, the
*   default $hook.tpl.php will be used.
* @return
*  The HTML generated by the template system.
*/
function _phptemplate_callback($hook, $variables = array(), $suggestions = array()) {
?>

id='pager' is now class='pager'

The 'pager' identifier has been changed from an id to a class in the event that there is more than one pager present on a page. So stylesheets need to be changed from #pager to .pager.

References:
- theme_pager : id="pager" to class="pager" (issue)

theme_form_element parameters changed

In Drupal 4.7:

<?php
theme_form_element
($title, $value, $description = NULL, $id = NULL, $required = FALSE, $error = FALSE)
?>

In Drupal 5:

<?php
theme_form_element
($element, $value)
?>

If you don't modify your implementation of this function in your theme (e.g. in template.php) then you will very likely see all your form labels display as an empty PHP array (e.g. 'Array').

References
- http://api.drupal.org/api/function/theme_form_element/5

module_exist() becomes module_exists()

jenlampton - August 21, 2007 - 23:48

I ran into these problems too, when upgrading a theme from 4.7 to 5.

Some of my theme functions in 4.7 called "module_exist" but in 5 that function is now "module_exists".

search form ID: search_form becomes search-form

jenlampton - August 22, 2007 - 17:32

if you've styled your search form, the Id on the form element went from:
id="search_form" to id="search-form"

 
 

Drupal is a registered trademark of Dries Buytaert.