Building custom widgets is fun, rebuilding them because we need to change the way it looks is not. With that in mind, lets build a skinnable WordPress widget that separates how it looks from what it does. For the purposes of this tutorial, I am assuming that you are comfortable creating a Widget and working with the API. Please refer to the Widget API as needed.

File Structure

Create a new folder in the wp-content/plugins folder to store your Widget. Inside the folder create a _views folder where we’ll store our default layout template file. The final files are available on my GitHub account here.

Creating The Widget:

Create a basic Widget with whatever functionality you would like.  I will keep my Widget very simple and simply display a title and message.

Widgets are classes that extend the WP_Widget class and implement the appropriate methods. Here is quick overview of what they do.

The __construct() method sets some options for our widget as well as calls __construct in WP_Widget.

/**
   * Standard __construct method
   */
  function __construct() {
    
    //setup some options
    $widget_options = array(
      'classname'        =>        'skinnable-widget',
      'description'     =>        'A widget whose layout can be overridden in a theme'
    );
    
    //call WP_Widget's __construct method
    parent::__construct( 'rw_skinnable_widget', 'Skinnable Widget', $widget_options);
    
  }

The form() method displays the admin side of the form (in our case, a text field and text area) as well as handles the saving and retrieving of the values.

/**
     * Admin side widget form.
     *
     * @see WP_Widget::form()
     *
     * @param array $instance Previously saved values from database.
     */
    function form( $instance ) {
      // get the saved values (if any) and store them in local variables
        $title = ( $instance['title'] ) ? $instance['title'] : '';
        $message = ( $instance['message'] ) ? $instance['message'] : '';
        
        //output the form as html
        ?>
        <p>
              <label for="<?php echo $this->get_field_id('title'); ?>">Title: </label>
              <input type="text" class="widefat" id="<?php echo $this->get_field_id('title');?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo $title;?>" />
            </p>
            <p>
              <label for="<?php echo $this->get_field_id('message'); ?>">Message:</label>
              <textarea class="widefat" id="<?php echo $this->get_field_id('message');?>" name="<?php echo $this->get_field_name('message');?>"><?php echo $message;?></textarea>
        </p>
        <?php 
    }

The update() method is used for sanitization of form values and in my example just strips and html tags from the input values before being saved.

 /**
     * Sanitize widget form values as they are saved.
     *
     * @see WP_Widget::update()
     *
     * @param array $new_instance Values just sent to be saved.
     * @param array $old_instance Previously saved values from database.
     *
     * @return array Updated safe values to be saved.
     */
    function update( $new_instance, $old_instance ) {
      $instance = array();
      $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
      $instance['message'] = ( ! empty( $new_instance['message'] ) ) ? strip_tags( $new_instance['message'] ) : '';
      return $instance;
    }

The widget() Method

This brings us to the widget() method. This is the method that controls what is displayed on the front-end of the site and is where we will be adding the functionality we need.

/**
     * Front-end display of widget.
     *
     * @see WP_Widget::widget()
     *
     * @param array $args     Widget arguments.
     * @param array $instance Saved values from database.
     */
    function widget( $args, $instance ) {
      
      // get the saved values (if any) and store them in local variables
          $title = ( $instance['title'] ) ? $instance['title'] : '';
          $message = ( $instance['message'] ) ? $instance['message'] : '';
          
          //add to the arguments array any custom items we want to use in the template
          $args['title'] = $title;
          $args['message'] = $message;

          //render the output
          $this->sw_load_template( $args );
      }

First, we get the title and message variables from the $instance array and store them in local variables.

Next we taking those variables and add them to the $args array that is passed as an argument to widget(). This is done so we can have a reference to them in the template file. I’ll explain how shortly so for now just play along.

The next line calls a custom method we have defined – sw_load_template(). Let’s look at it line by line.

/**
     * Method to load the template
     * @param array The information we're going to pass to the template. Typically, the args parameter from the widget() method.
     */
    private function sw_load_template( array $_vars ) {
        //first look to see if there is template in the theme
        $possible_locations = array(
            'custom_templates/'.self::TEMPLATE_NAME,
            self::TEMPLATE_NAME
        );
        
        //use the wordpress method locate_templaet() to find any custom views
        $_template = locate_template( $possible_locations, false, false);
        
        // use the default one if the theme doesn't have it
        if(!$_template) {
            $_template = '_views/' . self::TEMPLATE_NAME ;
        }
        // load it
        extract($_vars);
        require $_template;
    }

First, we create an array of possible places a template file could be hiding.

Next we look for the template using  locate_template() passing the possible locations array and false for the next two parameters which tells the method to not load the file. Feel free to add as many as required.

The next two lines check to see if there was a template found in any of our possible locations list and if not, loads the default template we will store in the _views folder.

Just before we load the template, will use  extract() on the $_vars array. If you remember we added to the $args array that is passed to this method.

When we extract the array we create local variables for each index/value pair in the array, which we can then use in our templates.

For example:

$args[‘title’] = “The title”;

Becomes


$title = “The Title”;

The last step is to use require() method to pull $_template into the widget.

Create A View

Now that we have the Widget looking for templates, we need to create the default one. Create a new file called “skinnable-widget-view.php” and place it into the _views folder we created earlier.

The one I have created is pretty basic. It has the standard widget items $before_widget, $after_widget wrapping the widget contents. The $before_title and $after_title are wrapping our $title content which is followed by $message wrapped in a div.

<?php echo $before_widget; ?>
    <?php echo $before_title; ?>
        <?php echo $title;?>
    <?php echo $after_title; ?>
    <div class="message">
          <?php echo $message;?>
    </div>
<?php echo $after_widget; ?>

Here is how the Widget looks in the Twenty Thirteen theme:

default_widget

Override The View

Now for the whole reason we’re here. Let’s override the default template file with a custom one.

Open the default skinnable-widget-view.php and save as copy into your active theme directory in one of the places we designated as possible locations in our widget() method.

Make any change you wish to the template file. I have simply added the sentence “I like to customize things” to the template above where the message is output

<?php echo $before_widget; ?>
    <?php echo $before_title; ?>
        <?php echo $title;?>
    <?php echo $after_title; ?>
    <div class="message">
        I like to customize things
          <?php echo $message;?>
    </div>
<?php echo $after_widget; ?>

Now when the widget is loaded it will load the custom template instead of the default one.

Here is the same widget in Twenty Thirteen but using the customized template:

Final Skinnable WordPress Widget screenshot

 

Well that’s it for now. I hope you enjoyed it!

 

Comments