WordPress 3: Building a Widget

Exclusive offer: get 50% off this eBook here
WordPress 3 Plugin Development Essentials

WordPress 3 Plugin Development Essentials — Save 50%

Create your own powerful, interactive plugins to extend and add features to your WordPress site

$23.99    $12.00
by Brian Bondari Everett Griffiths | May 2011 | Open Source WordPress

WordPress is a popular content management system (CMS), most renowned for its use as a blogging / publishing application. According to usage statistics tracker, BuiltWith (http://builtWith.com), WordPress is considered to be the most popular blogging software on the planet—not bad for something that has only been around officially since 2003.

In this article by Brian Bondari and Everett Griffiths, authors of WordPress 3 Plugin Development Essentials, we will learn about a special type of WordPress plugin: the widget. The architecture of widgets has undergone a radical change starting with the release of WordPress 2.8, so now we must talk about Object Oriented programming. We will learn a bit about its power as we extend the WP_Widget class to create our widget. We will also learn how to create a preference page in the manager so we can store our plugin's configuration details.

 

WordPress 3 Plugin Development Essentials

WordPress 3 Plugin Development Essentials

Create your own powerful, interactive plugins to extend and add features to your WordPress site

        Read more about this book      

(For more resources on WordPress, see here.)

The plan

What exactly do we want this plugin to do? Our widget will display a random bit of text from the database. This type of plugin is frequently used for advertisement rotations or in situations where you want to spruce up a page by rotating content on a periodic basis. Each instance of our plugin will also have a "shelf life" that will determine how frequently its content should be randomized.

Let's take a moment to come up with some specifications for this plugin. We want it to do the following:

  • Store multiple chunks of content, such as bits of Google Adsense code
  • Be able to randomly return one of the chunks
  • Set a time limit that defines the "shelf life" of each chunk, after which the "random" chunk will be updated

Widget overview

Even if you are already familiar with widgets, take a moment to look at how they work in the WordPress manager under Appearance | Widgets. You know that they display content on the frontend of your site, usually in a sidebar, and they also have text and control forms that are displayed only when you view them inside the manager. If you put on your thinking cap, this should suggest to you at least two actions: an action that displays the content on the frontend, and an action that displays the form used to update the widget settings inside the manager. There are actually a total of four actions that determine the behavior of a standard widget, and you can think of these functions as a unit because they all live together in a single widget object. In layman's terms, there are four things that any widget can do. In programmatic terms, the WP_Widget object class has four functions that you may implement:

  • The constructor: The constructor is the only function that you must implement. When you "construct" your widget, you give it a name, a description, and you define what options it has. Its name is often __ construct(), but PHP still accepts the PHP 4 method of naming your constructor function using the name of the class.
  • widget(): It displays content to users on the frontend.
  • form(): It displays content to manager users on the backend, usually to allow them to update the widget settings.
  • update(): It prepares the updated widget settings for database storage. Override this function if you require special form validation.

In order to make your widget actually work, you will need to tell WordPress about it by registering it using the WordPress register_widget() function. If you want to get a bit more information about the process, have a look at WordPress' documentation here.

Let's outline this in code so you can see how it works.

Preparation

As always, we're going to go through the same setup steps to get our plugin outlined so we can get it activated and tested as soon as possible.

  1. Create a folder inside the wp-content/plugins/ directory. We are naming this plugin "Content Rotator", so create a new folder inside wp-content/ plugins/ named content-rotator.
  2. Create the index.php file.
  3. Add the Information Head to the index.php file. If you forgot the format, just copy and modify it from the Hello Dolly plugin like we did in the previous article, Anatomy of a WordPress Plugin.
    We're giving you bigger sections of code than before because hopefully by now you're more comfortable adding and testing them. Here is what our index.php looks like:

    <?php
    /*--------------------------------------------------------------
    ----------------
    Plugin Name: Content Rotator
    Plugin URI: http://www.tipsfor.us/
    Description: Sample plugin for rotating chunks of custom content.
    Author: Everett Griffiths
    Version: 0.1
    Author URI: http://www.tipsfor.us/
    ----------------------------------------------------------------
    --------------*/
    // include() or require() any necessary files here...
    include_once('includes/ContentRotatorWidget.php');
    // Tie into WordPress Hooks and any functions that should run on
    load.
    add_action('widgets_init', 'ContentRotatorWidget::register_this_
    widget');
    /* EOF */

  4. Add the folders for includes and tpls to help keep our files organized.
  5. Add a new class file to the includes directory. The file should be named ContentRotatorWidget.php so it matches the include statement in the index.php file. This is a subclass which extends the parent WP_Widget class. We will name this class ContentRotatorWidget, and it should be declared using the extends keyword.

    <?php
    /**
    * ContentRotatorWidget extends WP_Widget
    *
    * This implements a WordPress widget designed to randomize chunks
    of content.
    */
    class ContentRotatorWidget extends WP_Widget
    {
    public $name = 'Content Rotator';
    public $description = 'Rotates chunks of content on a
    periodic basis';
    /* List all controllable options here along with a
    default value.
    The values can be distinct for each instance of the
    widget. */
    public $control_options = array();

    //!!! Magic Functions
    // The constructor.
    function __construct()
    {
    $widget_options = array(
    'classname' => __CLASS__,
    'description' => $this->widget_desc,
    );
    parent::__construct( __CLASS__, $this->name,$widget_
    options,$this->control_options);
    }
    //!!! Static Functions
    static function register_this_widget()
    {
    register_widget(__CLASS__);
    }
    }
    /* EOF */

This is the simplest possible widget—we constructed it using only the __ construct() function. We haven't implemented any other functions, but we are supplying enough information here for it to work. Specifically, we are supplying a name and a description, and that's enough to get started. Let's take a moment to explain everything that just happened, especially since the official documentation here is a bit lacking.

When we declared the ContentRotatorWidget class, we used the extends keyword. That's what makes this PHP class a widget, and that's what makes object-oriented code so useful.

The __construct() function is called when an object is first created using the new command, so you might expect to see something like the following in our index. php file:

<?php
$my_widget = new ContentRotatorWidget();
?>

However, WordPress has obscured that from us—we just have to tell WordPress the classname of the widget we want to register via the register_widget() function, and it takes care of rest by creating a new instance of this ContentRotatorWidget. There is a new instance being created, we just don't see it directly. Some of the official documentation still uses PHP 4 style examples of the constructor function— that is to say that the function whose name shares the name of the class. We feel that naming the constructor function __construct is clearer.

You may have wondered why we didn't simply put the following into our index.php file:

register_widget('ContentRotatorWidget'); // may throw errors
if called too soon!

If you do that, WordPress will try to register the widget before it's ready, and you'll get a fatal error:

"Call to a member function register() on a non-object".

That's why we delay the execution of that function by hooking it to the widgets_ init action.

We are also tying into the construct of the parent class via the parent::__ construct() function call. We'll explain the hierarchy in more detail later, but "parent" is a special keyword that can be used by a child class in order to call functions in the parent class. In this case, we want to tie into the WP_Widget __ construct() function in order to properly instantiate our widget.

Note our use of the PHP __CLASS__ constant—its value is the class name, so in this case, we could replace it with ContentRotatorWidget, but we wanted to provide you with more reusable code. You're welcome.

Lastly, have a look at the class variables we have declared at the top of the class: $name, $description, and $control_options. We have put them at the top of the class for easy access, then we have referenced them in the __construct() function using the $this variable. Note the syntax here for using class variables. We are declaring these variables as class variables for purposes of scope: we want their values to be available throughout the class.

Please save your work before continuing.

Activating your plugin

Before we can actually use our widget and see what it looks like, we first have to activate our plugin in the manager. Your widget will never show up in the widget administration area if the plugin is not active! Just to be clear, you will have to activate two things: your plugin, and then your widget.

The code is simple enough at this point for you to be able to quickly track down any errors.

Activating the widget

Now that the plugin code is active, we should see our widget show up in the widget administration area: Appearance | Widgets.

Take a moment to notice the correlation between the widget's name and description and how we used the corresponding variables in our constructor function. Drag your widget into the primary widget area to make it active.

Once it has been activated, refresh your homepage. Your active widget should print some text in the sidebar.

(Move the mouse over the image to enlarge it.)

Congratulations! You have created your first WordPress widget! It is printing a default message: function WP_Widget::widget() must be over-ridden in a sub-class, which is not very exciting, but technically speaking you have a functional widget. We still need to enable our widget to store some custom options, but first we should ensure that everything is working correctly.

Having problems?

No widget? If you have activated your plugin, but you do not see your widget showing up in the widget administration area, make sure you have tied into a valid WordPress action! If you misspell the action, it will not get called! The action we are using in our index.php is widgets_init—don't forget the "s"!

White screen? Even if you have PHP error-reporting enabled, sometimes you suddenly end up with a completely white screen in both the frontend and in the manager. If there is a legitimate syntax error, that displays just fine, but if your PHP code is syntactically correct, you end up with nothing but a blank page. What's going on?

A heavy-handed solution for when plugins go bad is to temporarily remove your plugin's folder from /wp-content/plugins, then refresh the manager. WordPress is smart enough to deactivate any plugin that it cannot find, so it can recover from this type of surgery.

If you are experiencing the "White Screen of Death", it usually means that something is tragically wrong with your code, and it can take a while to track it down because each time you deactivate the plugin by removing the folder, you have to reactivate it by moving the folder back and reactivating the plugin in the WordPress manager.

This unenviable situation can occur if you accidentally chose a function name that was already in use (for example, register()—don't use that as a function name). You have to be especially careful of this when you are extending a class because you may inadvertently override a vital function when you meant to create a new one. If you think you may have done this, drop and do 20 push-ups and then have a look at the original parent WP_Widget class and its functions in wp-includes/widgets.php. Remember that whenever you extend a class, it behooves you to look at the parent class' functions and their inputs and outputs. If this sounds like Greek to you, then the next section is for you.

WordPress 3 Plugin Development Essentials Create your own powerful, interactive plugins to extend and add features to your WordPress site
Published: March 2011
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on WordPress, see here.)

Parents and children: extending classes

If this is your first foray into the world of Object-Oriented programming or if you just need a refresher, let's take a moment to explain what is going on here. First of all, even though it is common parlance in the programming world, the "parent/ child" terminology does not necessarily provide an accurate description of what's happening in our PHP classes. We find it helpful instead to think in terms of overriding and redefining—when you extend a class, you can redefine the parent's functions and thereby override their behavior.

Let's look at a more familiar example: CSS. If you have done much web development, you have used Cascading Style Sheets to stylize your content. If you follow the rules of good semantic web development, you put your style definitions into a separate .css file which you reference in the head of your HTML documents:

<link href="/css/default.css" rel="stylesheet" type="text/css" />

If you want all paragraphs on your site to be black and regularly sized, you would add something like the following to the default .css file:

p {
font-size: medium;
color: black;
}

However, there will always be exceptions. Let's say you have a legalese.html page with legal terms, so you want the paragraph text to be impossibly small and hard to read. What's the solution? You override the default style by redefining the style declaration in the head of your page:

<link href="/css/default.css" rel="stylesheet" type="text/css" />
<style type="text/css">
p {
font-size: x-small; /* <-- overrides the declaration in
default.css */
}
</style>

Now all the paragraphs on legalese.html will be extra small. Good job—nobody will bother to read text so small! Now is your chance to disclose your plans to take over the world!

What if you have one paragraph on legalese.html that needs yet another style? Well, you can override the style again by redefining it inside that particular paragraph, for example:

<p style="font-size: large; font-weight: bold;">I AGREE TO THE
TERMS.</p>

Do you see how in each case we overrode the previous definition of the font-size attribute? Of course, we could have used different classes and definitions for each type of text, but we wanted to demonstrate the concept of inheritance and our ability to override inherited attributes. When the browser renders a particular paragraph, it will use the last style declaration it encountered. If the last declaration was in the CSS file, it uses that; if the last declaration was in the document head, it uses that; if a declaration was used inline alongside the content, it uses that. The browser literally remembers the last thing you told it about how to style any given content.

Imagine taking your mother out to dinner, and she can't make up her mind, so she keeps changing her order. The last thing she tells the waiter is what she'll be served.

What does this have to do with PHP and WordPress widgets? Similar to CSS style definitions, PHP functions describe behavior. Similar to CSS inheritance, the class hierarchy defined by extending classes tells our scripts which behavior should be implemented. In our example, the WP_Widget has a widget() function, which is what is currently displaying the default message reminding us that it must be "overridden in a sub-class". In other words, our ContentRotatorWidget class must define its own widget() function and thereby override it. The widget() function in the parent WP_Widget class is used until you define your own version of the widget() function and override it in the child class. Make sense?

In terms of the the parent/child terminology, imagine visiting a friend's house, knocking on their door, and having their kid answer it. You ask the child, "Hey, what content should be displayed here for this widget?" If the child knows the answer, your pages will get that text in their sidebars. If the child doesn't know the answer, he might say, "I don't know, let me go ask my dad", and then the parent WP_Widget class (the dad) would provide the "answer" to your "question". This chain can keep going—if the dad doesn't know, he asks the grandfather, and so on. Sorry, but in this hierarchical chain of authority, there is no PHP equivalent of "wife" or "girlfriend".

Hopefully this makes the concept of classes and inheritance clearer for you.

Objects vs. libraries: when to use static functions

You may have noticed that in our ContentRotatorWidget class some functions are static and some are not. What's going on?

In our example, we are using a static function to register the widget's class name. Even if we had thousand instances of this widget, the class name remains the same for all of them, so it is a good candidate for a static function. As the name suggests, a static function should be used to implement behavior that does not change.

The rest of the widget properties, however, are dynamic and will change from instance to instance. Objects distinguish themselves from libraries because you can have multiple instances of an object. You may not have noticed this, but in the widget administration area, you can in fact drag several instances of your widget into the "Primary Widget Area" drop zone.

Even though they are all instances of the ContentRotatorWidget, each instance has its own properties. If our class were "Books", then one instance might have a title of "No Country for Old Men" and another instance might have a title of "I Hope They Serve Beer in Hell". For each instance the title changes.

Objects use the $this variable to refer to the current instance of the object, that is THIS instance. So if you need to call a function inside the class, you call it via $this- >function_name(), or if you need to access a "class variable", you use $this- >variable_name. We'll see more examples of this as we go along.

Add custom text

Our simple widget is technically functional, but it doesn't do anything yet. After you have activated your widget and viewed your homepage, you will see some default text that we pointed out earlier: function WP_Widget::widget() must be over-ridden in a sub-class.

This is the output of the WP_Widget class' widget() function. If we think about our parent/child analogy, here we are getting a message from the parent telling the kid that he needs to take care of this function himself. How do we override the WP_Widget::widget() function? We simply add a widget() function to our ContentRotatorWidget class. Add the following function to the ContentRotatorWidget.php file, somewhere below the __construct() function (remember we like to keep our functions alphabetized):

/**
* Displays content to the front-end.
*
* @param array $args Display arguments
* @param array $instance The settings for the particular
instance of the widget
* @return none No direct output. This should instead print output
directly.
*/function widget($args, $instance)
{
print "Hi, I'm a sneezing unicorn.";

}

Note that this function takes two arguments, and the official documentation currently does a poor job of explaining them. You can have a look at the original class and read the documentation for the function we are overriding inside of wp-includes/ widgets.php, but it's not entirely clear what those arguments do. Just remember that when you override a function, it must take the same inputs and return the same output as the original. We'll use these arguments later so you can get some idea of how they're used.

Save your work and then refresh your homepage. You should see your text printed in place of the default message. Congratulations! You have successfully overridden your first function! Your ContentRotatorWidget stuck it to his old man and is now handling this function on his own.

Adding widget options

The other place where we need to customize our widget's content is in the manager—we need to provide a custom form for editing our widget's options. Let's start by adding a single option for the title. In order to do this, we need to implement another function in our widget and add some options:

  1. Create a form() function that prints out some HTML. Later, this function will print out some HTML form elements, but for now, let's just make sure this works. Add the following function to your ContentRotatorWidget.php file:

    /**
    * Displays the widget form in the manager, used for editing its
    settings
    *
    * @param array $instance The settings for the particular
    instance of the widget
    * @return none No value is returned directly, but form elements
    are printed.
    */
    function form( $instance )
    {
    print "Form elements go here";
    }

  2. Save your file and refresh your manager page. You should see your handiwork when you open your widget for editing:

    You may be thinking that all we need to do is print some form elements here, but the process here is deceptively complex because we need to handle multiple instances (and multiple HTML forms) of your widget. Each form element must have a unique name and ID. What to do? We let WordPress handle it via the WP_Widget class' get_field_id() and get_field_name() functions. We are going to build a simple template that allows you to adjust your form elements, and we will feed it the $control_options that we defined at the top of our ContentRotatorWidget class. Let's add a control option now.

  3. Update your ContentRotatorWidget class and edit the $control_options array so we have a control option for "title". Later, we can expand this array to include as many options as our widget requires.

    /* List all controllable options here along with a default value.
    The values can be distinct for each instance of the widget. */
    public $control_options = array(
    'title' => 'Content Rotator',
    );

  4. It's finally getting to the point where we need some helper functions that do things that are not directly related to this widget. We need to put the functions somewhere, but they don't necessarily belong in the ContentRotatorWidget class. So let's create a new class named ContentRotator, and save it inside the content-rotator/includes/ directory as ContentRotator.php. The following is what our ContentRotator.php looks like:

    <?php
    /**
    * ContentRotator
    *
    * Helper functions that assist the ContentRotatorWidget class
    */
    class ContentRotator {
    }
    /*EOF*/

    It's empty for now. We will be adding a handful of functions to it later, but first let's test it.

  5. Update the content-rotator/index.php file so it includes your new class. Add the following line to your index.php file:

    include_once('includes/ContentRotator.php');

    Save your work and refresh your homepage to check for any errors. You should now have a helper class hooked up and ready for use.

  6. The first helper function we are going add to ContentRotator.php is one we've used before: a simple parsing function. This lets us use simple templates and [+placeholders+] in order to avoid the confusing mess of PHP concatenation.
    Add this static function to the ContentRotator class:

    /**
    * parse
    *
    * A simple parsing function for basic templating.
    *
    * @param $tpl string A formatting string containing
    [+placeholders+]
    * @param $hash array An associative array containing keys
    and values e.g. array('key' => 'value');
    * @return string Placeholders corresponding to the keys
    of the hash will be replaced with the values the resulting string
    will be returned.
    */
    static function parse($tpl, $hash) {

    foreach ($hash as $key => $value) {
    $tpl = str_replace('[+'.$key.'+]', $value, $tpl);
    }
    return $tpl;
    }

    Save your work, refresh your homepage, and verify that no errors occurred.

  7. Add a tpls/ folder to your plugin's folder if you haven't already, and add a widget_controls.tpl file that contains the following text:

    <!--
    This .tpl file is used when editing a widget's options in the WP
    manager.
    It should only contain form *elements*; WordPress will supply the
    opening and closing <form> tags.

    For each key in the ContentRotatorWidget::$control_options array,
    you will have
    the following placeholders available:

    [+your_key.id+] - used inside id attributes, e.g.
    id="[+your_key.id+]"
    [+your_key.name+] - used inside name attributes, e.g.
    name="[+your_key.name+]"
    [+your_key.value+] - contains the current value of the option

    WordPress appends text to the names and id's to allow for
    multiple instances
    of the widget, so don't try hard-coding values here.
    -->

    <label for="[+title.id+]">Title</label><br/>
    <input id="[+title.id+]" name="[+title.name+]" value="[+title.
    value+]" /><br/>

    Notice that we've included a comment with some basic instructions for how to use this file. This is an important concept when it comes to good documentation: put the documentation where people need it.
    We're preparing a system that can handle more complex widgets. The placeholders are pretty easy to read, and there's no danger of crashing PHP with a bad concatenation because it's only a text file—it does not execute. Any frontend designer would be comfortable editing this template, and that's a big deal. Consistently throughout this article, we want to separate the logic from the presentation layer as much as possible because it makes for better code and better HTML.
    We still need to hook this template up to the wagon, so let's update our form() function next so it outputs some form elements instead of just static text.

  8. After the footwork of adding a helper class, we're ready to beef up the form() function in the ContentRotatorWidget class. Update the function so it looks like the following:

    /**
    * Displays the widget form in the manager, used for editing its
    settings
    *
    * @param array $instance The settings for the particular
    instance of the widget
    * @return none No value is returned directly, but form elements
    are printed. */
    public function form( $instance )
    {
    $placeholders = array();

    foreach ( $this->control_options as $key => $val )
    {
    $placeholders[ $key .'.id' ] = $this->get_field_id( $key
    );
    $placeholders[ $key .'.name' ] = $this->get_field_name(
    $key );
    // This helps us avoid "Undefined index" notices.
    if ( isset($instance[ $key ] ) )
    {
    $placeholders[ $key .'.value' ] = esc_attr( $instance[
    $key ] );
    }
    // Use the default (for new instances)
    else
    {
    $placeholders[ $key .'.value' ] = $this->control_
    options[ $key ];
    }
    }

    $tpl = file_get_contents( dirname(dirname(__FILE__)) .'/tpls/
    widget_controls.tpl');

    print ContentRotator::parse($tpl, $placeholders);
    }

Save your work and refresh your admin page. We have just put together a handful of moving parts, so it may take a little debugging before they all work together. We are making use of the helper class' ContentRotator::parse() function, and we are also using PHP's __FILE__ constant, which returns the name of the current file (ContentRotatorWidget.php). We use this in order to get a full path to the widget_ controls.tpl file.

We are utilizing the parent class' get_field_id() and get_field_name() functions. We call them using the $this variable. Since our child class does not contain these functions, PHP looks for these functions in the parent class. This is how we let WordPress handle the naming and identification of form fields. This ensures that we don't get into trouble when we have several instances of our widget active.

Once it all works, head to the widget administration page in your browser, and try adding a title to your activated widget. The default title, by the way, comes from the value you set back in the $control_options array at the top of ContentRotatorWidget.php. You may need to deactivate the widget and then drag a new instance into the primary widget area before everything refreshes. Remember to refresh your admin page frequently when developing widgets! Enter a new title for the widget instance and try saving it.

If you got this all working, then take a deep breath and congratulate yourself. You have built a reusable component for your widgets, and it follows some good architectural design. That's no small feat! The next step is to tackle this widget's namesake—we need to generate some random content and put it into rotation.

Generating random content

It's time to flesh out the widget() function. This is the function that prints out the content that is visible on the frontend, and we want it to print out some random content. We are going to approach this in phases so that we can test it.

  1. Firstly, add a helper function to ContentRotator.php that generates some random content. For now, we're going to generate a random number. Later, we will pull up some random content from the database, but always keep things simple the first time around so you can test them. Add the following static function to ContentRotator.php:


    /**
    Fetch and return a piece of random content
    */
    static function get_random_content()
    {
    return rand(1, 1000000);
    }

    This relies on PHP's rand() function, and it returns a random number between one and 1,000,000. It will suffice for our current testing.
    Before we go much further, let's "templatize" our widget output. This is another case where the solutions offered on most websites and in most books would have you concatenating a messy bunch of PHP and HTML, but we want to avoid that.

  2. Create a new template file named widget.tpl inside your contentrotator/ tpls/ directory:

    [+before_widget+]
    [+before_title+]
    [+title+]
    [+after_title+]
    [+content+]
    [+after_widget+]

    What's all that about? Well, remember how the widget() function takes two arguments? Those arguments are directly related to the widget's output, and we are going to use those arguments to create [+placeholders+] so we can easily control the output and formatting of our widget. If you had added a print_r($args) statement to your widget() function, you can inspect the arguments that WordPress is sending this function:


    // Output of print_r($args) from inside the widget() function;
    Array
    (
    [name] => Primary Widget Area
    [id] => primary-widget-area
    [description] => The primary widget area
    [before_widget] => <li id="contentrotatorwidget-6"
    class="widget-container ContentRotatorWidget">
    [after_widget] => </li>
    [before_title] => <h3 class="widget-title">
    [after_title] => </h3>
    [widget_id] => contentrotatorwidget-6
    [widget_name] => Content Rotator
    )

    Changing what these arguments are is beyond the scope of this article, but we are going to allow you a way to use these values as you customize your widget display. Unfortunately, we can't provide documentation in a comment because it may throw things off. For example, if our widget were used to returning bits of Google Adsense JavaScript, they would still execute even if they were inside an HTML comment. However, we have an obligation to explain the format and purpose of this .tpl file to our users, so we are going to create a readme.txt file with further information.

  3. Create a content-rotator/tpls/readme.txt file with the following instructions in it:

    The file called widget_controls.tpl contains the form elements
    necessary to edit a widget's settings. See widget_controls.tpl
    for more instructions on using that file.
    The widget.tpl template is used to format the output of the
    widget as it is seen by the outside world, for example, on your
    homepage. There are 4 primary built-in placeholders which are
    dictated by the template in use:
    [+before_widget+]
    [+after_widget+]
    [+before_title+]
    [+after_title+]
    There are also placeholders corresponding to the
    ContentRotatorWidget::$control_options array keys. The values of
    these are bound to an instance of the widget, so two instances
    of the same widget may have completely different values. These
    placeholders include:
    [+seconds_shelf_life+]
    [+title+]
    Lastly, the most important placeholder:
    [+content+] -- contains the random text as defined in the
    plugin'sadministration page
    There are additional placeholders created from the widget()
    function's $args array, for example:

    Array
    (
    [name] => Primary Widget Area
    [id] => primary-widget-area
    [description] => The primary widget area
    [before_widget] => <li id="contentrotatorwidget-6"
    class="widget-container ContentRotatorWidget">
    [after_widget] => </li>
    [before_title] => <h3 class="widget-title">
    [after_title] => </h3>
    [widget_id] => contentrotatorwidget-6
    [widget_name] => Content Rotator
    )
    Each key in this array corresponds to a placeholder. For example
    [+name+] and [+id+] are placeholders you can use in your widget.
    tpl file.
    The documentation for the available placeholders occurs in this
    readme.txt file so that it does not display publicly.

    We won't bother repeating ourselves and we'll assume you read the readme. txt file—we have listed a few placeholders that we haven't implemented yet. If our templating method is too unorthodox for you, have a look at the official documentation for more conventional examples: http://codex.wordpress. org/Widgets_API.

  4. Next, let's call the get_random_content() helper function in the ContentRotatorWidget.php widget() function so our widget can get some random content. Currently, our random content consists of a random number, but the important thing here is to get it so it displays on the frontend. Update the widget() function so it looks like the following:

    /**
    * Displays content to the front-end, using the tpls/widget.tpl
    template.
    *
    * @param array $args Display arguments
    * @param array $instance The settings for the
    particular
    instance of the widget
    * @return none No direct output. This should instead print
    output directly.
    */
    public function widget($args, $instance)
    {
    $placeholders = array_merge($args, $instance);
    $placeholders['content'] = ContentRotator::get_random_
    content();
    $tpl = file_get_contents( dirname(dirname(__FILE__)) .'/
    tpls/widget.tpl');
    print ContentRotator::parse($tpl, $placeholders);
    }

Save your work and refresh your homepage. You should now see a new random number each time you refresh your homepage. Furthermore, the format of the output should be entirely controlled by the widget.tpl file. To test this, you can edit it to include some additional HTML formatting, but we will leave that up to you.

WordPress 3 Plugin Development Essentials Create your own powerful, interactive plugins to extend and add features to your WordPress site
Published: March 2011
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on WordPress, see here.)

Expiration dates: adding options to our widget

One of the key specifications for this plugin is the ability to set how often content is refreshed. Maybe you want to include a "quote of the day" on your site, or maybe you want to update a chunk of content every hour. Each instance of our widget needs an expiration date.

How do we do that? The solution is a bit tricky, so pay attention. First, we need to add another control option to our widget that allows the managers to set how often the content expires in each widget instance. We are referring to this as the "shelf life", in keeping with some common grocery terms.

Update the ContentRotatorWidget.php file so the $control_options array has an additional option:

public $control_options = array(
'title' => 'Content Rotator',
'seconds_shelf_life' => 86400, // 86400 seconds in a day
);

We have given it a default value of 86400; we are opting to use seconds as our refresh interval, where 86,400 seconds is equal to 24 hours.

Next, we need to include some form elements so managers can submit new values for this option. The hard work we did previously pays off now. Simply add the form element to the tpls/widget_controls.tpl file so it contains elements for both control options:

<label for="[+title.id+]">Title</label><br/>
<input id="[+title.id+]" name="[+title.name+]" value="[+title.
value+]" /><br/>
<label for="[+seconds_shelf_life.id+]">Shelf Life (in seconds)</
label><br/>
<input id="[+seconds_shelf_life.id+]" name="[+seconds_shelf_life.
name+]" value="+seconds_shelf_life.value+]" />

