owen

Today is not the first day I’ve heard someone reference a web site and say, “Look at that cool shelf!”

What the heck are they talking about?

Maybe you’ve noticed it on my site, and maybe not because my design is purposefully inconspicuous. There is a small tab just under the masthead on the right side that says “More Stuff”. When you click on it, a large area slides open with a bunch of information on it. This is the “shelf”.

Personally, I’ve been calling this thing a “slidebar” (as opposed to a “sidebar”, no “L”), but I guess the Mac naming conventions apply somewhat. I first saw this type of thing on Shaun Inman’s site. But I’ve since seen it spread around to other sites, too.

Wanna learn how to make one and add some WordPress stuff to it? Let’s do it!

The first thing we need is some HTML into which we can build our shelf. Since I’m not privvy to your site design, I’m just going to assume that you have an area that is going to function as the “handle” of the shelf, like the tab on my site. You should also have the actual shelf contents.

You should already have these elements in your design, but not sliding open. Designing the site to look like how you like is up to you. Use CSS to make your design flexible. I haven’t tried doing the shelf with tables, but to persuade you against using tables I’ll tell you, “It doesn’t work,” even if I really haven’t tried it.

I suppose the key element is to orient the handle in such a way that when the shelf changes size it will push the handle down the page. This is important for a shelf that is at the top of the page. If you have a shelf at the bottom of the page, you need to make sure that your page scrolls down while your shelf expands. We’re not going to cover that in this tutorial.

You should have some code that contains a div for the shelf and a div for the handle. I have added a link in my code to use for the actual trigger inside the handle, but the code that causes the shelf to slide open is activated by a javascript event, so you could use nearly any tag, or even the whole handle div itself. I used an anchor tag because it has built-in UI cues - It changes the cursor to a hand when you move the mouse over it.

Something else to not about my code is that I’ve used width:100% on my divs which causes them to be fluid across the entire width of the page. If you’re using a fixed-width layout, this will still work - just put these divs inside your main fixed-width div.

Ok, let’s talk a little about javascript…

Yes all of the animatedness of these shelves is enabled by javascript.

Before you become intimidated and return to your plain static layout, I should reveal the big secret: Most of the complex javascript work is done for your already! By including a simple reference to a couple of javascript libraries, you can code your shelf with just a few lines of javascript code that tell the library which div to shelf-ify.

There are a few libraries to choose from for a task like this, but the choice for me essentially come down to choosing the library that would allow me as much flexibility in the future as possible. If I want to add other special effects to the site, I don’t want to be stuck with a shelf-only library. So I have chosen two.

The big dog of script libraries is Prototype. Prototype kicks so much butt, I fill with glee just thinking about it. Let me give just one relevant example showing why Protoype rules…

Normally when you’re writing javascript to affect your page elements, you need to address those elements to do something with them. Like, “Make the element with the ID ‘verdant’ have a green border.” Addressing elements by their ID is a very, very common practice in javascript - and the raw method that browsers provide to you for doing it is exhausting:

var verdant_element = document.getElementById('verdant');

This assigns a reference to the element with the ID ‘verdant’ to a variable in javascript called verdant_element. I can then use verdant_element to set properties of that element, like its border color:

verdant_element.style.border = '1px solid green';

If you have included the Prototype library in your page, you can do all of that like this:

$('verdant').style.border = '1px solid green';

Thank goodness for anything that saves typing, no? Ok, maybe I get excited about little things, but believe me, this stupid little $() function, along with some of the other functions that Prototype provides, have saved me hours and hours of coding. And it’s going to let you build a shelf, so you should like it too.

The other library I’m using is called moo.fx. moo.fx is one of many javascript effects libraries that extends the functionality of Prototype. There is another library called Scriptaculus that is pretty good, but I’m not using that one for two reasons: 1) It’s very slightly less simple. 2) My site uses moo.fx to do a couple of effects that Scriptaculus can’t do.

You’re welcome to try Scriptaculus if you want, but this tutorial isn’t going to cover its use.

Ok, so we’ve chosen Prototype and moo.fx. Download the script files from their respective sites, upload them to your server, and then add a reference to each them with the script tag inside the head tag:

<script type="text/javascript" src="http://example.com/js/prototype.js"></script>
<script type="text/javascript" src="http://example.com/js/moo.fx.js"></script>

You are eventually going to want to add these script lines into a WordPress theme. You need to be sure that the script files you are using are in the place that you’re referencing. The easiest way to be sure of that is to upload those scripts into the theme directory, and then use this javascript/PHP to create the correct references to the script files:

