FlickrScrollr Explained: PHP

The inner-workings of FlickrScrollr

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

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:

Flickr's RSS in the Location Bar

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

Flickr's RSS 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>&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/people/ennuidesign/&quot;&gt;jasonatennui&lt;/a&gt; posted a photo:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/ennuidesign/3023023846/&quot; title=&quot;Carly's Senior Photos 01&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3235/3023023846_5177ee8057_m.jpg&quot; width=&quot;160&quot; height=&quot;240&quot; alt=&quot;Carly's Senior Photos 01&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I took senior photos for my sister. These are my favorites.&lt;/p&gt;</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">&lt;p&gt;I took senior photos for my sister. These are my favorites.&lt;/p&gt;</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.

Posted Feb 28, 2009 by Jason Lengstorf.
This entry is filed under plugin, PHP, and FlickrScrollr.

Want more content like this? Subscribe for FREE!

Comments for This Entry

GravatarB. Ackles02:39AM on March 01, 2009

Your home-baked captcha thinks I'm a robot.

Thanks for the tutorial. Everything works great!

GravatarWill09:12AM on March 02, 2009

Very nice explanation, thanks.

Gravatari am web designing11:41PM on March 09, 2009

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~

Gravatari am web designing12:57AM on March 10, 2009

http://www.shahin.co.nr/featuring-ennui-design-and-a-great-scrolling-flickr-gallery/

GravatarJason Lengstorf11:50AM on March 10, 2009

@i am web designing:
Thanks for the write-up! Much appreciated!

GravatarAnthony01:00AM on March 15, 2009

Looks amazing! Can't wait to try this out. You have gained a new subscriber. Thanks for these great/useful posts.

GravatarAnthony03:58PM on March 23, 2009

Thanks again Jason for all the help and for putting up with my complete ignorance of php!

GravatarDavid07:10PM on April 12, 2009

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

GravatarJason Lengstorf07:38PM on April 12, 2009

@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]}">
    {$pic[1]}


  • THUMBNAIL_DISPLAY;
    }

    Add a style attribute to the tag and declare the new height and width you want to use:

    {$pic[1]}

    Then add the new size plus 1 to the plugin call:

    $('#flickrscrollr').FlickrScrollr({
    thumbWidth:51
    });


    Let me know if that works for you!

    Gravatardavid hechler07:32AM on April 15, 2009

    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

    Gravatardavid hechler08:07AM on April 15, 2009

    ok, so now its just not displaying the pictures. everything else works, help again?

    GravatarJason Lengstorf10:55AM on April 15, 2009

    @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!

    GravatarCasey Becking08:56AM on May 12, 2009

    Jason, Thanks again for an amazing piece of work. I love seeing how your going to push the bar again..

    GravatarJosh02:00PM on June 17, 2009

    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

    GravatarChris02:23PM on June 26, 2009

    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!

    ALLOWED TAGS: <tt><strong><em>