Achievements 7.x-1.4: Using #theme_wrappers
The Drupal Achievements module offers the ability to create achievements and badges similar to systems seen on Xbox 360, Playstation 3, Foursquare, Gowalla, GetGlue, and more. For a Drupal site, this could mean commenting a certain number of times, starting a forum topic, visiting the site every day of the week, or anything else that can be tracked and coded. The recently released 7.x-1.4 update focuses on changes that make theming easier.
One of those changes was implementing #theme_wrappers
. Like many other modules, Achievements has various HTML displays that are essentially containers of things: a group of unlocked achievements, a group of categorized achievements, etc. For stronger theming, one usually wraps those in an extra <div>
so that CSS folks can control the container's display. In the past, I've usually accomplished this with:
$build['achievements'] = array( '#prefix' => '<div class="achievement-groups">', '#suffix' => '</div>', );
Simliar code to the above exists in Drupal core (book.module
, field.module
, etc.) so I never gave it a second thought. However, for a themer, the above is problematic because there's no way to tweak that HTML without dipping into a hook_page_alter()
and rewriting or munging the #prefix
entirely. Since I've been away from Drupal theming for so long, I never knew there was a stronger alternative by using #theme_wrappers
. Not surprisingly, Drupal core uses this pattern alongside the "bad" #prefix
version, so a good contender for a "Novice" patch would likely be "Replace all uses of #prefix divs with #theme_wrappers".
Like other theme functions and files, #theme_wrappers
requires a hook_theme()
definition:
function achievements_theme() { return array( 'achievement_groups_wrapper' => array( 'render element' => 'element', ), ); }
In this case, we'll use a regular ol' theme function for the callback:
/** * Default theme for the wrapper around a user's achievements page. * * @param $variables * An associative array containing: * - element: A render containing the user's achievements page. */ function theme_achievement_groups_wrapper($variables) { return '<div id="achievement-groups">' . $variables['element']['#children'] . '</div>'; }
And finally, we can tweak the above $build
render array to use it:
$build['achievements'] = array( '#theme_wrappers' => array('achievement_groups_wrapper'), );
In this case, the resultant HTML will be exactly the same, but now a themer can more easily override it just by defining THEMENAME_achievement_groups_wrapper()
. This is a far cheaper method (mentally and performant-wise) than having to futz with hook_page_alter()
.