Paulund

Improving WordPress Shortcode Usability

In this tutorial we are going to talk about WordPress shortcodes and what I think is the missing piece with shortcodes in WordPress. First I'll start by saying I really like shortcodes, it allows you to give the author of the website full control of the content on the site and where it is positioned.

What Is A Shortcode?

A shortcode allows the user to run a PHP function at any point you want in the content. A default shortcode you get with WordPress is the gallery shortcode, to add a gallery to your website all you have to do is add [ gallery ] to the content area of your website. The name inside the square brackets is the name of the shortcode that you want to run at this position of the content. WordPress will then search for shortcodes on the the_content filter and using the function do_shortcode() will run the functions at this point of the content, the return of these functions will then be output into the rest of the content area. Shortcodes allow you to send extra parameters to the function by using attributes.


[shortcode_example attribute1="stuff" attribute2="things"/]

In the shortcode function the developer can now look up these attributes and use these values to change the output. You can also add content into the shortcode along with the attributes.


[shortcode_example attribute1="stuff" attribute2="things"]Shortcode Content Can Go Here[/shortcode_example]

This is great for the author as they now have full control of any functions that can help add dynamic controls to the site.

The Problem With Shortcodes

Although I do like using Shortcodes when building WordPress websites because of the flexibility you get, I feel that we are still missing a piece in WordPress to help improve the usability of Shortcodes for the content author. The problem with shortcodes is that the markup for them are similar to HTML, if you are a developer or used a bit of HTML before then this isn't a problem you understand it and know the syntax you need to use. But if you've never done HTML before (like most CMS users) then using shortcodes can be a bit daunting, not knowing what attributes are/how to use them/what you can put inside the shortcode, there are many reasons why authors don't like using them. Another problem with shortcodes are the attributes, the only way the author will know what attributes and what values they can use is by reading the documentation. This means whenever you want to try something new with the shortcode you will always need the documentation up to make changes which can take some time. You are also reliant on the developer providing you with good documentation about the shortcode, how you can use it, what attributes to use, the values you can send through, default values for the attributes etc.

How Can We Improve This?

When looking into improving the usability of shortcodes the first place you need to look at is the widget interface, at a simple level this functionality is exactly the same as using shortcodes in the content. You can split your content area up into blocks and bring in functionality for each block. The benefit of using Widgets is when they are added to the page you are presented with a form where you can enter in the attributes and content to use on the widget. Exactly what the content author wants, add something to the page, fill out the options and go. This is really what is missing with shortcodes, when they're added into the content area you need a form for the user to fill out, with textboxes, checkboxes, select dropdowns, we can then take the values of the form and use these in the shortcode attributes.

How To Improve Shortcodes

In a previous tutorial we investigated how we can create a button on the TinyMce editor to add our shortcodes into the content area. We will use this same technique to create an area for the user to select which shortcode they want to use, then use the WordPress in-built jQuery UI script to display a dialog box, populated with a form to select the attributes. From the images below you can see what we are going to create

First select a shortcode from the dropdown.

Next fill out a form with the shortcode options.

Submit the form the shortcode appears in the content area populated with the required attributes.

Add Button To TinyMce

First we need to create a way of adding the dropdown to the TinyMce content editor to display a list of all shortcodes that we want to display a form for. To add a new button to the TinyMce editor you need to use the WordPress filter of mce_buttons, this filter will pass in one parameter which is an array of the existing buttons, to add new buttons you need to simply add new elements to the end of the $buttons array and return the entire array.

add_filter( 'mce_buttons', 'pu_register_buttons' );

function pu_register_buttons( $buttons )
{
    array_push( $buttons, 'separator', 'puhortcodes' );
    return $buttons;
}

Include JavaScript File For Form

Because we are using jQuery UI to create the form, we need to add a new Javascript file which we will use to add the script that creates the form. To do this we need to use a filter mce_external_plugins to which allows us to add additional Javascript files at the point of the TinyMce scripts.


add_filter( 'mce_external_plugins', 'pu_add_buttons' );

function pu_add_buttons( $plugin_array )
{
    $plugin_array['pushortcodes'] = plugin_dir_url( dirname(__FILE__) ) . 'js/shortcode-tinymce-button.js';
    return $plugin_array;
}

Create New Filter To Include Certain Shortcodes

WordPress has two ways that you can extend the functionality of the code, this is either actions or filters. Actions allow you to add additional code functions to run at a certain time in the code. Filters allow you to pass in parameters, change the content and return a new value. Through out the internal code of WordPress there are actions and filters everywhere allowing you to change the functionality of the code, this is what you will use in any plugin development to add new stuff to WordPress. But you don't have to just use the internal WordPress actions and filters you can define your own to reuse elsewhere. In the below code we are going to use our own filter to add new tags to the shortcode dropdown. Notice in the code below the function apply_filters(), this tells WordPress to run the functions that have already been added to this filter. This filter will takes one parameter which is an array of shortcode tags we are going to use in the shortcode dropdown. The filter allows us to add additional elements to this shortcode tags array which will use to build up the dropdown.


