Thursday, April 10, 2025
•4 min read
How to Create a Custom Sidebar Widget Without a Plugin in WordPress
Custom sidebar widgets are still a solid way to add small, reusable bits of functionality to your WordPress site. You do not need a plugin for this - just a simple class that extends WP_Widget and a registration hook. Let’s wire one up step by step.
Step 1: Define the Widget Class
Open your active theme’s `functions.php` file (or better: a small custom plugin) and start by defining a widget class that extends `WP_Widget`. This sets up the structure WordPress expects:
1class My_Sidebar_Widget extends WP_Widget {
2
3 public function __construct() {
4 // Widget setup
5 }
6
7 public function widget( $args, $instance ) {
8 // Frontend output
9 }
10
11 public function form( $instance ) {
12 // Backend form fields
13 }
14
15 public function update( $new_instance, $old_instance ) {
16 // Save settings
17 }
18 }This by itself does nothing yet, but it gives you the four main methods every widget should implement.
Step 2: Fill Out the Widget Class
Constructor: Name and Description
1public function __construct() {
2 $widget_details = array(
3 'classname' => 'my_sidebar_widget',
4 'description' => 'A simple custom sidebar widget example.',
5 );
6
7 parent::__construct(
8 'my_sidebar_widget', // Base ID
9 'My Sidebar Widget', // Name in the admin UI
10 $widget_details
11 );
12 }Frontend Output: widget()
The `widget()` method controls what shows up in the sidebar on the frontend. We will use the instance title if set, and print a simple message as the widget content:
1public function widget( $args, $instance ) {
2 $title = ! empty( $instance['title'] ) ? $instance['title'] : '';
3
4 echo $args['before_widget'];
5
6 if ( ! empty( $title ) ) {
7 echo $args['before_title'] . esc_html( $title ) . $args['after_title'];
8 }
9
10 echo '<p>Hello, World!</p>';
11
12 echo $args['after_widget'];
13 }Admin Form: form()
The `form()` method builds the settings form in the Widgets screen. Here we add a single text field for the title and handle empty values safely:
1public function form( $instance ) {
2 $title = isset( $instance['title'] ) ? $instance['title'] : '';
3 ?>
4 <p>
5 <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
6 Title:
7 </label>
8 <input
9 class="widefat"
10 type="text"
11 id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
12 name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
13 value="<?php echo esc_attr( $title ); ?>"
14 />
15 </p>
16 <?php
17 }Save Settings: update()
1public function update( $new_instance, $old_instance ) {
2 $instance = array();
3 $instance['title'] = isset( $new_instance['title'] )
4 ? sanitize_text_field( $new_instance['title'] )
5 : '';
6
7 return $instance;
8 }Step 3: Register the Widget
Now you need to tell WordPress about the widget class using `register_widget()`. Add this below the class definition:
function register_my_sidebar_widget() {
register_widget( 'My_Sidebar_Widget' );
}
add_action( 'widgets_init', 'register_my_sidebar_widget' );After this, your widget will appear under Appearance -> Widgets. In newer WordPress versions with the block based widget editor, you will see it as a legacy widget and can still add it to any widget area.
Full Working Example
1<?php
2 // Custom sidebar widget class
3 class My_Sidebar_Widget extends WP_Widget {
4
5 public function __construct() {
6 $widget_details = array(
7 'classname' => 'my_sidebar_widget',
8 'description' => 'A simple custom sidebar widget example.',
9 );
10
11 parent::__construct(
12 'my_sidebar_widget',
13 'My Sidebar Widget',
14 $widget_details
15 );
16 }
17
18 public function widget( $args, $instance ) {
19 $title = ! empty( $instance['title'] ) ? $instance['title'] : '';
20
21 echo $args['before_widget'];
22
23 if ( ! empty( $title ) ) {
24 echo $args['before_title'] . esc_html( $title ) . $args['after_title'];
25 }
26
27 echo '<p>Hello, World!</p>';
28
29 echo $args['after_widget'];
30 }
31
32 public function form( $instance ) {
33 $title = isset( $instance['title'] ) ? $instance['title'] : '';
34 ?>
35 <p>
36 <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
37 Title:
38 </label>
39 <input
40 class="widefat"
41 type="text"
42 id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
43 name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
44 value="<?php echo esc_attr( $title ); ?>"
45 />
46 </p>
47 <?php
48 }
49
50 public function update( $new_instance, $old_instance ) {
51 $instance = array();
52 $instance['title'] = isset( $new_instance['title'] )
53 ? sanitize_text_field( $new_instance['title'] )
54 : '';
55 return $instance;
56 }
57 }
58
59 // Register the widget
60 function register_my_sidebar_widget() {
61 register_widget( 'My_Sidebar_Widget' );
62 }
63 add_action( 'widgets_init', 'register_my_sidebar_widget' );Useful Links
WordPress Developer Reference for WP_Widget:
Theme Handbook: Widgets API overview:
That is the basic pattern for a custom sidebar widget. From here you can swap out the static Hello World text with anything you need: recent items from an API, custom post queries, small forms, or anything else you can render with PHP and HTML.

I’m an experienced SEO professional with over a decade of helping over 100 businesses rank higher online, especially local businesses, e-commerce stores and SaaS. As the co-founder of LPagery, I specialize in practical, proven strategies for regular SEO and Local SEO success.