Custom widgets are fantastic additions to all WordPress themes and plugins, and they are relatively easy to create, once you have the no how. This tutorial will walk you through the steps needed to create just about any kind of widget. I will show you how to create different option fields, how to save widget options, how to use options to control the output of your widget, and, at the end, I will give you the complete code to an advanced Blog Authors Widget.

The Widget Class

There are several ways to set up a widget, but by far the best method is to use a CLASS structure. By creating a PHP class for our widget, it makes it very easy to create as many widgets as you wish, without having to worry about conflicting function names. You can simply duplicate the code from your first widget, rename the class, and you’re done! So we are going to use a class for our example widget, and it starts like this:

	* Example Widget Class

class pippin_example_widget extends WP_Widget {

	// all of our widget code will go here


You can name the class anything you want, but I would advise you to be meaningful in your naming convention. “My Awesome Widget” really doesn’t tell you anything, even though it probably is awesome. I always go for names that explain the widget’s function, such as “blog_authors_widget”. It is also a good practice to always prefix your class names, just as you should prefix your function names. This is to help avoid the possibility of conflicts with other developer’s functions or class names. So our example widget class name is “pippin_example_widget”.

The Widget Functions

Now that we have our widget class, we will begin filling it with the various functions we need to construct our widget. There will be four functions total:

  • pippin_example_widget()
  • widget()
  • update()
  • form()

Notice that I have not prefixed these function names. This is because each of these functions lives within our widget class and thus do not need unique names or prefixes.

The Constructor Function

The first function we will write is pippin_example_widget(), and yes, it should be named the same as your widget class. This is a very simple, short function that constructs our widget and gives it a name.

001 /** constructor */
002     function pippin_example_widget() {
003         parent::WP_Widget(false, $name = 'Example Widget');
004     }

The only thing you should ever need to change with this function is the $name variable. This variable determines the name that appears on the widget in the admin widgets panel.

The Widget Output

Next comes the function that controls the widget’s output to the front end of the site. This function can contain just about anything you want, including HTML, CSS, jQuery, PHP, and more. Because this function does not have many set constraints on what you can do with it, I’m just going to show you examples of how you can use it.

First of all, our base function is going to look something like this:

001 /** @see WP_Widget::widget */
002     function widget($args, $instance) {
003         extract( $args );
005     // these are our widget options
006     $title = apply_filters('widget_title', $instance['title']);
007     $text = $instance['text'];
008     $checkbox = $instance['checkbox'];
009     $textarea = $instance['textarea'];
010     $select = $instance['select'];
012     echo $before_widget;
014     if ( $title ) {
015     echo $before_title . $title . $after_title;
016     }
017          echo $after_widget;
018     }

There are several important things going on here. First of all, the two parameters passed to the function are used to retrieve the saved options that we have set on the widget panel (don’t worry, we haven’t actually gotten there yet). These two parameters should never change, and nor should the extract($args) function call just after the opening }.

The next couple lines are the widget options. The options are all stored in the $instance parameter, which is an array, so I have set up a unique variable name for each option.

  • $title – This is the main widget title
  • $text – This is our sample text input field
  • $checkbox – This is our sample checkbox field
  • $textarea – This is our sample textarea field
  • $select – This is our sample select menu

Note that these options don’t actually work just yet, but we will set them up in a moment. For now just pretend that we’ve already taken care of them :)

The widget() function above as it is will do nothing more than display the widget title, so we are going to want to make it a little more advanced. I said earlier that you can do just about anything with this function that you want. That’s because it is the function that controls the output of our widget on the front end of the site. We are going to use our option (defined a moment ago) to control the exact output of the widget

001 /** @see WP_Widget::widget */
002     function widget($args, $instance) {
003         extract( $args );
005     // these are our widget options
006         $title = apply_filters('widget_title', $instance['title']);
007     $text = $instance['text'];
008     $checkbox = $instance['checkbox'];
009     $textarea = $instance['textarea'];
010     $select = $instance['select'];
012     echo $before_widget;
014     // if the title is set
015     if ( $title ) {
016     echo $before_title . $title . $after_title;
017     }
019     // if the text field is set
020     if ( $text ) {
021     echo '
022 <div class="widget-text">' . $text . '</div>
023 ';
024     }
026     // if the checkbox is checked
027     if ( $checkbox == true ) {
028     echo '
030 This message is displayed if our checkbox is checked.
032 ';
033     }
035     // if text is entered in the textarea
036     if ( $textarea ) {
037     echo '
038 <div class="widget-textarea">' . $textarea . '</div>
039 ';
040     }
042     // output text depended on which option is picked
043     if ( $select == 'one' ) {
044     echo '
046 Option One is Selected
048 ';
049     } else if ( $select == 'two' ) {
050     echo '
052 Option Two is Selected
054 ';
055     } else {
056     echo '
058 Option Three is Selected
060 ';
061     }
062          echo $after_widget;
063     }

