We recently received a request to embed some JavaScript for a live chat client into multiple pages within our site. The live chat service provided the JS code snippet to our team along with the ID key we would need to use within the snippet to link the client on our pages with the live-chatters on the other side. There were also a few settings that could be changed within the snippet — things like background color, offset width, and location on the page.
Since we do not allow JavaScript tags within our WYSIWYG editor, we couldn’t just ask our Content Managers (CMs) to copy/paste the snippet right into the Body (or other) field. We also didn’t want to be called upon everytime the script needed to be embedded on a different page or when the ID key changed due to a new marketing campaign (or any other reason). We decided to use Shortcodes.
Shortcodes are little bits of code that, when parsed in a field that allows them, expand to a pre-defined output, replacing any pre-defined variables in the expansion.
For a quick example, a shortcode for embedding a link to Google may be:
1 |
[linkToGoogle] |
When that string is parsed in a shortcode-enabled field, it might render as:
1 |
<a href="http://www.google.com">Google.com</a> |
This is useful because, if the link to Google were to ever change, any number of instances of the shortcode can be updated all at once by one modification to the Shortcode code.
As I mentioned, Shortcodes can also take variables. For example:
1 |
[linkToGoogleResults searchString="Troy McClure"] |
might expand to
1 |
<a href="https://www.google.com/search?q=Troy+McClure">Search Results for Troy Maclure</a> |
This tutorial requires the contrib module Shortcode. We’ll write a custom module to extend its functionality and add a new shortcode. Here’s how to do it.
First, let’s create a module. I’ll call mine “tmbridge_custom_shortcodes” and, thus, create a directory, tmbridge_custom_shortcodes, in my custom modules directory and two files, tmbridge_custom_shortcodes.module and tmbridge_custom_shortcodes.info, in that directory.
I won’t speak to writing the info file in this post, but you can refer to this page on d.o for more information.
The first thing we need to do in this new module is name and describe our new shortcode and indicate the callback functions it will use:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php /** * @file tmbridge_custom_shortcodes.module */ /** * Implements hook_shortcode_info * * Define our shortcodes and their titles, descriptions, and callback functions. * See the comments below for an explanation of each parameter * * @param none * @return array */ function tmbridge_custom_shortcodes_shortcode_info() { $shortcodes['friendly_alert'] = array( 'title' => t('Friendly Alert Link'), // The title of this shortcode, displayed in the Drupal backend for administrators to enable/disable shortcodes for input types 'description' => t('Embeds a link that, when clicked, alerts the user with a friendly greeting.'), // Description shown along with the title in the Drupal backend 'process callback' => 'tmbridge_custom_shortcodes_shortcode_friendly_alert', // Custom function that deals with the variables and html output 'tips callback' => 'tmbridge_custom_shortcodes_shortcode_friendly_alert_tip' // Custom function that displays some help text to the user ); // $shortcodes['second_shortcode'] = array(); // $shortcodes['third_shortcode'] = array(); // and so on... return $shortcodes; } |
We need to define the variables (or attributes) for our new shortcode. We do this by implementing hook_theme():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/** * Implements hook_theme * * Define our variables/attributes for each custom shortcode * * @param none * @return array */ function tmbridge_custom_shortcodes_theme() { return array( 'shortcode_friendly_alert' => array( 'variables' => array('salutation' => '', 'message' => '', 'from' => ''), ), // 'shortcode_second_shortcode' => array(), // 'shortcode_third_shortcode' => array(), // and so on... ); } |
Next, let’s define our callback function for the new shortcode. This callback function takes the variables as defined by the user in the shortcode’s use in the WYSIWYG editor and applies any business logic, formatting, or modification (like setting a default, if empty):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/** * Implements hooke_shortcode_[shortcodename] * * Define our process callback function for our shortcode. This * takes in our shortcode attributes from the shortcode and if empty, sets * the property to the default value stated in this function. We then pass * in our attributes to the theme() function which returns the HTML. * * $attrs = shortcode_attrs(array( * 'attribute' => 'default_value_goes_here' * ), * * @param $attrs array Array of variables/attributes the user can customize * @return string */ function tmbridge_custom_shortcodes_shortcode_friendly_alert($attrs, $text) { if (empty($attrs["salutation"])) { $attrs["salutation"] = "Hello! "; } if (empty($attrs["message"])) { $attrs["message"] = "Have a great day!"; } if (empty($attrs["from"])) { $attrs["from"] = "From: Tim"; } return theme('shortcode_friendly_alert', array('salutation' => $attrs['salutation'], 'message' => $attrs["message"], 'from' => $attrs["from"])); } |
Now, we need to define the theme function that our process callback function calls. In this case, it’s simply ‘shortcode_friendly_alert’. This theme function returns the output of the shortcode with the variables replaced. Here’s where the magic of this module happens. You can put literally any markup you wish into this function’s output and populate as many variables within it with user-defined data (this means you could get data from any Drupal object that’s in scope, as well). It could be JavaScript (including AJAX functionality), CSS, output from other theme functions (blocks, views, etc.), Or… just run of the mill HTML markup.
In this tutorial, we’re just using some (really) basic JS and HTML to make the point, but I really want to drive home the wide breadth of functionality one could implement herein.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/** * Implements theme_shortcode_[shortcodename] * * This function returns the output of the shortcode. The variables/attributes * are passed in as an array. * * @param $vars array * @return string */ function theme_shortcode_friendly_alert($vars) { $output = ' <script> function friendlyAlert(salutation, message, from) { alert(salutation + " " + message + " " + from); } </script> <a href="javascript:friendlyAlert($vars['salutation'], $vars['message'], $vars['from']);"> Click here for a friendly message!</a> '; return $output; } |
Finally, let’s define our tip callback. This function outputs text below the WYSIWYG editor that tells the user what the shortcode is used for and shows the user what parameters are available.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/** * Implements hook_shortcode_[shortcodename]_tip * * This function outputs text below the WYSIWYG editor to tell the user what * shortcodes are available and what the parameters are for the shortcode. * * @param $format stdClass Information about which text format is being used * @param $long bool Whether this is the 'More Info' page for the format * @return string The text to be returned */ function tmbridge_custom_shortcodes_shortcode_friendly_alert_tip($format, $long) { $output = array(); $output[] = '<p><strong>' . t('[friendly_alert salutation="YOUR_SALUTATION" message="YOUR_MESSAGE" from="YOUR_FROM"][/friendlyalert ]') . '</strong> '; if ($long) { $output[] = t('Outputs a link to a friendly alert - salutation, message, and from are optional.') . '</p>'; } else { $output[] = t('Outputs a link to a friendly alert.') . '</p>'; } return implode(' ', $output); } |
And that’s it for the code! Simply enable the module and be sure to remember to enable the new shortcode in all the Text Formats you’d like it available within (/admin/config/content/formats). The available shortcodes are listed in the vertical tab “Shortcodes” under “Filter Settings:

You will then see your new shortcode available in all fields that use those Text Formats.
