Silverstripe Image Gallery Tutorial

I have had a few issues installing image gallery modules on Silverstripe 2.4. I'm new to using silverstripe so this is a beginners tutorial, the aim is to install a basic image gallery which fits the following criteria:

  • Allow CMS users to upload photos
  • Add custom fields to be associated with each image (such as title, caption etc.)
  • Display the images using a javascript image gallery of my choice

Another goal of this exercise was to better understand silverstripe - so the solution is simple, but effective and suitable for our needs.

What you will need for this image gallery:

Install SWFUpload

Get the SWFUploadField plugin - I checked out the latest revision from the repository. After that all that is requried is to place the swfupload folder in the root directory of your silverstripe install (the folder that contains the cms, mysite, themes, sapphire folders). Then run a /dev/build - in my instance it didn't seem like anything was built or at least no database fields were added or changed, don't worry if this is the case for you.

Note: rename the module folder to "swfupload" before placing in the root dir.

Install DataObjectManager

Again I checked out the latest revision from the repo. Following the same process again, moving the dataobject_manager folder into the root of the silverstripe install then running /dev/build.

Note: rename the module folder to "dataobject_manager" before placing in the root dir.

Create the Image class

This is where we can specify which fields we want to associate with each image in our gallery by creating a class that will represent each image. I have called my class ImageResource - you can call yours what you like as long as there is no naming clash with existing classes (there is already an Image class in ss for example).

 <?php 
// /mysite/code/ImageResource.php
class ImageResource extends DataObject
{
    static $db = array (
        'Title' => 'Text',
        'Caption' => 'Text'
    );
 
    static $has_one = array (
        'Attachment' => 'Image', //Needs to be an image
        'GalleryPage' => 'GalleryPage'
    );
 
    public function getCMSFields_forPopup()
    {
        return new FieldSet(
            new TextField('Title'),
            new TextareaField('Caption'),
            new FileIFrameField('Attachment')
        );
    }
}

The fields I have added are Title and Caption - I want each image in the gallery to be able to have a title and a caption. The Attachment is a type of Image, rather than a type of file such as in the DataObjectManager documentation, as noted on this thread.

Create the Gallery Page

This is the type of page you are going to create in the CMS in order to add images to the gallery and display the photos on the website.

<?php
// /mysite/code/GalleryPage.php
class GalleryPage extends Page
{
    static $has_many = array (
        'Images' => 'ImageResource'
    );
    public static $db = array(
    );
    public static $has_one = array(
    );
 
    public function getCMSFields()
    {
        $f = parent::getCMSFields();
        $manager = new ImageDataObjectManager(
            $this, // Controller
            'Images', // Source name
            'ImageResource', // Source class
            'Attachment', // File name on DataObject
            array(
                'Title' => 'Title', 
                'Caption' => 'Caption'
            ), // Headings 
            'getCMSFields_forPopup' // Detail fields
            // Filter clause
            // Sort clause
            // Join clause
        );
        $f->addFieldToTab("Root.Content.Gallery",$manager);
        return $f;
    }
}
 
class GalleryPage_Controller extends Page_Controller {
}

Note that this page has many Images that are types of ImageResource objects. The ImageDataObjectManager takes care of the interface in the CMS which will handle the CRUD for the images. One problem I had when following the documentation was the lack of Controller on the Page classes, so adding the GalleryPage_Controller class sorted out a few issues for me.

Create the Gallery layout view

A basic view to loop over the images and display them on the page:

<!-- /themes/yourtheme/templates/Layout/GalleryPage.ss -->
<% control Images %>
<ul>
    <li>$Title</li>
    <li>$Caption</li>
    <li>$Attachment.SetRatioSize(150,150)</li>
</ul>
<% end_control %>

Build

Now that the gallery page and image classes are set up, run a /dev/build - you should now be able to create a Gallery Page in the CMS. When editing that gallery page there should be a tab in "Main" called Gallery where you should be able to add a number of images at once, cycle through and add a title and/or caption for each. A

fter adding images and publishing the page, view the page on your site and each image should be crudely displayed on screen along with the title and caption if they exist. At this stage you should have a working image gallery, all we need to do is tidy up the html and incorporate some kind of javascript gallery to cycle through the photos.

Adding a jquery gallery plugin

I have had issues adding jquery plugins in the past mostly because of conflicts with multiple libraries declaring the $() function. I avoided these problems in this case, but I'm not sure if adding a form to the gallery page might conflict - the SilverStripeNavigator seems to load fine.

Download fancybox and have a look at the example index.html file to see what files are included and how to invoke the fancybox. Essentially what we need is the fancybox.js file (jquery.fancybox-1.3.1.js), the css file (jquery.fancybox-1.3.1.css), the images (in /fancybox/) and a way to invoke the fancybox on our gallery page ourselves (our own gallery.js script).

I copied the javascript files required into a directory in my themes folder: /themes/yourtheme/js/. I used jquery 1.4.2 which was poached from /sapphire/thirdparty/jquery/. Then I grabbed the js file for fancybox and also created a small script to load the gallery - all together the following files were loaded from the /js/ folder:
jquery.js
fancybox.js
gallery.js

I copied the css file for fancybox to /themes/yourtheme/css/fancybox.css, being sure to replace the references to images in the css file so that the paths are correct. This required changing url(' to url('../images/fancybox/ throughout the file.

I copied all the images for fancybox to the /themes/yourtheme/iamges/fancybox/ folder.

In order to grab the javascript and css files for the gallery overload the init() method of the GalleryPage_Controller:

class GalleryPage_Controller extends Page_Controller {
    function init() {
           parent::init();

          //Include fancybox Code
          Requirements::javascript('themes/hula/js/jquery.js');
          Requirements::javascript('themes/hula/js/fancybox.js');
          Requirements::javascript('themes/hula/js/gallery.js');
          Requirements::themedCSS('fancybox');
    }
}

Invoking the fancybox

To avoid the conflicts of $() my gallery.js uses noConflict():

$.noConflict();
jQuery(document).ready(function($) {
  // Code that uses jQuery's $ can follow here.
  $("a[rel=example_group]").fancybox({
    'transitionIn'    : 'none',
    'transitionOut'   : 'none',
    'titlePosition'   : 'over',
    'titleFormat'   : function(title, currentArray, currentIndex, currentOpts) {
      return 'Image ' + (currentIndex + 1) + ' / ' + currentArray.length + (title.length ? '   ' + title : '') + '';
    }
  });
});

As you can see I have pulled this straight from the fancybox example (even preserving the example_group naming :-s). Update the gallery view to something like:

<% control Images %>
  <a rel="example_group" href="$Attachment.URL" title="$Caption">$Attachment.SetRatioSize(150,150)</a>
<% end_control %>

Reloading the gallery page with ?flush=1 should see you viewing a nice fancybox gallery!

Notes

Much of this tutorial is dependent on the work of Uncle Cheese - such as the DataObjectManager and the SWFUploadField modules. Uncle Cheese also has an Image Gallery module, which I had some issues with installing on SilverStripe 2.4 but your mileage might vary. Check out Uncle Cheese's blog LeftAndMain.

Update:

I had some problems with SWFUpload whereby certain computers could not upload files, continuously getting errors such like:
Error #2044: Unhandled IO Error Event. Error #2038 File I/O Error.
Other computers could upload files fine.

At the root of the problem was an HTTP Status code being returned by the server: 406 Not Acceptable.

The solution for us was this one line in the .htaccess file to turn OFF mod_security:

<IfModule mod_security.c>
SecFilterEngine Off
</IfModule>

If you have the flashblock add on for firefox then make sure to add the domain to your whitelist! You may get an error like: the method 'admin' does not exist on 'ImageDataObjectManager'.

See this silverstripe post for more details
Here is a related SWFUpload issue

If you want to reorder images in the gallery just enable sorting for the data object manager in mysite/_config.php using:

SortableDataObject::add_sortable_class('ImageResource');

Then perform a /dev/build?flush=1 for the DataObjectManager to create the sort columns on the data object 'ImageResource'.

I am now using the Uploadify module instead of SWFUpload. Switching over is simply a matter of removing the SWFUpload folder and replacing with the Uploadify module.

A web hosting company based in New Zealand had to additionally apply these settings for uploadify (and I suspect swfupload) to work:

suhosin.session.cryptua=off
suhosin.session.encrypt=off