How to Create Custom WordPress Widget Step by Step With Example

Used before category names. Blog WordPress WordPress Development

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 an 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 Widget

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, form 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.

How to Create 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 theme 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 to the one of widget areas, you can change the widget title from Default Title to what you want.

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 the add_action() function.

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

Read more about WordPress Hooks and Actions

7. Final Code of Our Custom Widget

The final code will be the below codes in the 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 the Example Widget to one of your widgets areas 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 at the widget area. You will see the content produced by the widget.

Custom WordPress Widget

Text Domain

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

WordPress uses gettext to handle translation and localization. This hs-text-domain and __() tell 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 widget’s 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 set 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.

The 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 a custom WordPress widget for image upload. Let’s create our widget. Same as usual, create a widget class.

class HS_Image_Widget extends WP_Widget
{
}

In this example, we are going to upload an image into Media of WordPress and display it on the front-end. The constructor of this example is a little bit different from the Text Widget. Then first let’s 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 the 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 the constructor, we have a add_action() function to register JavaScript files. To use Media of WordPress we need to add media scripts and our own script to upload the image.

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

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

In the 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();
    });
});

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

Add the widget to a widget area

Select an image from the Media or upload it

Custom WordPress Widget

Click on the save button

Custom WordPress Widget

See the result on the website

Custom WordPress Widget
Tags: