Video icon 64
Learn to Code. Start your free trial today.
Advertisement

Building a Better Blogroll: Dynamic Fun with SimplePie and jQuery

by
Student iconAre you a student? Get a yearly Tuts+ subscription for $45 →

A traditional blogroll is a simple list of other sites, often in the sidebar, that are related, owned by, or otherwise friendly to the home site. Blogrolls are a great idea and on-point with the spirit of blogging, but how is a casual reader to know if any of these sites are truly of interest? Let's improve upon the concept of a blogroll by not just listing sites, but dynamically pulling recent headlines from them, and using some fun jQuery animation.

Step 1 - The Idea and the Technologies

For our example, we will be using the TUTS family of sites. The idea here is to build a "widget" (for lack of a better term). Along the top of our widget will be a line of logos from each of the different sites in our blogroll. The TUTS family have lovely simple block logos which will make this easy, but the concept could be adapted to any logo. Each of the logos will act as "tabs" or buttons which when clicked, will display recent headlines from the respective site. Here is quick overview of the technologies we will use

  • Of course we will be using XHTML/CSS to build and style the widget.
  • We will use jQuery and the Coda Slider plugin for the fun animation.
  • The recent headlines will be dynamically pulled using PHP and SimplePie.

Because of the use of PHP, you won't be able to download the source code, open it up on your local machine, and view the demo. You'll need to either run PHP on your local machine, or upload it to your own server to play with it.

Step 2 - Designing

Design first, code later. I find the results are always better this way. A little playing around in Photoshop and we have a simple-yet-modern design to work with:

step 1

Note the use of guides. Being as clean and accurate with your design work is just as valuable as being clean and accurate with your code! Note that the PSD files will be included in this demo.

I don't want to go into a ton of detail about how all the design work was done and how all the images were sliced out. Instead lets take a look at each one and I'll quickly explain.

body background Image for the background texture. Repeats across the entire body element.
tab Image for the PSDTUTS tab. Bottom half is for "on" position, top half is for "off" position.
tab Image for the VECTORTUTS tab. Bottom half is for "on" position, top half is for "off" position.
tab Image for the NETTUTS tab. Bottom half is for "on" position, top half is for "off" position.
tab Image for the AUDIOTUTS tab. Bottom half is for "on" position, top half is for "off" position.
tab Image for the "body" of the widget. This can repeat vertically so it can grow as tall as needed.
tab Image for the bottom of the widget.
tab Image for the "next" button, for moving ahead to the next tab.
tab Image for the "previous" button, for moving back to the previous tab.

Step 2 - Downloading the Files

Normally we might start by coding the XHTML/CSS we need for the widget first. That is usually the best way to go so you can ensure clean and semantic markup. However, for this example, I believe it will be easiest for us to download all the components we need to make this thing work, and then code around that. This is because the jQuery plugin "Coda Slider" we are using has a specific HTML structure it likes.

You'll need a home directory for this project, so go ahead and create a new folder. Then create an index.php file, a style.css file, and we'll need folders for images, inc, and js. More organization! Then download the following things:

  • Download the latest jQuery to your js folder and include in your head section.
  • Download the Coda Slider plugin and include the plugin file, as well as the easing and easing compatibility JavaScript files in your head section.
  • Download SimplePie. Put the simplepie.inc file in your inc folder. You don't need to include anything on the page for this just yet, we'll get into this later.

When you are through, the top of your index.php file should be like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

	<title>A Better Blogroll</title>

	<link rel="stylesheet" type="text/css" href="style.css" />

	<script src='js/jquery-1.2.6.min.js' type='text/javascript'></script>
	<script src="js/jquery-easing.1.2.js" type='text/javascript'></script>
	<script src="js/jquery-easing-compatibility.1.2.js" type='text/javascript'></script>
	<script src="js/coda-slider.1.1.1.js" type='text/javascript'></script>
</head>

Step 3 - The Markup

If you pop open the code for the demo that comes with the Coda Slider, you'll see there is quite a few "wrapping" DIVs going on. The whole slider is wrapped in one then all of the panels are wrapped in one, then each panel is wrapped and there is even an inner wrapper inside each panel. Looks a bit like "DIVitis" (The plague of amateur coders using way more DIVs than necessary). Fret not, however. While I can't argue that there is a lot of DIVs going on here, each of them serves a purpose unique to the slider and is necessary for its form and function. In fact, our unique design complicates things even more and requires the use of a few more DIVs here and there.

Here is the markup for the rest of the page, sans the actual content for each of the panels:

<body>
	
	<div id="blogSliderWrap">
		<div id="blogSlider">
			<div class="innerWrap">
				<div class="panelContainer">
					
					<div class="panel" title="PSDTUTS">
						<div class="wrapper">
	
							<!-- content for panel -->
	
						</div>
					</div>
	
					<div class="panel" title="NETTUTS">
						<div class="wrapper">
						
							<!-- content for panel -->
						
						</div>
					</div>
				
					<div class="panel" title="VECTORTUTS">
						<div class="wrapper">
						
							<!-- content for panel -->
						
						</div>
					</div>
				
					<div class="panel" title="AUDIOTUTS">
						<div class="wrapper">
						
							<!-- content for panel -->
						
						</div>
					</div>
				</div>
			</div>
		</div>
		
		<div id="push"></div>
	</div>

</body>

</html>

Notice how there is no markup for the list of logos at the top? That markup gets dynamically generated by the plugin based on how many panel it detects. It also gives each of the list items a unique class name. We will use these to apply the images we created. Pretty fancy eh? This makes it very easy to add and remove panels from this slider in the future. If you want a peak at the code it creates, you can use something like Firebug to view the source after it has been rendered:

step 3

Step 4 - The CSS

Now that we have the markup squared away, we can set about to styling. Again, rather than go through every single selector here, I'll just show you the entire CSS file and then below I'll go over some of the important points. There is also some commenting within the CSS you may find of interest.

	
/*
	GENERIC RESET & BASIC STRUCTURE
*/
* 									{ margin: 0; padding: 0; }
body 								{ font-family: Verdana, Arial, Helvetica, sans-serif;
						  		 	  background: url(images/body-bg.jpg); font-size: 11px; }
a 									{ /* remove the dotted outlines when clicking tabs */ 
						  		      outline: none; text-decoration: none; }
ul 									{ list-style: none; }


/*
	WIDGET STRUCTURE
*/
#blogSliderWrap 					{ width: 320px; margin: 50px auto;
									  background: url(images/widget-bottom-bg.jpg) 7px bottom no-repeat;
									  padding-bottom: 50px; position: relative; }
#blogSlider 						{ margin-left: 15px; padding: 25px 18px 0px 18px; width: 263px;
									  background: url(images/widget-middle-bg.jpg) center center repeat-y; }
.stripViewer 						{ position: relative; overflow: hidden; clear: both; }
.stripViewer .panelContainer 		{ position: relative; left: 0px; top: 0px; }
.stripViewer .panelContainer .panel { float: left; position: relative; width: 280px; }
.wrapper 							{ padding: 10px; }
.innerWrap 							{ width: 273px; overflow: hidden; }
#push 								{ height: 35px; }


/* 
	MAIN TABBED NAVIGATION
*/
.stripNav 							{ margin-left: 22px; position: relative; top: 18px; z-index: 99;
									  width: 285px; }
.stripNav ul li 					{ float: left; }

.stripNav li a 						{ /* Generic "CSS image replacement" */
									  display: block; height: 18px; text-indent: -9999px; }
/* The below class names are auto-generated by the JavaScript */
.stripNav li.tab1 a { background: url(images/tab-psdtuts.jpg) top center no-repeat; width: 63px; }
.stripNav li.tab2 a { background: url(images/tab-nettuts.jpg) top center no-repeat; width: 63px; }
.stripNav li.tab3 a { background: url(images/tab-vectortuts.jpg) top center no-repeat; width: 85px; }
.stripNav li.tab4 a { background: url(images/tab-audiotuts.jpg) top center no-repeat; width: 73px; }

.stripNav li a:hover, 
.stripNav li a:active, 
.stripNav li a:focus 				{ /* Restore focus styling that we removed when we removed outlines */
									  background-position: top center; }

/* It is neccessary to repeat the image paths here */
.stripNav li.tab1 a.current { background: url(images/tab-psdtuts.jpg) bottom center no-repeat; }
.stripNav li.tab2 a.current { background: url(images/tab-nettuts.jpg) bottom center no-repeat; }
.stripNav li.tab3 a.current { background: url(images/tab-vectortuts.jpg) bottom center no-repeat; }
.stripNav li.tab4 a.current { background: url(images/tab-audiotuts.jpg) bottom center no-repeat; }


/* 
	SUB NAVIGATION
*/
.stripNavL a, .stripNavR a 			{ display: block; position: absolute; width: 75px; 
							 		  height: 22px; text-indent: -9999px; }
.stripNavL a						{ bottom: 35px; left: 45px; background: url(images/previous.png); }
.stripNavR a 						{ bottom: 35px; right: 45px; background: url(images/next.png);
}


/* 
	HEADLINES STYLING 
*/
.panel ul 							{ width: 240px; }
.panel ul li a 						{ border-bottom: 1px solid #C1B599; color: #303030;
						  		  	  display: block; padding: 7px 10px; }
.panel ul li:last-child a 			{ /* Remove bottom border on last list item
	   							  	  Hooray for pseudo selectors! */
								  	  border: none; }
								  	  /* Unique rollover colors for each list */
