Unleash the Power of the WordPress Shortcode API

Share this article

WordPress introduced the Shortcode API in its version 2.5. This API allows developers to add some more or less complex features in their plugins or themes without the user having to insert any HTML code.

The advantage of the Shortcode API is that developers do not need to use regular expressions to detect if the user included their shortcodes into their posts: WordPress automatically detects the registered shortcodes.

In this tutorial, we will learn how to use the Shortcode API. We will create our own shortcodes, see how to use classic and unnamed attributes and also how to handle content.

Key Takeaways

  • The WordPress Shortcode API, introduced in WordPress version 2.5, allows developers to add complex features to their plugins or themes without users needing to insert any HTML code. WordPress automatically detects registered shortcodes, eliminating the need for developers to use regular expressions.
  • Shortcodes can be simple, such as [contact] to insert a contact form, or complex, using attributes like [sayhello to=”You”]. Attributes can even be unnamed, like [sphere 42], and some shortcodes can combine all these elements.
  • When creating shortcodes without attributes, WordPress provides the add_shortcode() function to register a shortcode. The callback function requires the content replacing the shortcode to be indicated in the return instruction. To retrieve content from a shortcode, two parameters are added to the replace_my_shortcode() function.
  • Attributes can add features to shortcodes, and unnamed attributes can be used for booleans. A function can be created to normalize attributes, looking over the array of attributes and changing numbered keys to named ones. This function should be used before applying the shortcode_atts() function so that unnamed attributes can still be retrieved.

How Does the Shortcode API Work?

Before using the Shortcode API, it is important to know how it works for the developer and for the end user.

First, the developer registers their shortcode with the WordPress function add_shortcode(). Then, WordPress will automatically detect when this shortcode is used and call the corresponding function which will replace the shortcode with specific text or HTML code.

For the user, it is really simple: they insert the shortcode into their post and this shortcode will be replaced each time the post is displayed.

Shortcodes can be more or less complex. For example, we can find simple shortcodes like [contact] inserting a contact form in place of the tag. Other shortcodes can be filled with some content, like [hello]Me[/hello], others again can use attributes, like [sayhello to="You"]. These attributes can even be unnamed: [sphere 42] is for example a shortcode using unnamed attributes, added by the WP Photo Sphere plugin. Finally, some shortcodes can combine all of that, so this API can really make some powerful stuff.

Shortcodes Without Attributes

Before creating more complex shortcodes, we will begin with some examples without attributes. As usual, the code presented here should be put in a file of your project (e.g. functions.php for a theme).

Create a Shortcode

WordPress provides us with a specific function to register a shortcode: add_shortcode(). This function requires two parameters which are the shortcode’s name and the function to call each time this shortcode is found.

add_shortcode('myshortcode', 'replace_my_shortcode');

Basically, the callback function only requires one thing: the content replacing the shortcode must be indicated in the return instruction.

function replace_my_shortcode() {
    return 'Hello World!';
}

This example works. If you write a post and insert into it the shortcode [myshortcode], it will be replaced by the text Hello World!. So it works. But it is limited and not very useful.

That’s why using the content of the shortcode can be a good idea. The question is: how to retrieve this content if, for example, the user wrote [myshortcode]You[/myshortcode]?

To get this content, we don’t need to change anything in the add_shortcode() call, but we will add two parameters to our replace_my_shortcode() function.

function replace_my_shortcode($atts, $content = '') {
    return 'Hello ' . $content . '!';
}

In the first parameter, we can retrieve the attributes used by the author of the post, but we will see that in the next part. Here, we are more interested in the second parameter which contains the text between the two tags of our shortcode.

If the user included some content in the shortcode, it will be in the $content variable. Otherwise, this variable will be an empty string so we can detect this case with a condition using, for example, the empty() function.

function replace_my_shortcode($atts, $content = '') {
    if (empty($content))
        return 'Hello World!';
    else
        return 'Hello ' . $content . '!';
}

Shortcodes in Other Shortcodes

We know how to create a shortcode and how to manage its content. But what if this content contains other shortcodes? For example, assume that we have two shortcodes: [name] which displays the author’s name, and [myshortcode] with the callback function above. Then, if the user writes [myshortcode][name][/myshortcode], the result will be “Hello [name]!”, which is surely not what we wanted here.

Asking WordPress to parse shortcodes present in the content of another shortcode is possible and can be done with the do_shortcode() function, as you can see in the code below.

function replace_my_shortcode($atts, $content = '') {
    return 'Hello ' . do_shortcode($content) . '!';
}

With this new callback function, our previous example gives us “Hello Jeremy” as a result (yes, we all have the same name!).

However, it is not the default behavior, and there is a reason for that. In fact, if the user inserts, for example, a shortcode which displays an image in our myshortcode shortcode, the result will not be very pretty. But there is another problem, described below.

With the do_shortcode() function, things like this:

[myshortcode]
    [name]
[/myshortcode]

or:

[myshortcode]
    [name][/name]
[/shortcode]
will be parsed without any problem. But other things like this:
[myshortcode]
    [myshortcode]You[/myshortcode]
[/myshortcode]
are problematic. With the last replace_my_shortcode() function shown above, the result will be “Hello Hello !You![/myshortcode]”. In other words, the first [/myshortcode] tag found closes the first [myshortcode] tag. The other [myshortcode] tag become an empty shortcode and the last [/myshortcode] tag is simply ignored.

Currently, there is no way to prevent this behavior using WordPress functions: do_shortcode() do not let us filter the shortcodes to search, so be careful if you intend to parse shortcodes into yours.

Shortcodes with Attributes

Attributes are useful to add some features to your shortcodes. With attributes, you will be able to get an image ID and other additional data like a name or whatever you might need to complete the shortcode’s content (if you handle content).

Handle Attributes

As we mentioned before, if WordPress finds attributes in the shortcode inserted by the user, it stores it in the first parameter of our callback function. This parameter is then an associative array containing all the used attributes.

The structure of this array is exactly as we expected: its keys are the attributes’ names and its values are theirs. For example, if the user inserted the shortcode [myshortcode name="Here is my name" n="5"], then we will find this array:

Array
(
    [name] => Here is my name
    [n] => 5
)
in the first parameter of our function.

All of the attributes used in the shortcode are stored in this array. However, if you use attributes, you may want to make some of them optional, with default values. That’s the reason why the WordPress function shortcode_atts() exists.

function replace_my_shortcode($atts, $content = '') {
    $atts = shortcode_atts(array(
            'name' => 'World',
            'n' => 1
        ), $atts);
        
	return 'Hello ' . $atts['name'] . '!';
}

This function will merge the $atts array provided by the user and the array given in first parameter which contains your default values. In the above example, if the user doesn’t fill the name attribute, we display “Hello World!”. Otherwise, the indicated name will be used.

Unnamed Attributes

Sometimes, an unnamed attribute can be a better solution than a traditional one. For example, to provide the ID of an image: [myimage 7] instead of [myimage id="7"]. The problem comes when we try to retrieve these special attributes. Without a name to search, which key should we choose?

As for the others, unnamed attributes can be found in the first parameter of our callback function, with numbered keys. An example will be clearer than a long explanation, so assume that the user gives us the shortcode [myshortcode 7 name="My name"]. Then, we find the following array in the first parameter of our callback function.

Array
Array
(
    [0] => 7
    [name] => My name
)

If there is more than one unnamed attribute, the only way to differentiate them from each other is their order. For example, we have the following array if the user inserts [myshortcode 7 name="My name" display test="value" 22].

Array
(
    [0] => 7
    [name] => My name
    [1] => display
    [test] => value
    [2] => 22
)

Often named attributes are preferable because they are easier to retrieve. However, unnamed attributes are not a big problem if you limit them to a small number or if they only serve as booleans. In fact, a shortcode like [myshortcode name="Me" show] is surely better for the user to type than [myshortcode name="Me" show="true"].

