Tutorial - Build a modular presentation tool in Drupal 7Tutorial - Build a modular presentation tool in Drupal 7


Today we're going to look at a use of Drupal that is a bit outside the norm. Instead of the usual business website, corporate blog, or news magazine site, let's look at a building a presentation tool. How or why would you use such a thing? Well, in a world where the Powerpoint or document-based presentations and proposals are rampant, sometimes you need to do something to stand out a bit. A web-based presentations are awesome because they can be accessed from anywhere you have a browser and it doesn't require spreading a file around or making sure someone has some prerequisite software to view it.

Because we're using Drupal anyways we're going to build in such a way that we can re-use our tool to build out multiple presentations if needed. The format I'm going to use is going to be a single scrollable page:

Click to view full size

With that, let's get started.


Required modules:
- Nodequeue
- Media
- Views

The technique I'm going to be using is to create several content types. Each content type will represent a type of layer of the layout of a presentation. For purposes of this tutorial I'll be calling these content types "tiles." By layering these tiles down the page I will be able to create build a complete presentation. I'll use Nodequeue to actually select and order the tiles.

One of the important things is going to be creating enough tiles with enough options that you will be able to use and reuse them for all kinds of different presentations. In my demo I'll be creating various fields as needed for my tiles. Here's what's on my list:

- Title tile: Main title of the presentation
- Subtitle tiles: Demarking main sections of the presentation
- Normal text tile: Regular text block
- 3 point tile: 3 points combined with images
- 2 column text tile: Slightly more styled text display.
- Text with floated image tile

I'll be using a text field for each tile that will act as an anchor link so that I can create a menu that scrolls to the appropriate place in the presentation if needed. I will also be adding in a "CSS styles" field on each content type in the event that someone would want to include special styles on the tile.

The first thing I need to do is create all my content types and populate them with the necessary fields. We'll take a look at one of mine for an example:


I kept it fairly simple for purposes of this tutorial but you may want to add in more fine-grained controls for your fields. For instance, if you have a tile with both text and image, maybe you want to include a checkbox that goes along with the image to float it left or right. Remember, making your system as modular as possible now will means that next time you'll save hours. Make sure in the "Manage display" tab you have all the labels hidden. When all is said and done you should have all your necessary tiles like this:


Make sure you note all of the machine names for these, as we will need to create TPL files for each.

The next thing we need to do is create our Nodequeue over in Structure -> Nodequeues. Title it whatever the name of your presentation is going to be and ensure that all the relevant content types are checked. Nodequeue will automatically create a View for the list. Pop on over to Structure -> Views and check out your list. You can leave most of the settings untouched, but make sure that your URL is pointing to wherever you want it to. It defaults to a system-defined setting.


Next we need to start populating our presentation with content so that we can start styling. You may find it useful to create one piece of content for each type so that you have all the visuals needed for styling. I'm going to create my necessary content and then head over to Structure -> Nodequeues again and start adding my content to my list.


Rearrange your content however you need to and let's get to styling.


We need to create separate TPLs for all of the different content type tiles we made. Remember that in Drupal 7 the naming suggestion for node TPLs is "node--[machine_name_here].tpl.php" and make sure you use 2 dashes. Also ensure that the system node.tpl.php file is in your template directory or else Drupal will ignore your custom templates.

There are 2 important things that I need to make sure of when I'm coding my templates:
1. Make sure that custom CSS is applied correctly from the CSS field I added
2. Make sure the correct content is being rendered from my custom fields

Let's tackle the second one because it's fairly simple. Drupal 7 gives us a PHP function called "render" that will output a complete field with the field markup included. First go to your Structure -> Content Types -> (pick a content type) Manage Fields. Note the machine names of your custom fields. These are what you'll need for this function to work. For instance, I have a field called "field_col_1" so to output that in my TPL file I need to say:


<?php print render($content['field_col_1']); ?>

You can do this with all of your custom fields as needed.

The first part above is a tad tricky because we do NOT want our CSS to be surrounded by markup divs. If you use the render function it won't work. We need a different function to get the raw data from the field.


$node = node_load($nid);
$field = field_get_items('node', $node, 'field_custom_css');
$css = $field[0][value];

PLEASE NOTE: This method may be a security risk so I don't recommend using this technique if you let the general public create content on your system. For more information on other ways of handling this please see this article.

In my content tiles I have a checkbox field called "separator" which, if checked, will add a class to my wrapping div. I need to use a similar method to get the value of my "separator" check box. Put together, here is what one of my templates looks like:


$node = node_load($nid);
$field = field_get_items('node', $node, 'field_custom_css');
$css = $field[0][value];

$field2 = field_get_items('node', $node, 'field_section_seperator');
$sep = $field2[0][value];
if ($sep == 1) {
  $sepcode = ' seperator';

<div class="section text-float<?php print $sepcode; ?>" style="<?php print $css; ?>">
  <div class="wrapper clearfix">
    <?php print render($content['field_img_1']); ?>
    <div class="text">
    <h3><?php print $title; ?></h3>
    <?php print render($content['body']);?>


As you can see I'm using a unique wrapper div class: "text-float". I will use this technique on all my template files so I can target them appropriately.

After you have created all your templates, go to your presentation URL that you indicated in the Views settings and make sure all your data outputs correctly and with the correct classes on everything.

Now for a bit of CSS. This process will be different for everyone but here is what mine looks like:


/* LAYOUT */
body { background:#ffffff; margin:0; padding:0; font-family:"futura-pt", serif; font-size:16px; font-weight:normal; line-height:1.4em; }
.wrapper { margin:auto; width:1000px; }

#navigation { height:60px; width:100%; background:#000000; color:ffffff; position:fixed; top:0; z-index:99; opacity:0.75; font-size:1.1em; text-transform:uppercase; text-align:center;}
#navigation .center { padding-top:15px; margin:auto; width:640px; }
#navigation ul li { margin:0 15px 0 0; padding:0; float:left; }
#navigation li a { color:#ffffff; padding:4px 7px; border-radius:5px; -webkit-border-radius:5px; -moz-border-radius:5px; text-shadow:1px 1px 0px #26225c; }


h1 { font-size:2.5em; line-height:1em; font-weight:700; margin:0; padding:0; text-transform:uppercase; }
h2 { font-family:"adelle"; font-style:italic; font-size:1.2em; font-weight:400; line-height:1em; margin:0; padding:15px 0 0 0;} 
h3 { font-family:"adelle"; font-size:1.2em; font-weight:700; line-height:1em; margin:0; padding:0; }
a:visited { color:#837fc0; text-decoration:none; }
a:active { color:#877fff; text-decoration:none; }
p { margin:1em 0 0 0; padding:0; font-size:1.1em; line-height:1.4em; }

.section { padding:0 0 100px 0; }
.section.seperator { background:url(../images/sep.png) top repeat-x; padding-top:100px; }

.section.main-title { margin-top:60px; padding:100px 0; text-align:center; }

.section.normal-text { margin:0; }
.section.normal-text .field-type-image { margin:0 0 60px 0; text-align:center; }

.section.three-point .point { width:306px; float:left; margin:0 40px 0 0; }
.section.three-point .point h3 { padding:20px 0; }
.section.three-point .point.last { margin-right:0; }

.section.subtitle { height:60px; background:#1c1c1c; color:#ffffff; text-align:center; padding-bottom:0; margin-bottom:100px; }
.section.subtitle h1 { padding-top:8px; }

.section.text-float .field-type-image { width:655px; float:right;}
.section.text-float .text { width:305px; float:left; padding-top:140px; }

.section.two-col .col { width:480px; float:left; margin:0 40px 0 0; }
.section.two-col .col.last { margin-right:0; }



Lastly we have to make sure we have a working menu. Like I said earlier, the purpose of this is to allow a user to jump down the page toa  section they want to view. Luckily we can simply find the IDs of the divs we want to jump to and then go into the menu page via Structure -> Mneus -> Main Menu and add some links like this:

And that's it!

Final notes

For the record, I would LOVE to see someone build this out using Field Groups / Field Collection instead of creating separate content types. The advantages would be that you could keep everything from a single presentation on a single edit form, which would be much cleaner and organized. Unfortunately, the last time I used Field Collection on a project I was throwing me tons of errors and some of my content wouldn't render properly. If I were building this out for a client it would probably still be my first step.

If you want to get really in depth you can try extending this tool to work with some additional modules. Imagine being able to add in Views or jQuery sliders, all working with a responsive layout. With some extra time and effort you can build a completely modular system that can present any data you need, what I've built today is just the tip of the iceberg.

Need a Custom Designed Theme?

If you need a custom designed theme for your business then our designers can work with you to create a unique concept that is consistent with your brand, clearly communicates your value proposition and helps you achieve your goals. >> Click here to contact us and let us know about your needs and we'll analyze and provide you with an estimate for designing and development your custom theme.