Save your work and refresh your manager page. You may need to deactivate your widgets and reactivate them before you see the new options available for editing.

Now we can tell each widget instance how long its content should persist, but we have not yet solved the trickier problem of enforcing this behavior. We handle that in the next section.

Expiration dates: enforcing the shelf life

Expiration dates are fairly simple. For example, if a container of milk is stamped with a date, we can read that date and compare it with today's date in order to know if that milk is past its prime. How does this apply to our rotating content? We have already solved the problem of determining how long a chunk of content should last before it gets refreshed, but what is our content's "manufacture date"? When exactly is our content considered new?

We are choosing to determine the "manufacturing date" as the time when a user first views our content. The expiration date will be determined by adding the seconds_ shelf_life value to this date. Since PHP and UNIX typically work in seconds, the arithmetic is simple: If the time right now is later than the manufacturing date plus the shelf life, then it is time to refresh the content. Alternatively, in pseudo code:

if ( $now > ($manufacturing_date + $shelf_life) ) {
// Refresh the content
}

Make sense? Sometimes these little logical quandaries are the most difficult part of a script. Now we have to integrate this logic into our code, and to do that, we are finally going to make use of the second argument to the widget() function: $instance. That's where information is stored about the specific instance of our widget. Since each instance has the potential to have different attributes (for example, "shelf life"), our calculations must be made according to each instance. In our grocery store analogy, we need to be able to say this bottle of milk is still good, but this bottle of milk needs to be replaced.

