I've been working on a Fantasy Site for next week's Do It With Drupal conference, a Drupal version of the Meetup.com site. It's involved digging deep into the Drupal 7 versions of Organic Groups, Views, Panels, Date, and lots of other modules. I quickly identified the main content types I needed: Group, Meeting, Place, and RSVP, but looking around the site I soon realized it would need extremely complex 'teaser' views of all these types. Each one would require lots of information from the content itself as well as related content, and each content type would need several totally different 'teaser' views.

The Challenge

The site's 'Group' content type is a good example. It needs a square teaser like the following for display on the home page. It includes the title, image, and location of the Group along with information about the most recent meeting.
group_square.jpg
That one seems relatively straightforward, but there is a totally different three column teaser for the 'Group' content type used on the 'Find a Group' page. Note that this group teaser has group information, membership information, and even includes what looks like an embedded 'teaser' view of next upcoming meeting.
group_teaser.jpg
The 'Meeting' content type, in turn, needs multiple different teasers. In addition to the version embedded in the 'Group' teaser above, there is a different, square view used in a carousel at the top of the 'Find a Group' page that looks like the following.
carousel.jpg
And there is yet another iteration of the Meeting 'teaser' used in views of upcoming meetings:
meeting_teaser.jpg

Alternative Solutions

Drupal gives us quite a few ways to create those different teasers. Since they are all displayed in Views, I could try to construct them by assembling each individual fields in the view itself. That would require lots of relationships to join in all the required content, though, and a lot of custom rewrites to format them correctly. In addition, much of the information comes from Organic Groups, but the D7 version of Organic Groups doesn't yet expose all of the necessary fields via its Views Relationships. (There is an issue about this on the Organic Groups issue queue, and hopefully that will be rectified in the future). Even without the Organic Groups problem, adding each individual field to a view and getting them to display exactly as we want them to would be challenging. Another way to approach the problem would be to create a custom node .tpl file for each content type, and manually add the html to each template to create the variations. This approach to creating the display variations would simplify the views considerably. Each view would be a simple 'content' view rather than a 'fields' view, and would use the the 'teaser,' 'square,' or 'carousel' view mode. To do this manually, I would have to create a separate .tpl file for each variation, create a preprocess hook to prepare the values they all need, add some custom code to define the additional 'View modes' for each of my content types, finally add theme suggestions so Drupal will look for a different .tpl file for each view mode. However, one of the requirements of the Meetup.com site is that each group be able to set its own theme. If I used custom .tpl files in the theme, I would have to replicate them all in every theme exposed to the groups. I really wanted a way to create the 'structure' of the teasers independently of the theme. What's the solution?

Enter Display Suite

That set of requirements led me to the Display Suite module. As its name implies, Display Suite provides a collection of tools to control the display of Drupal entities. It allows you to create as many custom 'View modes' as necessary; use a different layouts and place fields differently in each display mode; and use pre-build Display Suite layouts, existing Panels layouts, or build your own. In addition, it allows you to create custom 'fields' in addition to the node fields that would ordinarily be available, and place those fields wherever you need them. When you enable Display Suite and visit its settings page at admin/structure/ds, you'll see a screen like the following:
ds_configuration.jpg
The screen provides quick links to the 'Display Fields' screens for each entity and content type (some of which are otherwise pretty well buried in various places in the administration area). You can create custom View modes from this screen, and you can add custom fields. The custom fields can be created in various ways; Display Suite can locate values that you've created in a custom preprocess function, or you can paste in custom PHP code directly. For the Fantasy site, I chose to create some of the complex values I needed in hook_node_preprocess(), then add them to Display Suite as 'Preprocess' fields for placement in my teasers. For the complex group teaser illustrated above, I needed three values that weren't otherwise available: a count of the group members (member_count), a formatted verision of the city and state the group is located in (formatted_location_text), and a 'square' teaser view of the next meeting (next_meeting_view). As you can see from the screenshot above, if the group is private or there is no next meeting, that value needs to have some placeholder text to indicate that. The following code does the work of building those values in a preprocess function:
  
/**
 * Implements hook_preprocess_nodee().
 */
function groupal_preprocess_node(&$vars) {
  global $user;
  
  $node = $vars['node'];  
  switch($node->type) {
    case 'group':

      // Get the group and its gid.
      $group = og_get_group('node', $node->nid);
      $gid = $group->gid;

      // See if the group is public or private.
      $access = field_get_items('node', $node, 'group_access');
      $private = $access[0]['value'];
      if ($private && og_user_access($gid, 'view meeting content')) {
        $private = FALSE;
      }

      // Get a membership count.
      $memberships = og_membership_load_multiple(FALSE, array('gid' => $gid, 'entity_type' => 'user'));
      $vars['member_count'] = '
' . t("@count members", array('@count' => count($memberships))) . '
'; // Get a view of the next meeting. $next_meeting_id = // Logic to retrieve the nid of the next meeting for this group goes here; $next_meeting = node_load($next_meeting_id); if ($private) { $vars['next_meeting_view'] = '
' . t('Meeting details are available only to members.') . '
'; } elseif (!empty($next_meeting)) { $vars['next_meeting_view'] = '
' . drupal_render(node_view($next_meeting, 'square')) . '
'; } else { $vars['next_meeting_view'] = '
' . t('There are no upcoming meetings for this group.') . '
'; } // Get formatted text to display the location the way we want it. $vars['location_formatted_text'] = '' . t('@city, @state', array( '@city' => $node->locations[0]['city'], '@state' => $node->locations[0]['province'], )); } }
Now that those values are available in the preprocess function, I can go into Display Suite and add my new 'Preprocess' fields.
Add_field.jpg
For each one, I create a field that has a machine name matching the name of the variable from the preprocess function above.
preprocess_field.jpg
Then I go to the Display Fields screen for the 'Group' content type and select the 'Teaser' view. It looks like it normally would, until I choose the Display Suite option to use a custom layout -- in this case a three column layout. Once I select the three column layout, lots of new fields will become available. Some of them are the fields I always see, the ones added by Drupal's Field API tools. Others are new ones that Display Suite itself adds, like a customizable 'Title' field, a 'Read more' link, and the image of the node author, each of which can be placed and styled like standard fields. In addition, I see the preprocess fields I defined earlier. In the screenshot below, you can see the way the 'Display Fields' screen looks for the Group teaser after setting it up to use Display Suite's 3 column layout, as well as adding custom fields like 'Location Formatted Text' and 'Next Meeting View' to the appropriate regions of the layout.
display_fields.jpg
At this point the only custom code I have created is the preprocess hook and some custom css; I have't used any custom .tpl files, either. If I add the preprocess hook and css in a custom module rather than in my theme, it will be available across all themes. That way, when users are given the ability to switch themes, all the complex teasers will still contain the right information in the right layout. Better yet, all the Display Suite configuration is exportable, so it can be captured in a Feature and deployed elsewhere. See the video of this Do It With Drupal Session on Drupalize.me.

Published in

Karen Stevenson

Thumbnail
Karen is one of Drupal's great pioneers, co-creating the Content Construction Kit (CCK) which has become Field UI, part of Drupal core.

Featured Work

Latest Podcasts

Let's Connect

Want to learn more about working with us or just say hello?

Contact Us