Creating a WordPress Widget Plugin Tutorial

I wanted a widget that displays a list of all the posts displayed on the current page, but I couldn’t find a WordPress widget plugin that would do what I wanted. Ergo sum I’ll build it myself. Here’s a super short tutorial on how to create a WordPress widget plugin.

To accomplish this, we’ll create a plugin that registers a widget. This widget will grab the global $posts object from WordPress (which contains the posts that are being displayed on the current page), and list their titles in a widget.

Here’s my template code:

 * Plugin Name: My Posts Widget
 * Description: A widget that displays a list of all the posts displayed on the current page.
 * Version: 1.0
 * Author: Your Name

// Register and load the widget
function my_posts_widget_load() {
    register_widget( 'my_posts_widget' );
add_action( 'widgets_init', 'my_posts_widget_load' );

// Creating the widget 
class my_posts_widget extends WP_Widget {

    function __construct() {
            __('My Posts Widget', 'my_posts_widget_domain'),
            array( 'description' => __( 'A widget that displays a list of all the posts displayed on the current page.', 'my_posts_widget_domain' ), ) 

    // Creating widget front-end
    public function widget( $args, $instance ) {
        global $posts;

        $title = apply_filters( 'widget_title', $instance['title'] );
        echo $args['before_widget'];
        if ( ! empty( $title ) )
            echo $args['before_title'] . $title . $args['after_title'];
        // this is where we output the posts
        echo '<ul>';
        foreach ($posts as $post) {
            echo '<li><a href="' . get_permalink($post) . '">' . $post->post_title . '</a></li>';
        echo '</ul>';
        echo $args['after_widget'];

    // Widget Backend 
    public function form( $instance ) {
        if ( isset( $instance[ 'title' ] ) ) {
            $title = $instance[ 'title' ];
        else {
            $title = __( 'New title', 'my_posts_widget_domain' );
        // Widget admin form
        <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 ); ?>" />

    // Updating widget replacing old instances with new
    public function update( $new_instance, $old_instance ) {
        $instance = array();
        $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
        return $instance;

Here’s what’s happening in the code:

  1. We’re creating a new widget with the name “My Posts Widget”. This will appear in the list of available widgets in the WordPress admin dashboard.
  2. The widget has a title which is editable from the widget settings.
  3. In the widget method, we’re accessing the global $posts variable, which WordPress sets with all the posts being displayed on the current page.
  4. We’re then iterating through each of the posts and adding a link to the post in an unordered list.

To install this plugin, you need to:

  1. Create a my-posts-widget directory. The majority of plugins follow the same pattern re: use of “-” to separate words.
  2. Copy the code above and put it in my_posts_widget.php file inside my-posts-widget directory.
  3. Compress the my-posts-widget directory to
  4. Go to your WordPress admin dashboard, then go to “Plugins > Add New > Upload Plugin”.
  5. Choose the file and click “Install Now”.
  6. After installation, activate the plugin by clicking “Activate”.

After you’ve done this, you’ll see a new widget available in your list of widgets called “My Posts Widget”. You can add it to any widget area in your theme like you would with any other widget.

Please note that this plugin will display all posts that are being displayed on the current page, regardless of where they’re displayed. That includes posts in main query, posts in sidebars, posts in footer etc. If you need more precise control, you’ll need to modify the code to suit your needs.