SSWI — When in doubt, buff it out.

Slideshow Pro with PHP, CSS and JS,

Written in Frisco, TX on October 8, 2006 and tagged with , and .

7 Comments, 0 Tweets, why not add one?

My Flickr Stream

Well not exactly, but close enough to warrant the title I would think.

I know that I was supposed to publish another tutorial before this one, but I hacked this up last week, and thought it was cool enough to preempt the other post.  So at work the new design we just launched called for a rotating, hyperlinked slideshow, with cross-fading.

Normally it would be “To the Flash Cave!”, but I was feeling extra crotchety so I decided to basically recreate Slideshow Pro in PHP, CSS and some JS-foo.  Nothing to spectacular, but it is shiny.  Be warned, this is a very long tutorial… use at your own risk.

First, lets set some parameters

The slideshow needed to be:

  1. Dynamic
  2. Hyperlinkable on a per-image basis
  3. The images needed to be “retireable”
  4. The images needed to be “expireable”, meaning they have a date where they automatically fall out of the slideshow
  5. And non-techies needed to be able to interact with the system

My solution currently addresses points 1 - 3 directly; point 4 is just waiting for me to write a simple web form page.  Lower priority at the moment.  So lets take a look at the parts that are assembled to make up this Justice League of the web.

Hey, hey the gangs all here!

So we will of course be making use of PHP 5 and all its OOP goodnes; throw in a liberal sprinkling of prototype and script.aculo.us and finally some auto-generated CSS for spice.  Add that together, and you get this.

So lets go over the logic before we get into some code.  To maximize flexibility we are going to be storing information on each image in our slideshow in a SQL database table (for this example a MySQL DB).  We will query this table for all the images we have catalogued that aren’t retired or expired, and will use this information to generate CSS and JS to power our slideshow.

We all on the same page?  Good lets move onto the first bit of our code, the slideshow table structure.

CREATE TABLE `slideshow` ( `ID` bigint(20) NOT NULL auto_increment, `url` varchar(256) NOT NULL, `description` text NOT NULL, `filename` varchar(256) NOT NULL, `expiredate` date NOT NULL, `retired` tinyint(1) NOT NULL, KEY `ID` (`ID`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;

Nothing to scary here I would say.  But just in case lets look at each field in some more detail:

  • ID: Auto-incrementing ID, for sanity purposes.
  • url: The URL we want the load if the image is clicked
  • description: For those of us who care about useability and accessability, an image description
  • filename: The filename, sans extension of the file.  This is forward thinking, to the time that we have a web interface for the non-techies to upload images for the slideshow.
  • expiredate: This allows us to specify a date for an image to fall out of hte slideshow rotation.
  • retired: So we have an image that we want to remove from the slideshow, but not delete.  This could be for an annual event, concert whatever.

For the sake of this tutorial, we will use the data set from the Asbury Site.  Next lets look at the slideshow class file.

Slideshow Framework

Currently our class will only have one function create_show() but once we start to make a web interface this class will be come much more noisy.  Since I primarily talk about WordPress here, we will assume that you will be using this on a WP powered site.  If that is not the case, you should at least know how to connect to your DB… if that isn’t the case, stop now and come back when you do.  Here is the code for our class:

<?php // begin slideshow class class slideshow { function create_show() { global $wpdb; $today = date('Y-m-d'); $q = $wpdb->get_results( "SELECT ID, url, description, filename, expiredate, retired FROM slideshow WHERE retired = 0 AND expiredate < '$today' ORDER BY ID ASC" ); if( is_array( $q ) ) { return $q; } else { return array(); } } } // end slideshow class

So lets step through the function.  First we find out what todays date is and set it equal to $today.  Then we perform an sql query against our slideshow table, where we look for records that are not retired (equal to 0) and that have an expiredate less than $today.

Okay so now we have our one function, lets make some use of it.  Next we’ll look at the how we programmaticaly create CSS, HTML and the JS that powers the slideshow with this function.

Creating and putting the pieces together

To make the slideshow work, we are going to need three things: generated HTML, CSS and JS.  I like to split out generated markup and scripting into thier own files, so that the static content we have can benefit from cacheing.

Here is the code for slideshow.css.php:

// begin CSS generation functions $members = slideshow::create_show(); header('Content-Type: text/css; charset: UTF-8'); $i = 1; $num = count( $members ); ?> <?php foreach ( $members as $picture ) { echo "#" . 'spot-' . $i . "\n"; echo '{' . "\n"; echo ' position: absolute;' . "\n"; echo ' left: auto !important;' . "\n"; echo ' left: 7.8em;' . "\n"; echo '}' . "\n"; echo "\n"; $i++; } // end CSS generation functions

Nothing to out of the ordinary going on here, we call our create_show() function, then loop through the results returned creating a CSS rule for each result we find.  Next we create the JS that powers the cross-fading-foo we all love so much:

// begin JS generation code header('Content-Type: text/javascript; charset: UTF-8'); $members = slideshow::create_show(); $i = 1; $num = count( $members ); ?> var divs_to_fade = new Array(<?php foreach ( $members as $picture ) { ?><?php echo "'" . 'spot-' . $i . "'"; ?><?php $i++; ?><?php if ( $i == $num + 1 ) { echo ''; } else { echo ', '; }; } ?>); var i = 0; // the number of milliseconds between swaps. Default is five seconds. var wait = 5000; // the function that performs the fade function swapFade() { Effect.Fade(divs_to_fade[i], { duration:1, from:1.0, to:0.0 }); i++; if (i == <?php echo $num; ?>) i = 0; Effect.Appear(divs_to_fade[i], { duration:1, from:0.0, to:1.0 }); } // the onload event handler that starts the fading. function startSlideShow() { setInterval('swapFade()',wait); } <?php // end JS generation code ?>

Again, very straightforward. Some of you might have noticed that we queried for all of the fields in the table in each of these examples, but didn’t actually use the information.  We could have created another function, that only returned the ID for example, and used it when creating the CSS and JS.

I decided it was silly to have two functions, but if you want to go that way, by all means do.  It makes no difference to me.  Next we need to create some HTML.  I have this in a template file (slideshow.php) that I load via our nifty theme system.

When using WordPress you could place this code in the index template, or the header template wrapped in if ( is_home() ) if you wanted it to only show up on the root of your site.  Here is the code to generate the markup for the slideshow:

<?php // begin HTML generation functions $members = slideshow::create_show(); $i = 1; foreach ( $members as $picture ) { ?> <div id="spot-<?php echo $i; ?>"<?php if ( $i == 1 ) { echo ''; } else { echo ' style="display:none"'; } $i++; ?>> <a href="<?php echo $picture->url; ?>" title="<?php echo $picture->description; ?>"><img src="theme/default/images/spots/<?php echo $picture->filename; ?>.jpg" alt="<?php echo $picture->description; ?>" /></a> </div> <?php } // end HTML generation functions ?>

When run succesfully this code will give you something like this:

<div id="spot-1"> <a href="/url1/" title="URL and Image 1"><img src="/wp-content/themes/default/images/image1.jpg" alt="URL and Image 1" /></a> </div> <div id="spot-2" style="display:none"> <a href="/url2/" title="URL and Image 2"><img src="/wp-content/themes/default/images/image2.jpg" alt="URL and Image 2" /></a> </div> <div id="spot-3" style="display:none"> <a href="/url3/" title="URL and Image 3"><img src="/wp-content/themes/default/images/image3.jpg" alt="URL and Image 3" /></a> </div> <div id="spot-4" style="display:none"> <a href="/url4/" title="URL and Image 4"><img src="/wp-content/themes/default/images/image4.jpg" alt="URL and Image 4" /></a> </div> <div id="spot-5" style="display:none"> <a href="/url5/" title="URL and Image 5"><img src="/wp-content/themes/default/images/image5.jpg" alt="URL and Image 5" /></a> </div>

So that is it, you have the core of functionality that can be found in SlideShow Pro, for free throught the clever use of PHP, CSS and JS.  Now, let me say that I don’t have any problem with Todd’s product.  It is pretty amazing and very affordable, I just didn’t want to use Flash for this when there was a much more interesting method that could be employed.

Again to see this in action, just load the Asbury College Homepage and be amazed by the fadey goodness.

As always, questions and comments are welcome in the, uh… comments section.

If you post about this on Twitter, please use the hashtag #silly601.


personal avatar

Arthus Erea, on March 1, 2007

Very nice; I tried doing something like this a while back and ended up just going back to Flash. Of course, I didn’t know about script.aculo.us then. Flickr should use this on the front page!

personal avatar

tom, on March 1, 2007

nice tutorial derek, when thing would be always that easy :)
arthus, that was my first thought too, flickr should use this too. not exactly this handmade script, but a feature with a slideshow would be nice

is this available as a plugin?

personal avatar

Chris J. Davis, on March 1, 2007

Thanks for the comments guys. I should think that Flickr will use soemthing like this when they can, since they have been moving away from dependency on flash.

And Tom, I am using Derek’s theme for this month but this is my site (Chris J. Davis), not Derek’s. And no, it isn’t available as a plugin. I am not sure I will be rolling it up intp one.

personal avatar

Nathan Smith, on March 1, 2007

Very nice writeup, and nicely done on Asbury.edu as well. You’re cleanin’ up that on-horse town. :)

Also, hadn’t mentioned it before, so I will do so here: I’m really diggin your new site design. It’s very Jeff-Croft-esque, but with enough CJD flavah to make it feel unique. Might I suggest a little show/hide JS action on the tags though? It’s sort of overwhelming. Anyway, I’m just complaining needlessly. Don’t mind me.

personal avatar

Nathan Smith, on March 1, 2007

Update: I just realized it’s a skin. Please disregard my previous nit-picky-ness (nit-picky-ness spelled wrong intentionally).

personal avatar

tom, on March 1, 2007

forgive me 100000 times, im sorry :)

personal avatar

Andy, on March 1, 2007

Chris-

Thanks - onload=”startSlideShow();” did the trick - I must be going mental!

I am running it all in PHP4 so I guess it should work - I just stripped out the OO for now - all should still work though.

Thanks again!
-Andy