Creating Custom WordPress Widgets

With each new version of WordPress, the argument whether or not it qualifies as a CMS gets a little quieter.

In the WordPress core we have widgets, custom fields, custom taxonomies, and with version 2.9, an expansion of get_post_type. Add a few plugins and all sorts of post-types and custom write panels become a reality.

All this functionality is great so long as you, the developer, implement it in a way that is tough to break. Because once in the hands of the client, anything goes.

Flexible Layout

Then there is the issue of layout. For clients, moving content from one column to the other can be a technical hurdle, particularly for dynamic sites which rearrange content frequently to satisfy advertisers, audience demands, and so on.

Default drag-and-drop widgets are a great part of our arsenal, but adding your own custom widgets can really make life simpler for both developer and client.

Example Custom Widgets

In the quest to give more control to end users, Pro Theme has been experimenting with more custom widgets. Check out the demo for themes like The Local and Elemental for examples.

the local theme

Below are widgets we’ve started including with most themes, including Mimbo Pro:

  • Google Adsense. In the control panel you enter your Adsense ID and the widgets display ads accordingly. Works in any of the standard block sizes.
  • Community Tweets. Aggregates Twitter activity according to location latitude/longitude. Contains fields for Number of Tweets and Mile Radius.
  • Latest Tweets. Contains fields for Username and Number of Tweets
  • Post Author Details. Contains author avatar, date and comments feed.
  • Upcoming Posts. Displays a list of future-dated posts.
  • More from this Author. For single-post pages. Displays five headlines from the same author.
  • More from this Category. For single-post pages. Displays five headlines from the same category.
  • Print Preview. Uses javascript to render the page print-friendly and free of images.
  • Share This. Lets you post the current page to Twitter, StumbleUpon, Digg, Delicious and Facebook.
  • YouTube. Displays a featured video with fields for Embed Code and Description
  • Map Your Location. A Google Maps widget with fields for Location, Zoom Amount and Type of Map View (Roadmap, Satellite or Terrain).
  • Popular Posts. Displays five headlines of most-commented posts.
  • Subscribe to Feed. Includes an RSS icon and feed link.

We’ve gotten tons of great feedback from users who rely on positioning Google Adsense blocks and want to adjust their content accordingly. In the case of The Local, the entire homepage is 90% widgetized, with four columns to configure. Not to mention writers in the hyperlocal space who write unique content, but also rely on aggregating from other sites and social media sources.

How Do Custom Widgets Work

At the simplest possible level, custom widgets are implemented by 1) creating a class, and 2) registering a new widget. Forget about functionality within the widget for a moment and look at the basic setup which you would paste inside functions.php:

class My_Widget extends WP_Widget {
	function My_Widget() {
		parent::WP_Widget(false, 'Our Test Widget');
	}
function form($instance) {
		// outputs the options form on admin
	}
function update($new_instance, $old_instance) {
		// processes widget options to be saved
		return $new_instance;
	}
function widget($args, $instance) {
		// outputs the content of the widget
	}
}
register_widget('My_Widget');

That’s it. We can now visit our widgets panel to confirm:

custom widget

Adding editable functionality into our widget is another story. Using the “Popular Posts” widget as an example, my partner Ben Gillbanks will walk us through creating the rest.

Creating a “Popular Posts” Widget

Firstly we have to name the widget class. I prefix my functions and classes with bm_ (Binary Moon) as it means there will never be any clashes with other functions and plugins.

We can then name the widget in the constructor, which is the first function, and it should have the same name as the class. This will be called when the class is first created and it defines the name you see in the widget editor.

Next up, I create the last method which is a form function which defines what data can be editable within the widget. In this case, it’s simply the title of the widget to be displayed on the blog. The update method can often remain as it is, although you may want to do some data validation (make sure the data input is safe/ allowed).

Then finally, the widget method. This is where the widget itself is displayed. You’ll notice I am actually passing the arguments to another function that is elsewhere in the theme. The reason I do this is because I like to split the display out separately so that I can use the function directly in the theme without widgets as well.

Notice the $args parameter in the widget method. These args are actually the arguments you pass to the register sidebar method, before_widget, after_widget etc. You can read more about these and creating custom widgets on the WordPress Codex Widget API page.

Here is the final code:

<?php
class bm_widget_popularPosts extends WP_Widget {

	function bm_widget_popularPosts() {
		parent::WP_Widget(false, 'Popular Posts');
	}

	function widget($args, $instance) {
		$args['title'] = $instance['title'];
		bm_popularPosts($args);
	}

	function update($new_instance, $old_instance) {
		return $new_instance;
	}

	function form($instance) {
		$title = esc_attr($instance['title']);
?>
		<p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></label></p>
<?php
	}
 }
function bm_popularPosts($args = array(), $displayComments = TRUE, $interval = '') {

	global $wpdb;

	$postCount = 5;

	$request = 'SELECT *
		FROM ' . $wpdb->posts . '
		WHERE ';

	if ($interval != '') {
		$request .= 'post_date>DATE_SUB(NOW(), ' . $interval . ') ';
	}

	$request .= 'post_status="publish"
			AND comment_count > 0
		ORDER BY comment_count DESC LIMIT 0, ' . $postCount;

	$posts = $wpdb->get_results($request);

	if (count($posts) >= 1) {

		if (!isset($args['title']) {
			$args['title'] = 'Popular Posts';
		}

		foreach ($posts as $post) {
			wp_cache_add($post->ID, $post, 'posts');
			$popularPosts[] = array(
				'title' => stripslashes($post->post_title),
				'url' => get_permalink($post->ID),
				'comment_count' => $post->comment_count,
			);
		}

		echo $args['before_widget'] . $args['before_title'] . $args['title'] . $args['after_title'];
?>

		<ol>
<?php
		foreach ($popularPosts as $post) {
?>
			<li>
				<a href="<?php echo $post['url'];?>"><?php echo $post['title']; ?></a>
<?php
			if ($displayComments) {
?>
			(<?php echo $post['comment_count'] . ' ' . __('comments', BM_THEMENAME); ?>)
<?php
			}
?>
			</li>
<?php
		}
?>
		</ol>

<?php
		echo $args['after_widget'];
	}
}
?>

Further Uses for Custom Widgets?

Clients frequently need special notifications and other dynamic bits to display on their site with minimal setup. What other content that’s frequently handled via plugins would make a great custom widget?

Note: This post has also been translated by a reader into Belorussian