How to Extend the WordPress Recent Posts Widget

January 25, 2020 |

WordPress comes with a few handy widgets out of the box. One widget, for example, is the Recent Posts widget. By default, the recent posts widget only has a couple of settings that can be changed:

  • The number of posts to display
  • Show/hide the post date

What if we wanted to extend the widget to show additional fields from a post? To do this, we need to create a custom widget. In this post, we’ll extend the default WordPress Recent Posts widget to also include an excerpt and a “read more” link.

Getting Set Up

Using the WordPress recommended folder structure for custom theme development, create a folder called “inc” (includes) in your theme directory. Inside the “inc” directory, create another folder called “widgets”. Inside of the “widgets” directory, we’ll create a file called “widget-recent-posts.php”. The final path will look like: /wp-includes/inc/widgets/widget-recent-posts.php.

Since the WordPress recent posts widget already has most of the functionality we need, we’ll copy and reuse code from the recent posts file in our WordPress installation. The widget file we need is /wp-includes/widgets/class-wp-widget-recent-posts.php. Copy the contents of this file and paste it into the wodget-recent-posts.php file we created. In widget-recent-posts.php, create a function at the top of the file to register and load the widget using the “widgets_init” action hook:

// Register and load the widget
function load_custom_widget() {
    register_widget('Custom_Recent_Posts_Widget');
}
add_action('widgets_init', 'load_custom_widget');

Rename the class to match the widget we’re registering, “Custom_Recent_Posts_Widget”. In the class constructor, we’ll define the widget options in the $widget_opts variable.

// Name the new widget and extend the core functioning
public function __construct() {
    $widget_ops = array(
        'classname' => 'custom-recent-posts',
        'description' => __( 'Custom recent posts widget' ),
        'customize_selective_refresh' => true,
    );

    parent::__construct( 'custom-recent-posts', __( 'Custom Recent Posts' ), $widget_ops );
    $this->alt_option_name = 'widget_recent_blog_posts';
}

Including Our Custom Widget File

In functions.php, we need to include the path to our widget file:
require_once('inc/widgets/widget-recent-posts.php');

Registering the Sidebar and Widgetized Areas

We also need to make sure we register our sidebar/widgetized area in functions.php if a widgetized area in your theme doesn’t exist.

// Sidebars and widgetized areas
function rc_create_widget_area( $name, $id, $description ) {
    register_sidebar( array(
        'name' => __( $name ),   
        'id' => $id, 
        'description' => __( $description ),
        'before_widget' => '',
        'after_widget' => '',
        'before_title' => '<h2 class="widget-title">',
        'after_title' => '</h2>'
    ));
}

// Name the Widget area
rc_create_widget_area( 'Blog Sidebar', 'blog-recent-posts', 'Recent posts widget area for the blog template' );

Customizing Our Widget

Now that the initial setup is done, we can begin coding our custom recent posts widget to display more information.

Adding an Excerpt

In widget-recent-posts.php, locate the <ul></ul> element near line 92. Within this element, we’re going to modify the foreach loop to output our additional information. Within the loop, create the following variables the get the excerpt and trim the content so there is less text:

$post_excerpt = get_the_excerpt( $recent_post->ID ); 
$post_excerpt = wp_trim_words( $post_excerpt, 10 ); // re-assign variable and trim excerpt to 10 words

Next, add the new variable to the list item:

<li>
    <a href="<?php the_permalink( $recent_post->ID ); ?>"<?php echo $aria_current; ?>><?php echo $title; ?></a>
    <?php if ( $show_date ) : ?>
        <span class="post-date"><?php echo get_the_date( '', $recent_post->ID ); ?></span>
    <?php endif; ?>
    <p class="post-excerpt"><?php echo $post_excerpt; ?></p>
</li>

Adding a Read More Link

Adding a “Read More” link is just as simple. Below the post excerpt, create an anchor link with the the_premalink() function assigned as the href value:

<a href="<?php the_permalink($recent_post->ID); ?>" class="post-read-more">Read More</a>

Widget Settings

Great, the widget is almost finished! The next thing that needs to be done is to add settings for the excerpt and the read more link in the event we want these hidden in a different widget area. To do the, we just need to update the settings.

In the widget function near line 40, add the widget options to be processed and diplayed as html:

$show_excerpt = isset($instance['show_excerpt']) ? $instance['show_excerpt'] : false;
$show_link = isset($instance['show_link']) ? $instance['show_link'] : false;

In the update function near line 127, add the widget options to be saved to the database:

$instance['show_excerpt'] = isset( $new_instance['show_excerpt'] ) ? (bool) $new_instance['show_excerpt'] : false;
$instance['show_link'] = isset( $new_instance['show_link'] ) ? (bool) $new_instance['show_link'] : false;

In the form function near line 145, add the widget options to be shown in the widget form on the Widgets page:

$show_excerpt = isset($instance['show_excerpt']) ? (bool) $instance['show_excerpt'] : false;
$show_link = isset($instance['show_link']) ? (bool) $instance['show_link'] : false;

Within the form function, we also need to output the form markup that will make the new settings visible:

<p>
    <input 
        class="checkbox" 
        type="checkbox"<?php checked( $show_excerpt ); ?> 
        id="<?php echo $this->get_field_id( 'show_excerpt' ); ?>" 
        name="<?php echo $this->get_field_name( 'show_excerpt' ); ?>" 
    />
    <label for="<?php echo $this->get_field_id( 'show_excerpt' ); ?>"><?php _e( 'Display post excerpt?' ); ?></label>
</p>

<p>
    <input 
        class="checkbox" 
        type="checkbox"<?php checked( $show_link ); ?> 
        id="<?php echo $this->get_field_id( 'show_link' ); ?>" 
        name="<?php echo $this->get_field_name('show_link' ); ?>" />
    <label for="<?php echo $this->get_field_id( 'show_link' ); ?>"><?php _e( 'Display read more link?' ); ?></label>
</p>

To make these setting work in our code we just need to wrap the excerpt and the read more link in a conditional statements:

 <?php if ( $show_excerpt ) : ?>
    <p class="post-excerpt"><?php echo $post_excerpt; ?></p>
<?php endif; ?>

<?php if ( $show_link ) : ?>
    <a href="<?php the_permalink($recent_post->ID); ?>" class="post-read-more">Read More</a>
<?php endif; ?>

Wapping it Up

Now all you need to do is locate the new Widget in the WordPress backend and place it in your themes widgetized area. Here’s the final code for widget-recent-posts.php for reference.

Additional Resources