testing content.php

WordPress Shortcodes: A Complete Guide | Smashing WordPress

WordPress shortcodes were introduced in version 2.5 and since then have proved to be one of the most useful features. The average user acting as editor has the ability to publish dynamic content using macros, without the need for programming skills.

When a shortcode is inserted in a WordPress post or page, it is replaced with some other content. In other words, we instruct WordPress to find the macro that is in square brackets ([]) and replace it with the appropriate dynamic content, which is produced by a PHP function.

The usage is pretty simple. Let’s say we want to show the most recent posts in a given post. We could use something like this:

1 [recent-posts]

For a more advanced shortcode, we could set the number of posts to display by setting a parameter:

1 [recent-posts posts="5"]

Going one step further, we could set a heading for the list of recent posts:

1 [recent-posts posts="5"]Posts Heading[/recent-posts]

[Note: Have you already bought your copy of our brand new Smashing Book #3? The book introduces new practical techniques and a whole new mindset for progressive Web design. It will change the way you design websites for the better.]

Simple Shortcode

In the first part of this tutorial, we will create the code for this simple shortcode:

1 [recent-posts]

The creation process is simple and does not require any advanced PHP knowledge. The basic steps are:

  1. Create the function, which will be called by WordPress when it finds a shortcode.
  2. Register the shortcode by setting a unique name.
  3. Tie the registration function to a WordPress action.

All codes in this tutorial can be placed in functions.php or in a seperate PHP file that will be included in functions.php.


When a shortcode is found, it is replaced by some piece of code, which is the callback function. So, let’s create a function that fetches recent posts from the database.

01 function recent_posts_function() {
02    query_posts(array('orderby' => 'date', 'order' => 'DESC' , 'showposts' => 1));
03    if (have_posts()) :
04       while (have_posts()) : the_post();
05          $return_string = '<a href="'.get_permalink().'">'.get_the_title().'</a>';
06       endwhile;
07    endif;
08    wp_reset_query();
09    return $return_string;
10 }

As shown, we’re querying the database to get the latest post and return a string with a link to it. ?t is worth noting that the callback function does not print anything, but rather returns a string.


Now, we tell WordPress that this function is a shortcode:

1 function register_shortcodes(){
2    add_shortcode('recent-posts', 'recent_posts_function');
3 }

?f a shortcode of [recent-posts] is found in a post’s content, then recent_posts_function() is called automatically. We should ensure that the shortocode’s name is unique in order to avoid conflicts.


In order to execute our register_shortcodes() function, we will tie it to WordPress’ initialization action:

1 add_action( 'init', 'register_shortcodes');


Our simple shortcode is ready, and the next step is testing that it operates properly. Let’s create a new post (or open an existing one) and put the following line somewhere in the content:

1 [recent-posts]

Publish the post, and viewing it in a browser, you should see a link to the most recent post on your blog, as shown in this screenshot:

Simple shortcode

Advanced Shortcode


Shortcodes are flexible because they allow us to add parameteres in order to make them more functional. Let’s say we want to display a certain number of recent posts. To do this, we need to add an extra option to our shortcode that specifies how many recent posts to show.

We have to use two functions. The first one is WordPress’ built-in shortcode_atts() function, which combines user shortcode attributes with native attributes and fills in the defaults where needed. The second function is the extract() PHP function, which does what its name suggests: it extracts the shortcode attributes.

Extending our callback function, we add an argument, which is an array of attributes from which we extract the parameter for the number of posts. Then we query the database to get the desired number of posts and create an HTML list to show them.

01 function recent_posts_function($atts){
02    extract(shortcode_atts(array(
03       'posts' => 1,
04    ), $atts));
06    $return_string = '<ul>';
07    query_posts(array('orderby' => 'date', 'order' => 'DESC' , 'showposts' => $posts));
08    if (have_posts()) :
09       while (have_posts()) : the_post();
10          $return_string .= '<li><a href="'.get_permalink().'">'.get_the_title().'</a></li>';
11       endwhile;
12    endif;
13    $return_string .= '</ul>';
15    wp_reset_query();
16    return $return_string;
17 }

If the user skips the option, 1 is the default value. In the same way, we can add more attributes, enabling the shortcodes to accept multiple parameteres. Thanks to this enhanced function, we can set how many posts to show:

1 [recent-posts posts="5"]

When viewing it in the browser, you should see links to the five most recent posts in the content:

Advanced shortcode


We can take our shortcode one step further and add the ability to pass some content as an argument, which in this case will be a heading for the list of recent posts. To do this, we use a second parameter, $content, in the callback function and add it as an h3 heading before the list. The new function is as follows:

01 function recent_posts_function($atts, $content = null) {
02    extract(shortcode_atts(array(
03       'posts' => 1,
04    ), $atts));
06    $return_string = '<h3>'.$content.'</h3>';
07    $return_string .= '<ul>';
08    query_posts(array('orderby' => 'date', 'order' => 'DESC' , 'showposts' => $posts));
09    if (have_posts()) :
10       while (have_posts()) : the_post();
11          $return_string .= '<li><a href="'.get_permalink().'">'.get_the_title().'</a></li>';
12       endwhile;
13    endif;
14    $return_string .= '</ul>';
16    wp_reset_query();
17    return $return_string;
18 }

This kind of shortcode is similar to an HTML tag. We enclose the content in an opening and closing shortcode:

1 [recent-posts posts="5"]This is the list heading[/recent-posts]

The result is the same as the previous example, except for the new heading for the list of posts:

Content in shortcode

Shortcodes Anywhere, Anytime!


By default, shortcodes are ignored in WordPress sidebar widgets. Take the following as an example:

1 [recent-posts posts="5"]

If you type this shortcode into a widget, it would look something like this:

A shortcode in a widget before enabling the functionality

With WordPress, we can enable this functionality with a single line of code. To be able to add shortcodes in widgets, add the following:

1 add_filter('widget_text', 'do_shortcode');

Now, without having to change anything else, the shortcode will display properly in widgets:

A shortcode in a widget after enabling the functionality

Similarly, we can enable shortcodes in comments:

1 add_filter( 'comment_text', 'do_shortcode' );

And excerpts:

1 add_filter( 'the_excerpt', 'do_shortcode');

Shortcode TinyMCE Editor Button

While shortcodes are a handy way to add dynamic content to posts, the might be a bit confusing for the average user, especially when they get complicated, with multiple parameteres. Most users are not familiar with HTML-like syntax; and yet they have to remember the exact syntax and all available attributes of shortcodes, because even a minor syntax error could cause an undesirable result.

To resovle this, we can add a button to the TinyMCE editor`s interface, enabling the user to create a shortcode with a simple click. There are two basic steps to creating this button:

  1. Create the JavaScript file for the button.
  2. Register the button and the JavaScript file.


The JavaScript file is used to register the TinyMCE plugin through the TinyMCE API. We create a new file named recent-posts.js in the js directory of our theme, and then we type the following piece of code:

01 (function() {
02    tinymce.create('tinymce.plugins.recentposts', {
03       init : function(ed, url) {
04          ed.addButton('recentposts', {
05             title : 'Recent posts',
06             image : url+'/recentpostsbutton.png',
07             onclick : function() {
08                var posts = prompt("Number of posts", "1");
09                var text = prompt("List Heading", "This is the heading text");
11                if (text != null && text != ''){
12                   if (posts != null && posts != '')
13                      ed.execCommand('mceInsertContent', false, '[recent-posts posts="'+posts+'"]'+text+'[/recent-posts]');
14                   else
15                      ed.execCommand('mceInsertContent', false, '[recent-posts]'+text+'[/recent-posts]');
16                }
17                else{
18                   if (posts != null && posts != '')
19                      ed.execCommand('mceInsertContent', false, '[recent-posts posts="'+posts+'"]');
20                   else
21                      ed.execCommand('mceInsertContent', false, '[recent-posts]');
22                }
23             }
24          });
25       },
26       createControl : function(n, cm) {
27          return null;