Jordan Lev Logo Jordan Lev's Concrete5 Tips

How to make things work when building a Concrete5 website.

How to Build a Slideshow Block (With Flex Slider)

| Comments

Flex Slider (screenshot from flex.madebymufffin.com)
Flex Slider (screenshot from flex.madebymufffin.com)

If you need to build an image gallery or slideshow for a Concrete5 site, I’ve made some boilerplate code available that handles all of the editing and database infrastructure so you can concentrate on implementing the front-end (usually a jquery image gallery or slideshow plugin). The code is available here:

C5 Designer Gallery on GitHub

Read on for details and instructions on how to use it, using the Flex Slider as an example…

Installation

If you scroll down the github page, you will find instructions for customizing this package for your own use. In this blog post I’ll show you an example using the Flex Slider jQuery plugin. If you have a decent understanding of html, css, and javascript, you should be able to figure out how to use this boilerplate package code to implement any javascript or jquery gallery/slideshow plugin.

First, download the package by clicking the “ZIP” button at the top of the github page.

github download link
github download link

Unzip the downloaded file, and inside the extracted directory you should see a packages folder. Inside this folder is another folder called designer_gallery. Move this designer_gallery folder into your site’s packages directory.

You can install the package via Dashboard -> Add Functionality, and see it in action. But out of the box it doesn’t provide much in the way of a front-end (just an unstyled list of images and titles from the chosen file set). We’re going to modify the code in a few places, and then implement the “Flex Slider” jquery plugin as our front-end.

Configure the Back-End

Next, follow the steps outlined in the README (go back to the C5 Designer Gallery github page and scroll down to the “Customization Steps” section). Note that step 1 (uninstalling the package) only applies if you installed it after downloading.

For our example Flex Slider, we do the following:

  1. If you already installed the package on your site to test it out, uninstall it now via Dashboard -> Add Functionality. If you haven’t installed it on your site, make sure you at least copied the designer_gallery folder into your site’s packages directory.
  2. Rename the top-level designer_gallery folder to flex_slider. Then go into the flex_slider directory, and within that go into the blocks directory . You should see another folder called designer_gallery – rename this to flex_slider as well.
    Rename 2 directories
    Rename 2 directories
  3. Go back up to the top-level flex_slider directory (you should see 3 folders: blocks, helpers, and tools, and 2 files: controller.php and icon.png), and edit the controller.php file as follows:
    • Change the class name from DesignerGalleryPackage to FlexSliderPackage
    • Change the $pkgHandle from ‘designer_gallery’ to ‘flex_slider’
    • In the getPackageName() function, change ‘Designer Gallery’ to ‘Flex Slider’
    • In the getPackageDescription() function, change ‘Designer Gallery’ to ‘An awesome, fully responsive jQuery slider plugin.’ (or whatever you’d like – I just took this from the FlexSlider site).
      Change the package controller in 4 places
      Change the package controller in 4 places
  4. Go down into the blocks directory, and within that go into the flex_slider directory. Edit the controller.php file as follows:
    • Change the class name from DesignerGalleryBlockController to FlexSliderBlockController
    • Change the $btTable from ‘btDesignerGallery’ to ‘btFlexSlider’
    • In the getBlockTypeName() function, change ‘Designer Gallery’ to ‘Flex Slider’
    • In the getBlockTypeDescription() function, change ‘Designer Gallery’ to ‘An awesome, fully responsive jQuery slider plugin.’
      Change the block controller in 4 places
      Change the block controller in 4 places
  5. Edit the db.xml file as follows:
    • Change the table name from “btDesignerGallery” to “btFlexSlider”
      Change the db.xml file in 1 place
      Change the db.xml file in 1 place
  6. Optionally replace the package icon.png file with your own icon (a 97x97 PNG with rounded corners). We are going to skip this step for now.
  7. We want to allow for images in our slider to link to other pages in our site when clicked. In order to do so, we must install Mnkras’s free Page Selector Attribute addon. This adds a new attribute type to our system that lets users choose a page from the sitemap. When our package is installed in the next step, it will create a file attribute of this type which lets users choose the page to link to via File Manager properties.
  8. We’re all done with the back-end, so go ahead and install our new “Flex Slider” package via Dashboard -> Add Functionality. If you get any errors, go back through the steps to make sure you didn’t spell anything wrong, leave any words out, or lose any quotation marks.

