Tutorial: WordPress 2.8 Widget API

June 8, 2009

One of the many nice new features of WordPress 2.8 is the inclusion of a new widget API. As most of you probably know, my company Spiral Web Consulting maintains Google Analyticator which recently added a Google Analytics stat widget. When I heard WordPress was introducing a new widget API, I decided it would be fun to add API support to the existing Google Analytics stat widget. When looking through the Codex’s explanation of the new API, I realized they did not really include a good tutorial on how to create a widget using the API.

In this tutorial, I will teach you how to create a Hello World sidebar widget using the WordPress 2.8 widget API. I will provide the code throughout this post, and also provide the examples for download at the end of the post. This example will be demonstrated on the Default WordPress theme and provide two configurable lines of text that can be modified.

There are three main functions that every widget must include. These functions include widget(), update(), and form() and are each responsible for a different part of the widget. Let’s take a brief look at each function.

widget()

/**
  * Displays the Widget
  *
  */
  function widget($args, $instance){
    extract($args);
    $title = apply_filters('widget_title', empty($instance['title']) ? ' ' : $instance['title']);
    $lineOne = empty($instance['lineOne']) ? 'Hello' : $instance['lineOne'];
    $lineTwo = empty($instance['lineTwo']) ? 'World' : $instance['lineTwo'];

    # Before the widget
    echo $before_widget;

    # The title
    if ( $title )
    echo $before_title . $title . $after_title;

    # Make the Hello World Example widget
    echo '<div style="text-align:center;padding:10px;">' . $lineOne . '<br />' . $lineTwo . "</div>";

    # After the widget
    echo $after_widget;
}


The widget() function will be the first function we delve into. This function is responsible for displaying the widget. The above function was created for the Hello World example. This function will always require two parameters, $args and $instance.

$args contains the native WordPress variables for the widget that some themes use to ensure the widget is used properly. extract($args); creates those variables, such as $before_widget, $before_title, $after_title, and $after_widget. These are important to include to ensure that all themes will be compatible with your widget.

$instance is the instance of your widget that is currently being passed to the function. WordPress 2.8’s widget API adds the ability to have multiple instances of each widget. $instance is an array that will store all of your widget’s configurable options, which in this case is $title, $lineOne, and $lineTwo. It is important to note that when calling for each option, you should use an if statement to ensure that if the string was empty that the default will be used. This may not be necessary for each element so use desecration when doing this, but it can be useful when you do not want a certain value to be left empty. Another important thing to note is that there are certain WordPress values that WordPress will use differently. For instance, $title has a special filter applied because it is the title of the widget which WordPress recognizes.

update()

/**
  * Saves the widgets settings.
  *
  */
  function update($new_instance, $old_instance){
    $instance = $old_instance;
    $instance['title'] = strip_tags(stripslashes($new_instance['title']));
    $instance['lineOne'] = strip_tags(stripslashes($new_instance['lineOne']));
    $instance['lineTwo'] = strip_tags(stripslashes($new_instance['lineTwo']));

  return $instance;
}

update() is by far the simplest of the three functions. All update() does is save the values of each of the configurable options for the widget.

The update() function takes two different parameters, $new_instance and $old_instance. These variables are rather self explanatory. The old instance($old_instance) is overwritten by the new instance($new_instance) which values are taken from the widget form.

Always be sure to include the proper PHP functions such as strip_tags() and stripslashes() to ensure that no matter what a user puts in the widget options, they will not break the page the widget appears on.

form()

