Create Custom Widgets in Wordpress


Creating widgets for your wordpress templates is great as it adds flexibilty within the template presentations. A user can either opt to display or hide certain sections of a template or add something else on his own in those widgets.

The widgets menu in wordpress dashboard is not visible until you initialize the widgets with widgets_init() hook pre-built in wordpress. Here's an example of a widget field for top section of webtrickshome right below the menu in home page.

function whtheme_widgets_init() {
 
    register_sidebar( array(
        'name' => __( 'Header Banner' ),
        'id' => 'top-banner',
        'description' => __( 'This is the top most section in frontpage that contains a background image and a search box' ),
        'before_widget' => '<aside id="%1$s" class="widget %2$s">',
        'after_widget' => '</aside>',
        'before_title' => '<h2 class="widget-title">',
        'after_title' => '</h2>',
        )
    );
} 
add_action( 'widgets_init', 'whtheme_widgets_init' );

Here, the parameters are name, id and description of the widget along with the html elements to place before and after the widget an it's title. These html elements take up class names from the first parameter i.e. id and second parameter form function name that creates the widget itself by converting them to string value.

Now, the widget holder has been created, let's create a widget to place into it. It's a good practice to place all of the widgets in a single location which helps to keep your project files organized. You can create a directory named widgets for that purpose. You can also create separate files for enqueue functions and sidebar registration functions and require them in functions.php as it's automatically initiated by wordpress.

<?php
add_action('widgets_init', 'top_banner');

function top_banner() {
    register_widget('top_banner');
}

if( !class_exists( 'top_banner' ) ) :
    class top_banner extends WP_Widget {}
endif;

The wordpress hook on the top and the function below it registers and adds this widget in the dashboard under Appearances » Widgets. It's agood practice to check if the class you're going to create already exists before writing further blocks of codes. WP_Widget class holds all the functions required to create a widget and we all need to do is extend that class. Rest of the following codes will be placed inside this class.

public function __construct() {
    parent::__construct(
        'top_banner', 'Top Banner', array(
        'description' => __('Frontpage Top Banner')
        )
    );
}

This method adds the widget in the widget list with the name Top Banner and the defined description below it.

private function widget_fields() {
    $fields = array(            
        'banner_image' => array(
            'theme_widgets_name' => 'banner_image',
            'theme_widgets_title' => __('Upload Image'),
            'theme_widgets_field_type' => 'upload',
        ),
        'banner_title' => array(
            'theme_widgets_name' => 'banner_title',
            'theme_widgets_title' => __('Banner Title'),
            'theme_widgets_field_type' => 'text',
        ),
        'banner_icon' => array(
            'theme_widgets_name' => 'banner_icon',
            'theme_widgets_title' => __('Info Icon'),
            'theme_widgets_field_type' => 'Icon',
        ),
    );
    return $fields;
}

This function defines the input fields available in the widget. Each of the fieldnames must be an array that holds the same fieldname under theme_widgets_name, a title to display beside the field in dashboard under theme_widgets_title and the type of field under theme_widgets_field_type to generate the fields in dashboard.

public function widget($args, $instance) {
    extract($args);
    if($instance!=null){        
    $image = $instance['banner_image'];
    $title = $instance['banner_title'];
    $icon = $instance['banner_icon'];

    echo $before_widget; ?>
            
    <?php if (!empty($image)): ?>
        <img src = "<?php echo $image; ?>"/>
    <?php endif; ?>  
    <?php if (!empty($title)): ?>
        <?php echo $title; ?>
    <?php endif; ?>
    <?php if (!empty($icon)): ?>
        <i class="fa <?php echo $icon; ?>"></i>
    <?php endif; ?>                                                  

    <?php 
        echo $after_widget;
    }
}

This function defines the html output that is rendered by this widget. The entire content will be wrapped by the html element defined as before_widget and after_widget in sidebar registration and the widget title is wrapped up by the elements defined in before_title and after_title.

public function update($new_instance, $old_instance) {
    $instance = $old_instance;

    $widget_fields = $this->widget_fields();

    foreach ($widget_fields as $widget_field) {
        extract($widget_field);
        $instance[$theme_widgets_name] = theme_widgets_updated_field_value($widget_field, $new_instance[$theme_widgets_name]);
    }
    return $instance;
}    

This function requires no modifications and simply updates the field values.

public function form($instance) {
    $widget_fields = $this->widget_fields();
        
    foreach ($widget_fields as $widget_field) {
        extract($widget_field);
        $theme_widgets_field_value = !empty($instance[$theme_widgets_name]) ? esc_attr($instance[$theme_widgets_name]) : '';
        theme_widgets_show_widget_field($this, $widget_field, $theme_widgets_field_value);
    }
}    

This function also needs no modifications and is required to display the form fields.

Everything is fine upto here except an error that says theme_widgets_show_widgets_field() function is not defined. Now, you need to create a new file that holds the functions to display widget form fields and require it in the functions.php file as well.