Posts Tagged ‘2.8’

Writing a custom Wordpress multi-instance widget

Thursday, December 3rd, 2009

wplogoblue-hoz-rgb

While working on a soon-to-be finished Wordpress theme for a client, I ran into a situation where it would be useful to create a custom widget that they could use to organize content on their site. Basically, they wanted to be able to select a random post or page and display some associated meta data. Essentially a custom image and content teaser. They were going to be doing this several times throughout the site, but in slightly different configurations. A post here, a page there. It seemed silly to hard-code these features. Using a widget would allow them to swap them out for a Twitter stream, or an RSS news feed in the future.

Making multi-instance widgets in Wordpress 2.8+ couldn’t be easier. Here is a good example to start with from the Wordpress codex.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
class My_Widget extends WP_Widget {
	function My_Widget() {
		// widget actual processes
	}
 
	function widget($args, $instance) {
		// outputs the content of the widget
	}
 
	function update($new_instance, $old_instance) {
		// processes widget options to be saved
	}
 
	function form($instance) {
		// outputs the options form on admin
	}
}
register_widget('My_Widget');
?>

And here is my finished widget (evolved from the above example).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<?php
/*
 * Custom mini-post widget
 */
class FGX_MiniPost_Widget extends WP_Widget {
	function FGX_MiniPost_Widget() {
		// widget actual processes
		parent::WP_Widget(false, $name = 'Floragenex MiniPost', array(
			'description' => 'Display a teaser for a post or a page.'
		));
	}
 
	function widget($args, $instance) {
		// outputs the content of the widget
			global $post;
 
			extract( $args );			
			$type = $instance['type'];
			$include = (!empty($instance['include']) ? explode(',', $instance['include']) : '');
			$category = (is_numeric($instance['category']) ? (int)$instance['category'] : '');
 
                        // Set up query for posts with the provided filters
			query_posts(array(
				'post_type' => $type,
				'post__in' => $include,
				'post__not_in' => array($post->ID),
				'cat' => $category,
				'post_status' => 'publish',
				'meta_key' => 'teaser_value',
				'meta_value' => '',
				'meta_compare' => '!=',
				'orderby' => 'rand',
				'posts_per_page' => '1'
			));
 
			echo $before_widget;
 
                        // Output widget, if a post exists that matches our query
			if ( have_posts() ) :
				while ( have_posts() ) : the_post();
					$post_meta = get_post_custom($post->ID);
					echo (!empty($post_meta['image_value'][0]) ? '<a href="' . get_page_link() . '">' .
							 '<img alt="image" src="' . get_bloginfo('template_url') . '/scripts/timthumb.php?src=' . htmlentities($post_meta['image_value'][0]) . '&h=62&w=180&zc=1" />' .
							 '</a>' : '') .
							 '<h3><a href="' . get_page_link() . '">' . get_the_title() . '</a></h3>' .
							 '<p>' . htmlentities($post_meta['teaser_value'][0]) . '</p>' .
							 '<p><a class="learn-more" href="' . get_page_link() . '">learn more</a></p>';
				endwhile;
			else:
				echo '<p>No posts found.</p>';
			endif;
 
                        // Very important to reset the query here.
			wp_reset_query();
 
			echo $after_widget;
	}
 
	function update($new_instance, $old_instance) {
		// processes widget options to be saved
		return $new_instance;
	}
 
	function form($instance) {
		// outputs the options form on admin		
		$type = esc_attr($instance['type']);
		$include = esc_attr($instance['include']);
		$category = esc_attr($instance['category']);
 
                // Get the existing categories and build a simple select dropdown for the user.
		$categories = get_categories();
 
		$cat_options = array();
		$cat_options[] = '<option value="BLANK">Select one...</option>';
 
		foreach ($categories as $cat) {
			$selected = $category === $cat->cat_ID ? ' selected="selected"' : '';
			$cat_options[] = '<option value="' . $cat->cat_ID .'"' . $selected . '>' . $cat->name . '</option>';
		}
 
		?>
			<p>
				<label for="<?php echo $this->get_field_id('type'); ?>">
					<?php _e('Content type:'); ?>
				</label>
				<select id="<?php echo $this->get_field_id('type'); ?>" class="widefat" name="<?php echo $this->get_field_name('type'); ?>">
					<option value="post"<?php echo ($type === 'post' ? ' selected="selected"' : ''); ?>>Post</option>
					<option value="page"<?php echo ($type === 'page' ? ' selected="selected"' : ''); ?>>Page</option>
				</select>
			</p>
			<p>
				<label for="<?php echo $this->get_field_id('include'); ?>">
					<?php _e('Include post IDs (optional):'); ?>
				</label>
				<input id="<?php echo $this->get_field_id('include'); ?>" class="widefat" type="text" name="<?php echo $this->get_field_name('include'); ?>" value="<?php echo $include; ?>" />
			</p>
			<p>
				<label for="<?php echo $this->get_field_id('category'); ?>">
					<?php _e('Include category (optional):'); ?>
				</label>
				<select id="<?php echo $this->get_field_id('category'); ?>" class="widefat" name="<?php echo $this->get_field_name('category'); ?>">
					<?php echo implode('', $cat_options); ?>
				</select>
			</p>				
		<?php
	}
}
 
// register widget
register_widget('FGX_MiniPost_Widget');
?>

Just paste this code in your theme’s functions.php file and the widget should appear under your available widgets.

This was a quick braindump post, so please feel free to post with any specific questions.