/**
  * Creates the edit form for the widget.
  *
  */
  function form($instance){
    //Defaults
    $instance = wp_parse_args( (array) $instance, array('title'=>'', 'lineOne'=>'Hello', 'lineTwo'=>'World') );

    $title = htmlspecialchars($instance['title']);
    $lineOne = htmlspecialchars($instance['lineOne']);
    $lineTwo = htmlspecialchars($instance['lineTwo']);

    # Output the options
    echo '<p style="text-align:right;"><label for="' . $this->get_field_name('title') . '">' . __('Title:') . ' <input style="width: 250px;" id="' . $this->get_field_id('title') . '" name="' . $this->get_field_name('title') . '" type="text" value="' . $title . '" /></label></p>';
    # Text line 1
    echo '<p style="text-align:right;"><label for="' . $this->get_field_name('lineOne') . '">' . __('Line 1 text:') . ' <input style="width: 200px;" id="' . $this->get_field_id('lineOne') . '" name="' . $this->get_field_name('lineOne') . '" type="text" value="' . $lineOne . '" /></label></p>';
    # Text line 2
    echo '<p style="text-align:right;"><label for="' . $this->get_field_name('lineTwo') . '">' . __('Line 2 text:') . ' <input style="width: 200px;" id="' . $this->get_field_id('lineTwo') . '" name="' . $this->get_field_name('lineTwo') . '" type="text" value="' . $lineTwo . '" /></label></p>';
}

The final piece of the trifecta, form(), is used to display the form that is used on the WordPress admin interface when creating the widget. This form should include the proper input options for each configurable setting for the widget. It is important to note, WordPress now provides both the Save and Remove buttons natively, and it is not necessary to code in those buttons.

This function should also include an array of default values which will be used to populate the form the first time the widget is called in the WordPress admin interface.

WordPress 2.8 now has two different functions that are used in conjunction with the form. get_field_name() and get_field_id() will provide you will the correct field names and ids for each configurable option. This code is necessary in order to enable multiple instances of your widget.

If you are developing a plugin to be used in multiple languages, you must provide localization support by encapsulating your text with __( ). I don’t want to get into localization, so if you are planning on working with multiple languages you will need to look that up.

Piecing It All Together

So you have the three new functions and you are ready to make your widget a reality. Let’s take a look at the beginning of the Hello World example widget.

<?php
/*
 * Plugin Name: Hello World Example
 * Version: 1.0
 * Plugin URI: http://jessealtman.com/2009/06/08/tutorial-wordpress-28-widget-api/
 * Description: Hello World example widget using the the WordPress 2.8 widget API. This is meant strictly as a means of showing the new API using the <a href="http://jessealtman.com/2009/06/08/tutorial-wordpress-28-widget-api/">tutorial</a>.
 * Author: Jesse Altman
 * Author URI: http://jessealtman.com/
 */
class HelloWorldWidget extends WP_Widget
{
 /**
  * Declares the HelloWorldWidget class.
  *
  */
    function HelloWorldWidget(){
    $widget_ops = array('classname' => 'widget_hello_world', 'description' => __( "Example widget demoing WordPress 2.8 widget API") );
    $control_ops = array('width' => 300, 'height' => 300);
    $this->WP_Widget('helloworld', __('Hello World Example'), $widget_ops, $control_ops);
    }

In order to get WordPress to recognize this plugin, you need to give it the proper header. You should include a Plugin Name, Version, Plugin URI, Description, Author, and Author URI.

The next thing you need to do is declare your class. The class should be named something similar to what your widget is called. This class must extend the WP_Widget class in order to function properly. As with any class, you must give it a declaration.

In the class declaration, you need to have a few variables.$widget_ops contains the class name and the description of the widget. WordPress’ admin interface will use this to display the correct information for your widget. I opted to use $control_ops which is an optional parameter that can be passed to the WP_Widget function that will specify the width and height of the WordPress admin interface options menu for your widget. The final function in the class description is WP_Widget and must always be in the class declaration. This function creates your widget in the WordPress admin interface.

Following the class declaration you should provide the widget(), update(), and form() functions to your file. You can then create custom functions used throughout the class. You should place these functions after the form() function.

Wrapping It Up

In order to finish the widget, you need to register it. Let’s take a look at the end of the Hello World example widget.

}// END class

/**
  * Register Hello World widget.
  *
  * Calls 'widgets_init' action after the Hello World widget has been registered.
  */
  function HelloWorldInit() {
  register_widget('HelloWorldWidget');
  }
  add_action('widgets_init', 'HelloWorldInit');
