Create popular posts widget without any plugin

In this tutorial, we are going to check how to create a popular post widget without any plugins. Lots of themes have popular post widgets built-in. In our previous tutorial, we learned how to create a child theme in GeneratePress. GeneratePress doesn’t have a Popular Posts widget.

So it can be achieved either through a plugin or some code into a Custom HTML widget. Since we are creating child themes, we can easily create a popular post widget via the child theme. And this is a better practice to modify parent theme code using a child theme.

This is because if we change the code of the parent theme and the theme is updated later, all of our code will be deleted. In order to create a popular post widget, we have to create a post view counter.

The popular post can be determined in two ways, for example, by comment count or post view count. But lots of websites disabled their comment section or they are using 3rd party comment plugins. In this situation, the comment count is not applicable for that. So we stick with post view count.

CONTENTS

How to create post view counter?

WordPress doesn’t have any post view counter. It means we can’t track no of views for a particular post. We can achieve it by using different plugins. But we will not use any plugin here. Either we can add the code in the functions.php of the parent theme or we can use the code in functions.php of the child theme.

  1. Create functions.php inside our child theme directory.
  2. We have to enter the code into functions.php file.
//set post view counter
function count_post_visits() {
	if( is_single() ) {
		global $post;

		$views = get_post_meta( $post->ID, 'gp_child_post_viewed', true );
		
		if( $views == '' ) {
			update_post_meta( $post->ID, 'gp_child_post_viewed', '1' );   
		}else {
			$views_count = intval( $views );
			update_post_meta( $post->ID, 'gp_child_post_viewed', ++$views_count );
		}
	}
}
add_action( 'wp_head', 'count_post_visits' );

In the above example, we have created a function called count_post_visits() which will check if the query is for a single post type that means if the post is a custom post or it’s a regular post by using is_single() function.

Here we have created a meta field name gp_child_post_viewed that will store the post views. Now hook this function into the head section of our page by add_action( 'wp_head', 'count_post_visits' );.

After saving the functions.php file, if we reload the page and visit a post multiple times we can see a custom meta field has been generated i.e. gp_child_post_viewed.

How to view custom field in WordPress?

If you edit a particular post, we can see the meta fields panel below the Gutenberg editor. By default the panel is hidden. So we need to go to the option (:), at the very right side of our window. Then select Preferences from that menu.

After that, a new dialog box will appear. Now go to the Panels tab and find the Additional section and then Turn on the custom fields option. To load all custom fields we need to click on Enable & Reload.

After reloading our page, we can see a meta field called gp_child_post_viewed with the value of 2. It means we have visited that pot two times. Although you can manually change the no of your view for a particular post.

How to create a popular post widget?

We have successfully created a post-view counter. Now based on that value, we are going to create a popular posts widget. In order to create a widget, WordPress has a Widget API. You can learn more from there.

To create a widget, we need to extend the WordPress WP_Widgetclass. We can directly create a widget class inside our child theme’s functions.php or directly to parent them’s functions.php.

But as we are working on the GeneratePress child theme, we are going to create our theme more structured. So, create a folder called widgets inside our child theme directory and also create a PHP class file i.e. popularpost_widget.php inside widgets folder.

First, let’s check the basic structure of the WordPress widget class. After that, we will modify it to perform our goal.

class My_Widget extends WP_Widget {

	/**
	 * Sets up the widgets name etc
	 */
	public function __construct() {
		$widget_ops = array( 
			'classname' => 'my_widget',
			'description' => 'My Widget is awesome',
		);
		parent::__construct( 'my_widget', 'My Widget', $widget_ops );
	}

	/**
	 * Outputs the content of the widget
	 *
	 * @param array $args
	 * @param array $instance
	 */
	public function widget( $args, $instance ) {
		// outputs the content of the widget
	}

	/**
	 * Outputs the options form on admin
	 *
	 * @param array $instance The widget options
	 */
	public function form( $instance ) {
		// outputs the options form on admin
	}