Once you’ve installed (or re-installed) the package, test it out by adding the new “Flex Slider” block to a page. Notice that the block add/edit dialog is already taken care of for us, so all we need to worry about is implementing the front-end gallery/slideshow display.

The boilerplate code includes a pre-built add/edit dialog
The boilerplate code includes a pre-built add/edit dialog

Implement the Front-End

Now for the fun part!

Sample Flex Slider (screenshot from flex.madebymufffin.com)
Sample Flex Slider (screenshot from flex.madebymufffin.com)

Head over to the Flex Slider plugin page, and click the “Download The Kit” button over in the right sidebar (you may need to scroll down a little to see it). Unzip the downloaded file, and in the extracted folder you should see a couple of folders, an html file, a css file, and two javascript files.

We are going to copy some of these files into our package’s flex_slider block directory (SITEROOT/packages/flex_slider/blocks/flex_slider/), then modify them to suit our needs.

Copy the Javascript

Copy jquery.flexslider-min.js into our block’s js directory. Note that the FlexSlider download provides two javascript files – one is the full uncompressed file, and the other is minified for faster downloading. Most jquery plugins provide both types of files, and unless you need to hack or debug the plugin yourself, it’s usually best to only use the “minified” or “packed” version.

As with all things related to Concrete5, never include your own copy of the jquery library itself – this is always included by Concrete5 on every page, so if you include another copy if it in your own block, the two copies will conflict with each other and cause errors on the page. FlexSlider does not include the jquery library file in its download, so we don’t have to worry about this now – but keep it in mind if you implement a different plugin in the future.

Copy the Stylesheet

Copy flexslider.css into our block’s css directory. Note that with most jquery plugins, you are provided some CSS that applies to the functionality of the gallery/slider itself, and other CSS that is for the overall styling of the demo site. Fortunately for us, the FlexSlider plugin keeps these separate and the flexslider.css file only contains functionality-specific styles. But if you are implementing a different plugin, you’ll need to figure out which CSS is required in order for the gallery/slider to function versus what you want to leave out because it doesn’t fit your particular site’s theme.

Copy the Images

Most plugins provide images for the gallery/slider “chrome” – things like the next/previous navigation buttons and pagination controls. In the case of FlexSlider, it puts those images in its theme folder. Copy the contents of this folder (there should be 2 images: bg_control_nav.png and bg_direction_nav.png) into our block’s images directory.

Now go back to the flexslider.css file we copied in the previous step and search for all image url()’s. Notice that they refer to the images in the theme directory at the same level as the css file itself, but since we’ve moved the images into our images directory at a level above the css file, we need to modify those url()’s. So change url(theme/bg_direction_nav.png) to url(../images/bg_direction_nav.png), and change url(theme/bg_control_nav.png) to url(../images/bg_control_nav.png).

IMPORTANT: Note that the image files we’re working with in this step pertain only to the plugin “chrome”, and are not the actual images that will be displayed within the gallery or slideshow. The actual images will be chosen by the end-users of your site (this is the whole point of going through all this trouble to create a block – so that your end-users have the ability to choose and modify the images that each gallery/slideshow displays).

Examine the HTML

Open the demo.html file in the FlexSlider download and examine its contents. With pretty much every gallery or slideshow plugin, there are two important portions of code. One is the html markup that puts the images, links, titles, captions, etc. on the page. The other is the javascript that initializes the plugin and sets its options.

The two portions of code we care about
The two portions of code we care about

With many plugins, it can be quite challenging to determine what code you want in your own block versus what you want to leave out. There is unfortunately no single answer that applies to every situation – you will need to experiment a bit to get things just the way you want them. A good approach to this experimentation is to remove and add things to the demo page that comes with your gallery/slideshow plugin and see how they affect the look and functionality. Once you have an understanding of how the plugin works on an isolated page, then it will be easier to convert it to a Concrete5 block template.

