PMG Digital Made for Humans

How to Build Your Own WordPress Widgets

7 MINUTE READ | October 11, 2011

How to Build Your Own WordPress Widgets

Author's headshot

Christopher Davis

Christopher Davis has written this article. More details coming soon.

Widgets and dynamic sidebars allow WordPress to be one of the most flexible CMS’s on the planet. In WordPress 2.8 a new way of creating widgets was introduced. In this tutorial we’re going to cover creating WordPress widgets. We’ll also touch on the WP HTTP API and transients.

The mission: create a widget that displays our most recent tweet.

You create a new WordPress widget by doing two things: (1) creating a class that extends WP_Widget and (2) registering that widget with the 

register_widget()
 function.In you class you have to implement four methods (functions): a PHP4 style constructor with the same name as the class, update, form, and widget. The constructor is what sets up your options like the widget html class name and ID base – it’s also where you define the widget name. update takes care of cleaning the widgets data on save, and form contains the actual HTML input form for the widget. The widget function is where the magic happens: it contains all your display logic.

So your basic widget class might look something like this…

<?php
class pmgTutTweetWidget extends WP_Widget
{
    function pmgTutTweetWidget()
    {
        
    }
    
    function form( $instance )
    {
        
    }
    
    function update( $new, $old )
    {    
        
    }
    
    function widget( $args, $instance )
    {
        
    }
}

In your constructor, you define an associative array containing a classname and description. Classname is the HTML class that will get passed into the widget’s container. This is useful if your widget also includes styling elements. The description is shown on the widgets screen.

After defining the options array, you’ll pass it in the WP_Widget constructor, which takes three arguments: the id base of the widget, the widget title, and the options array.

<?php
class pmgTutTweetWidget extends WP_Widget
{
    function pmgTutTweetWidget()
    {
        $opts = array(
            ‘classname’ => ‘pmg-tweet-widget’,
            ‘description’ => __( ‘Display your most recent tweet’ )
        );
        
        parent::__construct( ‘pmg-tweet-widget’, __( ‘Latest Tweet’ ), $opts );
    }
    
    // …
}

Our widget is going to have to fields: a title and a twitter user name. We’ll create the form in the form function, which is going to receive an array of the options. Throughout this tutorial, we refer to this as $instance. Behind the scenes, WordPress is going to look for the options for a given widget in the database. Those options are passed as what we call $instance.

Of course, if this is a brand new widget, with no saved options, the array with be empty. So we can set up an array of defaults then use wp_parse_args to make sure those defaults are used. After that, it’s just a matter of some basic HTML form stuff. The only catch is that will use two WP_Widget methods to get field IDs and names: get_field_name and get_field_id. Both return “safe” names that don’t conflict with other widgets on the WordPress admin widget screen.

<?php
class pmgTutTweetWidget extends WP_Widget
{
    // …
    
    function form( $instance )
    {
        
        $defaults = array(
            ‘title’        => ”,
            ‘twitter’     => ‘agencypmg’,
        );
        
        $instance = wp_parse_args( $instance, $defaults );
        $display = array(
            ‘twitter’     => __( ‘Your Latest Tweet’ ),
            ‘custom’    => __( ‘A Custom Message’ )
        );
        ?>
            <p>
                <label for=“<?php echo $this->get_field_id( ‘title’ ); ?>“><?php _e( ‘Title’ ); ?></label>
                <input type=“text” name=“<?php echo $this->get_field_name( ‘title’ ); ?>“ class=“widefat” id=“<?php echo $this->get_field_id( ‘title’ ); ?>“ value=“<?php echo esc_attr( $instance[‘title’] ); ?>“ />
            </p>
            
            <p>
                <label for=“<?php echo $this->get_field_id( ‘twitter’ ); ?>“><?php _e( ‘Twitter’ ); ?></label>
                <input type=“text” name=“<?php echo $this->get_field_name( ‘twitter’ ); ?>“ class=“widefat” id=“<?php echo $this->get_field_id( ‘twitter’ ); ?>“ value=“<?php echo esc_attr( $instance[‘twitter’] ); ?>“ />
            </p>
        
        <?php
    }
    
    // …
    
} // end class

The update method receives two arguments: the old instance and the new (which contains the updated settings). This is your typical data validation stuff.

<?php
class pmgTutTweetWidget extends WP_Widget
{
    
    // …
    
    function update( $new, $old )
    {    
        $clean = $old;
        $clean[‘title’] = isset( $new[‘title’] ) ? strip_tags( esc_html( $new[‘title’] ) ) : ”;
        $clean[‘twitter’] = isset( $new[‘twitter’] ) ? esc_attr( $new[‘twitter’] ) : ”;
        return $clean;
    }
    
    // …
    
} // end class

widget handles the display of the widget. The first argument it receives the array of arguments for the sidebar (including the before and after widget tags and all that). It also receives the $instance which contains the options for the specific widget.

So, first off, let’s extract the general sidebar arguments, and echo out the $before_widget variable. Then we’ll see if we have a widget title. If we do, we can echo out the $before_title, $instance['title'] and $after_title variables.

