Blog, WordPress, WordPress Development, WordPress Snippet Codes

How to Create Custom WordPress Widget Step by Step With Example

One of the topics in WordPress is WordPress widget development. You can use widgets to add banners, advertisements, newsletter sign up forms, and other elements to your website. In this article, we will show you how to create a custom WordPress widget, step by step with example.

What Is WordPress Widget?

Widgets in WordPress contain pieces of code that you can add to your website’s sidebars or widget-ready areas (also called a sidebar).

Custom WordPress widget makes it easy for you to add additional functions to your website. Think of them as modules that you can use to add different elements by using a simple drag and drop interface.

By default, WordPress ships with several widgets. They provide you with basic utility features and are compatible with every WordPress theme.

However, sometimes, those standard widgets can’t perform the tasks you want. WordPress also allows developers to create their own custom widgets.

When to Use WordPress Widgets

You should use a widget whenever you want to add extra content to one or more pages in your site (and when I say page, I include posts, archives etc).

Think about how many users will need access to each widget and how important it is when you decide where to place it. Widgets in the sidebar will be more prominent than those in the footer, which some users may not even see.

So a latest posts widget or a call to action widget might be better off in the sidebar where people have more chance of interacting with them, while a social media feed could go in the footer.

If your theme also has special widget areas for the home page, you might want to use these for navigation around your site’s departments, lists of relevant content, or media such as a video welcoming people to the site.

Anatomy of a Widget

Visually, a widget comprises two areas:

  • Title Area
  • Widget Options

Where to Create Custom WordPress

It is up to you to choose whether you want to create the widget using a plugin or via editing the functions.php file.

A plugin will enable the custom widget to work on any site while adding code to functions.php. However, it will only be available when that particular theme is active.

Another tool that you can use is the Code Snippets plugin which allows you to easily add custom code to your WordPress website.

Widget Basics

In WordPress, you have to create a custom widget using the standard WP Widget class from the Widgets API. There are 18 functions that you can play around with. Out of these, four is the minimum requirement for any widget.

  • __construct() – constructor function where you can define your widget’s parameters.
  • widget() – contains the output of the widget.
  • form() – determines widget settings in the WordPress dashboard.
  • update() – updates widget settings.

Creating a Custom Widget in WordPress

One more thing to note is that we’re writing this code in the functions.php file for the currently loaded theme.

1. Extending the WP_Widget class

WordPress comes with a built-in WordPress Widget class. Each new WordPress widget extends the WordPress widget class.

Open your themes functions.php file with any editor you prefer. Create a new class that extends the base WP_Widget class.

class hs_example_widget extends WP_Widget {
    // The construct part  
    function __construct(){

    }
    // Creating widget front-end
    public function widget($args, $instance){

    }
    // Creating widget Backend 
    public function form($instance){

    }
    // Updating widget replacing old instances with new
    public function update($new_instance, $old_instance){

    }
}

2. Adding __construct()

We start implementing the four standard functions one by one. The first one is the constructor method, which will determine the custom widget’s ID, name, and description.

function __construct()
{
    parent::__construct(
    // widget ID
        'example_widget',
        // widget name
        __('HS Example Widget', 'hs-text-domain'),
        // widget description
        array('description' => __('Hostinger Widget Tutorial', 'hs-text-domain'),)
    );
}

3. Adding widget()

It defines the look of your WordPress custom widget on the front-end.

public function widget($args, $instance)
{
    $title = apply_filters('widget_title', $instance['title']);
    echo $args['before widget'];
    //if title is present
    If (!empty ($title))
        Echo $args['before_title'] . $title . $args['after_title'];
    //output
    echo __('Greetings from honarsystems.com!', 'hs-text-domain');
    echo $args['after_widget'];
}

we have configured the output of our widget so that it displays the phrase “Greetings from honarsystems.com!“.

4. Adding form()

We have to program the back-end of the widget using the form() method. You can see the result when you want to add the widget from the WordPress Widgets.

public function form( $instance ) {
    if ( isset( $instance[ 'title' ] ) )
        $title = $instance[ 'title' ];
    else
        $title = __( 'Default Title', 'hs-text-domain' );
    ?>
    <p>
        <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
        <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
    </p>
    <?php
}

Now you can see the widget in the Appearance > Widgets section in the admin panel.

Custom WordPress Widget

After adding into the one of widget areas, you can change widget title from Default Title to what you want.

Custom WordPress Widget

5. Adding update()

We have to implement update(), to save anything that’s input to that form. This will save the data input by users to the widget settings.

public function update( $new_instance, $old_instance ) {
    $instance = array();
    $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
    return $instance;
}

6. Registering the Widget

We define a function hs_register_widget() to register the widget class. Finally, we have to register the new custom widget using add_action() function.

function hs_register_widget() {
    register_widget( 'hs_example_widget' );
}
add_action( 'widgets_init', 'hs_register_widget' );

7. Final Code of Our Custom Widget

Final code will be below codes in functions.php file.

class hs_example_widget extends WP_Widget
{
    function __construct()
    {
        parent::__construct(
        // widget ID
            'example_widget',
            // widget name
            __('HS Example Widget', 'hs-text-domain'),
            // widget description
            array('description' => __('Hostinger Widget Tutorial', 'hs-text-domain'),)
        );
    }

    public function widget($args, $instance)
    {
        $title = apply_filters('widget_title', $instance['title']);
        echo $args['before widget'];
        //if title is present
        If (!empty ($title))
            Echo $args['before_title'] . $title . $args['after_title'];
        //output
        echo __('Greetings from honarsystems.com!', 'hs-text-domain');
        echo $args['after_widget'];
    }

    public function form( $instance ) {
        if ( isset( $instance[ 'title' ] ) )
            $title = $instance[ 'title' ];
        else
            $title = __( 'Default Title', 'hs-text-domain' );
        ?>
        <p>
            <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
        </p>
        <?php
    }

    public function update( $new_instance, $old_instance ) {
        $instance = array();
        $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
        return $instance;
    }
}

function hs_register_widget() {
    register_widget( 'hs_example_widget' );
}
add_action( 'widgets_init', 'hs_register_widget' );

Using the Example Widget

To add a widget to your site, you need to add it to a widget area. Go to Appearance > Widgets and add Example Widget to one of your widgets area which you prefer by drag and drop.

Widget areas are created by your theme because they relate to the design and layout of your site and not to functionality.

Most WordPress themes have widget areas in the sidebar and footer, although some will have multiple widget areas in lots of places, such as below or above the content or in the header.

Now go to your site and look the widget area. You will see the content produced by widget.

Custom WordPress Widget

Text Domain

there are a few things that you might want to ask. For example, what’s the purpose hs-text-domain?

WordPress uses gettext to handle translation and localization. This hs-text-domain and __() tells gettext to make a string available for translation.

If you are creating a custom widget for your theme, then you can replace hs-text-domain with your theme’s text domain.

Examples of Custom Widget

1. Text Widget

To build the text widget you will start by setting up a widget class that extends the WP_Widget class.

In the class constructor, you will call the parent constructor and pass it your widget’s base ID and name. Also in the class constructor, you will hook into the widgets_init action to register your widget.

public function __construct() {
    parent::__construct(
        'hs_text_widget', // Base ID
        'HS Text Widget', // Name
        array( 'description' => __( 'Honar Systems Text Widget', 'hs-text-domain' ), ) // Args
    );
}

Next, you will declare the arguments you will use when creating your widget. There are four arguments you must define, before_title, after_title, before_widget, and after_widget. These arguments will define the code that wraps your widgets title and the widget itself.

public function widget( $args, $instance ) {
    extract( $args );
    $title = apply_filters( 'widget_title', $instance['title'] );
    echo $before_widget;
    if ( ! empty( $title ) ) {
        echo $before_title . $title . $after_title;
    }
    echo __( 'Hello, World!', 'hs-text-domain' );
    echo $after_widget;
}

After defining your arguments, you will define the widget function. This function takes two parameters, the $args array from before, and the $instance of the widget, and is the function that will process options from the form and display the HTML for the widget on the front-end of your site. In the example above the widget function simply outputs the widget title, while passing it through the widget_title filter. It then outputs a simple widget wrapper and the content of the widget’s text field. As outlined in the example, you can access the options from the widget that are stored in the $instance.

public function form( $instance ) {
    if ( isset( $instance[ 'title' ] ) ) {
        $title = $instance[ 'title' ];
    }
    else {
        $title = __( 'New title', 'hs-text-domain' );
    }
    ?>
    <p>
        <label for="<?php echo $this->get_field_name( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
        <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
    </p>
    <?php
}

Next, you will define the form function. This function takes one parameter, $instance, and outputs the form that the user uses to create the widget in the Widgets admin screen. In the example above, the function starts by defining the $title and $text variables and setting them to the previously entered values, if those values exist. Then it outputs a simple form with a text field for the title and a textarea for the text content.

public function update( $new_instance, $old_instance ) {
    $instance = array();
    $instance['title'] = ( !empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
    return $instance;
}

Lastly you will define the update function. This function takes two parameters, $new_instance and $old_instance, and is responsible for updating your widgets with new options when they are submitted. Here you simply define $instance as an empty array. You then set the title and text keys to the $new_instance values if they exist. You then return $instance.

Final code will be code below:

class HS_Text_Widget extends WP_Widget {
    public function __construct() {
        parent::__construct(
            'hs_text_widget', // Base ID
            'HS Text Widget', // Name
            array( 'description' => __( 'Honar Systems Text Widget', 'hs-text-domain' ), ) // Args
        );
    }

    public function widget( $args, $instance ) {
        extract( $args );
        $title = apply_filters( 'widget_title', $instance['title'] );

        echo $before_widget;
        if ( ! empty( $title ) ) {
            echo $before_title . $title . $after_title;
        }
        echo __( 'Hello, World!', 'hs-text-domain' );
        echo $after_widget;
    }

    public function form( $instance ) {
        if ( isset( $instance[ 'title' ] ) ) {
            $title = $instance[ 'title' ];
        }
        else {
            $title = __( 'New title', 'hs-text-domain' );
        }
        ?>
        <p>
            <label for="<?php echo $this->get_field_name( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
        </p>
        <?php
    }

    public function update( $new_instance, $old_instance ) {
        $instance = array();
        $instance['title'] = ( !empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';

        return $instance;
    }

}
add_action( 'widgets_init', 'register_hs_text_widget' );

function register_hs_text_widget() {
    register_widget( 'HS_Text_Widget' );
}

2. Image Widget

In this example we are going to create custom WordPress widget for image upload. Lets create our widget. Same as usual, create widget class.

class HS_Image_Widget extends WP_Widget
{
}

In this example we are going to upload image into Media of WordPress and display it on the front-end. Constructor of this example is the little bit different from the Text Widget. Then first let define other functions.

widget function

public function widget($args, $instance)
{
    // Our variables from the widget settings
    $title = apply_filters('widget_title', empty($instance['title']) ? __('Title', 'hs-text-domain') : $instance['title']);
    $image = !empty($instance['image']) ? $instance['image'] : '';
    ob_start();
    echo $args['before_widget'];
    if (!empty($instance['title'])) {
        echo $args['before_title'] . $title . $args['after_title'];
    }
    if ($image): ?>
        <img src="<?php echo esc_url($image); ?>" alt="">
    <?php endif; 
    echo $args['after_widget'];
    ob_end_flush();
}

form function

public function form($instance)
{
    $title = !empty($instance['title']) ? $instance['title'] : __('Title', 'hs-text-domain');
    $image = !empty($instance['image']) ? $instance['image'] : '';
    ?>
    <p>
        <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label>
        <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>"
               name="<?php echo $this->get_field_name('title'); ?>" type="text"
               value="<?php echo esc_attr($title); ?>">
    </p>
    <p>
        <label for="<?php echo $this->get_field_id('image'); ?>"><?php _e('Image:', 'hs-text-domain'); ?></label>
        <img class="widefat" src="<?php echo esc_url($image); ?>"/>
        <input class="widefat" id="<?php echo $this->get_field_id('image'); ?>"
               name="<?php echo $this->get_field_name('image'); ?>" type="hidden"
               value="<?php echo esc_url($image); ?>"/>
        <button class="upload_image_button button button-primary"><?php _e('Upload Image', 'hs-text-domain') ?></button>
    </p>
    <?php
}

In this form we have a hidden field to store image url and pass it to back-end.

update function

public function update($new_instance, $old_instance)
{
    $instance = array();
    $instance['title'] = (!empty($new_instance['title'])) ? strip_tags($new_instance['title']) : '';
    $instance['image'] = (!empty($new_instance['image'])) ? $new_instance['image'] : '';
    return $instance;
}

registration

add_action('widgets_init', 'register_hs_text_widget');
function register_hs_text_widget()
{
    register_widget('HS_Image_Widget');
}

and finally constructor function

public function __construct()
{
    add_action('admin_enqueue_scripts', array($this, 'hs_scripts'));
    parent::__construct(
        'hs_image_widget', // Base ID
        'HS Image Widget', // Name
        array('description' => __('Honar Systems Image Widget', 'hs-text-domain'),) // Args
    );
}

public function hs_scripts()
{
    wp_enqueue_script('media-upload');
    wp_enqueue_media();
    wp_enqueue_script('our_admin', get_template_directory_uri() . '/our_admin.js', array('jquery'));
}

In constructor we have a add_action() to register JavaScript file. To use Media of WordPress we need add media scripts and our own script to upload the image.

These scripts will be added to admin section and not to user (front-end) section.

We defined hs_script() function to enqueue scripts. But we need our JS file to. Then create it beside of the functions.php file.

In JavaScript file, insert below code:

jQuery(document).ready(function ($) {
    $(document).on("click", ".upload_image_button", function (e) {
        e.preventDefault();
        var $button = $(this);
        // Create the media frame.
        var file_frame = wp.media.frames.file_frame = wp.media({
            title: 'Select or upload image',
            library: { // remove these to show all
                type: 'image' // specific mime
            },
            button: {
                text: 'Select'
            },
            multiple: false  // Set to true to allow multiple files to be selected
        });
        // When an image is selected, run a callback.
        file_frame.on('select', function () {
            // We set multiple to false so only get one image from the uploader
            var attachment = file_frame.state().get('selection').first().toJSON();
            $button.siblings('input').val(attachment.url);
            $button.siblings('img').attr('src',attachment.url).trigger('change');
            //trigger('change') active save button to save data
        });

        // Finally, open the modal
        file_frame.open();
    });
});

Important thing in this code is trigger(‘change’). After uploading image, the save button of widget in admin area will not be activate because it did not detect changes but we changed the image. To solve this issue we have to add trigger to activate the save button.

Add widget to a widget area

Custom WordPress Widget

Select an image from Media or upload it

Custom WordPress Widget

Click on save button

Custom WordPress Widget

See the result on website

Custom WordPress Widget