4 min read

How to Create a Custom Sidebar Widget Without a Plugin in WordPress

By Jonas Lindemann

Custom sidebar widgets add small, reusable features to your WordPress site. You don't need a plugin for this: a class that extends WP_Widget and a registration hook are enough.

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:

php
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

php
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:

php
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:

php
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()

php
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:

php
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

php
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' );

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.

About the Author

I've worked in SEO for more than ten years and helped over 100 businesses rank higher, mostly local businesses, e-commerce stores and SaaS companies. As co-founder of LPagery I work on local SEO, programmatic SEO and AI search visibility, and I test the strategies in these articles on our own sites and with our customers.