Advanced FlexSlider Construction in Drupal 7

Flex Slider is a popular Drupal module used to create responsive sliders with the FlexSlider 2 jQuery plugin. It's powerful and flexible with good hooks available for customization. It's not always clear, though, how to construct sliders in more complex situations.

The Challenge

Our example scenario consists of two content types. The first, call it Roadkill, has two fields of interest: a multivalue image field and a standard body field. The second, Cuisine, has a multivalue field collection field (field_cuisine_slider). The field collection field consists of a reference to a Roadkill node plus a single value image field.

The challenge is to create a slider with the following characteristics:

  • The main slide consists of the field collection image field plus the body text of the referenced node.
  • The slider uses thumbnail navigation using the first image of each referenced node.

(Note: this scenario may appear a little contrived, but it's actually based on a real case in which one group of users could create and edit the first content type and another group of users could create and edit the second content type.)

Site Building

The amount of extra site building is actually pretty minimal. First, we need a couple of modules (other than Flex Slider and the modules used to setup the content type architecture):

Next, create a new view mode. In Display Suite, you can do this by going to Admin→Structure→Display Suite→View modes→Add a view mode. Give it a name, like Cuisine Slider (machine name cuisine_slider) and enable it at least for field collection entities.

In the field collection (Admin→Structure→Field collections→your field collection→manage display→Custom display settings), enable the new view mode for this field collection. Save the field collection, then configure the view mode so that it contains just the image. This will be the main slide image. We'll add the text later in code. Save the field collection again.

(Note: you could instead add text from the Roadkill node here using the Rendered entity field formatter and appropriate configuration on the Roadkill node, but we're doing it this way to look at a particular facet of Flex Slider.) 

Now, add a FlexSlider option set in Admin→Configuration→Media→FlexSlider→Add. Give it a name, like Cuisine Slider (machine name cuisine_slider) and on the Navigation and Control Settings vertical tab, set Paging Controls to Thumbnails. You might also uncheck Slideshow on the General Slideshow and Animation Settings tab so that the slider doesn't rotate automatically, but that's up to you. Save the option set.

In the Cuisine content type, manage the display where you are going to use the slider (Admin→Structure→Content types→your content type→Manage display). For the field collection field, set the Format to FlexSlider. Choose the Option Set you just created (Cuisine Slider), and the view mode you created (Cuisine Slider). Change the number of values to display or skip if you want. Click Update and then save the content type.

That's all the site building that's necessary. Just four things:

  1. Create a view mode
  2. Configure the field collection to use the view mode
  3. Create a FlexSlider option set
  4. Configure the content type to tie it together.

Write Some Hooks

FlexSlider defines several useful hooks, but we only need one of them plus one other core hook.

In your theme's template.php file, write an implementation of template_preprocess_field. In this hook, we:

  1. Extract the field collection fields we need
  2. (This is key) Put them in a place accessible to the other hook we're implementing.

You can use any method you want to get the field collection fields in an easier to manage state; I just used the function from this Four Kitchens post verbatim.

 * Implements template_preprocess_field
function mytheme_preprocess_field(&$vars, $hook) {

  if ($vars['element']['#field_name'] == 'field_cuisine_slider') {

    $field_array = array('field_roadkill', 'field_main_slide_image');
    _rows_from_field_collection($vars, 'field_cuisine_slider', $field_array);

    // Copy the rows into the item array so they will get passed to the flexslider list preprocessor.
    // Do this here to keep the row processor generic.
    foreach ($vars['items'][0]['#items'] as $index => $item) {
      $vars['items'][0]['#items'][$index]['row'] = $vars['rows'][$index];

 * Creates a simple text rows array from a field collections, to be used in a
 * field_preprocess function.
 * @param $vars
 *   An array of variables to pass to the theme template.
 * @param $field_name
 *   The name of the field being altered.
 * @param $field_array
 *   Array of fields to be turned into rows in the field collection.

function _rows_from_field_collection(&$vars, $field_name, $field_array) {
  $vars['rows'] = array();
  foreach($vars['element']['#items'] as $key => $item) {
    $entity_id = $item['value'];
    $entity = field_collection_item_load($entity_id);
    $wrapper = entity_metadata_wrapper('field_collection_item', $entity);
    $row = array();
    foreach($field_array as $field){
      $row[$field] = $wrapper->$field->value();
    $vars['rows'][] = $row;

Next, write an implementation of template_preprocess_flexslider_list (see that is part of the FlexSlider module). In this hook, we're doing a few things for each slide:

  1. Retrieve the values from the referenced Roadkill node we need for the slider.
  2. Set the $items[$index]['title'] element to the body of the Roadkill node. The FlexSlider theme function wraps this in a <p class="flex-caption"> tag, so you might want to do some processing on the text to ensure there are no disallowed tags (like <div>).
  3. Set the $items[$index]['thumb'] element to the first image of the referenced Roadkill node.
 * Implements template_preprocess_flexslider_list
function mytheme_preprocess_flexslider_list(&$vars) {

  // Only process the optionset we defined
  if (isset($vars['settings']['optionset']->name == 'cuisine_slider') {

    $items = &$vars['items'];
    foreach ($items as $index => $item) {

      // Use entity_metadata_wrapper for more standard access
      $roadkill = entity_metadata_wrapper('node', $item['row']['field_roadkill']);

      // The thumbnail is the first image in the referenced roadkill
      $thumb = $roadkill->field_image[0]->value();
      $thumb_style = $vars['settings']['optionset']->imagestyle_thumbnail;
      $items[$index]['thumb'] = image_style_url($thumb_style, $thumb['uri']);

      // The caption is the body of the referenced roadkill. The 'title' index becomes the 'caption' 
      // index in flexslider list theme functions.
      $items[$index]['title'] = $roadkill->body->value->value(array('sanitize' => TRUE));

Move Along

In this example, we've taken a relatively complex challenge and reduced it to a few configuration steps and a couple of hooks. All that's left is the theming.

Drupal 101 Evening Course in Dallas in January

Now in its fourth year, Collin College Continuing Education is offering a 6 week, 18 total hour introductory course in Drupal Website Development 101.  Six consecutive Tuesdays, January 20th - Feburary 24th, from 6:30 to 9:30 pm.  The cost is $199.  More info.

What can you expect to learn?

  • Introductory Drupal website development concepts and building blocks
  • Drupal website hosting and maintenance
  • Installing modules and themes
  • Top 20 Drupal modules
  • Basic Drupal SEO principles and modules
  • and how to create several complete Drupal websites with different functionality

The only prerequisite is basic Internet and web usage experience, and a tolerance for the instructor's stupid sense of humor.  This 101 course won't have any software coding / programming.

The Drupal course will be taught at the Collin College Courtyard Campus in Plano, near Preston and Park.  Computers are provided.  Nice ones too.  Only while in the class though, you can't take them home.

More info and register!

Dealing With Email On Drupal Development Sites

Sometimes, even when you've worked with a system for a long time, you can still uncover surprising things that have been around for awhile but were previously unknown to you.

Such was the case for the Reroute Email module. Maybe you've already heard of it, but I had not. In fact, for years, I've dreaded working on email issues for existing sites with notification systems, fearing I would spam live site users. In at least one case, I've sent an inadvertent content update notification to a not-so-small user population. Fortunately, I wasn't using Samuel L Ipsum to generate dummy content or things could have gotten much more uncomfortable.

Recently, I had the great idea of writing a module to intercept site emails and redirect them to a different, safer address. I followed this with the thought, "I wonder if a module like that already exists," and as is so often the case with Drupal, the answer was, "of course." In fact, this functionality has been around since the days of Drupal 5, and appears to have been part of the devel module before splitting off on its own. That's a long time to fly under my radar, especially considering the are nearly 375,000 reported downloads.

Why You Might Want To Use It

Many sites use notification systems to send emails to users when you change existing content or publish new content. Some sites send out notification emails to users as content goes through a moderation workflow. A site may send out emails to e-commerce customers or in response to contact form submissions. The list goes on and on.

What happens, though, when you pull the database down to your local development environment? Maybe you were able to sanitize the database with Drush when you pulled it, or maybe not. You may think your sanitization caught every email address on your site, but it probably didn't (think Rules or contact form or update notifications). Are you really going to remember to change all those email addresses every time you sync the database? Maybe the first time and the second time, maybe even the third or fourth time. If you're like most people though, you'll eventually decide that it's not necessary, since you're "not working on email right now; plus, it's such a pain."

That's where Reroute Email comes in.

Installation and Configuration

I'm assuming you already know how to install a Drupal module, so I'll spare you those particular details. The main idea is to configure things so Reroute Email is automatically setup in environments where you need it. In this case, we're talking about your local development environment.

The first thing to do is to ensure that the module gets enabled whenever you synchronize the database locally. This is easy if you use drush and sql-sync or sql-sync-pipe. Just add a target-command-specific element to your Drush alias:

'target-command-specific' => array(
 'sql-sync' => array(
   'enable' => array('reroute_email'),
 'sql-sync-pipe' => array(
   'enable' => array('reroute_email'),

After that, it's just a matter of setting variables in your local settings.php to configure it the way you want:

// This setting allows you to defeat Reroute Email even if 
// it's enabled in the Drupal system sense, so make sure it's
// set to "1"
$conf['reroute_email_enable'] = 1;

// Specify where you want to redirect emails. You can 
// define more than one email by separating them with
// spaces, commas or semicolons
$conf['reroute_email_address'] = '';

// Adds an extra message to the body with information
// about the redirection
$conf['reroute_email_enable_message'] = 1;

Keep in mind that if you set these values in your local settings.php, you cannot override them by changing them in the UI (i.e., Admin >> Configuration >> Development >> Reroute Email).

You can send a test email through the module from Admin >> Configuration >> Development >> Reroute Email >> Test email form.


There is always a caveat, isn't there? Reroute Email uses hook_mail_alter() to do its work, so if any of your modules send mail in any way except through drupal_mail() (e.g., by calling drupal_mail_system()->mail() or PHP mail() directly), they will bypass this hook and thus not get redirected.

Of course, since it uses hook_mail_alter(), Reroute Email should work with any standard Drupal mail mechanism, whether you're using just the default Drupal mail or something more complex, like Webform with MailSytem, MimeMail and SMTP Authentication.

Note that if your site is setup with the default Drupal mail, you may also need to setup outgoing mail on your local development environment. It doesn't seem like this is something that would be that difficult, but it can get quite tricky.

Do One Thing Well

Reroute Email is a small module that has been around for a long time. It does one really useful thing and it does it simply and well. If only we could say that about more Drupal modules.

North Texas Drupal November Meetup

We had a great meetup tonight with lots of interesting discussions on Drupal security, hosting, tools, drush and more.  And a visit from a Drupler from LA!  No meetup in December - we will see everyone in 2015.
Here's the notes and links I have from the meetup.

Drupageddon related links




VPN Setup

Cheap bulk emailing

North Texas Drupal October Meetup

We had yet another great meeting of the nascent North Texas Drupal users group this past October 20th.

Travis Tidwell asked the question- When Should You *Not* Use Drupal?  While we all love and user Drupal, it is not always the best tool for the job.  Check out his slides below for more info as well as some notes and related links.

Ian Whitcomb took us through building multi-site Drupal, including solutions such as MultisiteDomain AccessOrganic Groups and andPantheon One.

We also had a discssion of Drupal security, including the recent major core exploit.   Here is a way to see if your site was compromised using a drush command.  

Blog article about presentation with Video and Slides­

Static Site Generators

Bootstrapping your site

"API-first" Development

  • Drupal 8 with Symfony is a solid contender
  • Recommend to start simple with Symfony and bring in Drupal if requirements need it.
  • Other API-first platforms

Twitter Issues On Pantheon?

Having trouble getting your Twitter feed working on Pantheon? Does it work locally but not in your Pantheon environments? If your Twitter solution uses PHP's http_build_query function (as does the Rise theme's front page), you're not going crazy. It's them, not you.

The http_build_query function takes an array and returns a URL encoded query string suitable for use by functions that might find query strings handy, like PHP's curl functions. By default, PHP uses the & character to separate query string parameters, but on Pantheon, this value is set to use the HTML entity &amp; instead. If you try to pass a query string with &amp; instead of &, it will fail.

Fortunately, you can override this value using  the third paramter of the call to http_build_query. For example,

http_build_query($my_params, '', '&');

But what if the call is in somebody else's code and you don't want to hack it and cause kitten-death? Well, there is still a potential solution. If you are not relying on the &amp; output from http_build_query elsewhere on your site, you can globally override Pantheon's value with a setting in your site's settings.php file :

ini_set('arg_separator.output', '&');

That's it. No Twitter token regenerating, no hacking, no hair pulling. Just a one line fix.

North Texas Drupal Users Group - Sept meetup

Great meetup of the North Texas Drupal Users Group last night.  The new Addison Treehouse cowork / incubator space was good enough to host us.

First off Kyle Taylor showed off his efforts in integrating the (becoming standard) Bootstrap theme with the core Color module and LESS.  The lead Bootstrap maintainer, Mark Carver, is one of our members and was in house to answer deep Bootstrap questions.

Then Randall Knutson did a presentation on Static Drupal – Taking the Pain out of Drupal Hosting.  It's based on some work he's doing at Phase2, to improve the load times and security of Drupal sites. You can learn more from his blog post and download the Static module on

We're working on the what and where for the October meetup - stay tuned!