For booleans, unnamed attributes are a good idea: we set them as true if they are present, and as false otherwise. However, a question remains here: what about default values?

If you apply the shortcode_atts() function, the returned array will lose the numbered keys. In other words, you will not be able to retrieve unnamed attributes after applying the shortcode_atts() function.

That’s why, if you only use unnamed attributes for booleans, you should create a function to normalize your attributes. You look over the array of attributes and, if the key is a number, you change the attribute to a named one, setting its value to true to indicate that the parameter is asked.

function normalize_attributes($atts) {
    foreach ($atts as $key => $value) {
    	if (is_int($key)) {
            $atts[$value] = true;
            unset($atts[$key]);
    	}
	}
	
	return $atts;
}

Then all you need to do now is to use this function before applying shortcode_atts(). That way, your unnamed attributes will still be there, and you can even give them default values, as you can see in the example below.

function replace_my_shortcode($atts, $content = '') {
    $atts = normalize_attributes($atts);
    $atts = shortcode_atts(array(
            'name' => 'World',
            'hide' => false
        ), $atts);
    
    if (!$atts['hide'])
        return 'Hello ' . $atts['name'] . '!';
    else
        return '';
}

In this example, if the user inserts [myshortcode name="You"], we display “Hello You!”. However, if the shortcode retrieved is [myshortcode hide], then we display nothing. Absurd, but you understood the idea!

In Conclusion

The Shortcode API is a powerful tool for developers.

It can do a lot of different things, from inserting a floating blockquote to displaying a video with many options.

Using attributes lets your users set various details, but make sure to document these options to let the user find all the power of your shortcode.

To make their life easier, you can also add a button to the WordPress editor to automatically insert your shortcode into a post. For example, if your shortcode uses media files, you might be interested in this recent article on adding a media button.

Some examples of shortcodes inspired by the functions described in this tutorial are grouped in a test plugin which you can download here.

Frequently Asked Questions (FAQs) about WordPress Shortcode API

What is the WordPress Shortcode API and why is it important?

The WordPress Shortcode API is a set of functions that allow developers to create specific custom code snippets, known as shortcodes, that users can insert into their posts and pages. These shortcodes can perform a variety of functions, such as embedding media, creating forms, or displaying content. The Shortcode API is important because it simplifies the process of adding complex elements to a WordPress site, making it more accessible for users without extensive coding knowledge.

How do I create a basic shortcode in WordPress?

To create a basic shortcode in WordPress, you need to add a function to your theme’s functions.php file. This function should define what the shortcode does. For example, you could create a shortcode that displays a button with a link. Here’s a simple example:

function my_button_shortcode($atts, $content = null) {
return '<a class="my-button" href="' . $atts['url'] . '">' . $content . '</a>';
}
add_shortcode('my_button', 'my_button_shortcode');

In this example, [my_button url="http://example.com"]Click me![/my_button] would output a button that says “Click me!” and links to example.com.

Can I use shortcodes in widgets?

Yes, you can use shortcodes in widgets. However, by default, WordPress text widgets do not process shortcodes. To enable this functionality, you need to add the following line of code to your theme’s functions.php file:

add_filter('widget_text', 'do_shortcode');

This tells WordPress to process shortcodes in text widgets.

How can I create a shortcode that accepts attributes?

To create a shortcode that accepts attributes, you need to modify your shortcode function to accept an $atts parameter. This parameter is an associative array of attributes that the user can specify in the shortcode. Here’s an example:

function my_button_shortcode($atts, $content = null) {
$atts = shortcode_atts(array(
'url' => 'http://example.com',
'color' => 'blue'
), $atts);

return '<a class="my-button ' . $atts['color'] . '" href="' . $atts['url'] . '">' . $content . '</a>';
}
add_shortcode('my_button', 'my_button_shortcode');

In this example, [my_button url="http://example.com" color="red"]Click me![/my_button] would output a red button that says “Click me!” and links to example.com.

How can I nest shortcodes?