?>

First thing to notice is that this is outside of the HelloWorldWidget class. You must not include the final function in your class. The HelloWorldInit() function uses the register_widget() function provided by WordPress. This function will register the widget with WordPress and allow users to access it via the WordPress admin interface. The add_action() function is also WordPress specific. This function will add your HelloWorldInit() function to WordPress’ widget_init() function. This ensures your widget is run when WordPress initiates widgets.

Finished Product

<?php
/*
 * Plugin Name: Hello World Example
 * Version: 1.0
 * Plugin URI: http://jessealtman.com/2009/06/08/tutorial-wordpress-28-widget-api/
 * Description: Hello World example widget using the the WordPress 2.8 widget API. This is meant strictly as a means of showing the new API using the <a href="http://jessealtman.com/2009/06/08/tutorial-wordpress-28-widget-api/">tutorial</a>.
 * Author: Jesse Altman
 * Author URI: http://jessealtman.com/
 */
class HelloWorldWidget extends WP_Widget
{
 /**
  * Declares the HelloWorldWidget class.
  *
  */
    function HelloWorldWidget(){
    $widget_ops = array('classname' => 'widget_hello_world', 'description' => __( "Example widget demoing WordPress 2.8 widget API") );
    $control_ops = array('width' => 300, 'height' => 300);
    $this->WP_Widget('helloworld', __('Hello World Example'), $widget_ops, $control_ops);
    }

  /**
    * Displays the Widget
    *
    */
    function widget($args, $instance){
      extract($args);
      $title = apply_filters('widget_title', empty($instance['title']) ? '&nbsp;' : $instance['title']);
      $lineOne = empty($instance['lineOne']) ? 'Hello' : $instance['lineOne'];
      $lineTwo = empty($instance['lineTwo']) ? 'World' : $instance['lineTwo'];

      # Before the widget
      echo $before_widget;

      # The title
      if ( $title )
      echo $before_title . $title . $after_title;

      # Make the Hello World Example widget
      echo '<div style="text-align:center;padding:10px;">' . $lineOne . '<br />' . $lineTwo . "</div>";

      # After the widget
      echo $after_widget;
  }

  /**
    * Saves the widgets settings.
    *
    */
    function update($new_instance, $old_instance){
      $instance = $old_instance;
      $instance['title'] = strip_tags(stripslashes($new_instance['title']));
      $instance['lineOne'] = strip_tags(stripslashes($new_instance['lineOne']));
      $instance['lineTwo'] = strip_tags(stripslashes($new_instance['lineTwo']));

    return $instance;
  }

  /**
    * Creates the edit form for the widget.
    *
    */
    function form($instance){
      //Defaults
      $instance = wp_parse_args( (array) $instance, array('title'=>'', 'lineOne'=>'Hello', 'lineTwo'=>'World') );

      $title = htmlspecialchars($instance['title']);
      $lineOne = htmlspecialchars($instance['lineOne']);
      $lineTwo = htmlspecialchars($instance['lineTwo']);

      # Output the options
      echo '<p style="text-align:right;"><label for="' . $this->get_field_name('title') . '">' . __('Title:') . ' <input style="width: 250px;" id="' . $this->get_field_id('title') . '" name="' . $this->get_field_name('title') . '" type="text" value="' . $title . '" /></label></p>';
      # Text line 1
      echo '<p style="text-align:right;"><label for="' . $this->get_field_name('lineOne') . '">' . __('Line 1 text:') . ' <input style="width: 200px;" id="' . $this->get_field_id('lineOne') . '" name="' . $this->get_field_name('lineOne') . '" type="text" value="' . $lineOne . '" /></label></p>';
      # Text line 2
      echo '<p style="text-align:right;"><label for="' . $this->get_field_name('lineTwo') . '">' . __('Line 2 text:') . ' <input style="width: 200px;" id="' . $this->get_field_id('lineTwo') . '" name="' . $this->get_field_name('lineTwo') . '" type="text" value="' . $lineTwo . '" /></label></p>';
  }

}// END class