<script type="text/javascript" src="<?php bloginfo('stylesheet_directory'); ?>/prototype.js"></script>
<script type="text/javascript" src="<?php bloginfo('stylesheet_directory'); ?>/moo.fx.js"></script>

The PHP call to bloginfo() inside of those script tags ensures that the URL for the current theme directory is used as the location from which to pull the javascript libraries. Very handy!

Ok, the libraries are loaded, let’s make them do something…

In order to get our shelf to work, we’ll need to activate the javascript code that handles that operation. This is probably best done when the page first loads so that it’s ready to go immediately.

To execute some javascript code when the page first loads, we’re going to tap some Prototype code. Add this code into a script tag on your page:


<script type="text/javascript">Event.observe(window, 'load', initShelf, false);</script>

The Event.observe() function is telling the browser to execute a function called initShelf when the ‘load’ event of the window occurs. Basically, it calls initShelf() when the page first loads. So we’ll need an initShelf() function, which we’ll add to the script tag from above:


<script type="text/javascript">
Event.observe(window, 'load', initShelf, false);

function initShelf()
{
shelffx = new fx.Height("shelf", {duration: 300});
shelffx.hide();
}
</script>

There are two lines in initShelf(). The first line creates a new moo.fx Height effect called shelffx using the element with the ID of “shelf”. Remember that the div of our shelf has an ID of “shelf”. A moo.fx Height effect toggles whether an element is visible by expanding or contracting its height. Hey! That’s exactly what a shelf does!

The second line in initShelf() is important because it hides the shelf when the page loads. A place where it’s easy to get caught when coding these things is to use CSS’ display:none to make the shelf invisible when the page loads. The problem with that is that moo.fx (and other libraries) can’t determine how high the shelf should be when fully expanded. By using this method, we give the effects library a chance the measure the shelf before hiding it, and it happens so fast that 99.9% of the time, you don’t even realize that it happened.

If things have gone well, you should’nt see the shelf when you load the page, just the handle. In fact, my sample code does just that.

Let’s see if we can get that shelf to open…

Think about what we want to do. When someone clicks on the handle, we want to toggle the showing of the shelf. Let’s see if that language plays out in code.

First, find the handle in your html. In my sample code it’s an achor tag. Add a javascript onclick event handler to that tag:

<a href="#" onclick="shelffx.toggle();return false;">The handle</a>

The onclick handler executes its javascript whenever someone clicks on it. In our handler, we’re executing two separate cammands, as each command in javascript is separated by a semicolon. The first command, shelffx.toggle();, does all the hard work of the actual toggling of the shelf. Wasn’t that difficult?

The second command in the onclick handler is only necessary if your handle is also a link. When you click a link the browser usually navigates to the href specified in the link tag. Even though in this case it’s “#”, we don’t want the browser to move to the top of the page whenever someone clicks the shelf handle. So by executing return false; in the onclick handler, we tell the browser to stop processing of the click right there so that it doesn’t navigate to the bookmark. Simple.

If you’ve followed along, you’ll notice that we’re done. We have a working shelf. It’s not pretty, but you can apply CSS to all of those elements just like you would anything else.

If you make the shelf a solid color and then use a background image for the handle that transitions from the shelf color at the top to the background color of your page at the bottom, you’ll have a lovely-looking shelf. Apply a style to the link to make it look like a tab. I’ve even seen a shelf on a site that used a pull-string as the trigger, and when you moved the mouse over it, it animated!

All that’s fine, I suppose, but all we have here is a sample page. Let me give you some pointers on including a shelf in your WordPress design. There are some tricks here that you may want to know even if you don’t intend to install a shelf on your site.

Adding the shelf to your theme should be pretty simple.

It’s likely that your shelf code would best be placed in the header file. Add the two div tags for that content to your header.php, and also include the script tags in your head area. Make sure you use the bloginfo() calls so that the browser knows to look for Prototype and moo.fx in the theme directory.

Depending on how much work you’re going to do inside your shelf, you might want to make a separate file of it. Just create a new file (call it, say, shelf.php) and put the two div tags and their contents in it. The script tags will stay in header.php. Then in your header.php file, use a PHP include to output the shelf.php file. Such a thing would look like this:

<?php include "shelf.php"; ?>

The file that contains those divs will be executed and appear in that place in your page output.

And why build a shelf at all if you’re not going to put content in it? WordPress provides some methods for obtaining content that you can use for your shelf, but you have to be careful how you obtain and use it.

