Web Development Tutorials

Programming

Create a WordPress Widget

A WordPress widget is a self-contained block you drop into a sidebar or footer — a search box, a list of recent posts, a promo panel. You create a WordPress widget by extending the WP_Widget class, which gives you four methods: a constructor that names the widget, widget() for the front-end output, and form() plus update() for its admin settings. This tutorial builds a “Recent Posts” widget from a small plugin, registers a sidebar to hold it, and shows the exact HTML it renders.

Requirements to create a WordPress widget:

  • WordPress 6.0 or newer (tested on WordPress 7.0.2).
  • Administrator access to install a plugin and edit widget areas.
  • PHP 7.4 or newer — the version your WordPress already runs on.

How To Create a WordPress Widget.

The objective is to register a widget an author can place from Appearance → Widgets, configure with a title and a post count, and have it print a list of recent posts on the front end.

Step 1.

First, create a plugin file so the widget survives a theme switch. In wp-content/plugins/, make a folder named ndriel-widget and, inside it, a file named ndriel-widget.php. The header comment is what lists it on the Plugins screen.

<?php
/**
 * Plugin Name: NdrieL Recent Posts Widget
 * Description: A simple recent-posts widget with a configurable title and count.
 * Version:     1.0.0
 */

if (!defined('ABSPATH')) {
    exit;
}

Step 2.

Next, register a widget area — a sidebar — for the widget to sit in, and render it in your theme. register_sidebar() runs on the widgets_init hook. The before_widget and before_title wrappers it defines are handed to every widget placed there, so markup stays consistent.

add_action('widgets_init', function () {
    register_sidebar(array(
        'name'          => 'Ndriel Sidebar',
        'id'            => 'ndriel-sidebar',
        'before_widget' => '<div class="widget %2$s">',
        'after_widget'  => '</div>',
        'before_title'  => '<h3 class="widget-title">',
        'after_title'   => '</h3>',
    ));
});

Then output that area wherever the theme should show it — usually in sidebar.php:

<?php if (is_active_sidebar('ndriel-sidebar')) : ?>
    <aside class="sidebar">
        <?php dynamic_sidebar('ndriel-sidebar'); ?>
    </aside>
<?php endif; ?>

Step 3.

Then, build the widget class. Extend WP_Widget and call the parent constructor with an ID base, a display name, and a description. The widget() method prints the front-end output; it wraps the title in the sidebar’s before_title markup and lists recent posts. Always escape what you print — esc_html(), esc_url().

class Ndriel_Recent_Posts_Widget extends WP_Widget {

    public function __construct() {
        parent::__construct(
            'ndriel_recent_posts',
            'Ndriel Recent Posts',
            array('description' => 'The site&rsquo;s most recent posts.')
        );
    }

    public function widget($args, $instance) {
        $title = apply_filters('widget_title', $instance['title'] ?? '');
        $count = empty($instance['count']) ? 5 : (int) $instance['count'];

        echo $args['before_widget'];
        if ($title) {
            echo $args['before_title'] . esc_html($title) . $args['after_title'];
        }

        $posts = get_posts(array('numberposts' => $count));
        echo '<ul>';
        foreach ($posts as $post) {
            printf(
                '<li><a href="%s">%s</a></li>',
                esc_url(get_permalink($post)),
                esc_html(get_the_title($post))
            );
        }
        echo '</ul>';
        echo $args['after_widget'];
    }

Step 4.

Next, add the two admin methods. form() draws the settings fields shown when an author adds the widget; get_field_id() and get_field_name() generate the unique attributes WordPress needs. update() then sanitises and saves those values when the author clicks Save.

    public function form($instance) {
        $title = $instance['title'] ?? 'Recent Posts';
        $count = $instance['count'] ?? 5;
        ?>
        <p>
            <label for="<?php echo $this->get_field_id('title'); ?>">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('count'); ?>">Number to show:</label>
            <input class="tiny-text"
                   id="<?php echo $this->get_field_id('count'); ?>"
                   name="<?php echo $this->get_field_name('count'); ?>"
                   type="number" min="1" value="<?php echo esc_attr($count); ?>">
        </p>
        <?php
    }

    public function update($new_instance, $old_instance) {
        $instance          = array();
        $instance['title'] = sanitize_text_field($new_instance['title']);
        $instance['count'] = (int) $new_instance['count'];
        return $instance;
    }
}

Step 5.

Finally, register the widget so WordPress knows about it, then place it. Call register_widget() on the same widgets_init hook as the sidebar. Activate the plugin, open Appearance → Widgets, drag Ndriel Recent Posts into Ndriel Sidebar, set a title and a count, and save.

add_action('widgets_init', function () {
    register_widget('Ndriel_Recent_Posts_Widget');
});

Result of the WordPress widget.

Once placed, the widget prints the sidebar wrapper, the title, and a list of the most recent posts — each a real permalink pulled from the database. This is the exact HTML the widget produced when rendered with a title of “Recent Posts” and a count of 3 on WordPress 7.0.2:

<div class="widget widget_ndriel_recent_posts">
  <h3 class="widget-title">Recent Posts</h3>
  <ul>
    <li><a href="http://ndriel.local/programming/force-a-file-download-in-php/">Force a File Download in PHP</a></li>
    <li><a href="http://ndriel.local/programming/match-text-with-regular-expressions-in-php/">Match Text With Regular Expressions in PHP</a></li>
    <li><a href="http://ndriel.local/programming/make-an-http-request-in-php-with-curl/">Make an HTTP Request in PHP with cURL</a></li>
  </ul>
</div>

Rendered in the sidebar, that markup looks like this:

WordPress widget rendered in a sidebar: a 'Recent Posts' box listing three linked post titles.

Notes on the WordPress widget:

  • Return nothing from widget() — echo instead. Unlike a shortcode, a widget’s widget() method prints its output directly. The two are opposites; mixing them up is a common slip.
  • Always wrap the output in $args['before_widget'] / $args['after_widget'] and the title in before_title / after_title. Those come from register_sidebar(), so your widget matches every other one in the area.
  • update() is your sanitising gate — run text through sanitize_text_field() and cast numbers, because the values come from whoever edits the widget.
  • To register more than one widget, call register_widget() once per class. Each needs its own unique ID base in the constructor.
  • If the widget prints, remember to enqueue any CSS it relies on rather than inlining a style block.

References:

//

Featured tutorial

Leave a comment

Your email address will not be published. Required fields are marked *