/**
  * Register Hello World widget.
  *
  * Calls 'widgets_init' action after the Hello World widget has been registered.
  */
  function HelloWorldInit() {
  register_widget('HelloWorldWidget');
  }
  add_action('widgets_init', 'HelloWorldInit');
?>

If you combine all of these code snippets together, this is what your final PHP file should look like. Click the images for a larger view.

Single Widget – Front End
Single Widget Front End

Single Widget – Back End
Single Widget Back End

Double Widget – Front End
Double Widget Front End

Double Widget – Back End
Double Widget Back End

Plugin Interface
Plugin Interface

Download

Download the Hello World Example

Other Useful Resources

45 Responses

Trackbacks

  1. 10 Cool WordPress 2.8 Hacks and Tutorials to tinker with - Daily SEO blog
    June 12th, 2009
  2. Extensive Wordpress 2.8 Getting Started Guide | tripwire magazine
    June 13th, 2009
  3. WordPress 2.8: Features, Tips and Tricks from the experts — gunnerpress.com
    June 13th, 2009
  4. 10 tutorial per WordPress 2.8 — Studio404 Web Agency
    June 15th, 2009
  5. 10 Incredibly Useful WordPress 2.8 Tutorials
    June 17th, 2009
  6. New And Comprehensive Wordpress 2.8 Tutorial and Hack Toolbox | Graphic and Web Design Blog - Inspiration, Resources and Tools
    July 20th, 2009
  7. New And Comprehensive Wordpress 2.8 Tutorial and Hack Toolbox - Programming Blog
    July 21st, 2009
  8. Plugins and Widgets and Wordpress–Oh my! « My Corner
    July 25th, 2009
  9. Widgets For Dummies? - WordPress Tavern Forum
    August 21st, 2009
  10. maxpagels.com
    September 22nd, 2009
  11. How to use widget multiple times | Webmaster area - web development - source code
    September 26th, 2009
  12. Création d’un widget pour Wordpress | PixieDaydream
    October 31st, 2009
  13. Davoscript
    April 6th, 2010