What I have done is use the option values to control what is displayed. For example, I checked to see if the CHECKBOX field was checked (or had a value of TRUE), and if it was, display a message. I also displayed a different message for each SELECT menu option. These are all really, really simple examples but they convey a very important point: by utilizing your widget options (and a little bit of syntax) you can display anything you want inside of a widget.

While I have left the output to nothing more than simple text messages, you can just as easily use the options to control a post query, just as I did with my Better Recent Posts Widget.

Saving the Widget Options

The next function in our widget class is the update() function. This one does nothing more than save the options chosen from the widgets panel. It’s a very simple function.

001 /** @see WP_Widget::update */
002     function update($new_instance, $old_instance) {
003     $instance = $old_instance;
004     $instance['title'] = strip_tags($new_instance['title']);
005     $instance['text'] = strip_tags($new_instance['text']);
006     $instance['checkbox'] = strip_tags($new_instance['checkbox']);
007     $instance['textarea'] = strip_tags($new_instance['textarea']);
008     $instance['select'] = strip_tags($new_instance['select']);
009     return $instance;
010     }

Remember how I told you that the widget options were stored in an array variable called $instance? Well, this function takes two parameters, $old_instance which contains all the option values already saved, and $new_instance which contains all of the options that we have just updated. the function does nothing more than take the old instance and set each value in the array equal to the appropriate value in the new instance, thus saving our options

It is important to note that each of the instance variables matches those of the widget() function above. If your variable names do not match, your options will not save correctly.

There is only one more function to write, and that is the one that displays the widget options form in the widgets panel in the WordPress admin.

The Widget Options Form

Once again, there is nothing really special about this function, it simply outputs an HTML form with a field for each of our options. Let’s see the function, then I’ll explain parts of it.

001 /** @see WP_Widget::form */
002 function form($instance) { 
004     $title = esc_attr($instance['title']);
005     $text = esc_attr($instance['text']);
006     $checkbox = esc_attr($instance['checkbox']);
007     $textarea = esc_attr($instance['textarea']);
008     $select = esc_attr($instance['select']);
010     ?>
012      <p>
013         <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Widget Title'); ?></label>
014         <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text"value="<?php echo $title; ?>" />
015     </p>
017      <p>
018         <label for="<?php echo $this->get_field_id('text_field'); ?>"><?php _e('This is a single line text field:'); ?></label>
019         <input class="widefat" id="<?php echo $this->get_field_id('text_field'); ?>" name="<?php echo $this->get_field_name('text_field'); ?>"type="text" value="<?php echo $text_field; ?>" />
020     </p>
022     <p><
023         <input id="<?php echo $this->get_field_id('checkbox'); ?>" name="<?php echo $this->get_field_name('checkbox'); ?>" type="checkbox" value="1" <?php checked( '1', $checkbox ); ?>/>
024         <label for="<?php echo $this->get_field_id('checkbox'); ?>"><?php _e('This is a checkbox'); ?></label>
025     </p>
027     <p>
028         <label for="<?php echo $this->get_field_id('textarea'); ?>"><?php _e('This is a textarea:'); ?></label>
029         <textarea class="widefat" id="<?php echo $this->get_field_id('textarea'); ?>" name="<?php echo $this->get_field_name('textarea'); ?>"><?php echo $textarea; ?></textarea>
030     </p>
032     <p>
033         <label for="<?php echo $this->get_field_id('select'); ?>"><?php _e('This is a select menu'); ?></label>
034         <select name="<?php echo $this->get_field_name('select'); ?>" id="<?php echo $this->get_field_id('select'); ?>" class="widefat">
035             <?php
036             $options = array('one', 'two', 'three');
037             foreach ($options as $option) {
038                 echo '<option value="' . $option . '" id="' . $option . '"', $select == $option ? ' selected="selected"' : '', '>', $option, '</option>';
039             }
040             ?>
041         </select>
042     </p>
044     <?php
045 }

This function takes one $instance parameter, which allows our HTML form to read the saved options. The HTML form in this function is very straight forward, so if you have questions about it, please ask in the comments. I would like to explain how we connect each FORM field with its corresponding option, and how we ensure that the value entered (or selected) in each field is saved correctly.

There are several key functions used inside of this form() function:

  • $title – This is the main widget title
  • $text – This is our sample text input field
  • $checkbox – This is our sample checkbox field
  • $textarea – This is our sample textarea field
  • $select – This is our sample select menu

The first and second of these functions must match the option names at the top of this form() function, and also those of the option names used in the other functions. So, for example, for the TITLE option, we use $this->get_field_id(‘title’) and $this->get_field_name(‘title’). If these values do not match those of the other functions, your options will not save.