Update the ContentRotatorWidget.php widget() function so it looks like the following:

public function widget($args, $instance)
{
if ( !isset($instance['manufacture_date'])
|| time() >= ($instance['manufacture_date']
+ $instance['seconds_shelf_life'] ) )
{
$instance['content'] = ContentRotator::get_random_
content($instance);
$instance['manufacture_date'] = time();
$all_instances = $this->get_settings();
$all_instances[ $this->number ] = $instance;
$this->save_settings($all_instances);
}
$placeholders = array_merge($args, $instance);
$tpl = file_get_contents( dirname(dirname(__FILE__)) .'/tpls/
widget.tpl');

print ContentRotator::parse($tpl, $placeholders);
}

A lot is going on there, so let's devote some time to breaking it down.

Explaining the $instance

You can see our "expiration date" logic in the if-statement, which relies on PHP's time() function to determine the current time (in seconds). The trickiest part of this code is when we actually have to refresh the content. To pull this off, we are tying into WP_Widget's get_settings() and save_settings() methods (remember, a "method" is simply a function inside of a class). Those functions get and save settings for ALL instances of a widget, not just the current instance, which complicates things.

If you were to print_r($this->get_settings()) inside the widget function, you would see an array of arrays. Each widget gets its own array; we just need to know which number our widget is. To distinguish our widget's unique place inside that array of arrays, we are making use of a class variable from the parent class: $this- >number. We make the necessary changes to our $instance, and then we slip our $instance back into $all_instances by overwriting the unique spot in the $all_ instances array:

$all_instances[ $this->number ] = $instance;

So what data is stored in a particular $instance? Performing a print_r($instance) would yield something like the following:

Array
(
[content] => 924297
[manufacture_date] => 1295813716
[title] => Content Rotator
[seconds_shelf_life] => 3
)

You can see that this is information about our ContentRotatorWidget and not WordPress widgets in general. How did all that information get in there? We have to apologize for this, because it probably qualifies as "clever", and in computer code, "clever" is usually a euphemism for "complicated and poorly documented". Normally a widget's options would only be created and changed via the backend manager by the form you displayed via the form() function, but we only created options for title and seconds_shelf_life, so how did the content and manufacture_date get in there? These two lines populate the other values of $instance:

$instance['content'] = ContentRotator::get_random_content();
$instance['manufacture_date'] = time();

The "clever" thing about this is that they are populated when a user on the frontend views a page, not when you save the widget in the manager. Since this is a bit uncommon, we don't have a nice WordPress API function to use, so we have to use the parent class' save_settings() function, which does in fact save data to the database. How do we know to use that function? We read through the parent class and its functions in wp-includes/widgets.php.

Save your work, and then try activating two instances of the Content Rotator widget: one should have a shelf-life of five seconds and the other should have a shelf life of zero seconds. Refresh your homepage a few times to get the full effect. You should see one instance of the widget spit out a random number with each page request, and the other instance should only refresh every five seconds.

This was the hardest part of our widget. The only thing we have left to do is to replace our random number generator with something that pulls real content from the database. To do that, we must modify the ContentRotator::get_random_ content() function so it picks some content at random. Some readers may feel they can take it from here, but we're going to carry on and show you how to create a custom manager page inside of the WordPress manager so you can add and remove chunks of content.

Adding a custom manager page

It's not written anywhere as a hard core rule, but in general, we try to put a plugin's configuration page under the Plugins menu. There is nothing that prevents you from creating our own custom menus, but often developing a custom menu item for your plugin is nothing but pure vanity; it's a plugin, not the second coming! So we are going to add a custom menu item to the Plugins menu.

Let's first create a sample page that will show up when we click on our custom menu item. Later on, we'll customize this, but for now, let's keep it simple. Create a new file inside the content-rotator/includes/ directory named admin_page.php and put some sample text into it:

<div class="wrap">
<?php screen_icon(); ?>
<h2>Content Rotator Administration</h2>
<p>We're remodeling...</p>
</div>

Notice that we're wrapping everything with a div tag that uses the wrap class. Use this class for best results. We are also using a theme function, screen_icon(). This is not required; it's just common practice.

You may have noticed that we are not using a .tpl file for this. We try to avoid sloppy mixes of PHP and HTML whenever possible, but it is a blurry line when it comes to building forms, so here we are using a "standard" PHP file.

Now that we have a target page, we have to make a function that displays that page. Inside of ContentRotator.php, add a static function as shown in the following code snippet:

/**
* Controller that generates admin page
*/
static function generate_admin_page()
{
include('admin_page.php');
}

We also need a function that will create our custom menu item. Add the following static function to ContentRotator.php:

/**
* Adds a menu item inside the WordPress admin
*/
static function add_menu_item()
{
add_submenu_page(
'plugins.php', // Menu page to attach to
'Content Rotator Configuration', // page title
'Content Rotator', // menu title
'manage_options', // permissions
'content-rotation', // page-name (used in the
URL) 'ContentRotator::generate_admin_page' // clicking
callback function
);
}

We pause for a moment to remind you to distance yourself from this WordPress function. Having six inputs is too confusing, so we've added some comments to help you out. The rule of thumb is that having any more than three inputs probably means that you should rewrite your function or repackage your inputs. Please, don't write functions like this.

Finally, we need to hook our add_menu_item() function to a WordPress event. Add the following function call to your content-rotator/index.php file:

add_action('admin_menu', 'ContentRotator::add_menu_item');

Save your work and then refresh your manager page. Try clicking on the Plugins menu—you should see a custom menu item for Content Rotator. Click on it and verify that you can see your custom admin_page.php.

Adding options to the custom manager page

Let's face it: a static manager page isn't very useful for anything other than testing. We want to use this page to add our custom content, so what we really need on it is a form. There are many ways to store content and randomize it, and what we are going to show you isn't necessarily the best way, but it will demonstrate how you can store options in the database using a custom manager page. A more thorough solution would not be as valuable as a teaching tool.

We are going to build a form with two fields: one that allows the user to enter a block of content, and another that accepts the character (or characters) that separates that content into units. For example, this could be our content block:

man, bear, pig

Then, our separator would be a simple comma (","). If your content is more complex, you may need a more complex separator.

We need to store two settings in the database, so let's make the following changes. First, update your admin_page.php file so it contains two form elements:

<div class="wrap">
<?php screen_icon(); ?>
<h2>Content Rotator Administration</h2>
<?php print $msg; ?>
<form action="" method="post" id="content_rotation_admin_
options_form">
<h3><label for="separator">Separator</label></h3>
<p>This separates units of content. It can be simple like
a comma, or complex like &lt;!--SEPARATOR--&gt;<br/>
<input type="text" id="separator" name="separator"
value="<?php print esc_attr( get_option('content_rotation_
content_separator') ); ?>" /></p>

<h3><label for="content_block">Content Block</label></h3>
<p>
Use the separator above to separate blocks of content,
e.g. <code>man, bear, pig</code><br/>
or <code>&lt;a href="http://mysite.com/"&gt;MySite.
com&lt;/a&gt;&lt;--SEPARATOR--&gt;
&lt;a href="http://yoursite.com/"&gt;YourSite.com&lt;/
a&gt;</code><br/>
<textarea rows="5" cols="50" id="content_block"
name="content_block"><?php print get_option('content_rotation_
content_block'); ?></textarea>
</p>
<p class="submit"><input type="submit" name="submit"
value="Update" /></p>
<?php wp_nonce_field('content_rotation_admin_options_
update','content_rotation_admin_nonce'); ?>
</form>
</div>

Notice that we're using WordPress' get_option() function to supply values to our form elements. Also, have a gander at the wp_nonce_field() function. What is a nonce? A nonce is a "number used only once", and it is an important security feature. By including a nonce as a hidden field on your forms, you can reduce the risk of your form being hijacked by a cross-site request forgery (CSRF). WordPress generates a unique value for this form which gets validated when the form is submitted. This makes it harder to post malicious data to your form. The full explanation of this technique is beyond the scope of this article, but you should use it for security reasons.

Any time we create a form, we also must handle the submission of that form. We need to program some code that handles the form data after it has been submitted. Let's do that next.

We need to save the form values if they were properly submitted. We do this by updating our controller function inside of ContentRotator.php:

/**
* Controller that generates admin page
*/
static function generate_admin_page()
{
$msg = ''; // used to display a success message on updates
if ( !empty($_POST) && check_admin_referer('content_rotation_
admin_options_update','content_rotation_admin_nonce') )
{
update_option('content_rotation_content_separator',
stripslashes($_POST['separator']) );
update_option('content_rotation_content_block',
stripslashes($_POST['content_block']) );
$msg = '<div class="updated"><p>Your settings have been
<strong>updated</strong></p></div>';
}
include('admin_page.php');
}

If you have built PHP form handlers in the past, you may be more familiar with a big if-else statement which decides whether it displays the form or processes the form based on whether or not it has been submitted. Our approach here is simpler. The check_admin_referer() function will terminate the script if the submission was not authentic, so we can't use an if-else construct. Instead we use a simple if-statement.

It's important to summarize the exact syntax that needs to be used for the wp_nonce_ field() and the check_admin_referer() functions because they need to match up. Some of the official documents for these functions are confusing, so here's the short syntax:

wp_nonce_field($action_name, $nonce_name);
check_admin_referer($action_name, $nonce_name);

Where $action_name is the name of the action and $nonce_name is the name of the nonce. If you have a page with multiple forms on it, it's important that you give unique values to each instance of the wp_nonce_field() function. However, the most important thing to remember here is that the arguments passed to the check_ admin_referer() function must match exactly the values passed to the wp_nonce_ field() function. If they do not match, WordPress will exit with a message. Oddly the message reads "Are you sure you want to do this?" which gives little inkling as to the root cause.

We use WordPress' update_option() function to store the options in the database, and we are using PHP's stripslashes() function to help sanitize the data. Note that the option names here match the names used by the get_option() functions in the admin_page.php page. So once again we have a pair of functions whose inputs must match.

Lastly, we are using a simple $msg variable to store a message to show whether or not the options have been updated. We are using some standard WordPress styling information by using a <div class="updated"> block here, and we encourage you to do the same.

Save your work and refresh your manager page. You should now be able to save custom configuration details and have them persist when you revisit the configuration page. For testing, we recommend that you use a comma separator and a simple comma-separated list. Enter in some text now before proceeding.

Randomizing content from the database

The stars are in alignment—we have custom content in the database, we have a widget that displays content, and choosing the random content all depends on a single function: ContentRotator::get_random_content(). Let's update that function, so it pulls our content from the database:

static function get_random_content(){
$separator = get_option('content_rotation_content_
separator');
$content_block = get_option('content_rotation_content_
block'); // Ensure that the user has entered valid settings
if ( empty($content_block) )
{
return '';
}
elseif (empty($separator))
{
return $content_block;
}
// Get an array of non-empty chunks
$content_array = explode($separator, $content_block);
$sanitized_array = array();
foreach ($content_array as $chunk)
{
$chunk = trim($chunk);
if (!empty($chunk))
{
$sanitized_array[] = $chunk;
}
}
$chunk_cnt = count($sanitized_array);
if ( $chunk_cnt)
{
$n = rand(0, ($chunk_cnt - 1));
return $sanitized_array[$n];
}
else
{
return '';
}
}

This all relies on the WordPress get_option() function and PHP's explode() function (make sure you use same option names that you used in the generate_ admin_page() function). We are using PHP's trim() function to do some cleanup in the event that someone entered in some empty content, but it's a fairly straightforward function. If you needed to test its ability to pick one item out of the list, you could simply supply static values to the $separator and $content_block variables.

When you save your work now, your initial draft of this widget is complete. Congratulations!

Review of PHP functions used

The following is a list of some of the PHP functions and constants used:

  • __CLASS__: PHP constant that contains the name of the PHP class in which it appears.
  • __FILE__: PHP constant that contains the name of the file in which appears.
  • parent::__construct(): A convenient way to run the __construct in the parent class. This statement is only used in a child class.
  • trim(): Removes whitespace from the beginning and end of a string.
  • rand(x,y): Picks a random number between x and y.
  • explode($separator, $str): Separates a string $str into an array by splitting it at each instance of $separator.
  • stripslashes(): Removes backslashes from form-submitted data.

Summary

We have created a total of seven files to build this plugin:

  • includes/admin_page.php
  • includes/ContentRotator.php
  • includes/ContentRotatorWidget.php
  • index.php
  • tpls/readme.txt
  • tpls/widget.tpl
  • tpls/widget_controls.tpl

If you made it to this point, give yourself a pat on the back. You've now created your first widget along with a custom manager page. These are important tools to have in your toolbox as you continue to develop WordPress plugins.


Further resources on this subject:


About the Author :


Brian Bondari

Brian Bondari is a musician, composer, and teacher with equal loves for both music and technology. His hobbies include reading, hiking, composing music, and playing with his pet rabbit. He also spends an exorbitant amount of time lying on the floor grading papers.

Brian earned his doctorate from the University of Kansas in 2009 and is currently an Assistant Professor of Music Theory and Composition at the University of Texas at Tyler. When he is not writing music or grading papers, he serves as Senior Editor for the multi-author technology blog, http://www.TipsFor.us.

You can also visit him at http://www.bondari.com.

Everett Griffiths

Everett Griffiths is a freelance PHP/Perl developer and database architect specializing in Content Management Systems and plugin development. His hobbies include playing guitar and running. He currently resides in Los Angeles with frequent trips abroad.

Books From Packt

WordPress Plugin Development: Beginner's Guide
WordPress Plugin Development: Beginner's Guide

WordPress Top Plugins
WordPress Top Plugins

WordPress 3 Complete
WordPress 3 Complete

WordPress 3 Site Blueprints
WordPress 3 Site Blueprints

WordPress 3.0 jQuery
WordPress 3.0 jQuery

WordPress 3 Ultimate Security
WordPress 3 Ultimate Security

WordPress and Flash 10x Cookbook
WordPress and Flash 10x Cookbook

WordPress 3.0 Search Engine Optimization
WordPress 3.0 Search Engine Optimization

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software