19 JS Toggle Boxes

Posted: Jul 25, 2005, under WordPress, DHTML. Updated: Oct 5, 2006. Add a comment!

This post is about the JS Toggle Boxes plugin for WordPress.

Note: It works equally well in v1.5.x and v2.x. I haven’t tested it on older versions and I have no idea whether it would work.

1. Overview

1.1. Description

Here’s a plugin that helps to reduce clutter by placing on/off JavaScript toggle links on the page elements of your choice. What this means is that you can pick any elements on your blog pages (such as the categories list, or the comment form) and let the visitor choose which and how many they’d like to see at the same time.

Of course, visitors need JavaScript activated for it to work, but statistics say up to 99% of visitors do. The plugin is also non-JavaScript friendly and allows you to revert to safe defaults so your visitors don’t miss a thing.

Even better, this plugin makes use of cookies so that each visitor’s choices are remembered automatically for as long as they keep using those cookies.

1.2. Distribution terms

This plugin can be freely distributed, modified and used under the terms of the MIT License.

1.3. Live demo

There are examples all over this blog. Look at the sidebar for instance, I’ve placed many bits inside toggle boxes. You can click on the toggle markers to show/hide the boxes. Notice how as you move from one page to another (or reload) the preferences are remembered.

1.4. Contact

Either add a comment to this post, or email me at skippy zuavra net.

1.5. Additional credits

2. Get the plugin

  1. Current version is 1.4.
  2. Grab the plugin here: js_toggle_boxes.txt.
  3. Right-click on the above link, download it as js_toggle_boxes.php.
  4. Upload it to the wp-content/plugins/ directory under your WP installation.
  5. Go to your WP administration panel, under “Plugins”, look it up in the list and Activate it.

3. Using the plugin

3.1. Set your preferences (optional)

Should you need to set your preferences, you will do so by editing the plugin file. The options are after the credits and license. Changing the options is entirely options, since the defaults should work well for most people. These preferences apply to version 1.1+. Always get the latest!

  • JSTB_CSS_SHOWN_CLASS, JSTB_CSS_HIDDEN_CLASS: These define the CSS class names that will be used to apply the show/hide property. You will probably not need to change these two; the defaults will most likely not clash with other class names. If you change the class names make sure to remember them, you will need them later.
  • JSTB_COOKIE_LIFETIME: The cookie lifetime, in days. Best left at the 365 day default. You want persistent cookies for this plugin to make sense and if they’re persistent you might as well go for a long lifetime. Set to 0 (zero) to obtain session cookies (that die when the user close the browser and are kept in RAM, never on disk).Please note that some browsers are rumored to enforce a maximum cookie lifetime of 90 days. Plus, naturally, the users may override cookie handling using their browser preferences.
  • JSTB_OVERLOAD_CSS_CLASSES: This tells the plugin whether to output CSS that will overload the two classes named above with the “block” and “none” display properties, respectivelly. Leaving it set to true is highly recommended. If you don’t, I’m assuming you know what you’re doing.
  • JSTB_SEPARATE_SCRIPT: If you set this to true, the JavaScript code will be offloaded at a separate URL, thus enabling browsers to cache it. If you enable this, make sure you can load the plugin file directly in your browser. People often protect their wp-content/ directory with a htaccess file saying “Deny from all”. That’s a very good thing, but if you do that please add the following, so the interdiction doesn’t apply to this plugin:
    <Files ~ "^js_toggle_boxes.php">
       Allow from all
    </Files>

3.2. Initialization

Important: You must call the PHP function JSTB_box_js() somewhere in a central place in your theme. This function will output crucial JavaScript code needed for the entire setup to work. The best place to do this is header.php, inside the <head>...</head> section, like this:

<head>
. . .
<?php if (function_exists('JSTB_box_js')) JSTB_box_js(); ?>
</head>

3.3. Image preloading (optional)

It is possible to use two images instead of the link you need to click to toggle.

Note: This functionality is available only starting with version 1.3 of this plugin.

  1. Choose two images. They should be relatively small (10-16 pixels) and equal in size to each other. Make sure that people can easily tell what they do; the best idea is probably to make one of the images some kind of “plus” sign and the other a “minus” sign.
  2. Upload the images somewhere on your webserver. You can put them anywhere, just make sure you can see them in the browser, and remember to write down the location.
  3. Preload the images. This means telling the plugin that later you’re gonna want to use that image pair for toggle links. Choose a certain file in your WP theme (header.php is a very good place, preferrably after the initialization code described above) and add the following:
    <?= function_exists('JSTB_load_image') ?
    JSTB_load_image('image_pair_name',
    get_bloginfo('stylesheet_directory').'/images/toggle_minus.gif',
    get_bloginfo('stylesheet_directory').'/images/toggle_plus.gif'
    ) :''; ?>
    Tip: Using get_bloginfo() to supply the first part of the image location is a good idea, because it means you don’t have to modify this should your blog address ever change.

