One of the topics in WordPress CMS is how to create custom WordPress widget development. You can use widgets and plugins to add banners, advertisements, newsletter sign-up forms, and other elements to your website. Most widgets affect on website’s layout and other works could be done by plugins. 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 the custom Widget in WordPress
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 WordPress 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
in WordPress. 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, the form
is the minimum requirement for any custom widgets.
- __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.
After adding to one of the 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.
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
__()
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
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
Click on the save button
See the result on the website