add_action('admin_footer', 'pu_get_shortcodes');
function pu_get_shortcodes()
{
    echo '<script type="text/javascript">
    var shortcodes_button = new Object();';

    $shortcode_button_tags = array();

    $shortcode_button_tags = apply_filters('pu_shortcode_button', $shortcode_button_tags);

    if(!empty($shortcode_button_tags))
    {
        foreach($shortcode_button_tags as $tag => $code)
        {
            echo "shortcodes_button['{$tag}'] = '{$code}';";
        }
    }

    echo '</script>';
}

For us to add shortcodes to this dropdown we need to add new filters to the pu_shortcode_button filter. Here we are using the filter pu_shortcode_button to add a new Facebook shortcode, inside the function all we are doing is adding a new element to the array. The key is going to be the shortcode name, the value is the title we present to the user, then we just return the entire array.


add_filter('pu_shortcode_button', 'add_facebook_shortcode', 10, 1);
function add_facebook_shortcode( $shortcode_tags )
{
    $shortcode_tags['facebook_like_box'] = 'Facebook Like Box';
        
    return $shortcode_tags;
}

Creating The jQuery UI Form

To create the form that is going to appear when you select the shortcode we can use the jQueryUI dialog box, then add the HTML to create the form. JQueryUI comes built in to WordPress with the scripts needed for the dialog box, to use these we just need to run the wp_enqueue_script() function, with the parameter of jquery-ui-dialog. But WordPress doesn't come with the stylesheets for the jQueryUI dialog box so we need to include these styles in the WordPress admin area. We can use Google CDN to get the default jQueryUI stylesheets by using the wp_enqueue_style() and the URL for the Google CDN.


add_action('admin_enqueue_scripts', 'add_dialog_box_scripts');
function add_dialog_box_scripts()
{
    wp_enqueue_script( 'jquery-ui-dialog', false, array('jquery') );
    wp_enqueue_style( 'jquery-style', '//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css' );
}

With these scripts included on the page we can now create the dialog box with the form elements populated for the shortcode attributes.

Add Form To Dialog Box

With creating the form we are going to use another custom WordPress filter to add form elements to the dialog box. The below code will be the HTML in the footer of the admin area, this HTML is what we need to create the dialog box that will be displayed when the user selects a shortcode. As the form elements are going to be added when you select a shortcode this needs to be done with Javascript, therefore we are going to create a JavaScript variable and add all the form elements into this object so we can use this in the Javascript to create the form.

add_action('admin_footer', 'pu_shortcode_dialog');
function pu_shortcode_dialog()
{
    echo '<div id="shortcode-dialog" title="Shortcode Form">
            <form class="shortcode-dialog-form"></form></div>';

    echo '<script type="text/javascript">
    var shortcodes_form = new Object();';

    $shortcode_form = array();
    $shortcode_form = apply_filters('pu_shortcode_form', $shortcode_form);

    if(!empty($shortcode_form))
    {
        foreach($shortcode_form as $tag => $form)
        {
            echo "shortcodes_form['{$tag}'] = '{$form}';";
        }
    }

    echo '</script>';
}

We now have a JavaScript object variable shortcodes_form that is populated with all the form elements for each shortcode. As the shortcode is the key for the object, we use this when a shortcode is selected to get all the form elements, we will then take these form elements and add these to the empty dialog box. ## Shortcode Button JavaScript

The following code is the Javascript file that we will use to create our shortcode button on the TinyMce editor. On the click event of the user selecting a shortcode we will construct the form by grabbing the form elements from the shortcodes_form variable, emptying the dialog box and re-adding everything for the selected shortcode into the form. Because we are using the jQueryUI dialog box we can construct the submit button of the form and tell it exactly what we want to do once the form is submitted. Using the jQuery function serializeArray() it will get an array of all the fields on the shortcode form, then all we have to do is loop through this array and create the attributes for the shortcode, once the shortcode is constructed you can output this content into the TinyMce editor.