Comments

  1. Great tutorial. The new WordPress 2.8 widget API is worlds better than the system they had before. The old API always seemed more like a hack that was brought it to WordPress (which, it indeed was) and never properly thought out.

    • I’m just glad they added an official way to create widgets. I am also happy they made it so that widgets are built with the ability to have multiple instances. This new WordPress version is going to make a developer’s life much easier (in terms of widget creation).

  2. Jesse,

    Nice little tutorial here. One problem with the new Widget class is that if you don’t have 2.8 it obviously won’t work so maybe you need to have an old style version of your widget as well. With the new update system it might not be that big of a problem, but who knows how these things work out.

    I created a WordPress widget maker over at Widgetifyr.com, and let users generate their widgets in either style. If you get a change take a look and let me know what you think.

    Hey I use your podcast plug in and it seems to work great.

    Thanks
    Glenn

    • I guess I should have added that little tidbit in the tutorial somewhere, but I thought it was implied (the WordPress 2.8 is the only version of WordPress that will run this widget).

      I just took a quick glance over your site, and I must say it seems like a pretty neat tool. I have never been a fan of code generators however, since they tend to have the ability to add extra bloat that isn’t necessary. Overall though it seems like it could be an extremely useful tool for creating a new widget quicker than ever. I will have to look into it further the next time I need to build a widget! Good job!

      Also, thanks for the kind words about Podcasting.

  3. Thanks for the useful info. It’s so interesting

  4. Now that WP 2.8 is out, I’m really gonna try this. Thanks!

  5. What If I don’t want the widget to appear in the sidebar? I want my widget to be embedded in a post or page using short codes. I don’t see anywhere where we are explicitly telling wordpress to push this widget in to the sidebar.

    • That technically wouldn’t be considered a WordPress widget in that case. This tutorial was made strictly for widgets that WordPress will see as a sidebar widget. We aren’t explicitly saying it is for the sidebar, but that is how WordPress registers widgets. Here is an article explaining WordPress widgets.

    • If you do a search, there are plenty of tutorials on how to widgetise areas other than the sideabar.

      I’m not sure about using short codes, though. That would probably require some work.

  6. Great tutorial, thanks a ton!

    I just wanted to let you know that I think some code should be changed just a bit. In function form() you have get_field_name(’title’) . ‘”> It should be get_field_id(’title’) . ‘”> so that the for matches up with the id for the input field.

    Thanks again!

    • No, I believe Jesse is correct. The ‘for’ parameter of a <label> tag should match up with the ‘name’ parameter of an <input> tag.

      • No, Eric was correct, the for attribute value is the id of the input field, not its name.

        HTML 4.01 Specification
        17.9.1 The LABEL element

        for = idref [CS]
        This attribute explicitly associates the label being defined with another control. When present, the value of this attribute must be the same as the value of the id attribute of some other control in the same document.

        http://www.w3.org/TR/html4/interact/forms.html#h-17.9.1

  7. Federico González Brizzio

    June 30th, 2009

    Reply

    Excellent! I’m working to make two news groups (instances) for the same widget in sidebar. You can view it here http://www.cuencadelplata-granchaco.org/private/ “Novedades” & “Noticias de interés”.

    Thanks from Ushuaia, Argentina

  8. Thanks for a wonderful tutorial

  9. Keep working, great job, I love it!

  10. How do I use get_field_name() and get_field_id() with an array of options. For instance, a plugin I created allows setting an option per user role, and I save the option as an array as follows:

    $show_link['subscriber'] = true;
    $show_link['contributor'] = true;
    etc. etc.

    How can I still implement this?

    • I am assuming you want each of these options customizable separately correct? If so, this should be rather simple. All you need to do is change the variable declarations to an array.

      For instance, this sample plugin uses $lineOne and $lineTwo to indicate the separate lines of the output. I can easily change these options to an array, such as $line['one'] and $line['two']. You should be able to leave everything else the same way and the plugin will work fine.

      In your case, all you need to do is define each index of $show_link as an index of $instance. This way it will all relate correctly.

      I modified my Hello World example to better explain what I am doing. You can download it here.

  11. I neeed to convert one ’single’ widget to multi. I really don’t know how it to do. This widget use other pinciples — register_sidebar_widget and register_widget_control functions…

  12. Very good article, thank you for sharing. Great job

  13. Just wanted to join in with the general chorus of appreciation for providing this tutorial.

    Thanks very much!

    Si

  14. Excellent article this has been an brilliant read.

  15. Awesome tutorial. Perfect for those of us who just upgraded to 2.8

  16. Just wanted to say thank you.

    I found other tutorials for this and they were no where near as clear as yours. They said things like “The code should be self explanatory”. If that were the case I would’ve just gone to the codex!

    I made a plugin for DART for publishers ad tags and turned template tags into widgets with this guide.

    Thanks!

  17. This is super helpful! The first tutorial that I have found that doesn’t assume I’m a programming pro. Thanks a lot.

  18. How can i create a single instance widgets using this class?
    I dont want multiple instance widget.

    Thanks,

  19. How do I make two different widgets in my plugin file? I tried duplicating the whole process with different names for the other widget but only one shows. I looked at another plugin that has multiple widgets with this class, I’m not sure what I should be doing.

  20. Thanks for the awesome tutorial. Following your example I was able to create my first ever Wordpress widget.

  21. Great post, Information about these Issues Always seem to make my day better!

  22. Another Good wordpress post, I will be sure to bookmark this post in my Propeller account. Have a awesome day.

  23. thanks for info,
    good

  24. I have widgets installed & customized in my own blog , it was not that easy .

    But this article has helped me to get an idea on how easy to make use of widgets

    I appreciate Jesse’s efforts on this article

  25. Eminem is the best rapper, i have a collection of his live concerts and cds-~*

Leave a Reply