Creating WordPress Shortcodes for jQuery Tools Tabs

Example Tabs Shortcode Output

The following code is my solution for creating a set of WordPress shortcodes to generate the HTML needed to reproduce the minimal setup for tabs using the jQuery Tools library.

The Problem

I wanted my client to be able to create a set of jQuery Tools tabs using the following shortcodes:

[tab title="Tab 1"]Tab 1 content goes here.[/tab]
[tab title="Tab 2"]Tab 2 content goes here.[/tab]
[tab title="Tab 3"]Tab 3 content goes here.[/tab]

In the above scenario, I need my [tab] shortcode to process each tab sending the tab title and content back to my [tabgroup] shortcode function. Then, my [tabgroup] function needs to output the following HTML:

<!-- the tabs -->
<ul class="tabs">
<li><a href="#">Tab 1</a></li>
<li><a href="#">Tab 2</a></li>
<li><a href="#">Tab 3</a></li>
<!-- tab "panes" -->
<div class="panes">
<div>First tab content. Tab contents are called "panes"</div>
<div>Second tab content</div>
<div>Third tab content</div>

The Solution

In order to produce the above HTML, I choose to store the output of my [tab] shortcode function in a global variable. Then, once the recursion is finished in the [tab] function, I process that global variable in the [tabgroup] function and return the output.

Here’s the code to make that happen:

* jQuery Tools - Tabs shortcode
add_shortcode( 'tabgroup', 'jqtools_tab_group' );
function jqtools_tab_group( $atts, $content ){
$GLOBALS['tab_count'] = 0;

do_shortcode( $content );

if( is_array( $GLOBALS['tabs'] ) ){
foreach( $GLOBALS['tabs'] as $tab ){
$tabs[] = '<li><a class="" href="#">'.$tab['title'].'</a></li>';
$panes[] = '<div class="pane"><h3>'.$tab['title'].'</h3>'.$tab['content'].'</div>';
$return = "\n".'<!-- the tabs --><ul class="tabs">'.implode( "\n", $tabs ).'</ul>'."\n".'<!-- tab "panes" --><div class="panes">'.implode( "\n", $panes ).'</div>'."\n";
return $return;

add_shortcode( 'tab', 'jqtools_tab' );
function jqtools_tab( $atts, $content ){
'title' => 'Tab %d'
), $atts));

$x = $GLOBALS['tab_count'];
$GLOBALS['tabs'][$x] = array( 'title' => sprintf( $title, $GLOBALS['tab_count'] ), 'content' =>  $content );


I hope this solution helps some of you guys out there. In addition, if you see any way to refine my code, please let me know in the comments.

NOTE: For information on setting up the JavaScript and CSS to power and style the above tabs, please see the jQuery Tools Minimal Setup for Tabs.


  1. Just what I was looking for! Excellent tutorial, worked like a charm! Thanks for that :-)

  2. Ricky Lee says:

    Working beautifully but I need to embed a third level shortcode and can’t figure out how to position do_shortcode($content) for the tab content

    Check out the Storage Tab.


  3. Joe Negron says:

    Very clean! Forgive me if this is an obvious question, but where do I put your snip-it? shortcodes.php? or into the theme-files?

  4. That’s what I ended up doing, but I wasn’t sure if you could somehow make it global across all themes… But I was able to get it going on a test page. Thanks for the quick response and again for publishing your tweak. Very VERY Clean!

  5. Nice, i just wonder that href=”#” is bit stupid, must better would be something like

    <!-- the tabs -->

    <a href="#title-1" rel="nofollow">Tab 1</>
    <a href="#title-2" rel="nofollow">Tab 2</a>
    <a href="#title-3" rel="nofollow">Tab 3</a>

    <!-- tab "panes" -->

    First tab content. Tab contents are called "panes"
    Second tab content
    Third tab content

  6. Bill Bliss says:

    I wanted to wire up support for browser history using the support in jQuery Tools, but it required a few changes to the code in my last comment.

    I didn’t like the look of automatically generated anchor tags though, e.g. “#pane-tab-1″, “#pane-tab-2″ etc. so I added a “anchor” attribute to the [tab] shortcode.

    Now the syntax is:

    [tab title="Title Text" anchor="anchor-label"]

    (Do not include the # in anchor-label.)

    For example, the shortcode:

    [tag title="About" anchor="about"]

    will generate HTML that looks like this:

    <a href="#about" rel="nofollow">Pane contents</a>

    Here is the modified code:

    // WordPress shortcodes for jQuery Tools tabs/panes
    function genShortcode_tabgroup( $atts, $content ){
    $GLOBALS['tab_count'] = 0;

    do_shortcode( $content );

    if( is_array( $GLOBALS['tabs'] ) ){
    foreach( $GLOBALS['tabs'] as $tabNum =&gt; $tab ){
    $tabs[] = '<a href="#' . $tab['anchor'] . '" rel="nofollow">' . $tab['title'] . '</a>';
    $panes[] = '' . $tab['content'] . '';
    $return = "\n" . '<!-- Begin jQuery Tools tabs -->' .
    '' . implode( "\n", $tabs ) . '' .
    "\n" . '<!-- tab "panes" -->' . implode( "\n", $panes) .'' .
    "\n" . '<!-- End jQuery Tools tabs -->';
    return $return;

    function genShortcode_tab( $atts, $content ){
    extract(shortcode_atts(array('title' =&gt; 'Tab %d', 'anchor' =&gt; 'pane-tab-%d'), $atts));

    $curTab = $GLOBALS['tab_count'];
    $GLOBALS['tabs'][$curTab] = array( 'title' =&gt; sprintf( $title, $curTab ), 'anchor' =&gt; sprintf( $anchor, $curTab ), 'content' =&gt; $content );


    add_shortcode( 'tabgroup', 'genShortcode_tabgroup' );
    add_shortcode( 'tab', 'genShortcode_tab' );

    // Thesis hook to call jQuery Tools and other page initialization
    function prepPage(){ ?&gt;

    // Set up ul.pane-tabs (jQuery Tools Tabs)
    $(function() {
    $("ul.pane-tabs").tabs("div.panes &gt; div", { history: true });

    &lt;?php }

    add_action('thesis_hook_after_content_area', 'prepPage');

    // End WordPress shortcodees for jQuery Tools tabs/panes

    • Bill Bliss says:

      Michael, looks like the commenting system interpreted HTML inside my


      block as valid HTML, hopefully you can still make sense of it.

  7. Excellent write up, thanks for sharing. I did want to point out one thing in case anyone else has been experiencing the same quirk. The in-line HTML comments in the following line of code have an affect on how WordPress renders the final HTML:

    $return = "\n".''.implode( "\n", $tabs ).''."\n".''.implode( "\n", $panes ).''."\n";

    That will produce a couple unwanted paragraph tags which screw up spacing above the tab panes:

    Tab 1
    Tab 2
    Tab 3

    Note the unclosed p tags right before each comment. Not sure why WordPress does this, but if you’re having this problem, just remove the comments from the line of code so it looks like this:

    $return = "\n".''.implode( "\n", $tabs ).''."\n".''.implode( "\n", $panes ).''."\n";

    Thanks again for the great write up!

  8. Hi Michael,

    Thanks for the post – very useful indeed! I have a further question that perhaps you can shed some light on – Is there a way to correctly use shortcodes from within jquery tools?

    For instance, I am using jquery tools to invoke an overlay, which ideally will have a contact form in it using Contact Form 7 and it’s shortcode. If I use [contact-form 1 "Contact form 1"] within a page or post, the contact form is correctly displayed, however if I use that shorcode within a parent div that resides within the overlay, “[contact-form 1 "Contact form 1"]” is rendered on the screen, and not the form the shortcode relates to.

    Have you managed to get shortcodes working from within jquery tools overlays please?


    • David,

      It sounds like you are confused between server-side processing and client-side processing. jQuery is a JavaScript tool which is thereby processed client-side. Any client side processing will not handle WordPress shortcodes. In order to do what you are asking, you need to write some code which processes your output server-side prior to displaying in the browser via your jQuery overlay.

      This type of coding is fairly complex as it requires a full understanding of both server-side and client-side techniques. At some point I may write a tutorial that deals with this concept; however, at this point, I don’t have the time. Perhaps my comments so far have given you a clue as to how you need to go about this.

  9. Hi- excellent information. I was wondering if you could spell out how you are enqueing the script? I’m having a bit of trouble getting wordpress to find (and execute) the jquery script. Thanks!

    • Mike,
      See if this helps:

      I’m enqueueing jQuery Tools and my theme’s CSS for the tabs via two function calls which look like the following (you’ll of course need to add some of your own CSS for the tabs – i.e. tabs.css as referenced below):

      wp_enqueue_script( 'jquery-tools', '', array( 'jquery' ), '1.2.5' );
      wp_enqueue_style( 'tabs', get_bloginfo( 'stylesheet_directory'). '/library/css/tabs.css' );

      In addition, I enqueue another script which initializes my tabs; however, as that script contains some other JavaScript not concerned with the tabs, I’m not including the enqueue here. Rather, you’d just need to include the following JavaScript in a file and add it to your theme via wp_enqueue_script():

      $("ul.tabs").tabs("div.panes > div");
  10. I think I got it working.
    Added the $ sign in the function, like so:

    $("ul.tabs").tabs("div.panes > div");


  11. Awesome writeup! :p
    helped me finish my first shortcodes based tabs-setup in WP.

  12. Excellent write up mate. Have been looking to add anchor links to tabs generated using code very similar to yours, so that they can be referenced using an external url. Seen something in the above comments that I’m yearning to try tonight. Will post back for some assistance (if needed) and comments. Excellent.

  13. I’m having a little bit of trouble modifying my current theme’s vertical tabs shortcode to allow anchors. See it below:

    // vtabs
    function kaya_shortcode_vtabs( $atts, $content = null ) {
    ), $atts));

    $out= '';
    foreach ($atts as $tab) {
    $out .= '<a href="#" rel="nofollow">' .$tab. '</a>';

    $out .= '';

    $out .= do_shortcode($content) .'';

    return $out;

    add_shortcode('vtabs', 'kaya_shortcode_vtabs');
    /*** VTAB PANES
    function vtabpanes( $atts, $content = null ) {
    ), $atts));

    $out= '' . do_shortcode($content) .'';

    return $out;
    add_shortcode('vtab', 'vtabpanes');

    Someone please help out here. I want to add anchoring so as to makes the tabs addressable via url.

  14. What about multiple tabs per page? ;)

  15. I have to say cool! started working on tabs shortcode, then, well, I couldn’t fins a solution for the parsing tabs links before the content.
    Thanks for sharing, keep up the great work.

  16. how can I give sliding effect for tab content?

  17. Thanks for this tutorial buddy. Keep it up.

  18. Awesome writeup! :p
    helped me finish my first shortcodes based tabs-setup in WP.

Leave a Reply