WordPress galleries – slideshow hack

WordPress 3.5 has a very nice photo new gallery UI, and because I’m the kind of guy who just can’t be happy with nice, I had to go and hack it to make it run a slide show by default.

If you’re a wordpress.com user, you already have the slideshow feature – and I’ll bet money that it’s a damn sight more refined than mine – but for those of us running our own sites, here’s all you need to create simple, straighforward slideshows using any size of image:

1) Paste this into your functions.php file:

function slide_gallery_shortcode($foo, $attr) {
	global $post;

	static $instance = 0;
	$instance++;

	// We're trusting author input, so let's at least make sure it looks like a valid orderby statement
	if ( isset( $attr['orderby'] ) ) {
		$attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
		if ( !$attr['orderby'] )
			unset( $attr['orderby'] );
	}

	extract(shortcode_atts(array(
		'order'      => 'ASC',
		'orderby'    => 'menu_order ID',
		'id'         => $post->ID,
		'itemtag'    => 'dl',
		'icontag'    => 'dt',
		'captiontag' => 'dd',
		'columns'    => 1,
		'size'       => 'full',
		'include'    => '',
		'exclude'    => ''
	), $attr));

	$columns = 1;
	$size    = 'full';

	$id = intval($id);
	if ( 'RAND' == $order )
		$orderby = 'none';

	if ( !empty($include) ) {
		$include = preg_replace( '/[^0-9,]+/', '', $include );
		$_attachments = get_posts( array('include' => $include, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );

		$attachments = array();
		foreach ( $_attachments as $key => $val ) {
			$attachments[$val->ID] = $_attachments[$key];
		}
	} elseif ( !empty($exclude) ) {
		$exclude = preg_replace( '/[^0-9,]+/', '', $exclude );
		$attachments = get_children( array('post_parent' => $id, 'exclude' => $exclude, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
	} else {
		$attachments = get_children( array('post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
	}

	if ( empty($attachments) )
		return '';

	if ( is_feed() ) {
		$output = "\n";
		foreach ( $attachments as $att_id => $attachment )
			$output .= wp_get_attachment_link($att_id, $size, true) . "\n";
		return $output;
	}

	$itemtag = tag_escape($itemtag);
	$captiontag = tag_escape($captiontag);
	$columns = intval($columns);
	$itemwidth = $columns > 0 ? floor(100/$columns) : 100;
	$float = is_rtl() ? 'right' : 'left';

	$selector = "gallery-{$instance}";

	$gallery_style = $gallery_div = '';
      	$size_class = sanitize_html_class( $size );

	$gallery_div = "\n";

	return $output;
}

add_filter('post_gallery', 'slide_gallery_shortcode', 4, 2);

This is just a hacked version of the gallery shortcode handler from WordPress’ media.php file. All I do is reset a few defaults and remove some default CSS that messes with how I want it to look.

2) Create a new javascript file:

// Milliseconds, obviously.
var initial_fade_in = 500;
var fade_in_time    = 1000;
var fade_out_time   = 1000;
var slide_interval  = 10000;
var running         = true;

$(document).ready(function() {
    $('DIV.gallery dl:first').animate({opacity: 1.0}, initial_fade_in);
    $('DIV.gallery dl:first').addClass('active');

    // Optionally, you can create a 'Next' element (graphic, button, whatever)
    // and place it anywhere inside the 'gallery' div.
    $('DIV.gallery').hover(function (){
	$(this).css('opacity', '0.9');
	$('.gallery #next').fadeIn();
	running = false;
    }, function(){
	$(this).css('opacity', '1.0');
	$('.gallery #next').fadeOut();
	running = true;
    });

    $('.gallery #next a').hover(function(){
	running = false;
    },
				function (){
				    running = true;
				});

    $('.gallery #next a').click(function(){
	running = true;
	next_slide();
	running = false;
	return false;
    });

});

function next_slide() {

    if (!running){
	return;
    }

    var $active = $('.gallery dl.gallery-item.active').length ? $('.gallery dl.gallery-item.active')
	: $('.gallery dl.gallery-item:last');

    var next = 0;
    $next =  $active.next('dl').length ? $active.next('dl')
	: $('.gallery dl:first'); 

    $active.addClass('last-active');

    // Some browsers do funny things with JQuery animate if the element being manipulated
    // isn't at least notionally on the page. Use 'opacity: 0' instead of 'display: none'
    // as the initial state.
    $next.css({opacity: 0.0})
	.animate({opacity: 1.0}, fade_in_time, function() {
	    $('div.gallery dl.last-active').animate({opacity:0}, fade_out_time, function(){
		$('div.gallery dl.last-active').removeClass('active last-active');
	    });
	})
	.addClass('active');

}

$(function() {
    setInterval( "next_slide()", slide_interval );
});


2a) Add the necessary links to your header.php file:


<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="<?php bloginfo('template_url'); ?>/js/wp-slideshow.js"></script>
<!-- or whatever you've name it... -->


3) Add some CSS styling:

Needless to say, you’ll want to customise the colours:

/* Gallery slide show styles */
.gallery {
      position:relative; 
      top: 0px;
      left: 0px;
      min-height: 800px;
      background: transparent;
}

.gallery dl {
      position:absolute;
      top:250;
      left:250;
      margin-left: 1em;
      z-index:8;
      opacity:0.0;
}

gallery dl.active {
    z-index:10;
    opacity:1.0;
    border: 1px solid #c6c6c6;
}

.gallery dl.last-active {
      z-index:9;
}

dd.gallery-caption {
    color: #fff;
    border: 1px solid #c6c6c6;
    border-bottom: 1px solid #000;
    background: #000;
    opacity: 0.6;
    height: 3em;
    margin: 0;
    margin-top: -3em;
    padding: 1em;
    text-align: left;
    text-shadow: 1px 1px 1px #000;
    font-size: 10pt;
    font-weight: normal;
    font-family: 'helvetica neue',helvetica,sans-serif;
}

dd.gallery-caption a {
    color: #68a;
}