TutorialInserting Widgets With Shortcodes

Advertisement

The shortcode ability of WordPress is extremely underrated. It enables the end user to create intricate elements with a few keystrokes while also modularizing editing tasks. In a new theme we’re developing, I decided to look into adding widgets anywhere with shortcodes, and it turns out that it isn’t that difficult.

Some of the widgets that can be added with shortcodes.
Some of the widgets that can be added with shortcodes.

This tutorial is for experienced WordPress users; we will be looking at the widgets object and shortcodes without delving into too much detail about how and why they work. If you are looking for more information, I suggest reading Mastering WordPress Shortcodes and the Widgets API article in the Codex.

Grabbing A Random Widget

The first thing I looked into was how to output any widget without shortcodes. Once done, implementing a shortcode is a relatively trivial matter. Digging around in the Codex, I found the the_widget() function, which does just what I want.

It takes three parameters:

  • The widget’s class name,
  • The widget’s instance settings,
  • The widget’s sidebar arguments.

Once I saw this, my face lit up. Not only can I output a widget anywhere, but I can pass different sidebar arguments to any widget. This is great because I can specify parameters such as before_widget and after_widget.

This also opens up the possibility of easily changing the style of the widget from within the shortcode, but more on that later.

After applying some CSS, the calendar widget can be added anywhere.
After applying some CSS, the calendar widget can be added anywhere.

Output Buffering

When adding a shortcode, you scan the text for a particular string, do something with it and return the result you want to see. It’s obvious that we will be using the_widget(), but that function only echoes content. To get around this problem we’ll be using output buffering.

Take a look at the following two examples; the result is exactly the same.

the_widget( 'WP_Widget_Archives' );
ob_start();
the_widget( 'WP_Widget_Archives' ); 
$contents = ob_get_clean();
echo $contents;

First we start our buffer. From this point on, anything that is echoed goes into our buffer instead of actually being echoed. By using ob_get_clean(), we can pull the contents of the buffer into a variable (and also clear the buffer). Once this is done we can echo that variable, or pass it on by returning it if we’re in a function.

Creating The Shortcode

Now we know everything we need, so let’s create the skeleton of our shortcode. First we need to figure out what arguments we need to pass, and what arguments we want to allow the user to pass via the shortcode tag.

  • Widget type – Which widget do we want to show;
  • Title – The title of the widget (used in the instance parameter);
  • Other instance parameters;
  • Other sidebar arguments.

I’ll admit that this is a bit vague. The reason is that each widget will need a separate set of possible arguments due to the varied functionality they have. For an archive widget, we can specify whether or not we want the post count. For a category widget, we could also specify the hierarchical attribute.

Solving this problem requires a flexible shortcode, and good end-user documentation.

The best way to make sure the shortcode is used properly is to provide good documentation.
The best way to make sure the shortcode is used properly is to provide good documentation.

The Shortcode Skeleton