Since implementing the theme system, a feature of WordPress has been misplaced - Setting default categories or omitting a single category. So if you wanted to put your “Asides” category in the shelf, and omit those posts from your main loop, you would have a bit of a problem.

It seems that most people have solved this issue by unknowingly executing two post queries. WordPress executes the default post query before it even loads a theme file. Then in the theme file, a new set of query instructions is compiled and fed to the engine, and a new query is executed to overwrite the default one. Seems kind of inefficient. Fortunately, there is another way.

WordPress 2.0+ (you are using the latest version, aren’t you?) themes allow you to add a file called functions.php into your theme directory. This file behaves like a plugin, and can contain PHP functions that are available for your theme to use. WordPress loads this file if it is present in your theme directory, so you do not need to explicitly call it.

To modify the parameters of the main post query before the query is executed the first time, you can add some code to functions.php:


add_action('pre_get_posts', 'pre_get_posts');
function pre_get_posts(&$qs) {
if($qs->query_var['cat'] != '4') $qs->set('cat', '-4');
return $qs;

}

This code adds a function that gets called just before WordPress runs the query to request posts. The function, pre_get_posts() checks to see if the user requested category 4 directly, and if they didn’t, then it excludes posts from category 4 from the results.

Another issue you may have with running a shelf is when you query explicitly for the “Asides” category to display it separately in the shelf. Because the query for the shelf would presumably happen before the main Loop, the query that the shelf uses would overwrite the data that the Loop would normally use.

In that case, it’s useful to have some functions in functions.php that will cache the original $wp_query object, run the Asides query, and then restore the original $wp_query object from cache. The WP Codex talks about how to create multiple Loops on the page using a cache.

If you’re using PHP5 and implementing your query cache, you need to use the clone keyword to make a copy of the original query, otherwise the query is stored as a reference and gets overwritten when you thing the query has already been cached. If you use this code, you can create a version of the clone that works as a function and is compatible with PHP4:

<?php
if ((version_compare(phpversion(), '5.0') < 0) && !function_exists('clone')) {eval('function clone($object) {return $object;}');}
?>

You can then create a couple of functions for your functions.php that let you begin and end a context where your Asides are being displayed:

<?php
function begin_asides() {
global $queryswap, $wp_query;

$queryswap= clone($wp_query);<br>
query_posts('cat=4&amp;posts_per_page=3');<br>

}

function end_asides() {

global $queryswap, $wp_query;

$wp_query = $g2_queryswap;

}

?>

To use these functions, call begin_asides() before a copy of a regular Loop and end_asides() afterward, and that Loop will display only the last 3 posts from category 4, while leaving the main post Loop on the page intact. To be clear:

<?php begin_asides(); ?>
<?php if (have_posts()) : ?>
<?php while(have_posts()): the_post(); ?>

		&lt;li&gt;&lt;a href="&lt;?php the_permalink() ?&gt;" rel="bookmark"&gt;&lt;?php the_title(); ?&gt;&lt;/a&gt;&lt;/li&gt;<br>
	&lt;?php endwhile; ?&gt;<br>

<?php else: ?>

<?php _e(‘Sorry, there are no Asides at this time.’); ?>

<?php endif; ?>

<?php end_asides(); ?>

There are a bunch of functions available from plugins that can retrieve a list of the latest comments and upcoming events. Be careful when you use these that they they are able to be used before the Loop. Sometimes plugin developers assume that things that are normally initialized in the Loop have already been initialized because they expect you to insert their plugin code into the sidebar, which normally exeutes after the Loop. If you put one of these functions into your shelf and it doesn’t work, or it mangles the posts that appear in the main content area (this is actually very common), that might be the issue.

Alternatively, you could try what I have done on this site and output the shelf content at the end of the page, then use javascript to move it into the shelf div. This is a little more complicated, but it produces a pleasing result when the page is rendered without combinations of javascript or stylesheet.

Simply arrange for your shelf content to be output to a div named “hiddendiv” somewhere else on your page. You can use CSS to hide this content with #hiddendiv{display:none}. Then, change the code of your javascript initShelf() function to something like this:

function initShelf()
{
$('shelf').innerHTML = $('hiddendiv').innerHTML;
$('hiddendiv').innerHTML = '';
shelffx = new fx.Height("shelf", {duration: 300});
shelffx.hide();
}

That will move the content of hiddendiv into the shelf before the shelf is activated, and the content will appear at the top (or wherever the shelf div is located) instead of inside the hidden area.

I hope you have found this tutorial useful. If you have questions or remarks, please leave them in the comments!