	/**
	 * Processing widget options on save
	 *
	 * @param array $new_instance The new options
	 * @param array $old_instance The previous options
	 *
	 * @return array
	 */
	public function update( $new_instance, $old_instance ) {
		// processes widget options to be saved
	}
}

We can see there is a total of four methods including the constructor.

  1. __construct() : We can set out widgets basic information like widget id, description etc.
  2. widget() : Using this method we can generate our widget UI. For example, we want to show our popular post innside unorder list (<ol>). We can do that from this method.
  3. form() : After drag and drop widget to sidebar or footer widget area, we can see there are some basic fields like title, description, no of post to show etc. The form() method store all the fileds that are required for a widget.
  4. update() : It will update old instance value with new one. For example, we want to show 10 posts as in popular post widget. So, update() methid will update all fields value.

Create a constructor for popular post widget:

function __construct() {
	parent::__construct(
	  
		// Base ID of your widget
		'gp_child_popular_post_widget', 
	  
		// Widget name will appear in UI
		__('GP Popular Post Widget', 'generatepresschild'), 
	  
		// Widget description
		array( 'description' => __( 'Show popular posts', 'generatepresschild' ), ) 
	);
}

In the parent constructor, we need to pass 3 arguments i.e. our widget id ( gp_child_popular_post_widget ), widget name that will appear in our widget UI, and widget description ( Show popular posts ).

Create popular post widget UI:

public function widget( $args, $instance ) {
	$title = apply_filters( 'widget_title', $instance['title'] );
	  
	// before and after widget arguments are defined by themes
	echo $args['before_widget'];
	
	if ( ! empty( $title ) ){
		echo $args['before_title'] . $title . $args['after_title'];
	}
	// This is where you run the code and display the output
	
	$popularpost = new WP_Query( 
		array( 
		'posts_per_page' => $instance['post_count'],
		'meta_key' => 'gp_child_post_viewed', 
		'orderby' => 'meta_value_num', 
		'order' => 'DESC'  
		) 
	);?>
	
	<ul>
	
		<?php while ( $popularpost->have_posts() ) : $popularpost->the_post();?>
			<li><a href="<?php the_permalink();?>"><?php the_title();?></a></li>
		<?php endwhile;?>
	</ul>
	<?php echo $args['after_widget'];
}

Now we need our custom post view counter (gp_child_post_viewed) here. By using WP_Query(), we are going to query our WordPress database. Here we have set 'meta_key' => 'gp_child_post_viewed'. It will show the posts based on our post counter meta i.e. “gp_child_post_viewed” and we have also set 'order' => 'DESC', that will show the post in descending order. It means the most viewed post will show at the top.

By 'posts_per_page' => $instance['post_count'] option, we can set how many posts will show in Widget.

Widget settings UI:

public function form( $instance ) {

	$title        = isset( $instance['title'] ) ? $instance['title'] : __( 'New title', 'generatepresschild' );
	$post_count  = isset( $instance['post_count'] ) ? absint( $instance['post_count'] ) : 5;
	
	// Widget form
	?>
		<p>
			<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 ); ?>" />
		</p>
		<p>
			<label for="<?php echo $this->get_field_name( 'post_count' ); ?>"><?php _e( 'No. of posts:' ); ?></label>
			<input class="widefat" id="<?php echo $this->get_field_id( 'post_count' ); ?>" name="<?php echo $this->get_field_name( 'post_count' ); ?>" type="number" value="<?php echo esc_attr( $post_count ); ?>" />
		</p>
	<?php 
}

The above code will create our widget settings UI. There is two instances in our widget i.e. title and post_count.

Update widget settings:

public function update( $new_instance, $old_instance ) {
	$instance = array();
	$instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
	$instance['post_count'] = (int) $new_instance['post_count'];
	return $instance;
}

This code will save our widget settings into the database. Suppose we need 4 posts to show in the widget area instead of 5. We can easily update from the widget settings area, and the update() will update our widgets settings into the database.

The full source code:

<?php

class gp_child_popular_post_widget extends WP_Widget {
  
	function __construct() {
		parent::__construct(
		  
			// Base ID of your widget
			'gp_child_popular_post_widget', 
		  
			// Widget name will appear in UI
			__('GP Popular Post Widget', 'generatepresschild'), 
		  
			// Widget description
			array( 'description' => __( 'Show popular posts', 'generatepresschild' ), ) 
		);
	}
	  
	// Creating widget front-end
	public function widget( $args, $instance ) {
		$title = apply_filters( 'widget_title', $instance['title'] );
		  
		// before and after widget arguments are defined by themes
		echo $args['before_widget'];
		
		if ( ! empty( $title ) ){
			echo $args['before_title'] . $title . $args['after_title'];
		}
		// This is where you run the code and display the output
		
		$popularpost = new WP_Query( 
			array( 
			'posts_per_page' => $instance['post_count'],
			'meta_key' => 'gp_child_post_viewed', 
			'orderby' => 'meta_value_num', 
			'order' => 'DESC'  
			) 
		);?>
		
		<ul>
		
			<?php while ( $popularpost->have_posts() ) : $popularpost->the_post();?>
				<li><a href="<?php the_permalink();?>"><?php the_title();?></a></li>
			<?php endwhile;?>
		</ul>
		<?php echo $args['after_widget'];
	}
			  
	// Widget Backend 
	public function form( $instance ) {

		$title        = isset( $instance['title'] ) ? $instance['title'] : __( 'New title', 'generatepresschild' );
		$post_count  = isset( $instance['post_count'] ) ? absint( $instance['post_count'] ) : 5;
		
		// Widget form
		?>
			<p>
				<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 ); ?>" />
			</p>
			<p>
				<label for="<?php echo $this->get_field_name( 'post_count' ); ?>"><?php _e( 'No. of posts:' ); ?></label>
				<input class="widefat" id="<?php echo $this->get_field_id( 'post_count' ); ?>" name="<?php echo $this->get_field_name( 'post_count' ); ?>" type="number" value="<?php echo esc_attr( $post_count ); ?>" />
			</p>
		<?php 
	}
		  
	// 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'] ) : '';
		$instance['post_count'] = (int) $new_instance['post_count'];
		return $instance;
	}
	 
	// Class wpb_widget ends here
} 

You can directly copy the code to functions.php or create a file in the widget folder that I have mentioned above and include the file into functions.php.

<?php
//include this line top of your functions.php
require_once( get_stylesheet_directory() . '/widgets/popularpost_widget.php');

How to register widget?

In order to register the widget, we need to write some code in the functions.php file.

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

Here in widgets_init hook, we will register our custom widget by register_widget() function. You can see we have passed our widget class name as an argument i.e. gp_child_popular_post_widget. In order to register the widget, make sure you have included the class file in your functions.php file.

How to set the popular post widget at sidebar?

I am using WordPress 5.8. So, the widget area is a little bit different from the previous version of WordPress. WordPress 5.8 update, we can see all registered widget areas of the current theme and also check the live update of our widgets.

  1. Go to Appearance>Widgets.
  2. Now go to registered widget area where you want to show your widget. In this case we are going to show it at top of our right sidebar.
    Wordpress widget area
  3. Now click on the plus (+) icon to add the the widget.
    select widget
  4. If you can’t see our newly registered widget, just enter the widget name at search box and click to add.
    add widget
  5. Here you can see the live view of our popular post widget.
    Popular post widget generatepress
  6. Now click on it and enter the title as Popular Post. We can also change the no of post from there. By default it set as 5.
    Generatepress popular post settings
  7. After that, click on update.

If we go to the website, we will see the popular post widget in the right sidebar.

About Ashis Biswas

A web developer who has a love for creativity and enjoys experimenting with the various techniques in both web designing and web development. If you would like to be kept up to date with his post, you can follow him.

1 thought on “Create popular posts widget without any plugin”

Leave a Comment