FlickrScrollr Explained: PHP
A More In-Depth Exploration of FlickrScrollr
NOTE: Ok, so I totally rushed the FlickrScrollr out the door on Tuesday in order to keep the Instant Tip Tuesday series alive (because, let's face it, if I'd only made it three weeks before I missed a Tuesday—well, I wouldn't be much of a blogger at all, would I?). However, in doing so, I didn't really explain how the plugin works or any of the advanced configurations of it. In an effort to rectify that, I'm going to break the code down in this post.
The Goal of This Post
First, I'd like to readdress what FlickrScrollr is and how it works, then I'd like to pick apart how the plugin was built. Because this plugin uses both a PHP class and a jQuery plugin, this writeup is going to be a little on the long side, and will be broken into two posts: one for the PHP class, and one to cover the jQuery plugin.
Overview
FlickrScrollr is a combination of PHP and jQuery that parses a Flickr RSS feed and creates an animated thumbnail display. It's in its infancy, so please post any issues you find with it in the comments so I can address them.
View the Demo | Download the Source
Requirements
- A server running PHP5+ (SimpleXML won't work on PHP4 or lower)
- The latest build of jQuery
- A Flickr account
Implementation
To implement FlickrScrollr on an HTML page, start by linking to the stylesheets:
<link rel="stylesheet" href="css/jquery.lightbox-0.5.css" type="text/css" media="screen" />
<link rel="stylesheet" href="css/jquery.flickrscrollr.css" type="text/css" media="screen" />
Next, include the required JavaScript before the closing body tag:
<script type="text/javascript" src="js/jquery-1.3.1.min.js"></script>
<script type="text/javascript" src="js/jquery.lightbox-0.5.min.js"></script>
<script type="text/javascript" src="js/jquery.flickrscrollr-1.0.1.min.js"></script>
With all required stylesheets and scripts included, we parse the feed and generate the markup like so:
<?php
require_once 'inc/FlickrScrollr.inc.php';
$flickr = new FlickrScrollr('http://api.flickr.com/services/feeds/photos_public.gne?id=29080075@N02&lang=en-us&format=rss_200');
echo $flickr;
?>
Finally, implement the jQuery plugins to add interactivity:
<script type="text/javascript">
$(document).ready(function(){
$('#flickrscrollr ul li a').lightBox();
$('#flickrscrollr').FlickrScrollr();
});
</script>
Customizing FlickrScrollr
FlickrScrollr comes with a few built-in options to allow you to customize it to better suit your needs:
- thumbWidth—the width of the thumbnail in pixels plus 1 to accomodate the border. Default: 76
- leftBtn—the path to the image that will serve as the left button. Default: 'images/fs_leftBtn.gif'
- rightBtn—the path to the image that will serve as the right button. Default: 'images/fs_rightBtn.gif'
- totalPics—the total number of photos in your RSS feed. Flickr will only provide 20 photos in its stream, so this setting is only for use with sets that contain less than 20 images. It controls the total width of the scroller, so if there are only ten photos and this is set to 20, the scroller will be too large and will allow the user to scroll beyond your thumbnails. Default: 20
- displayNum—the number of photos to display at a time. NOTE: It's recommended that totalPics is divisible by displayNum to avoid cutting off your display (i.e. totalPics is 20, displayNum should be 1, 2, 4, 5, or 10) Default: 4
To set any of the options to something other than the default value, simply pass them as arguments:
$('#flickrscrollr').FlickrScrollr({
leftBtn: 'img/newLeftBtn.jpg',
rightBtn: 'img/newRightBtn.jpg',
displayNum: '5'
});
Understanding FlickrScrollr—Step 1: The RSS
To start, we have our RSS feed from Flickr. You find this by going to your photostream, then grabbing the feed's URL, which can be found in two diffent places: 1) By clicking the RSS icon that appears in the location bar:

Or 2) Clicking the "Latest" link at the bottom of the page:

The URL you end up with should look something like this:
http://api.flickr.com/services/feeds/photos_public.gne?id=29080075@N02&lang=en-us&format=rss_200
If you look at the source of the RSS feed, you'll see some XML that looks something like this:
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:flickr="urn:flickr:" >
<channel>
<title>Uploads from jasonatennui</title>
<link>http://www.flickr.com/photos/ennuidesign/</link>
<description></description>
<pubDate>Tue, 11 Nov 2008 11:19:54 -0800</pubDate>
<lastBuildDate>Tue, 11 Nov 2008 11:19:54 -0800</lastBuildDate>
<generator>http://www.flickr.com/</generator>
<image>
<url>http://farm4.static.flickr.com/3132/buddyicons/29080075@N02.jpg?1218414199#29080075@N02</url>
<title>Uploads from jasonatennui</title>
<link>http://www.flickr.com/photos/ennuidesign/</link>
</image>
<item>
<title>Carly's Senior Photos 01</title>
<link>http://www.flickr.com/photos/ennuidesign/3023023846/</link>
<description><p><a href="http://www.flickr.com/people/ennuidesign/">jasonatennui</a> posted a photo:</p>
<p><a href="http://www.flickr.com/photos/ennuidesign/3023023846/" title="Carly's Senior Photos 01"><img src="http://farm4.static.flickr.com/3235/3023023846_5177ee8057_m.jpg" width="160" height="240" alt="Carly's Senior Photos 01" /></a></p>
<p>I took senior photos for my sister. These are my favorites.</p></description>
<pubDate>Tue, 11 Nov 2008 11:19:54 -0800</pubDate>
<dc:date.Taken>2008-10-12T12:55:40-08:00</dc:date.Taken>
<author flickr:profile="http://www.flickr.com/people/ennuidesign/">nobody@flickr.com (jasonatennui)</author>
<guid isPermaLink="false">tag:flickr.com,2004:/photo/3023023846</guid>
<media:content url="http://farm4.static.flickr.com/3235/3023023846_55e334f843_o.jpg"
type="image/jpeg"
height="3456"
width="2304"/>
<media:title>Carly's Senior Photos 01</media:title>
<media:description type="html"><p>I took senior photos for my sister. These are my favorites.</p></media:description>
<media:thumbnail url="http://farm4.static.flickr.com/3235/3023023846_5177ee8057_s.jpg" height="75" width="75" />
<media:credit role="photographer">jasonatennui</media:credit>
<media:category scheme="urn:flickr:tags">seniorphotos carlylengstorf</media:category>
</item>
// About 19 more photos go here...
</channel>
</rss>
That looks overwhelming, right? Don't worry, we barely have to deal with it at all! The only pieces we need for each photo are these:
<title>Carly's Senior Photos 01</title>
<link>http://www.flickr.com/photos/ennuidesign/3023023846/</link>
. . .
<media:thumbnail url="http://farm4.static.flickr.com/3235/3023023846_5177ee8057_s.jpg" height="75" width="75" />
So how do we sort through all that code to get at the pieces we need? With PHP, it's actually pretty easy!
Step 2: The PHP
In order to handle the RSS feed, we'll be using PHP's SimpleXML extension. We're going to create an object with two methods that will 1) parse the RSS feed and provide the information in an easy-to-use format, and 2) format that information into valid XHTML.
Create the Class
First we need to set up our object and store the feed URL in a variable. We'll do this with a class variable and a constructor function. A constructor is an object-specific method in PHP5 that allows for commands to be executed at the instantiation of a new object. In our case, we want to be able to create a new FlickrScrollr class with the syntax:
$obj = new FlickrScrollr('http://api.flickr.com/your_feed_url');
However, we also want to allow for the $feed variable to be directly set, like so:
$obj = new FlickrScrollr();
$obj->feed = 'http://api.flickr.com/your_feed_url';
By setting the default for $feed to NULL by default, our class doesn't break down if the feed isn't passed on instantiation. Here's what the __construct() function looks like:
class FlickrScrollr
{
public $feed;
function __construct($feed=NULL)
{
$this->feed = $feed;
}
}
Parse the Feed
Now we're ready to actually parse the feed. To do this, we're going to create a protected method called parse(). This will break the RSS feed into just the pieces we need, and return that information in an easy-to-use array:
protected function parse()
{
$rss = simplexml_load_file($this->feed);
foreach ($rss->channel->item as $item) {
$link = $item->link;
$title = $item->title;
$media = $item->children('http://search.yahoo.com/mrss/');
$thumb = $media->thumbnail->attributes();
$thumbSRC = $thumb['url'];
$width = $thumb['width'];
$height = $thumb['height'];
$imgSRC = str_replace('_s', '', $thumbSRC);
$photos[] = array($link, $title, $thumbSRC, $imgSRC, $width, $height);
}
return $photos;
}
So, let's take this in baby steps. First, we load the RSS feed using SimpleXML. This puts all of the information in the feed into one variable, $rss. We then pass that variable to a foreach loop, but we drill a little deeper into the variable to extract each photo. The way SimpleXML works, you can move through the XML in a very intuitive fashion: simply connect the dots to get to the information you want!
Passing $rss->channel->item as $item effectively chunks the RSS feed into individual entries. In the case of our Flickr feed, each photo is contained between <item> tags (this is a standard in RSS feeds).
Once the photos have been separated, we just continue drilling to access the photo's URL and title:
$link = $item->link;
$title = $item->title;
Ah, but wait! There's some tomfoolery going on with our thumbnail that takes a little further explanation. What's with the <:media:thumbnail ... />?
The "media:thumbnail" is an example of an XML concept called "namespaces"—essentially, a namespace in XML is a way to guarantee that an XML value is unique. If you look toward the top of the RSS feed, you'll see this line:
<rss version="2.0"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:flickr="urn:flickr:" >
In effect, xmlns:media="http://search.yahoo.com/mrss/" is creating an alias for any XML tag started with media:—every tag will be replaced with the URL, which guarantees that the tag is unique, no matter what other XML file it may be combined with.
What that means to us, as developers, is that we need to access the namespace in order to use the information it stores. Fortunately, this is supported by SimpleXML. To access the media: namespace, we use the following snippet of code:
$media = $item->children('http://search.yahoo.com/mrss/');
Now all the XML tags containing the media: namespace will be stored in the $media variable, in the same way the whole feed was stored in $rss. Now we access the thumbnail, but we have to use the attributes call, since the information is stored as an attribute in the tag, rather than as a value (i.e. <tag>value</tag>).
$thumb = $media->thumbnail->attributes();
$thumbSRC = $thumb['url'];
$width = $thumb['width'];
$height = $thumb['height'];
Finally, we need to get the URL of the medium-size image Flickr creates. Strangely, this is the only URL that isn't included in the feed, so we'll have to employ a little creativity to get it. The way Flickr names their images, they append a size identifier to the end of the image number (i.e. "_s" for square, or thumbnail, "_o" for original size, etc.). The medium-size image is the default, so nothing is appended. Therefore, to get to it, we can just pop the "_s" off our thumbnail URL, like so:
$imgSRC = str_replace('_s', '', $thumbSRC);
Finally, we just return all the information we've grabbed into a multi-dimensional array.
Extract the User ID
The next method, getUserId() is a little tricky, as we're using a regular expression. What we're attempting to do is to extract the user ID out of the feed URL to allow us to link directly to the user's photostream. Originally, I had simply used a series of str_replace() functions, but it was pointed out by Will that not all Flickr RSS feeds are formatted the same, meaning some feeds wouldn't match the strings I'd defined, leaving room for errors and/or bad links.
A regular expression allows for pattern matching, rather than specific string matching, which is both very useful and a little intimidating. Consider our pattern:
$pattern = "/^(.*id=)([A-Za-z0-9@]{1,})(&.*)$/";
I won't go into the fine details of regex here (that's an entire blog post/series in and of itself), but what we're essentially saying in this pattern is, "From the beginning of the supplied string, match everything up until you find the characters 'id=', then match one or more letters (both upper- and lowercase) or digits until the string meets an ampersand (&), then grab everything up until the end of the string."
Each piece of the pattern enclosed within parentheses (i.e. "(.*id-)") will be stored in a special variable, which is simply a sequentially numbered PHP variable (i.e. $1, $2, $3, etc.). We can use these special variables to reformat the matched elements as we see fit. For our purposes, we just want to pull the second match (the information between 'id=' and the next ampersand), since that's our user ID. We then pass this pattern and replacement, along with the feed URL, to preg_replace(), which looks like this:
$replacement = '$2';
return preg_replace($pattern, $replacement, $this->feed);
With our user ID now stored in a variable, we're ready to build our markup!
Put Together the XHTML Markup
Our next method is going to be a public one called display():
public function display()
{
$thumbs = NULL;
$pics = $this->parse();
$user = $this->getUserId();
foreach($pics as $pic) {
$thumbs .= <<<THUMBNAIL_DISPLAY
<li>
<a href="{$pic[3]}" title="<a href="{$pic[0]}">{$pic[1]}</a>">
<img src="{$pic[2]}" alt="{$pic[1]}" />
</a>
</li>
THUMBNAIL_DISPLAY;
}
$display = <<<FLICKR_DISPLAY
<div id="flickrscrollr">
<div id="fs_wrapper">
<ul>$thumbs
</ul>
</div>
<a href="http://flickr.com/photos/$user/" class="fs_morelink">View All Photos</a>
</div>
FLICKR_DISPLAY;
return $display;
}
Our first step is to declare an empty variable that will hold the thumbnails as we step through the array returned by parse(), which is our next step. We load the return value of parse() into a variable we'll name $pics, and load the user ID extracted by getUserId() into a variable called $user
Next we initiate a loop to cycle through our array of photos and build list items, using the array index of each piece of information returned by parse() to place the necessary information into the markup.
foreach($pics as $pic) {
$thumbs .= <<<THUMBNAIL_DISPLAY
<li>
<a href="{$pic[3]}" title="<a href="{$pic[0]}">{$pic[1]}</a>">
<img src="{$pic[2]}" alt="{$pic[1]}" />
</a>
</li>
THUMBNAIL_DISPLAY;
}
After cycling through all of the photos, we place the markup into a wrapper, leaving it ready for display:
$display = <<<FLICKR_DISPLAY
<div id="flickrscrollr">
<div id="fs_wrapper">
<ul>$thumbs
</ul>
</div>
<a href="http://flickr.com/photos/$user/" class="fs_morelink">View All Photos</a>
</div>
FLICKR_DISPLAY;
return $display;
Finishing Touches
Finally, we use the magic method __toString() to allow us to output the contents of display() simply by echoing the FlickrScrollr object:
public function __toString()
{
return $this->display();
}
This step is a precaution against errors caused by trying to echo an object without a __toString() method declared. If this method is omitted, attempting to echo the object (i.e. echo $flickrscrollr;) would cause a fatal error.
Conclusion
The jQuery plugin is going to be examined in the next installment, which I'm hoping to post very soon. Please leave any issues or suggestions for the PHP class in the comments below.
Comments for This Entry
Your home-baked captcha thinks I'm a robot.
Thanks for the tutorial. Everything works great!
Very nice explanation, thanks.
This is one hell of a plugin Jason, probably one of the best FlickrScroller I've ever come across, I like the way you packaged the whole thing, plus this page of yours, I think it's probably going to double up you're download numbers.
Cheers~
http://www.shahin.co.nr/featuring-ennui-design-and-a-great-scrolling-flickr-gallery/
@i am web designing:
Thanks for the write-up! Much appreciated!
Looks amazing! Can't wait to try this out. You have gained a new subscriber. Thanks for these great/useful posts.
Thanks again Jason for all the help and for putting up with my complete ignorance of php!
Im really struggling to customise the thumbnail size, any chance you could give me a brief explanation?
Im not much of a programmer and i dont understand about passing arguments as you suggest, although im sure i would pick it up pretty quickly.
Great plugin, good work
Thanks
@David:
Actually, I didn't supply a method to change the size of the thumbnails. When I put together the 2.0 release of this, I'll add in that functionality.
The quick-and-dirty fix is to find the display function in FlickrScrollr.inc.php and edit this section of the code:
foreach($pics as $pic) {
$thumbs .= <<
{$pic[1]}">
THUMBNAIL_DISPLAY;
}
Add a style attribute to the
Then add the new size plus 1 to the plugin call:
$('#flickrscrollr').FlickrScrollr({
thumbWidth:51
});
Let me know if that works for you!
Hey, thanks for the code. I downloaded your source and threw it up on my site (dhechler.com/flickr) but its not working. it seems the
ok, so now its just not displaying the pictures. everything else works, help again?
@david hechler:
I'm not sure what's going on in your code, but it would appear that no photos are loading, though no error is being reported.
You're on PHP5 and your error reporting is set to E_ALL? That'll make a difference. :)
Email me if you're still having problems!
Jason, Thanks again for an amazing piece of work. I love seeing how your going to push the bar again..
Great plugin!
Does anyone know how this could be updated to scroll vertically. I'm sure it wouldn't be too hard; I'm just not that great with jQuery.
Cheers,
Josh
Hello, if you wanted to implement this into a WordPress blog how would you do it? When I cited the script directly and used your markup the script throws errors. Any thoughts? Thanks in advance.
Post a Comment
Want to show your face? Get a gravatar!