Note the image_pair_name name, which is the name you’ll be using to refer to this image pair. Use any name you want, but remember it for later.

Usually you only need to preload an image pair once, and you can reuse its name wherever you have a JSTB_box_toggle() call. The only case you need to preload more than once is if you’re actually using different images for different links. If that’s the case, preload all the pairs in one place, then use whichever name you want in the later calls.

3.4. Activation

Edit a theme script, such as comments.php or sidebar.php. You will have to go through the following steps for each box you want to apply this to.

  1. Pick a cookie name, an unique id and a default state (either hidden or shown). It’s strongly recommended to use the “shown” class as default. Always consider that JavaScript may be off in the visitor’s browser. In such a case you most likely want the non-JS default to allow the visitor to see the box.
  2. Locate a box that you want to toggle. List elements or DIV’s are the prime candidates for this. Grant it the unique ID and default class you’ve chosen.
    <li><h2>Categories</h2>
    <ul id="category_list" class="JSTB_shown">
    . . .
    </ul>
    </li>
    Tip: You only really need to include the class="" if you want the default state to be “hidden”. Otherwise, having no class declaration achieves the same effect as declaring it to be “shown”. Plus, if you ever decide to change the class names you don’t have to worry about replacing them in so many places.
  3. Pick a spot for the toggle link. In the case above an obvious spot would be right after the “Categories” word. The plugin conveniently provides a PHP function which will output the adequate JavaScript code for you. You should obtain this:
    <li><h2>Categories <?=function_exists('JSTB_box_toggle')? JSTB_box_toggle('[+/-]', 'toggle', 'Click to toggle', 'cookie_category', 'category_list') :''?></h2>
    <ul id="category_list" class="JSTB_shown">
    . . .
    </ul>
    </li>
    Parameters: in order, you must pass to the function:
    1. The link text (the one you will click on). ([+/-] in the example above)
      Tip: If you want to use an image pair instead of a text link then use image:image_pair_name for this parameter. Remember to preload the image pair first!
    2. A class attribute value for the link (optional; pass an empty string to omit). (toggle)
    3. A title attribute value for the link (optional; pass an empty string to omit). (Click to toggle)
    4. The cookie name. (cookie_category)
    5. The id of the target box. (category_list)

  4. Finally, you must output some code that will read the cookie and enforce the current preferences upon the box. This is achieved also through a PHP function. After you add it you should have the following:
    <li><h2>Categories <?=function_exists('JSTB_box_toggle')? JSTB_box_toggle('[+/-]', 'toggle', 'Click to toggle', 'cookie_category', 'category_list') :''?></h2>
    <ul id="category_list" class="JSTB_shown">
    . . .
    </ul>
    <?=function_exists('JSTB_box_init')? JSTB_box_init('cookie_category', 'JSTB_shown', 'category_list') :''?>
    </li>

    Parameters: in order, you must pass to the function:

    1. The cookie name. (cookie_category)
    2. The default fallback class in case the cookie isn’t available (shown class is recommended). (JSTB_shown)
    3. The id of the target box. (category_list)

    You must call JSTB_box_init() after the target box has been declared. See the example. You cannot apply JavaScript to an element which doesn’t exist yet, so you need to first make sure the box was fully created.

That’s it, now you can upload back the script and you will see the effects.

4. Neat tricks

4.1. The alternate switch

Besides using the plugin as an on/off switch you can also use it to display 2 alternate boxes! Take a look at my calendar on the sidebar. You will notice that when the month list dissapears a calendar appears instead, and the other way around.The trick is simple:

  • First of all, make sure to place the alternate boxes one right after another.
  • Both JSTB_box_toggle() and JSTB_box_init() accept an extra parameter which contains a 2nd box id.
  • You will have to add a class="JSTB_hidden" declaration to one of the alternative boxes.
  • Make sure you mention the two id’s in the same order in both JSTB_ function calls.

Here’s an example:

<li><h2>Categories <?=function_exists('JSTB_box_toggle')? JSTB_box_toggle('[+/-]', 'toggle', 'Click to toggle', 'cookie_calendar', 'calendar' ,'months') :''?></h2>
<div id="calendar">
. . .
</div>
<ul id="months" class="JSTB_hidden">
. . .
</ul>
<?=function_exists('JSTB_box_init')? JSTB_box_init('cookie_calendar', 'JSTB_shown', 'calendar', 'months') :''?>
</li>

