Quick Tip: How to Use Shortcodes Within Widgets in WordPress
We can do a lot of different things with shortcodes in WordPress, as we explored in our article describing the WordPress Shortcode API. However, by default, WordPress only allows the use of shortcodes in posts (and pages), and not anywhere else.
If you want to use shortcodes in widgets, it’s not possible by default. However, in this quick tip, I’ll cover how you can enable this functionality.
Allowing the Use of Shortcodes in the Text Widget
WordPress provides several widgets by default. One of them is the ‘Text’ widget, which, as its name suggests, allows you to add any text to a widget. You can also use it to add any HTML code.
That means that you can also play with JavaScript code in this widget, so it’s pretty powerful. However, if you need more, like a PHP script to access some data stored in the server, this widget won’t help you by default.
It’s similar to a post. That’s why, like in a post, we would like to be able to use shortcodes to do anything we want. To do that, we can use the widget_text
filter. This filter is called to allow modifications in the content of a ‘Text’ widget. We’ll use it here to ask WordPress to parse shortcodes in this widget.
Parsing shortcodes in WordPress is achieved thanks to the do_shortcode()
function. It accepts one required parameter, the text to parse, and it returns the parsed text. That means that we can directly use this function as a callback function in the widget_text
filter.
The code below can be used in a plugin file or in the functions.php
file of your theme.
<?php
add_filter('widget_text', 'do_shortcode');
?>
And we’re done. Now, any existing shortcode you type in the ‘Text’ widget will be parsed.
Creating a New Shortcodes Widget
Alternatively, we can also create our own widget. As the default ‘Text’ widget works perfectly, we can simply adapt its code from the following (found in the /wp-includes/default-widgets.php
file). It’s worth noting that we should create our own plugin, never modify core WordPress files.
<?php
class WP_Widget_Text extends WP_Widget {
public function __construct() {
$widget_ops = array('classname' => 'widget_text', 'description' => __('Arbitrary text or HTML.'));
$control_ops = array('width' => 400, 'height' => 350);
parent::__construct('text', __('Text'), $widget_ops, $control_ops);
}
/**
* @param array $args
* @param array $instance
*/
public function widget( $args, $instance ) {
/** This filter is documented in wp-includes/default-widgets.php */
$title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base );
/**
* Filter the content of the Text widget.
*
* @since 2.3.0
*
* @param string $widget_text The widget content.
* @param WP_Widget $instance WP_Widget instance.
*/
$text = apply_filters( 'widget_text', empty( $instance['text'] ) ? '' : $instance['text'], $instance );
echo $args['before_widget'];
if ( ! empty( $title ) ) {
echo $args['before_title'] . $title . $args['after_title'];
} ?>
<div class="textwidget"><?php echo !empty( $instance['filter'] ) ? wpautop( $text ) : $text; ?></div>
<?php
echo $args['after_widget'];
}
/**
* @param array $new_instance
* @param array $old_instance
* @return array
*/
public function update( $new_instance, $old_instance ) {
$instance = $old_instance;
$instance['title'] = strip_tags($new_instance['title']);
if ( current_user_can('unfiltered_html') )
$instance['text'] = $new_instance['text'];
else
$instance['text'] = stripslashes( wp_filter_post_kses( addslashes($new_instance['text']) ) ); // wp_filter_post_kses() expects slashed
$instance['filter'] = ! empty( $new_instance['filter'] );
return $instance;
}
/**
* @param array $instance
*/
public function form( $instance ) {
$instance = wp_parse_args( (array) $instance, array( 'title' => '', 'text' => '' ) );
$title = strip_tags($instance['title']);
$text = esc_textarea($instance['text']);
?>
<p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" /></p>
<p><label for="<?php echo $this->get_field_id( 'text' ); ?>"><?php _e( 'Content:' ); ?></label>
<textarea class="widefat" rows="16" cols="20" id="<?php echo $this->get_field_id('text'); ?>" name="<?php echo $this->get_field_name('text'); ?>"><?php echo $text; ?></textarea></p>
<p><input id="<?php echo $this->get_field_id('filter'); ?>" name="<?php echo $this->get_field_name('filter'); ?>" type="checkbox" <?php checked(isset($instance['filter']) ? $instance['filter'] : 0); ?> /> <label for="<?php echo $this->get_field_id('filter'); ?>"><?php _e('Automatically add paragraphs'); ?></label></p>
<?php
}
}
?>
We don’t have a lot of details to change here. The first thing to change is the name of the class. I chose to name it WP_Widget_Shortcodes
but feel free to choose any name you want. As the constructor of this class sets some information about the widget itself, we also need to modify it.
<?php
public function __construct() {
$widget_ops = array('classname' => 'widget_shortcodes', 'description' => __('Arbitrary text or HTML with shortcodes.'));
$control_ops = array('width' => 400, 'height' => 350);
parent::__construct('shortcodes', __('Shortcodes'), $widget_ops, $control_ops);
}
?>
The other thing to change is in the widget()
method which describes to WordPress how to display the widget. We change the content of the $text
variable which contains the text to display. We remove the call to the widget_text
filter, and we apply the do_shortcode()
function to this content.
<?php
$text = empty( $instance['text'] ) ? '' : do_shortcode($instance['text']);
?>
We then need to register our widget, to be able to add it like any other widget. This can be achieved thanks to the widgets_init
action triggered once WordPress registered the default widgets.
<?php
add_action('widgets_init', function() {
register_widget('WP_Widget_Shortcodes');
});
?>
Now you can find our widget in the list of the available widgets. You can add it to any compatible zone, and it will interpret any shortcode you use.
Closing Words
As we saw above, enabling the use of shortcodes in widgets is not very complicated, but you need to be careful. In fact, not every shortcode will fit in the place where widgets are displayed. If the shortcode has a fixed width, that can be a problem.
Note that the changes we used in the default ‘Text’ widget are minimal. You can change anything else if you want to customize your widget. You can retrieve the filter we used and the widget we created in an example plugin available to download here if you’d like to experiment further.