Ignore Javascript/CSS Includes

Don
Don’t copy these

Note that we are not copying the tags that include javascript and css files, because those will be generated for us by C5 (it does this automatically for any files we put in our block’s /js/ and /css/ directories).

Convert HTML and Javascript to Concrete5 Block View Template

Open the block’s view.php file in your text editor. Delete everything after the first line (although you might want to read through it first, especially if you’re implementing your own plugin in the future).

Copy the two portions of code we identified above from the FlexSlider’s demo.html file and paste them into our block’s view.php file.

Our block's view.php file (after pasting in code from FlexSlider's demo.html file)
Our block's view.php file (after pasting in code from FlexSlider's demo.html file)

The pasted code contains “hard-coded” images, but since we want to allow our end-users (the people managing the site) to upload and choose their own images, we need to replace it with a little bit of PHP code. The block already has a controller.php file that handles all the messy work of getting the chosen images and collating all of the meta-information about each one – and it provides this information to the view.php file via the $images variable. We want our code to loop through the images in this variable, and output a snippet of html for each one.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class="flexslider">
  <ul class="slides">
      <li>
          <img src="demo-stuff/inacup_samoa.jpg" />
          <p class="flex-caption">Captions and cupcakes. Winning combination.</p>
      </li>
      <li>
          <a href="http://flex.madebymufffin.com"><img src="demo-stuff/inacup_pumpkin.jpg" /></a>
          <p class="flex-caption">This image is wrapped in a link!</p>
      </li>
      <li>
          <img src="demo-stuff/inacup_donut.jpg" />
      </li>
      <li>
          <img src="demo-stuff/inacup_vanilla.jpg" />
      </li>
  </ul>
</div>

If you look at how the demo html is structured, you’ll see that an <li> element contains an <img> tag, optionally surrounded by an <a> tag for a link, and optionally followed by a <p> tag for a caption. Since it is easier to troubleshoot problems when you build things in small pieces, we will take on each of these features one at a time.

Display Images

Let’s start with the image tag (it often helps to build/test/fix just one small piece at a time). Replace the code shown above with this:

1
2
3
4
5
6
7
8
9
10
11
<div class="flexslider">
  <ul class="slides">
  
      <?php foreach ($images as $img): ?>
      <li>
          <img src="<?php echo $img->large->src; ?>" />
      </li>
      <?php endforeach; ?>
  
  </ul>
</div>

As we loop through $images, we are putting each image into a variable called $img. The $img variable will be an object containing lots of useful information about each image, including src’s and dimensions for the various resizes (as determined by the block add/edit settings). $img->large is usually what you want to use for slideshows like this (there is also $img->thumb if you want thumbnails, and $img->orig if you trust your users enough and want the full-sized image as it was originally uploaded). For the Flex Slider implementation, we don’t need to specify width, heights, or alt attributes – but if you implement a different plugin in the future you can retrieve them via $img->large->width, $img->large->height, and $img->title (respectively).

Now take a look at the javascript code:

1
2
3
4
5
<script type="text/javascript">
  $(window).load(function() {
      $('.flexslider').flexslider();
  });
</script>

In this case, we don’t need to alter anything there, because we haven’t changed the “flexslider” class name of our wrapper div above.

So now let’s test it out and see if it works. The block should already be installed, so just go to a page on your site (or create a new one), enter edit mode, and add the “Flex Slider” block. Choose a file set (or create one first if needed), and click “Add”, then exit edit mode and publish the page.

It's alive!
It's alive!

Pretty neat, eh? We haven’t even done much work, and we already have a functioning (albeit sparse) slider.

Display Image Captions

Now let’s add in the captions. Flex Slider uses paragraph tags after each image to denote captions (of course other plugins will have slightly different methods). So below the <img src="<?php echo $img->large->src; ?>" /> line, add this new line:

1
<p class="flex-caption"><?php echo $img->title; ?></p>

Go back to your browser and reload the page…

I am a caption for an image of an image with a caption
I am a caption for an image of an image with a caption

There they are. Note that we’re using the image “title” property for the caption, and that property is set to the filename by C5 upon upload – so you will most likely need to inform your users that they’ll want to set these manually when adding a new slider block.

Optional Output

There is one problem with our code so far – if the user removes or never assigns a “title” attribute for an image, the dark background for the caption still shows up in the slider.

Dark background shows even with no caption
Dark background shows even with no caption

This can be fixed by taking the existing <p class="flex-caption"><?php echo $img->title; ?></p> line and surrounding it with a PHP “if” statement, like so:

1
2
3
<?php if ($img->title): ?>
  <p class="flex-caption"><?php echo $img->title; ?></p>
<?php endif; ?>

Links

When this package is installed, it creates a new page attribute called “Gallery Link To Page” (assuming you have the Page Selector Attribute installed first). This lets users choose a page that the image can link to when clicked (the destination page is set via the File properties, just like the title attribute).

Users can set image link destinations via File Manager properties
Users can set image link destinations via File Manager properties

Just like with the image src and title, this link will be provided to us by the controller, and we can access it with $img->linkUrl. Take the existing <img src="<?php echo $img->large->src; ?>" /> line and wrap it in a link tag, like so:

1
<a href="<?php echo $img->linkUrl; ?>"><img src="<?php echo $img->large->src; ?>" /></a>

Go back to your browser and reload the page to make sure everything still works…

Of course now we have the same problem as we did with captions – if the user doesn’t provide a page to link to in the file properties, we don’t want to output the link in our slider. So again we’ll use a PHP “if” statement, although this one is a little trickier because we have to worry about both an opening and closing tag (<a> and </a>):

1
2
3
4
5
<?php if ($img->linkUrl): ?>
  <a href="<?php echo $img->linkUrl; ?>"><img src="<?php echo $img->large->src; ?>" /></a>
<?php else: ?>
  <img src="<?php echo $img->large->src; ?>" />
<?php endif; ?>

Avoid Conflicts Between Multiple Blocks

Everything should be working well now, but there is one more potential issue we want to address in our code: if more than one Flex Slider block is added to a page, we will run into problems because the javascript code will get run multiple times (because the view.php file will be used again for each block on the page). Running the same javascript code multiple times isn’t necessarily an issue, but it is for us because the code we copied from the flex slider demo is using a class selector (.flexslider), which means it will find all elements having the “flexslider” class – even ones that are from other blocks of this type.

My preferred solution to this problem is using the block’s ID number to create a unique DOM id for the slider element. This lets us be sure that our javascript code is only going to be applied to the html markup for one specific placement of the block on a page (and if Flex Slider blocks will be added to the page more than once, each one will have its own unique id).

First change the wrapper element (<div class="flexslider">) to this:

1
<div class="flexslider" id="flexslider<?php echo $bID; ?>">

Next, change the javascript initialization code ($('.flexslider').flexslider();) to this:

1
$('#flexslider<?php echo $bID; ?>').flexslider();

(Note that although we added an id to the div, we still want to keep the class for css purposes.)

Complete view.php Code

For reference, here is the complete code for the block’s view.php file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php defined('C5_EXECUTE') or die(_("Access Denied.")); ?>

<!-- Hook up the FlexSlider -->
<script type="text/javascript">
  $(window).load(function() {
      $('#flexslider<?php echo $bID; ?>').flexslider();
  });
</script>

<!--=============================
Markup for FADE animation
=================================-->
<div class="flexslider" id="flexslider<?php echo $bID; ?>">
  <ul class="slides">

      <?php foreach ($images as $img): ?>
      <li>

          <?php if ($img->linkUrl): ?>
              <a href="<?php echo $img->linkUrl; ?>"><img src="<?php echo $img->large->src; ?>" /></a>
          <?php else: ?>
              <img src="<?php echo $img->large->src; ?>" />
          <?php endif; ?>

          <?php if ($img->title): ?>
              <p class="flex-caption"><?php echo $img->title; ?></p>
          <?php endif; ?>

      </li>
      <?php endforeach; ?>

  </ul>