add_shortcode( 'widget', 'my_widget_shortcode' );
function my_widget_shortcode( $atts ) {

// Configure defaults and extract the attributes into variables
extract( shortcode_atts( 
	array( 
		'type'  => '',
		'title' => '',
	), 
	$atts 
));

$args = array(
	'before_widget' => '<div class="box widget">',
	'after_widget'  => '</div>',
	'before_title'  => '<div class="widget-title">',
	'after_title'   => '</div>',
);

ob_start();
the_widget( $type, $atts, $args ); 
$output = ob_get_clean();

return $output;

There are two common attributes all shortcodes will have. The type is where the user will specify the widget type, and the title is where the user specifies the title (no surprises there).

Once we have our $atts, we figure out the $args — the widget’s sidebar parameters. Since this is a commercial theme, we don’t need to give the user control over these arguments, so they are just hard coded for now.

In the final section we’ll put it all together to create the final widget.

Extending the Shortcode

Once this is done we can get crazy with our shortcode parameters. One example is allowing the user to pick a scheme. For our example, this is dark or light, but you could easily specify an exact color.

All we need to do is add an argument to the shortcode, add a CSS class to our widget based on this argument and let our style sheet do the rest.

add_shortcode( 'widget', 'my_widget_shortcode' );

function my_widget_shortcode( $atts ) {

// Configure defaults and extract the attributes into variables
extract( shortcode_atts( 
	array( 
		'type'   => '',
		'title'  => '',
		'scheme' => 'light'
	), 
	$atts 
));

$args = array(
	'before_widget' => '<div class="box widget scheme-' . $scheme . ' ">',
	'after_widget'  => '</div>',
	'before_title'  => '<div class="widget-title">',
	'after_title'   => '</div>',
);

ob_start();
the_widget( $type, $atts, $args ); 
$output = ob_get_clean();

return $output;

If you need to make this even more flexible, you can allow a background color to be specified, you can add the $args using parameters from the shortcode, and much more.

This solution works perfectly with custom widgets as well. All you need to do is add the class name as the type and accommodate for its specific instance settings

Conclusion

By now you should be on your way to creating wonderful things with this shortcode. It is great for end users and also a very useful tool to test widgets before releasing a theme.

We use this in our themes to make them even more flexible for our users. The ability to put anything anywhere, easily, is one that all themes should have!

(cp)

↑ Back to top

The Smashing Team loves high-quality content and cares about little details. Through our online articles, books and eBooks and Smashing Conferences, we are committed to stimulating creativity and strengthening the Web design community’s creative forces.

  1. 1

    I have been using this method with my plugins for quite some time.
    I generally set the $args before_* and after_* values to ” (null) as one cannot know the styles being using in every theme where the plugin might be installed. Obviously this does not apply to one-off implementations just something to consider.

    0
  2. 2

    Andy @ Tadpole.cc

    December 11, 2012 8:11 am

    That’s pretty cool. I could even see adding an “Add/Insert Widget ” UI to the post edit page so users could select which widget they want and its parameters.

    0
  3. 3

    Brent Christensen

    December 11, 2012 8:21 am

    Nice. Simple. Me Likey.

    0
  4. 4

    Thanks for this. I have recently been building a lot of WordPress themes for work, friends, and some non-profits and this can surely be a powerful tool.

    0
  5. 5

    The problem with shortcodes is that you are marking up your posts with a lot of plugin specific content. The second you remove that plugin, you have a lot of ugly short code text that most likely aren’t going to be replaced by another plugin.

    It would be much more useful if WordPress could auto-remove/auto-hide them, and there was a standard for the types of shortcodes plugin developers use. That way I could have a single short code used by Plugin X or Y with similar intentions, but different implementations.

    0
    • 6

      You’re right, leftover shortcodes could be a concern. It shouldn’t be too hard for a developer to create a plugin that replaces the stale shortcodes with empty output:

      add_shortcode( ‘oldshortcode’, ‘__return_false’ );

      0
    • 7

      I’d like to clarify that I do believe short codes are a truly useful feature in WordPress. They allow you to insert complex media into a post that you might not be able to add in any other way.

      My point was that they are imperfect, and are not backwards compatible. If you intend on making short codes, or creating a site that utilizes them, you need to realize this and only use them when it truly makes sense.

      0
  6. 8

    I agree with Tyler Carter.
    The logic of the website should not be part of the common website content.

    Shortcodes are grate for small projects, especially when the editor is less skilled. But on larger projects (more serious) it will just mess up the content. When you let editors use what ever shortcode they want – quote: “It enables the end user to create intricate elements..” the programmer has “no” chance to keep the site in order. It’s like tables in the content or external text formatting pasted from the Word editor.

    The Jeffs solution is even messier approach. If you build a website where you plan to use hook over the hook over the hook over the hook :) for no real reason.. I don’t think it will be long lasting.

    I think the article is not generally bad. It shows yet another possibility how to play with WordPress. But It should stay in the concept level only.

    0
  7. 9

    Great stuff Daniel. Never considered implementing this in themes I’ve previously built but will be trying to work it into some new ones maybe. I’ve always stayed clear of shortcodes because of the reasons already mentioned. Might be good to use this with do_shortcode() and custom widgets in template files rather than creating dynamic sidebars to add content.
    Thanks ;)

    0
  8. 10

    Another option is to simply add a widget area whereever you like.

    This way you can drag any widget into this widget area without any need to add code or plugins.

    0
  9. 11

    Can the_widget(); be used to output anything other than the native widgets?

    0

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top