<?php
class pmgTutTweetWidget extends WP_Widget
{
    // …
    
    function widget( $args, $instance )
    {
        extract( $args );
        echo $before_widget;
        if( $instance[‘title’] )
        {
            echo $before_title . strip_tags( $instance[‘title’] ) . $after_title;
    }
    }
} // end class

Next up, we’ll avoid the question of getting the tweet and call another method, get_tweet, that we’ll implement later (see below). Then we can echo out the $after_widget variable.

<?php
class pmgTutTweetWidget extends WP_Widget
{
    // …
    
    function widget( $args, $instance )
    {
        extract( $args );
        echo $before_widget;
        if( $instance[‘title’] )
        {
            echo $before_title . strip_tags( $instance[‘title’] ) . $after_title;
        }
        ?>
            <div class=“pmg-tweet-tweet”>
                <?php echo $this->get_tweet( esc_attr( $instance[‘twitter’] ) ); ?>
            </div>
        <?php
        echo $after_widget;
    }
    
    // …
    
} // end class

This is a bit of a crash course in the WordPress HTTP API and transients.

What we don’t want to do on every page load is hit the Twitter API. So, instead, we’re going to save our tweet as a transient, WordPress’ method for storing data that expires. In our method, we’ll see if we can get the transient first. If we can, then we’ll just return that. Otherwise, we’ll have to go to the API.

<?php
class pmgTutTweetWidget extends WP_Widget
{
    // …
    
    function get_tweet( $user )
    {
        /**
        * Try to fetch our tweet from the database so we don’t have to hit the
        * Twitter api
        */
        if( $tweet = get_transient( ‘pmg_tweet_’ . $user ) )
        {
            return $tweet;
        }
        else // no dice, gotta go for twitter
        {
         }
     }
}

To fetch our tweet, we’ll use wp_remote_get. Which will either return an array of a whole bunch of stuff or a WP_Error object. The array will contain header and status code information, so we can make sure we actually got a response. If we didn’t, just return an empty string. Maybe better luck next time.

Twitter will give us a JSON, which can decode with PHP’s json_decode After that, we’ll see if our status is set, grab it, and make any links clickable with WordPress’ make_clickable function.

The final piece of the puzzle is setting our transient, so we don’t have to do this whole API call over and over again. After that, we can return the tweet.

function get_tweet( $user )
{
    /**
    * Try to fetch our tweet from the database so we don’t have to hit the
    * Twitter api
    */
    if( $tweet = get_transient( ‘pmg_tweet_’ . $user ) )
    {
        return $tweet;
    }
    else // no dice, gotta go for twitter
    {
        // build our url, can’t pass strings directly to wp_remote_get :/
        $url = ‘http://api.twitter.com/1/users/show.json?id=’ . $user;
        
        // fetch!
        $resp = wp_remote_get( $url );
        
        // bail if we failed to get a 200 response (or got a WP_Error object)
        if( is_wp_error( $resp ) || 200 != $resp[‘response’][‘code’] ) return ”;
        
        // parse the json
        $obj = json_decode( $resp[‘body’] );
        
        // get the status and make any links clickable
        $status = isset( $obj->status->text ) ? make_clickable( $obj->status->text ) : ”;
        
        // Set our transient so we don’t have to hit twitter again for 12 hours.
        set_transient( ‘pmg_tweet_’ . $user, $status, 60 * 60 * 12 );
        
        // Whew, return the tweet
        return $status;
    }
}

That’s the twitter function is reusable anywhere you’d like.

The very last step is to register the widget. Hook a function in widget_init. Inside it, you can call register_widget, which takes one argument: the class name we’ve been working on above.

<?php
// Register our widget
add_action( ‘widgets_init’, ‘pmg_add_tut_widget’ );
function pmg_add_tut_widget()
{
    register_widget( ‘pmgTutTweetWidget’ );
}

Stay in touch

Bringing news to you

Subscribe to our newsletter

By clicking and subscribing, you agree to our Terms of Service and Privacy Policy

That’s it! All the code for this tutorial is available as a plugin, so check it out!


Related Content

thumbnail image

AlliPMG CultureCampaigns & Client WorkCompany NewsDigital MarketingData & Technology

PMG Innovation Challenge Inspires New Alli Technology Solutions

4 MINUTES READ | November 2, 2021

thumbnail image

Applying Function Options to Domain Entities in Go

11 MINUTES READ | October 21, 2019

thumbnail image

My Experience Teaching Through Jupyter Notebooks

4 MINUTES READ | September 21, 2019

thumbnail image

Working with an Automation Mindset

5 MINUTES READ | August 22, 2019

thumbnail image

3 Tips for Showing Value in the Tech You Build

5 MINUTES READ | April 24, 2019

thumbnail image

Testing React

13 MINUTES READ | March 12, 2019

thumbnail image

A Beginner’s Experience with Terraform

4 MINUTES READ | December 20, 2018

ALL POSTS