To nest shortcodes, you simply include one shortcode inside another. However, not all shortcodes are designed to be nested. If you want to create a shortcode that can contain other shortcodes, you need to make sure your shortcode function processes the enclosed content with the do_shortcode() function. Here’s an example:

function my_container_shortcode($atts, $content = null) {
return '<div class="my-container">' . do_shortcode($content) . '</div>';
}
add_shortcode('my_container', 'my_container_shortcode');

In this example, [my_container][my_button url="http://example.com"]Click me![/my_button][/my_container] would output a button inside a container.

Can I use shortcodes in my theme files?

Yes, you can use shortcodes in your theme files. To do this, you need to use the do_shortcode() function. Here’s an example:

echo do_shortcode('[my_button url="http://example.com"]Click me![/my_button]');

This would output the same button as the previous examples, but directly in a theme file.

How can I create a shortcode that displays a custom post type?

To create a shortcode that displays a custom post type, you need to use the WP_Query class to query the posts, and then loop through the results. Here’s an example:

function my_posts_shortcode($atts) {
$atts = shortcode_atts(array(
'post_type' => 'post',
'posts_per_page' => 5
), $atts);

$query = new WP_Query($atts);

$output = '<ul>';

while ($query->have_posts()) {
$query->the_post();
$output .= '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
}

$output .= '</ul>';

wp_reset_postdata();

return $output;
}
add_shortcode('my_posts', 'my_posts_shortcode');

In this example, [my_posts post_type="product" posts_per_page="10"] would output a list of the 10 most recent products.

How can I create a shortcode that displays a form?

To create a shortcode that displays a form, you need to return the HTML for the form from your shortcode function. Here’s an example:

function my_form_shortcode() {
return '<form action="/submit" method="post">
<input type="text" name="name" placeholder="Your name">
<input type="email" name="email" placeholder="Your email">
<input type="submit" value="Submit">
</form>';
}
add_shortcode('my_form', 'my_form_shortcode');

In this example, [my_form] would output a simple form with fields for name and email.

How can I create a shortcode that displays a gallery?

To create a shortcode that displays a gallery, you need to query the attachments for a post and output them in your desired format. Here’s an example:

function my_gallery_shortcode($atts) {
$atts = shortcode_atts(array(
'id' => get_the_ID(),
'size' => 'thumbnail'
), $atts);

$attachments = get_children(array(
'post_parent' => $atts['id'],
'post_type' => 'attachment',
'post_mime_type' => 'image'
));

$output = '<div class="my-gallery">';

foreach ($attachments as $attachment) {
$output .= wp_get_attachment_image($attachment->ID, $atts['size']);
}

$output .= '</div>';

return $output;
}
add_shortcode('my_gallery', 'my_gallery_shortcode');

In this example, [my_gallery id="123" size="medium"] would output a gallery of medium-sized images attached to the post with the ID 123.

How can I create a shortcode that displays a Google Map?

To create a shortcode that displays a Google Map, you need to return an iframe with the Google Maps URL. Here’s an example:

function my_map_shortcode($atts) {
$atts = shortcode_atts(array(
'address' => '1600 Amphitheatre Parkway, Mountain View, CA',
'width' => '600',
'height' => '450'
), $atts);

$address = urlencode($atts['address']);

return '<iframe width="' . $atts['width'] . '" height="' . $atts['height'] . '" frameborder="0" style="border:0" src="https://www.google.com/maps/embed/v1/place?key=YOUR_API_KEY&q=' . $address . '" allowfullscreen></iframe>';
}
add_shortcode('my_map', 'my_map_shortcode');

In this example, [my_map address="1 Infinite Loop, Cupertino, CA"] would output a Google Map of Apple’s headquarters. Note that you need to replace YOUR_API_KEY with your actual Google Maps API key.

Jérémy HeleineJérémy Heleine
View Author

Currently a math student, Jérémy is a passionate guy who is interested in many fields, particularly in the high tech world for which he covers the news everyday on some blogs, and web development which takes much of his free time. He loves learning new things and sharing his knowledge with others.

apiChrisBshortcodeWordPress
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week