So, every time I need to write a widget for a client, or for a site I’m working on, I have to fire up google. Even though its something I do relatively often, I just can’t seem to remember what exactly I need to hook into, and how to build the actual widget function. Fortunately, this information is impossible to find all in one place – you’ve got Automattic’s page on widgetizing plugins, which is not just confusing, but the code is actually wrong, and won’t work.
Most of the other sample code I’ve found on how to write a widget for your wordpress plugin is either outdated, or not explained, making it pretty difficult to write and customize your own.
First things first – if you really want to know how this all works, check out the source. Its the best place to figure out what is going on. WordPress widgets source
For my own good as much as yours, here’s the skinny:
First things first – the copypasta edition:
<?php
/*
Plugin Name: Widget Example
Plugin URI: http://yourcodegarage.com/blog
Description: Sample Widget Code
Author: Peter Butler
Author URI: http://yourcodegarage.com/blog/
*/
// Hook into wordpress at the "widgets_init" stage. We need this to get things going.
// We're calling mywidget_init, which will register the widget with wordpress.
add_action("widgets_init", "mywidget_init");
// This is our init function - it's going to register our new widget,
// and if we so please, create a control for it.
function mywidget_init()
{
// This line is required - it cactually registers the widget for use on
// the widgets admin page, and it contains the code to display on the
// front end when the widget is enabled.
register_sidebar_widget('My Custom Widget', 'custom_widget');
register_widget_control('My Custom Widget', 'custom_widget_control', '500', '500');
}
// This is the function called by register_sidebar_widget.
// This is where the action happens - WordPress calls this function to actually display
// the widget in the dynamic sidebar on the front end.
// Note the $args parameter - this is required for the sidebar variables
// ($before_widget, etc) to work properly!
function custom_widget($args) {
// Make sure to extract $args.
extract($args);
// Get the options we set in the widget control (remove this line if there arent any).
$custom_widget_options = get_option('custom_widget_options');
?>
<?php
//echo the html that should display before the widget as set by register_sidebar().
echo $before_widget;
?>
<?php echo $before_title;?>
<?php echo $custom_widget_options['title']; ?>
<?php echo $after_title; ?>
<?php echo $custom_widget_options['text']; ?>
<?php echo $after_widget; ?>
<?php
}
// This is the callback function for our widgets control -
// here we'll keep the code to allow the user to set the widget options.
function custom_widget_control() {
// Check if the option for this widget exists - if it doesnt, set some default values
// and create the option.
if(!get_option('custom_widget_options'))
{
add_option('custom_widget_options', array('title'=>'Custom Text Widget', 'text'=>'This the widget text'));
}
$custom_widget_options = $custom_widget_newoptions = get_option('custom_widget_options');
// Check if new widget options have been posted from the form below -
// if they have, we'll update the option values.
if ($_POST['custom_widget_title']){
$custom_widget_newoptions['title'] = $_POST['custom_widget_title'];
}
if ($_POST['custom_widget_text']){
$custom_widget_newoptions['text'] = $_POST['custom_widget_text'];
}
if($custom_widget_options != $custom_widget_newoptions){
$custom_widget_options = $custom_widget_newoptions;
update_option('custom_widget_options', $custom_widget_options);
}
// Display html for widget form
?>
<p>
<label for="custom_widget_title">Title:<br />
<input
id="custom_widget_title"
name="custom_widget_title"
type="text"
value="<?php echo $custom_widget_options['title']; ?>"/>
</label>
</p>
<p>
<label for="custom_widget_text">Text:<br />
<textarea rows=10 cols=25
id="custom_widget_text"
name="custom_widget_text" ><?php echo $custom_widget_options['text']; ?></textarea>
</label>
</p>
<?php
}
Download the example plugin here
It’s commented fairly well, so that should be a good starting point. For those of you who want a little more explanation, read on…
First things first – we need wordpress to see that our widget is out there just waiting to be implemented. To accomplish this, we’ll hook into the widgets_init action like this:
add_action("widgets_init", "mywidget_init");
Now, when wordpress calls the widgets_init action, our widget initiation function (mywidget_init()) will get called. Read more about actions here.
The function mywidget_init is our callback function in that particular action. When this function gets called, we want to register our widget, as well as our widget control – like this:
function mywidget_init()
{
register_sidebar_widget('My Custom Widget', 'custom_widget');
register_widget_control('My Custom Widget', 'custom_widget_control');
}
The first line registers the widget with wordpress – we’re calling the wordpress function register_sidebar_widget(), which takes these parameters:
function register_sidebar_widget($name, $output_callback, $classname = ”)
The second line registers our widget control. The widget control function will be what allows the user to change any options for the widget on the widgets page on the backend. Here’s a closer look at the register_widget_control() function:
function register_widget_control($name, $control_callback, $width = ”, $height = ”)
Now we’re ready to create our configuration box for the widget – this is what will be displayed on the backend, and allow the user to choose any options you make available. We’ll be using the function we specified in register_widget_control() – custom_widget_control().
To briefly run through this function:
if(!get_option('custom_widget_options'))
{
add_option('custom_widget_options', array('title'=>'Custom Text Widget', 'text'=>'This the widget text'));
}
$custom_widget_options = $custom_widget_newoptions = get_option('custom_widget_options');
First, we get the option we’re going to use to store the configuration infomation for this widget. If it doesnt exist (meaning that this is the first time the widget code has been run, so our plugin has likely just been installed), we’ll create it with some default values. I like to try to keep all the configuration values stored in just one option field, so I prefer to put multiple variables into an array, and serialize them for storage in the database (update – wordpress handles the serializing/unserializing for you with the function maybe_serialize. Read more about it here.)
if ($_POST['custom_widget_title']){
$custom_widget_newoptions['title'] = $_POST['custom_widget_title'];
}
if ($_POST['custom_widget_text']){
$custom_widget_newoptions['text'] = $_POST['custom_widget_text'];
}
if($custom_widget_options != $custom_widget_newoptions){
$custom_widget_options = $custom_widget_newoptions;
update_option('custom_widget_options', $custom_widget_options);
}
Next, we check if values have been posted from the widget configuration form (which we’ll create in a minute). If the values we’re looking for have been posted, we know the user is updating the widget, so we update our wordpress option with the new values.
<p> <label for="custom_widget_title">Title:<br /> <input id="custom_widget_title" name="custom_widget_title" type="text" value="<?php echo $custom_widget_options['title']; ?>"/> </label> </p> <p> <label for="custom_widget_text">Text:<br /> <textarea rows=10 cols=25 id="custom_widget_text" name="custom_widget_text" ><?php echo $custom_widget_options['text']; ?></textarea> </label> </p>
Lastly, we display the actual html form for the widget configuration, making sure to display the values from our option. Putting it all together, here is the function:
function custom_widget_control() {
// Check if the option for this widget exists - if it doesn't, set some default values
// and create the option.
if(!get_option('custom_widget_options'))
{
add_option('custom_widget_options', array('title'=>'Custom Text Widget', 'text'=>'This the widget text'));
}
$custom_widget_options = $custom_widget_newoptions = get_option('custom_widget_options');
// Check if new widget options have been posted from the form below -
// if they have, we'll update the option values.
if ($_POST['custom_widget_title']){
$custom_widget_newoptions['title'] = $_POST['custom_widget_title'];
}
if ($_POST['custom_widget_text']){
$custom_widget_newoptions['text'] = $_POST['custom_widget_text'];
}
if($custom_widget_options != $custom_widget_newoptions){
$custom_widget_options = $custom_widget_newoptions;
update_option('custom_widget_options', $custom_widget_options);
}
// Display html for widget form
?>
<p>
<label for="custom_widget_title">Title:<br />
<input
id="custom_widget_title"
name="custom_widget_title"
type="text"
value="<?php echo $custom_widget_options['title']; ?>"/>
</label>
</p>
<p>
<label for="custom_widget_text">Text:<br />
<textarea rows=10 cols=25
id="custom_widget_text"
name="custom_widget_text" ><?php echo $custom_widget_options['text']; ?></textarea>
</label>
</p>
}
Lastly, we’ve got to display the widget. We’ll need to use the function we called from register_sidebar_widget(), in this case custom_widget.
The first thing we need to make sure of is that we pass in, and extract the variable $args, like this:
function custom_widget($args) {
// Make sure to extract $args.
extract($args);
The widget will display without passing in args, but its necessary, because this is what holds some vital information for our widget. In this particular example, $args holds this information:
Array ( [name] => Right Sidebar [id] => Right Sidebar [before_widget] => <li id="my-custom-widget" class="widget custom_widget"> [after_widget] =></li> [before_title] => <h3 class="widgettitle">[after_title] =></h3> [widget_id] => my-custom-widget [widget_name] => My Custom Widget )
The most important bits that $args holds are the sidebar variables – before_widget, after_widget, before_title, and after_title. Without these, the widget isnt going to display properly. I’ve wasted countless hours (on multiple occasions) trying to figure out why my widget isnt displaying correctly, only to realize that I forgot to pass $args in.
Next, we set up the variables the widget needs to use to display – again, we’ve got them in an array, which is serialized and held in the wp_options database table. To access it, we use get_option(option name).
$custom_widget_options = get_option('custom_widget_options');
Now, it’s just a matter of displaying whatever the widget was intended to display – simple html and php will do the trick here. Make sure to echo $before_widget and $after_widget surrounding the actual content, and $before_title and $after_title surrounding the title. Doing so keeps your widget’s styling in line with the rest of the sidebar.
<?php echo $before_widget;?> <?php echo $before_title;?> <?php echo $custom_widget_options['title']; ?> <?php echo $after_title; ?> <?php echo $custom_widget_options['text']; ?> <?php echo $after_widget; ?>
Putting it all together, here is the widget output function:
function mywidget_init()
{
// This line is required - it cactually registers the widget for use on
// the widgets admin page, and it contains the code to display on the
// front end when the widget is enabled.
register_sidebar_widget('My Custom Widget', 'custom_widget');
register_widget_control('My Custom Widget', 'custom_widget_control', '500', '500');
}
// This is the function called by register_sidebar_widget.
// This is where the action happens - WordPress calls this function to actually display
// the widget in the dynamic sidebar on the front end.
// Note the $args parameter - this is required for the sidebar variables
// ($before_widget, etc) to work properly!
function custom_widget($args) {
// Make sure to extract $args.
extract($args);
// Get the options we set in the widget control (remove this line if there arent any).
$custom_widget_options = get_option('custom_widget_options');
?>
<?php
//echo the html that should display before the widget as set by register_sidebar().
echo $before_widget;
?>
<?php echo $before_title;?>
<?php echo $custom_widget_options['title']; ?>
<?php echo $after_title; ?>
<?php echo $custom_widget_options['text']; ?>
<?php echo $after_widget; ?>
<?php
}
And that’s it! Your widget is ready for action. Now get out there and make a widget!
[sorry to spam]
But– you might want to change:
add_action("init", "mywidget_init");
to
add_action("widgets_init", "mywidget_init");
if the widget / plugin is running from the same file (myplugin.php) the first init is called and works, the second causes confusion, an error and finally a non-working plugin! it could be specific to my setup, but widgets_init sounds like its meant for the job!?
Hey, really good walkthough and example. Helped me a lot, thanks!
Thanks for your Good Tutorial on WP Widget
Hello Peter,
thank you very much for that great tutorial! I was digging through several other tuts which where either outdated or quite confusing – your tutorial gave me a quick start in creating a first widget.
Thanks a lot!!!
Me again – just a short question:
Would it be easy possible to have the entered content deleted if the widget is dropped again back to the “Available Widgets” area and just kept if one drag it into the “Inactive Widget” area?
Kind regards,
Christian
Can you explain how to show a description for the widget inactive?
When the widget is inactive,
I see:
My Custom Widget
My Custom Widget
I’d like to be able to bring up:
My Custom Widget
This Widget is for …
Good Platform to learn plugin for beginners.
I have a question, i am not able to style the widget taking use inputted background – border color.
Can you plz help me out?
April 18, 2009
invaluable: i can’t say better than that. this is a thorough and exact tutorial- unlike the 20 others i’ve read and broken my patience with in the last 12 hours. thank you, keep it up.
oh yeah, its appalling yet sadly true- the code on Automattic’s site doesn’t even produce a widget. all that CSS management, high google ranking *whistles and bells* and the guy’s tutorial produces nothing close to a working widget.
- Callum