Wordpress

Widgetizing a WordPress Plugin: Example Widget Code

March 22, 2009   ·   By   ·   13 Comments   ·   Posted in Wordpress, Writing Plugins

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…

Tell WordPress Your Widget Exists

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 = ”)

  • $name – The widgets name.  Displayed as the title of the widget on the widget page.
  • $output_callback – Function called to actually display the widget for the user on the frontend.
  • $classname – Sets the class of the widget on the frontend.  Useful for styling specific widgets with CSS.  Ends up defaulting to $output_callback, which is generally just as useful.

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 = ”)

  • $name – Again, this is the widgets name.  It’s important to make sure that the name entered here matches the name you used in register_sidebar_widget – it appears that this string is the only thing that connects them (see what I did there?).  If you can’t figure out why your widget wont stop saying “There are no options for this widget.”, check here first.
  • $control_callback – This is the function we’ll use to display the options, as well as update any values we need to change based on the user’s input on the admin side.  This function contains code for any the face time your widget will get on the back end.
  • $width – An interesting tidbit – I didnt know this (or height) existed before I had a look in the widgets source code.  Setting a width value will expand (but not shrink) the width of your widget options box.  Great if your widget needs a particularly wide control box for entering blocks of text, or something similar.
  • $height – Same as width (well, not exacty the same.  Im assuming you’ve figured out what this one does).
widewidget

A particularly wide widget. Make them as wide as you like with the width parameter.

Creating a configuration box

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
?&gt;
<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>
}

Displaying your widget

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
)

picture-2The 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!

Example Plugin Source

WordPress magazine theme

13 Comments
  1. 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

    • Hey Callum – I’m glad to hear I wasn’t the only one having trouble with widgets. Good luck!

      • … so that’s my plugin updated with support for widgets with many thanks to you. Took only an hour or so after i discovered your post- although I’ve been hacking away at other’s templates since 8PM last night! grr.

        Great stuff! only issue is with edited titles… If a user adds a new / altered title it appears in the WordPress dashboard as Plugin Name: New Plugin Name. No big problem, it could be quite useful… but doesn’t sit right with me.

      • Glad the post could help – I haven’t had a chance to download your plugin yet, but I’ll have a look!

        As for the widget title issue – I started to say that if we just renamed that variable, WordPress might not recognize it as the “title”, but now I’m really intrigued as to how WordPress figured that out in the first place. Sounds like its time for a trip to the core files..

  2. [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!?

    • I agree Callum – I’m not sure why I chose init in the first place, but widgets_init definitely sounds like the right choice. I’ve updated the sample code with that, as well as removing all the serialize/unserialize calls – I found out a few days later that these are harmless, but unnecessary.

      Thanks for the insight Callum!

  3. Derek

    Hey, really good walkthough and example. Helped me a lot, thanks!

  4. Thanks for your Good Tutorial on WP Widget

  5. Christian

    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!!!

  6. Christian

    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

  7. Janka

    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 …

  8. 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?

Submit a Comment