The only other part to the options form that might be a little confusing is the way that the SELECT field is set up. After we’ve done the normal field name and ID stuff, as described a moment ago, we use a FOREACH loop to display the options available in this SELECT menu. We use the foreach loop because we need to have a way of making the saved option as the selected option when we load the page, and because it is much more efficient than simply writing out each option. In order to mark the correct option as selected when the page loads, we use the conditional that looks like this:

001 foreach ($options as $option) {
002     echo '&lt;option value="' . $option . '" id="' . $option . '"', $select == $option ? ' selected="selected"' : '', '&lt;', $option, '&lt;/option&lt;';
003 }

This essentially says: display the option value and id, and if it matches the value of the option saved in the database (remember our $instance variable), include the selected=”selected” attribute.

And that’s it for our widget options form. This also marks the end of our widget class, which means that there is only one more step before our widget is available to use in WordPress.

Activating the Widget

Our widget is built, it’s options can be saved, and all we need to do is turn it on. To do that, we use the add_action() function to hook our widget into WordPress.

001 // register example widget
002     add_action('widgets_init', create_function('', 'return register_widget("pippin_example_widget");'));

This hook will register our widget and make it available for use. Note that the parameter passed to the register_widget() function inside of the hook is the same as our widget class name. If you use a different value than the name of your widget class, the widget will not work.

That’s everything! Keep reading below to see the complete code for an actually useful widget that you can use to display your blog authors.

Simple Blog Authors Widget

To help provide “real world” sense to this tutorial, I’m providing the code for a complete widget that will provide a simple widget that can be used to list your blog authors. The widget includes options for:

  • Widget Title
  • Author Gravatars
  • Author Post Counts

I’m not going to explain the code, as hopefully I’ve done that well enough above. If you want, simply copy the code below into your functions.php, or go to Pippin’s Plugins and download the complete widget as a plugin for free.

The widget code:

001 /**
002  * Authors Widget Class
003  */
004 class pippin_simple_authors_widget extends WP_Widget {
006     /** constructor */
007     function pippin_simple_authors_widget() {
008         parent::WP_Widget(false, $name = 'Simple Authors Widget');
009     }
011     /** @see WP_Widget::widget */
012     function widget($args, $instance) {
013         extract( $args );
014         global $wpdb;
016         $title = apply_filters('widget_title', $instance['title']);
017         $gravatar = $instance['gravatar'];
018         $count = $instance['count'];
020         if(!$size)
021             $size = 40;
023         ?>
024               <?php echo $before_widget; ?>
025                   <?php if ( $title )
026                         echo $before_title . $title . $after_title; ?>
027                             <ul>
028                             <?php
030                                 $authors = $wpdb->get_results("SELECT ID FROM $wpdb->users ORDER BY ID");
032                                 foreach($authors as $author) {
034                                     $author_info = get_userdata($author->ID);
036                                     echo '<li>';
038                                         echo '<div style="float: left; margin-left: 5px;">';
040                                         echo get_avatar($author->ID, 40);
042                                         echo '</div>';
044                                         echo '<a href="' . get_author_posts_url($author->ID) .'" title="View author archive">';
045                                             echo $author_info->display_name;
046                                             if($count) {
047                                                 echo '(' . count_user_posts($author->ID) . ')';
048                                             }
049                                         echo '</a>';
051                                     echo '</li>';
052                                 }
053                             ?>
054                             </ul>
055               <?php echo $after_widget; ?>
056         <?php
057     }
059     /** @see WP_Widget::update */
060     function update($new_instance, $old_instance) {
061         $instance = $old_instance;
062         $instance['title'] = strip_tags($new_instance['title']);
063         $instance['gravatar'] = strip_tags($new_instance['gravatar']);
064         $instance['count'] = strip_tags($new_instance['count']);
065         return $instance;
066     }
068     /** @see WP_Widget::form */
069     function form($instance) { 
071         $title = esc_attr($instance['title']);
072         $gravatar = esc_attr($instance['gravatar']);
073         $count = esc_attr($instance['count']);
075         ?>
076          <p>
077           <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label>
078           <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text"value="<?php echo $title; ?>" />
079         </p>
081         <p>
082           <input id="<?php echo $this->get_field_id('count'); ?>" name="<?php echo $this->get_field_name('count'); ?>" type="checkbox" value="1" <?php checked( '1', $count ); ?>/>
083           <label for="<?php echo $this->get_field_id('count'); ?>"><?php _e('Display Post Count?'); ?></label>
084         </p>
086         <p>
087           <input id="<?php echo $this->get_field_id('gravatar'); ?>" name="<?php echo $this->get_field_name('gravatar'); ?>" type="checkbox" value="1"<?php checked( '1', $gravatar ); ?>/>
088           <label for="<?php echo $this->get_field_id('gravatar'); ?>"><?php _e('Display Author Gravatar?'); ?></label>
089         </p>
091         <?php
092     }
094 } // class utopian_recent_posts
095 add_action('widgets_init', create_function('', 'return register_widget("pippin_simple_authors_widget");'));