Here we’ll cover creating a dynamic widget: one that accepts, formats, and displays user input.
Today we’re continuing David’s discussion of widgets from a few weeks ago. In his post, David covered how to make a static widget: one that displays, say, a predefined block of images and text, or today’s date, but without input or customization by the user.
Here we’ll be covering creating a user-editable widget, which takes user input, formats it, and displays it. This would let you create, for example, a “social media widget” that lets the user choose some number of social media buttons to display, and to provide the relevant URLs for each button to link to. More generally, just about any truly useful widget is going to need some amount of user input.
To follow along, it’ll help if you’ve read David’s earlier piece. More generally, you’ll need basic knowledge of PHP functions, and of the principles of object-oriented programming (OOP) such as classes, objects, and inheritance. Let’s get started!
Our Widget Should Go in a Plugin
I recommend you register your custom widgets in one or more separate plugins. Otherwise, when you switch themes, you’ll lose your widgets.
First things first: Where’s the code for this widget going to go? Two obvious candidates exist: a custom plugin, and the functions.php
file of the active theme.
I recommend you register your custom widgets in one or more separate plugins. Otherwise, when you switch themes, you’ll lose your widgets—which you definitely don’t want if they’re doing important stuff like serving a custom nav menu, a bunch of “buy now” buttons, etc. As we’ve argued recently, functions.php
should confine itself to presentational (meaning, broadly, “visual”) functions that relate to the particular theme they’re part of. To do otherwise smells of theme creep.
The Goal: A “Now Listening” Widget With a Working Audio Player
Let’s say we’re running a music blog, and we’d like to add a “Now Listening” widget that gives the title of our current favorite song, plus a working HTML5 audio player to play the song itself, right from the widget.
Dynamic Data We’ll Need
We’ll need to make the widget accept two pieces of dynamic data:
- A text field describing the song (artist, song title, date, etc.).
- A link to an MP3 file of the song, which we’ll use for both the audio player and a download link.
How the Finished Product Should Look
The widget should take the two pieces of dynamic data listed above:
And it should display them on the front end with a working HTML5 audio player and a download link:
Our Starting Point: A Static Widget
So we’ve figured out that we’re writing a plugin, and we’ve followed David’s advice on basic widget setup. That gets us something like this:
<?php
/*
Plugin Name: WPShout Test Widget
Description: A plugin to make a test tutorial widget
Version: 1.0
Author: WPShout
Author URI: https://wpshout.com/
*/
function wpshout_register_widgets() {
register_widget( 'WPShout_Favorite_Song_Widget');
}
add_action( 'widgets_init', 'wpshout_register_widgets' );
class WPShout_Favorite_Song_Widget extends WP_Widget {
function WPShout_Favorite_Song_Widget() {
// Instantiate the parent object
parent::__construct(
'wpshout_favorite_song_widget', // Base ID
__('WPShout Favorite Song Widget', 'text_domain'), // Name
array( 'description' => __( 'Widget for playable favorite song', 'text_domain' ), ) // Args
);
}
function widget( $args, $instance ) {
echo 'I am some static text...';
}
}
Creating the Plugin
If the “creating a plugin” side of this process is confusing to you, please check out David’s tutorial on creating WordPress plugins.
Briefly, here’s the process:
- Create an appropriately named plugin folder, say
wpshout-test-widget
. - Save the code above as a PHP file inside that folder, again with an appropriate filename, say
wpshout-test-widget.php
. - Upload that folder to your
plugins
directory insidewp-content
, and the new plugin will show up in your list of installed plugins. - Activate the new plugin.
You should now have a new widget (with name “WPShout Favorite Song Widget” and description “Widget for playable favorite song”) in the list of widgets in “Appearance -> Widgets.” You can place it anywhere inside a widget area and it’ll output the following: “I am some static text…”
Let’s Make it Dynamic
form()
: Where the Magic Happens
We make our widget dynamic by adding user-editable form fields.
WordPress widgets allow for user input in the usual way: with HTML form elements like input
s and textarea
s. So to make our widget dynamic, we basically need to make it contain form fields that allow the user to input his or her audio link and text description.
There’s a specific way to do this inside the WP_Widget
class. It’s a method (OOP-speak for “function”) called form()
, and in our case it looks like this:
// Widget form creation
function form($instance) {
$link = '';
$songinfo = '';
// Check values
if( $instance) {
$link = esc_attr($instance['link']);
$songinfo = esc_textarea($instance['songinfo']);
} ?>
<p>
<label for="<?php echo $this->get_field_id('link'); ?>"><?php _e('Link', 'wp_widget_plugin'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('link'); ?>" name="<?php echo $this->get_field_name('link'); ?>" type="text" value="<?php echo $link; ?>" />
</p>
<p>
<label for="<?php echo $this->get_field_id('songinfo'); ?>"><?php _e('Song Info:', 'wp_widget_plugin'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('songinfo'); ?>" name="<?php echo $this->get_field_name('songinfo'); ?>" type="text" value="<?php echo $songinfo; ?>" />
</p>
<?php }
Our Variables: $link
, $songinfo
, and $instance
That looks complicated, but there are really two main things we’re interested in: a $songinfo
variable, and an HTML input
element to let the user set it; and a $link
variable, and an input
to let the user set it.
You’ll also notice an $instance
variable, passed into the form()
method as its only argument. $instance
basically means “What stuff is stored”—it’s an array of the current values (for things like “link” and “songinfo”) that the widget has, and which we’ll be using our input
s to both display and update.
So what we’re doing here is, for starters, setting $link
and $songinfo
to their initial values—that is, their values in the current widget instance that’s been passed in as $instance
. That’s what the code up through the section labeled “Check values” does for us.
The Form Itself
Next comes the section that’s written largely in plain HTML. Here, we’re creating elements that should be familiar from HTML forms: input
elements to both display and change form values, and label
elements to say what each form field is for.
The most important pieces of the code above are the name
and value
properties of each input
element. As with any HTML form, the name
property says which variable we’re changing, and the value
property captures both what the variable’s value is at present and what we’ll be changing it to.
We’re setting both these names and value
s to PHP variables. For songinfo
, for example, we set name
to a value we retrieve with: <?php echo $this->get_field_name('songinfo'); ?>
, and we set value
to the $songinfo
variable itself.
Some Tips for Understanding form()
The code probably looks pretty ugly, especially if you don’t know what the _e()
function does. To help you traverse the code, here are two tips:
- If you simply name the
get_field_id
andget_field_name
calls consistently with the PHP variable name in that part of the form—for example,get_field_id('songinfo')
andvalue="<?php echo $songinfo; ?>"
—then you don’t have to think too deeply about the relationships there. It becomes boilerplate. - The _e() function just lets you substitute text in different namespaces, like if you wanted to make a Polish version of the plugin. If you’re not sure about it, simply edit the first argument and don’t worry too much about the second. And if you’d prefer more simplicity (and are certain that the plugin won’t ever be internationalized), you can simply replace the whole function with a string value: <?php _e(‘Link’, ‘wp_widget_plugin’); ?> would just become “Link”.
form()
is the most complicated piece of the exercise, so take a bit of time to fiddle with it if you’re not yet seeing how it fits together.
update()
: Some Necessary Boilerplate
Because of the way the widget API is written, we’ll also need a method to actually tell the widget to update itself—or, to use the language we introduced above, to change its instance data.
That code looks like this:
function update($new_instance, $old_instance) {
$instance = $old_instance;
// Fields
$instance['link'] = strip_tags($new_instance['link']);
$instance['songinfo'] = strip_tags($new_instance['songinfo']);
return $instance;
}
This method takes two parameters: $new_instance
, which will be loaded with the new values from the form()
method described above, and $old_instance
, which still contains the previous values, before our most recent form save.
All we’re doing here is setting each element of the $instance
array to its new value (while doing a bit of simple form validation with the strip_tags()
function, just in case the user uploaded anything dangerous).
In practical terms, you just need to remember to create one line like the two lines under “// Fields” above for every dynamic value you have in your form. So if you’ve added a songyear
variable in form()
, you’d add this line in update()
:
$instance['songyear'] = strip_tags($new_instance['songyear']);
Once we’re done defining new values for the $instance
array, we just return
the updated array, and the WP_Widget code does the rest of the updating process on its own.
widget()
: The Fun Part
Now that we’ve defined the values of our link
and songinfo
variables, we’re ready to actually use those variables to display dynamic content on our site. As you know from the static widget we built above, we write widgets to the page with the widget()
method. That method now looks like this:
function widget( $args, $instance ) {
echo $args['before_widget'];
echo '<h2>Now Listening:</h2>';
echo $instance['songinfo'];
echo
'<p>
<audio controls>
<source src="' . $instance['link'] . '" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<a href="' . $instance['link'] . '">Download it</a>
</p>';
echo $args['after_widget'];
}
As you see, widget()
continues to take two arguments: $args
and $instance
. The most important is $instance
, which is still the array that contains our dynamic values.
What we’re doing in the code above is printing out, using PHP’s echo
, the contents of the widget. We’re including the properties of our $instance
variable where they belong:
$instance['songinfo']
is included in text just after the widget’s title.$instance['link']
is included in two places: as the URL of the<audio>
element that will play the audio file in the widget, and as the URL of the link element that lets you download the MP3 itself.
We’re also printing out both $args['before_widget']
and $args['after_widget']
. WordPress uses these to wrap each of a widget area’s widgets in consistent formatting—for example <li id="wpshout_favorite_song-2" class="widget widget_wpshout_favorite_song"> ... </li>
. This part is optional, but you’ll want it to make widgets contained and easy to consistently style.
How the Whole Thing Looks
Okay, ready?
<?php
/*
Plugin Name: WPShout Test Widget
Description: A plugin to make a test tutorial widget
Version: 1.0
Author: WPShout
Author URI: https://wpshout.com/
*/
function wpshout_register_widgets() {
register_widget( 'WPShout_Favorite_Song_Widget');
}
add_action( 'widgets_init', 'wpshout_register_widgets' );
class WPShout_Favorite_Song_Widget extends WP_Widget {
function WPShout_Favorite_Song_Widget() {
// Instantiate the parent object
parent::__construct(
'wpshout_favorite_song_widget', // Base ID
__('WPShout Favorite Song Widget', 'text_domain'), // Name
array( 'description' => __( 'Widget for playable favorite song', 'text_domain' ), ) // Args
);
}
function widget( $args, $instance ) {
echo $args['before_widget'];
echo '<h2>Now Listening:</h2>';
echo $instance['songinfo'];
echo
'<p>
<audio controls>
<source src="' . $instance['link'] . '" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<a href="' . $instance['link'] . '">Download it</a>
</p>';
echo $args['after_widget'];
}
function update($new_instance, $old_instance) {
$instance = $old_instance;
// Fields
$instance['link'] = strip_tags($new_instance['link']);
$instance['songinfo'] = strip_tags($new_instance['songinfo']);
return $instance;
}
// Widget form creation
function form($instance) {
$link = '';
$songinfo = '';
// Check values
if( $instance) {
$link = esc_attr($instance['link']);
$songinfo = esc_textarea($instance['songinfo']);
} ?>
<p>
<label for="<?php echo $this->get_field_id('link'); ?>"><?php _e('Link', 'wp_widget_plugin'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('link'); ?>" name="<?php echo $this->get_field_name('link'); ?>" type="text" value="<?php echo $link; ?>" />
</p>
<p>
<label for="<?php echo $this->get_field_id('songinfo'); ?>"><?php _e('Song Info:', 'wp_widget_plugin'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('songinfo'); ?>" name="<?php echo $this->get_field_name('songinfo'); ?>" type="text" value="<?php echo $songinfo; ?>" />
</p>
<?php }
}
And viola! We’ve got a plugin that instantiates a new WP_Widget
subclass, and defines its widget()
, update()
, and form()
methods in the way we need for our “Now Listening” widget object to work.
In Conclusion…
For a complete plugin, you’d likely want to give the widget some styling (using a CSS file, also inside the plugin, that you enqueue
d in the main PHP file).
And, of course, there’s lots you could do to make this plugin better if you intended to release it to the public at large. For example, how about being able to choose your audio file by browsing for it in the WordPress Media Uploader? (Curious how you’d do that? Here’s a great tutorial.)
But I hope this gives you a general sense of how the form()
and update()
methods work, and sparks your imagination about how to make widgets do what you need.
Thanks for reading, and if you have any questions or comments we’d love to hear them!
[…] Check Tutorial Here […]
good something intresting i will go on the top to read and applicate this tuto on my theme
[…] nor how to make them for yourself (we did cover that one before, with the basics and a guide to user-editable ones). Nope, here we’ll explain how you make areas appear in your theme where your end-user can […]