</div>

Further Customization: Sliding Effect

Next, let’s implement a “sliding” effect (as opposed to “fading”). As per the Flex Slider documentation, we can do so by setting the animation option to “slide”, like so:

1
2
3
4
5
$(window).load(function() {
  $('#flexslider<?php echo $bID; ?>').flexslider({
      animation: 'slide'
  });
});

Go back to the browser and reload…

Eh... not so much
Eh… not so much

Didn’t work as smoothly as the fader, but that’s okay – this is part of the process when building slideshows and galleries. When you run into problems such as these, the best thing to do is go back to the demo code and/or the documentation for the plugin you’re using. In this case, a closer look through the demo.html file shows that the “slide” effect has slightly different sample code, along with a note explaining that “you need to add an extra container element for the overflow: hidden property on the slider” – so let’s go ahead and do that. In the block’s view.php file, add a new wrapper div around the existing <div class="flexslider" id="<?php echo $bID; ?>"> element. Change this:

1
2
3
4
5
6
7
8
<!--=============================
Markup for FADE animation
=================================-->
<div class="flexslider" id="flexslider<?php echo $bID; ?>">
  <ul class="slides">
      ...[The rest of the code here]...
  </ul>
</div>

…to this:

1
2
3
4
5
6
7
8
9
10
<!--=============================
Markup for SLIDE animation
=================================-->
<div class="flex-container">
  <div class="flexslider" id="flexslider<?php echo $bID; ?>">
      <ul class="slides">
      ...[The rest of the code here]...
      </ul>
  </div>
</div>

(Don’t forget that last closing </div> tag!)

Note that we don’t need to set the overflow:hidden style on this new wrapper ourselves because it’s already taken care of in the flexslider.css file.

As per the sample code, we also need to tell the flexslider which class we’re using for our container div, so change the javascript from this:

1
2
3
4
5
$(window).load(function() {
  $('#flexslider<?php echo $bID; ?>').flexslider({
      animation: 'slide'
  });
});

…to this:

1
2
3
4
5
6
$(window).load(function() {
  $('#flexslider<?php echo $bID; ?>').flexslider({
      animation: 'slide', //<-- Don't forget this comma!
      controlsContainer: '.flex-container'
  });
});

As usual, go back to your browser and reload… it should look better now.

Further Customization: Responsive Sizing

The only remaining issue is that some of the images are taller than others. This can be solved in several different ways, depending on the overall design of your site. The easiest solution is to edit the block in C5, enable cropping, and specify a width and a height.

Enable image cropping
Enable image cropping

This approach may introduce other problems, though – such as the width of the slider being wider than the images – you will need to play around with your site’s CSS, and probably set explicit width and height styles on the wrapper div itself.

Another approach would be to modify your site styles so that it is a “responsive layout”, and let the slider shrink and grow with the page around it – this probably requires making the width of your page columns somewhat fluid (without an explicit width style).

Because these issues are specific to your site’s design, I will leave it to you to figure out the most appropriate solution for your particular situation.

Enabling Thumbnail Images

The flex slider design we implemented does not require any thumbnail images, but some galleries/sliders do. If you need to display thumbnail images in your front-end, edit the block controller file (packages/flex_slider/blocks/flex_slider/controller.php), and set the $showThumbControls option to true by changing this line:

1
private $showThumbControls = false;

…to this:

1
private $showThumbControls = true;

Now when users add or edit the block, they will be given the additional option to set thumbnail image sizes.

Setting $showThumbControls to true in the block controller enables additional thumbnail settings in the block add/edit dialog
Setting $showThumbControls to true in the block controller enables additional thumbnail settings in the block add/edit dialog

To output thumbnail images in your block’s view.php file, do the same thing you would do for the “large” image, except use $img->thumb instead of $img->large (so within the $images loop, call $img->thumb->src, $img->thumb->width, and $img->thumb->height).

Complete Implementation

Here is the complete package with all of the code from this blog post:

flex_slider.zip

Comments