(function() {

    tinymce.PluginManager.add('pushortcodes', function( editor )
    {
        var shortcodeValues = [];
        jQuery.each(shortcodes_button, function(i)
        {
            shortcodeValues.push({text: shortcodes_button[i], value:i});
        });

        editor.addButton('pushortcodes', {
            type: 'listbox',
            text: 'Shortcodes',
            onselect: function(e) {
                var v = e.control._value;

                var content = '';
                var dialogForm = '<table>';

                if(shortcodes_form[v] != undefined)
                {
                    dialogForm += shortcodes_form[v];

                    if(dialogForm != '<table>')
                    {
                        dialogForm += '</table>';
                        jQuery('.shortcode-dialog-form').empty();
                        jQuery('.shortcode-dialog-form').append(dialogForm);

                        jQuery("#shortcode-dialog").dialog({
                            width: 700,
                            resizable: false,
                            buttons: {
                                "Add Shortcode": function(){
                                    var formArray = jQuery('.shortcode-dialog-form').serializeArray();

                                    if(formArray.length > 0)
                                    {
                                        content = '[' + v + ' ';
                                        jQuery(formArray).each(function(i){
                                            content += jQuery(this)[0].name + '="'+ jQuery(this)[0].value +'" ';
                                        });

                                        content += '][/'+v+']';
                                    }

                                    tinyMCE.activeEditor.selection.setContent( content );
                                    jQuery( this ).dialog( "close" );
                                }
                            }
                        });
                    }
                } else {
                    tinyMCE.activeEditor.selection.setContent( '[' + v + '][/' + v + ']' );
                }
            },
            values: shortcodeValues
        });
    });

})();

These are all the files we need to create the shortcode form button plugin, but how would you use this to improve the usability of your shortcodes.

Using Filters To Add Shortcode

At the start of this article you saw how you can easily create new filters to use to add extra content to an array, the benefit of using filters for this is so each of our shortcodes can add a new function to add to the array. The first filter we are going to use is the pu_shortcode_button filter that will add content to the shortcode dropdown. This takes one parameter which is the array of shortcodes and will return this same array with the new content added to it. This is the same filter you will use on all your shortcodes, to add them to this dropdown to select the shortcode, as this is an array the key value pairing is important, the key of the array should be the same tag as the shortcode, the value is the text that is going to be displayed on the shortcode dropdown.


add_filter('pu_shortcode_button', 'pu_add_facebook_shortcode', 10, 1);
function pu_add_facebook_shortcode( $shortcode_tags )
{
    $shortcode_tags['facebook_like_box'] = 'Facebook Like Box';

    return $shortcode_tags;
}

The next filter we need to use is the filter that will create the array of form elements inside the dialog box. The filter we need to use is pu_shortcode_form, which again takes one parameter and will return that same parameter with the content of the form inside. Again the key value pairing of this array is important as it helps define what content to get for each shortcode, the key is the tag of the shortcode and the value is the entire form elements to use for this shortcode.


add_filter('pu_shortcode_form', 'pu_add_facebook_form', 10, 1);
function pu_add_facebook_form( $shortcode_tags )
{
    $shortcode_tags['facebook_like_box'] = apply_filters('pu_shortcode_form_add_text', null, 'page_name', 'Page Name');
    $shortcode_tags['facebook_like_box'] .= apply_filters('pu_shortcode_form_add_text', null, 'width', 'Width', 300);
    $shortcode_tags['facebook_like_box'] .= apply_filters('pu_shortcode_form_add_checkbox', null, 'show_faces', 'Show Faces');
    $shortcode_tags['facebook_like_box'] .= apply_filters('pu_shortcode_form_add_checkbox', null, 'show_stream', 'Show Stream');
    $shortcode_tags['facebook_like_box'] .= apply_filters('pu_shortcode_form_add_checkbox', null, 'show_header', 'Show Header', true);
    $shortcode_tags['facebook_like_box'] .= apply_filters('pu_shortcode_form_add_checkbox', null, 'show_border', 'Show Border');
    $shortcode_tags['facebook_like_box'] .= apply_filters('pu_shortcode_form_add_select', null, 'color_scheme', 'Color Scheme', array('light' => 'Light', 'dark' => 'Dark'));

    return $shortcode_tags;
}

As you can see from this example I am using custom filters again to get the content of each of the form elements, the reason we do this is for a few good reasons: - We will always get a consist output from these functions, so the form element will always come in the same layout.

  • They can be accessed from anywhere in the code, if shortcodes are in themes or plugins you can still access these filters.
  • It allows other developers to change the output of these filters.

Creating Textbox Form Element Filter

The following code will show the default behaviour of the text element filter, this takes 4 parameter in all and we will use these to define the attributes of the form element. The return of this filter will be used to add the element to the form, so we are going to return a table row with simply a input type of text.


add_filter('pu_shortcode_form_add_text', 'pu_add_text_form_element', 10, 4);
function pu_add_text_form_element( $content, $name, $title, $value = '' )
{
    return sprintf('<tr><td>%s</td><td><input type="text" id="%s" name="%s" value="%s" /></td></tr>',
        $title,
        $name,
        $name,
        $value);
}

Then we can continue this and create the filter for the other form elements.