.panel ul#psd-list li a:hover 		{ background: #b20202; color: white; }
.panel ul#net-list li a:hover 		{ background: #4a8c7f; color: white; }
.panel ul#vector-list li a:hover 	{ background: #1f5293; color: white; }
.panel ul#audio-list li a:hover 	{ background: #4f7c11; color: white; }
  • The outer-most wrap (#blogSliderWrap) contains the background image for the bottom of the widget. Laying on top of that is the "expandable" part of widget, which contains the vertically-repeatable background image (#blogSlider)
  • In order to keep the content from appearing to "fly in" from outside of the main white area, yet another wrap was needed (.innerWrap) that slims the inside down even further to prevent that. This is unique to our super-cool drop shadowed design.
  • As I mentioned earlier, the markup for the main navigation is generated on-the-fly by the JavaScript, but that doesn't mean we can't still style it with CSS. The style for (.stripNav) uses relative positioning to kick it over into place as well as ensure that it is on top of all over page elements.
  • We use the unique class names the JavaScript gives us to use basic CSS image replacement and apply our images to each tab. Note that shared attributes (like height) are applied generically while unique attributes (like width) are applied specifically.
  • The JavaScript also auto-generates two special page elements for moving ahead a single tab or moving backward a single tab. We apply images and positioning to these as well
  • Ultimately, each panel will contain and unordered list of headlines. We will give each of these a unique ID. For a bonus nice touch, each of them will have a rollover color that matches the logo color of the originating site.

Step 5 - Activating the Slider

Now with the images, markup, and CSS all in place, we can kick off the slider. Include the following JavaScript at the bottom of your head section.

<script type='text/javascript'>
	$(function () {
		$("#blogSlider").codaSlider();
	});
</script>

Now we have a perfectly functional slider, with nothing in it.

step 3

Step 6 - Pulling the Headlines with SimplePie

SimplePie is a PHP feed parser which makes it pretty darn easy to pull in RSS feeds and use the content as we wish. In our example, all we need are the headlines and links, but pulling the feed is always the same regardless of what you use.

At the very top of your index.php file, include the following PHP code:

<?php
	require_once('inc/simplepie.inc');
	$total_articles = 10;

	$psdtutsfeed = new SimplePie('http://feeds.feedburner.com/psdtuts');
	$psdtutsfeed->handle_content_type();
	for ($x = 0; $x < $psdtutsfeed->get_item_quantity($total_articles); $x  )
	{
		$psdtutsarticles[] = $psdtutsfeed->get_item($x);
	}
?>

This code will go out and get the RSS feed from the main PSDTUTS RSS feed (http://feeds.feedburner.com/psdtuts). Then we create an array of the 10 most recent headlines. Now down in our "panel" for PSDTUTS, we'll need to cycle through this array and echo out the linked headlines. Here is the new code for the PSDTUTS panel:

<div class="panel" title="PSDTUTS">
	<div class="wrapper">

		<ul id="psd-list">
			<?php
				foreach ($psdtutsarticles as $item)
				{
					echo '<li><a href="' . $item->get_link() . '">' . $item->get_title() . '</a></li>';
				}
			?>
		</ul>

	</div>
</div>

You can guess where we need to go from here... We need to do the exact same thing for each of our four panels. No need to list all the code out here, as all we do is create new variables for each of the feeds, pull them in, and create new arrays for each of those feeds. Then we loop through each of those new arrays just like we did for PSDTUTS to echo out the linked headlines.

Notice how the unordered list we used for the PSDTUTS headlines had a unique ID of "psd-list". That isn't entirely necessary, but I have used that as a hook in this example to apply a different rollover color for each headline list.

Our widget is now nearly complete!

step 6

Step 7 - Fixing up IE

Despite being fully valid code, both IE6 and IE7 were showing some quirks with the background images. Oh well, our super-cool drop shadow isn't in any way necessary. We can leave it in place as "progressive enhancement" for folks with quality modern browsers and pull it out for IE, leaving just a simple white box.

Include an IE-Only Stylesheet in your head section like so:

<!--[if IE]>
	<link rel="stylesheet" type="text/css" href="style-ie.css" />
<![endif]-->

Then create the style-ie.css file in your home directory and include the following:

#blogSliderWrap {
	background: white;
	width: 285px;
	position: relative;
	overflow: hidden;
}

#blogSlider {
	background: white;
	width: 285px;
	padding: 0;
	margin: 0;
}

.stripNav {
	margin: 0;
	top: 0px;
}

Now everything is A-OK in Internet Explorer. The background is simply just white:

step 6

So there you have it, a better blogroll for all! Clearly, the technologies presented here can be used for all kinds of interesting things beyond a simple blogroll. The slider is a fantastic plugin that could used for a photo gallery, a portfolio, step-by-step instructions, or any number of applications. The ability to pull in RSS feeds to use on web pages is also very powerful (and potentially abuse-able). See the SimplePie documentation for all you can do with it, and remember to use it for the powers of good!

Advertisement