Bootstrap Collapsible Shortcode Plugin

There are a bunch of these out there but the ones I knew of didn’t quite do what was needed by the Focused Inquiry faculty involved in this project.

They wanted a couple things to be possible.

  1. The ability to link to specific elements via URL and have them expand.
  2. The URL to those elements to remain consistent even if the order of the elements was changed.
  3. An “email this URL” link to enable faculty to send the URL to students
  4. Plus/Minus indicators based on expanded/collapsed.

Most shortcode plugins I’ve seen either don’t have an ID for the collapse element or make it sequential (which changes if you shift the order). Neither works well for a URL that needs to be consistent. I’ve never seen one to do the email element.

In my head, I made this way harder than it needed to be. It ends up being just two shortcodes- one for the collapsible container and one for the item-level elements.

I found this Bootstrap snippet that did most of the functional Bootstrap stuff that I needed.

I found a script to let me expand elements via URL parameters.

I reminded myself what a freaking mailto link structure looked like.

Now I just had to figure out what variables needed to be set in the shortcode and how the two needed to interact.

The shell (the part that holds the various collapsing divs) is pretty straight forward. The only variable I needed was the title. It gets echoed around a bit but it’s all the same variable.

This line do_shortcode($content) is what enables the subsequent shortcodes to run inside this shortcode. You call it [topic title=”whatever”] [/topic]

//basic shell construction
function bsc_topic( $atts, $content = null ) {    
    extract(shortcode_atts( array(
         'title' => '', //topic title should be unique
    ), $atts));
    $clean_title = strtolower(urlencode($title)); //cleansing the title
    $clean_title = preg_replace('/[^a-z0-9]+/i', '_', $title); //a bit more cleaning
    $html = '<h3>' . $title  . '</h3>'; //might as well use the title
    $html .= '<div class="container" id="fi-cite">';//special id in case we need to do some targeted CSS
    $html .= '<div class="panel-group" id="' . $clean_title . '" role="tablist" aria-multiselectable="true">';
    $html .= do_shortcode($content);//this little bit it what 
    $html .=  '</div></div>';//closes things out
    return  $html;
}
add_shortcode( 'topic', 'bsc_topic' );

Now for each collapsing element, we needed a short code that contains the title element and whatever content it’s supposed to hold. This will also do the plus/minus icon and the email link/icon. These elements will likely also hold shortcodes so do_shortcode($content) is important again.

//each item
function bsc_item( $atts, $content = null ) {  
    global $post; 
    $url = get_permalink($post);//gets our base URL to send the email link
    extract(shortcode_atts( array(
             'title' => '', //item title should be unique           
        ), $atts));   
    $clean_title = strtolower(urlencode($title)); //cleaning title
    $clean_title =preg_replace('/[^a-z0-9]+/i', '_', $clean_title); //cleaning title
    $html = '<div class="panel panel-default">';
    $html .= '<div class="panel-heading" role="tab" id="head'.$clean_title.'">';
    $html .= '<h4 class="panel-title">';
    $html .= '<a role="button" data-toggle="collapse" href="#' . $clean_title . '" aria-expanded="true" aria-controls="'.$clean_title.'">';
    $html .= '<i class="more-less glyphicon glyphicon-plus plus-icon"></i>' . $title . '</a>'; 
    $html .= '<a class= "mail-icon" href="mailto:?&subject=Information%20about%20'.$title.'&body='.$url.'#'.$clean_title.'"><i class="glyphicon glyphicon-envelope bs-mail"></i></a></h4></div>'; //builds the email link and the pretty email icon
    $html .='<div id="'.$clean_title.'" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne">';
    $html .= '<div class="panel-body">';
    $html .= do_shortcode($content) . '</div></div></div>';//key part here to allow shortcodes to function within the content
    return  $html;
}
add_shortcode( 'item', 'bsc_item' );

The javascript to make this work is pretty straight forward.

 //toggles +/-   
  function toggleIcon(e) {
    jQuery(e.target)
        .prev('.panel-heading')
        .find(".more-less")
        .toggleClass('glyphicon-plus glyphicon-minus');
  }
  jQuery('.panel-group').on('hidden.bs.collapse', toggleIcon);
  jQuery('.panel-group').on('shown.bs.collapse', toggleIcon);

//expands via URL
 jQuery(document).ready(function() {
        if(window.location.hash != null && window.location.hash != ""){
          console.log(location.hash);
        jQuery('.collapse').removeClass('in');
        jQuery(window.location.hash + '.collapse').collapse('show');
      }
   });

The full plugin is here but is based on the idea that you’re already using a bootstrap theme.