
With WordPress 2.8, Automatic introduced a new widget management panel but also a new way of making your own widgets. Before is was a bunch of messy functions, now it’s a nice widget API easier than ever.
Justin Tadlock wrote a very comprehensive article about making widget in 2.8 and I will use this to make a widget that displays only posts from a given category name. In CMS like build I often need a way to display the recent post from the new/blog category and I always end up pasting a custom WP_Query. And I am not happy about that. I’d rather use a widget that will do the job for me from the admin.
(If you just want the code and don’t care about the explanations the file is downloadable here. Just include it in your function.php file and you’re done.)
Let’s get started
First we have to create the class that will old all the widget methods. This class should extend the WP_Widget class to be able to use all the built in functions that will make your life easier.
class Posts_By_Cat extends WP_Widget {
Then we need to set up a constructor for this class, in order to create the widget object in php. A constructor is automatically called when WordPress call the widget.
function Posts_By_Cat() {
/* Widget settings. */
$widget_ops = array( 'classname' => 'posts_by_cat', 'description' => 'Display posts from only one defined category' );
/* Create the widget. */
$this->WP_Widget( 'posts_by_cat-widget', 'Posts by Category', $widget_ops);
}
Now think about what a widget needs to do: display stuff on the front end, display editing option in the back end, save values passed from the back end. And we will have exactly that, one function for each.
Display on the front end
function widget( $args, $instance ) {
extract( $args );
/* User-selected settings. */
$title = apply_filters('widget_title', $instance['title'] );
$catname = $instance['catname'];
// to sure the number of posts displayed isn't negative or more than 15
if ( !$number = (int) $instance['number'] )
$number = 10;
else if ( $number < 1 )
$number = 1;
else if ( $number > 15 )
$number = 15;
//the query that will get posts from a specific category.
//Wr slug the category because you actualy need the slug and not the name
$r = new WP_Query(array('category_name' => $this->slug($catname), 'showposts' => $number, 'nopaging' => 0, 'post_status' => 'publish', 'caller_get_posts' => 1));
//display the posts title as a link
if ($r->have_posts()) :
?>
<?php echo $before_widget; ?>
<?php if ( $title ) echo $before_title . $title . $after_title; ?>
<ul>
<?php while ($r->have_posts()) : $r->the_post(); ?>
<li><a href="<?php the_permalink() ?>" title="<?php echo esc_attr(get_the_title() ? get_the_title() : get_the_ID()); ?>"><?php if ( get_the_title() ) the_title(); else the_ID(); ?> </a></li>
<?php endwhile; ?>
</ul>
<?php echo $after_widget; ?>
<?php
wp_reset_query(); // Restore global post data stomped by the_post().
endif;
echo $after_widget;
}
Display the back end option form
function form( $instance ) {
/* Set up some default widget settings. */
$defaults = array( 'title' => 'Example', 'catname' => 'news', 'number' => 5);
$instance = wp_parse_args( (array) $instance, $defaults ); ?>
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>">Title:</label>
<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $instance['title']; ?>" />
</p>
<p>
<label for="<?php echo $this->get_field_id( 'catname' ); ?>">Category name:</label>
<input class="widefat" id="<?php echo $this->get_field_id( 'catname' ); ?>" name="<?php echo $this->get_field_name( 'catname' ); ?>" value="<?php echo $instance['catname']; ?>" />
</p>
<p>
<label for="<?php echo $this->get_field_id( 'number' ); ?>">Number of posts to show</label>
<input id="<?php echo $this->get_field_id( 'number' ); ?>" name="<?php echo $this->get_field_name( 'number' ); ?>" value="<?php echo $instance['number']; ?>" size="3" />
<br /><small>(at most 15)</small>
</p>
<?php
}
Update values when the options are saved
function update( $new_instance, $old_instance ) {
$instance = $old_instance;
/* Strip tags (if needed) and update the widget settings. */
$instance['title'] = strip_tags( $new_instance['title'] );
$instance['catname'] = strip_tags( $new_instance['catname'] );
$instance['number'] = $new_instance['number'];
return $instance;
}
And now all we need to do is register our widget with WordPress and it should appear in the widget panel
/* Add our function to the widgets_init hook. */
add_action( 'widgets_init', 'post_by_cat_widgets' );
/* Function that registers our widget. */
function post_by_cat_widgets() {
register_widget( 'Posts_By_Cat' );
}
The whole code with the slug function
<?php
/* Add our function to the widgets_init hook. */
add_action( 'widgets_init', 'post_by_cat_widgets' );
/* Function that registers our widget. */
function post_by_cat_widgets() {
register_widget( 'Posts_By_Cat' );
}
class Posts_By_Cat extends WP_Widget {
function Posts_By_Cat() {
/* Widget settings. */
$widget_ops = array( 'classname' => 'posts_by_cat', 'description' => 'Display posts from only one defined category' );
/* Widget control settings. */
//$control_ops = array( 'width' => 300, 'height' => 350, 'id_base' => 'posts_by_cat-widget' );
/* Create the widget. */
$this->WP_Widget( 'posts_by_cat-widget', 'Posts by Category', $widget_ops);
}
function widget( $args, $instance ) {
extract( $args );
/* User-selected settings. */
$title = apply_filters('widget_title', $instance['title'] );
$catname = $instance['catname'];
// to sure the number of posts displayed isn't negative or more than 15
if ( !$number = (int) $instance['number'] )
$number = 10;
else if ( $number < 1 )
$number = 1;
else if ( $number > 15 )
$number = 15;
//the query that will get post from a specific category.
//Wr slug the category because you actualy need the slug and not the name
$r = new WP_Query(array('category_name' => $this->slug($catname), 'showposts' => $number, 'nopaging' => 0, 'post_status' => 'publish', 'caller_get_posts' => 1));
//display the posts title as a link
if ($r->have_posts()) :
?>
<?php echo $before_widget; ?>
<?php if ( $title ) echo $before_title . $title . $after_title; ?>
<ul>
<?php while ($r->have_posts()) : $r->the_post(); ?>
<li><a href="<?php the_permalink() ?>" title="<?php echo esc_attr(get_the_title() ? get_the_title() : get_the_ID()); ?>"><?php if ( get_the_title() ) the_title(); else the_ID(); ?> </a></li>
<?php endwhile; ?>
</ul>
<?php echo $after_widget; ?>
<?php
wp_reset_query(); // Restore global post data stomped by the_post().
endif;
echo $after_widget;
}
function update( $new_instance, $old_instance ) {
$instance = $old_instance;
/* Strip tags (if needed) and update the widget settings. */
$instance['title'] = strip_tags( $new_instance['title'] );
$instance['catname'] = strip_tags( $new_instance['catname'] );
$instance['number'] = $new_instance['number'];
return $instance;
}
function form( $instance ) {
/* Set up some default widget settings. */
$defaults = array( 'title' => 'Example', 'catname' => 'news', 'number' => 5);
$instance = wp_parse_args( (array) $instance, $defaults ); ?>
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>">Title:</label>
<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $instance['title']; ?>" />
</p>
<p>
<label for="<?php echo $this->get_field_id( 'catname' ); ?>">Category name:</label>
<input class="widefat" id="<?php echo $this->get_field_id( 'catname' ); ?>" name="<?php echo $this->get_field_name( 'catname' ); ?>" value="<?php echo $instance['catname']; ?>" />
</p>
<p>
<label for="<?php echo $this->get_field_id( 'number' ); ?>">Number of posts to show</label>
<input id="<?php echo $this->get_field_id( 'number' ); ?>" name="<?php echo $this->get_field_name( 'number' ); ?>" value="<?php echo $instance['number']; ?>" size="3" />
<br /><small>(at most 15)</small>
</p>
<?php
}
function slug($string)
{
$slug = trim($string);
$slug= preg_replace('/[^a-zA-Z0-9 -]/','', $slug); // only take alphanumerical characters, but keep the spaces and dashes too...
$slug= str_replace(' ','-', $slug); // replace spaces by dashes
$slug= strtolower($slug); // make it lowercase
return $slug;
}
}
?>
I’ve got some ideas for improvement, like option to display the excerpt of each post or not but it has proven very useful so far. Now it is your turn to build your own widgets.
Related Items and Services:Ladders at great prices
Security Management available here













Nice article on wordpress plugin building! Keep up!
Just what I was looking for…
Now where do I save this so it shows up in the widgets section?
Well you can either add the script to the functions.php file in your wordpress theme, or create a file just for it and include it in your functions.php file. I use the second option so I just copy the file with the widget in the theme folder and add the include and done. When you’ve got a few widgets like this it is very handy.
Thanks for this – it should make a good base for a widget I want, and an introduction into how to build other widgets in future.
Nice content on wordpress plugin building! Thank you for share
Before you invent the wheel, always check if someone else have done it before…
This is exactly what I needed! Thanks man!
No worries, always glad to help.