4.2. Remembering user preferences

If you know JavaScript and/or CSS, you can use the JS functions created by this plugin and devise your own features. The plugin provides general purpose cookie handling functions (read, write and delete) as well as a JavaScript htmlspecialchars() equivalent. You can use these, for instance, to remember the search string that the visitor used most recently.

5. Development and support

I’m usually very busy so I won’t provide any support for individual installations, sorry. Leave a comment or drop me an email at probablyme zuavra net and maybe I’ll get back to you. I’d also appreciate a heads up if you find bugs or ways to improve the script.

5.1. Known issues

5.1.1. The sidebar links

In order to work, JSTB needs you to grant unique identificators to HTML blocks, using the id attribute. Some WP functions will insist on generating HTML blocks all by themselves, and they don’t have a parameter for the id attribute either. Such cases are a problem for JSTB.

5.1.1.1. wp_list_pages

wp_get_pages() is such a case. Fortunately, there’s a rather simple workaround: add title_li= to the parameter string. That’s right, without a value. This tells it to NOT generate an <ul></ul> tag pair to enclose the list in.

Of course, you still need to put it in, by hand. But in doing so you are able to add the id attribute. Problem solved. Here’s the example:

<p><strong>Important</strong> <?=function_exists('JSTB_box_toggle')?JSTB_box_toggle('[+/-]','toggle','Click to toggle','jstb_info','jstb_info'):''?></p>
<ul id="jstb_info">
<?=wp_list_pages('title_li=&sort_column=menu_order&echo=0', true)?>
</ul>
<?=function_exists('JSTB_box_init')?JSTB_box_init('jstb_info','JSTB_shown','jstb_info'):''?>

Note how the call to wp_list_pages() is enclosed in a hand-crafted <ul></ul> pair.

5.1.1.2. wp_get_links or get_links_list

This ones are bit trickier, because they don’t even have the kinds of parameters that wp_list_pages() does. You can’t tell them to let you provide the enclosing block yourself. You can’t tell them an id to be added to the main block or to each link category. You’re stuck.

There are some workarounds but be warned, they’re ugly and complicated:

  • Hack wp-includes/template-functions-post.php and modify wp_list_pages() to accept a parameter that will grant the <ul> an id. Not exactly pretty, because you lose the modifications when you upgrade.
  • Enclose the calls in <li><h2>Title</h2><ul><?php wp_get_links();?></ul></li>, and use the extra <ul> and <h2> to inject the things the plugin needs. This will turn out fairly OK for lists (see my sidebar) but you’ll have a bit of a trouble styling everything to look nice.
  • Look at The WP Codex for a little bit of magic PHP code that will expose the <ul> so you can add what this plugin needs. Here it is again, modified accordingly:
    
    <ul>
     <?php
     $link_cats = $wpdb->get_results("SELECT cat_id, cat_name FROM $wpdb->linkcategories");
     foreach ($link_cats as $link_cat) {
      $cat_id = $link_cat->cat_id;
     ?>
      <li id="linkcat-<?=$cat_id?>">
       <h2><?=$link_cat->cat_name;?></h2>
       <?=function_exists('JSTB_box_toggle')? JSTB_box_toggle('[+/-]', 'toggle', 'Click to toggle', 'cookie_link_'.$cat_id, 'link_list_'.$cat_id) :''?>
       <ul id="link_list_<?=$cat_id?>">
        <?php wp_get_links($link_cat->cat_id); ?>
       </ul>
       <?=function_exists('JSTB_box_init')? JSTB_box_init('cookie_link_'.$cat_id, 'JSTB_shown', 'link_list_'.$cat_id) :''?>
      </li>
     <?php } ?>
    </ul>
    

5.2. To-do list

  • I need some cross-browser (IE/Gecko) JavaScript code that can detect whether a CSS class has already been declared or not. This would allow me to declare the shown/hidden classes only if they haven’t already been defined.

6. Version history

  • 1.4 (Sep 12, 2006):
    • Breaks image-to-link dependency and allows same image to be reused by several toggle links.
  • 1.3 (Sep 10, 2006) (unreleased):
    • Added preliminary support for using images as toggle links.
  • 1.2 (Nov 29, 2005):
    • Changed homepage and download links, author name and contact, due to development takeover. License remains MIT.
  • 1.1 (Sep 10, 2005):
    • Optionally, offload the (rather large) JavaScript code at a separate URL, thus enabling browsers to cache it. For maximum compatibility, the default setting implements the old behaviour.
    • More, better organized preferences.
  • 1.0 (Jul 25, 2005):
    • First release.