WordPress 2.8 Single Post Navigation Widget
July 27th, 2009 by Michael • WordPress Tutorials • 9 Comments
Since WordPress 2.8, there is a new Widget API. In our post Build A WordPress 2.8 Widget With The New Widget API, I have used a simple example to describe how to build a Widget. This time Heiko and I've created something more complex.
It is a Post Navigation Widget, which lists in the single post view (single.php) a specific number of posts which were published before this post and a certain number of posts which were published after this post. I think this is a nice way to show older posts in the sidebar. Here's a screenshot, left of the backend, right of the sidebar:

I created a query to check if the class WP_Widget even exists, so the user won't get any error messages in WordPress versions prior to 2.8.
<?php
if (class_exists('WP_Widget')) {
class WPE_Widget_Post_Navigation extends WP_Widget {
function WPE_Widget_Post_Navigation() {
$widget_ops = array('classname' => 'wpe_widget_post_navi', 'description' => __( "Some posts before and after the current post") );
$this->WP_Widget('wpe-post-navi', __('WPE Single Post Navigation'), $widget_ops);
}
function widget($args, $instance) {
if(is_single()) {
global $post, $wpdb;
extract($args);
if ( !$number = (int) $instance['number'] )
$number = 5;
elseif( $number < 1 )
$number = 1;
elseif( $number > 10 )
$number = 10;
$title_before = apply_filters('widget_title', empty($instance['title_before']) ? 'Posts before' : $instance['title_before']);
$title_after = apply_filters('widget_title', empty($instance['title_after']) ? 'Posts after' : $instance['title_after']);
$before_widget_2 = preg_replace("/(wpe\-post\-navi-\d+)/", "$1-1", $before_widget);
$querystr = "
SELECT *
FROM $wpdb->posts wposts
WHERE wposts.ID != $post->ID
AND wposts.post_type = 'post'
AND wposts.post_status = 'publish'
AND wposts.post_date %s '$post->post_date'
ORDER BY wposts.post_date %s
LIMIT $number
";
$leading_posts = $wpdb->get_results(sprintf($querystr, '<', 'DESC'), OBJECT);
$trailing_posts = $wpdb->get_results(sprintf($querystr, '>', 'ASC'), OBJECT);
if ($trailing_posts && count($trailing_posts)) {
echo $before_widget_2 . $before_title . $title_before . $after_title . "<ul>";
$trailing_posts = array_reverse($trailing_posts);
foreach ($trailing_posts as $post) {
setup_postdata($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
}
echo "</ul>" . $after_widget;
}
if ($leading_posts && count($leading_posts)) {
echo $before_widget . $before_title . $title_after . $after_title . "<ul>";
foreach ($leading_posts as $post) {
setup_postdata($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
}
echo "</ul>" . $after_widget;
}
wp_reset_query();
}
}
function update( $new_instance, $old_instance ) {
$instance = $old_instance;
$instance['title_before'] = strip_tags($new_instance['title_before']);
$instance['number'] = (int) $new_instance['number'];
$instance['title_after'] = strip_tags($new_instance['title_after']);
return $instance;
}
function form( $instance ) {
$title_before = ($instance['title_before'] == '') ? 'Posts before' : esc_attr($instance['title_before']);
$title_after = ($instance['title_after'] == '') ? 'Posts after' : esc_attr($instance['title_after']);
if ( !$number = (int) $instance['number'] )
$number = 5;
elseif ( $number < 1 )
$number = 1;
elseif ( $number > 10 )
$number = 10;
?>
<p><label for="<?php echo $this->get_field_id('title_before'); ?>">Title before:</label>
<input class="widefat" id="<?php echo $this->get_field_id('title_before'); ?>" name="<?php echo $this->get_field_name('title_before'); ?>" type="text" value="<?php echo $title_before; ?>" /></p>
<p><label for="<?php echo $this->get_field_id('title_after'); ?>">Title after:</label>
<input class="widefat" id="<?php echo $this->get_field_id('title_after'); ?>" name="<?php echo $this->get_field_name('title_after'); ?>" type="text" value="<?php echo $title_after; ?>" /></p>
<p><label for="<?php echo $this->get_field_id('number'); ?>">Number of posts to show before and after current post:</label>
<input id="<?php echo $this->get_field_id('number'); ?>" name="<?php echo $this->get_field_name('number'); ?>" type="text" value="<?php echo $number; ?>" size="3" /><br />
<small>(at most 10)</small></p>
<?php
}
}
register_widget('WPE_Widget_Post_Navigation');
}
?>
Most of this should be self-explanatory. Now to the function widget () , which does the actual work. Here we had to do a little trick, because the widget actually creates 2 widgets, and they would get the same ID. That wouldn't be valid, so the code adds a -1 to one of the widget elements:
$before_widget_2 = preg_replace("/(wpe\-post\-navi-\d+)/", "$1-1", $before_widget);
2 queries are getting executed. One for the posts before this post and one for the posts after this post. if posts are available they will show up on the sidebar.
Download Widget.
Then unpack and copy the code into functions.php. Please note, the widget is for WordPress 2.8.
Info
- Published in WordPress Tutorials
- Tags: Widget, Widget API, WordPress, wp2.8
- Comment feed
- read: 15108 | today: 4
- leave a Comment




Great plugin!
By the way, can we control how many words in excerpts?
This is nice tweak.... and add some Widget feature make this code very useful for created extra ordinary wordpress
hi,
this page uses some widget to show the previous post name and the next post name, how do you do it? using this widget?
thanks,
hi, I found that it was simpler than that and there is a function (the regular function) for these links in wordpress, so I forgot to look closely at the functions that were already there.
Encouragements,
Hi, thanks for this nice widget, i use it and hope lot of users will like it. One question, how can i give the headlines befor & after an h2 for the layout?
@zauberer: In your functions.php you have a function
register_sidebar(array( 'name' => 'Sidebar', 'before_widget' => '<li id="%1$s" class="widget %2$s">', 'after_widget' => '</li>', 'before_title' => '<h2 class="widgettitle">', 'after_title' => '</h2>' ));You can change the values to your need.
How would one include this in a plugin as oppose to functions.php?
After following this tutorial, I couldn't get a couple of things to work. The permalinks will not work with the register_post_type() and arrays outlined in a function; I simply removed this and permalinks worked fine