How to Make A Sidebar Widget To Display Recent Custom Posts by Jared Williams


Jared Williams is the developer and host of WPHonors. He is also the developer, designer and author New2WP.com, a great source for all things WordPress, and also the design blog Tweeaks.com. Jared is always seeking new and original ways to contribute to the WordPress community.

How to Make A Sidebar Widget To Display Recent Custom Posts

In this tutorial I will walk through how to create a custom sidebar widget for WordPress that enables you to display recent posts for all registered posts types. This is a plugin I developed and wrote about on New2WP. The default Recent Posts widget built into WordPress only lets you list recent posts for the ‘post’ post type (regular blog posts).

Now that you are able to define your own custom post types in WordPress 3.0, the need to be able to easily display recent posts for your custom post types in the same way with the use of a widget will most likely become a desirable feature at some point for you.

I’ve found myself short custom functions as a solution for my custom post types. I started reusing the function on my sites using custom post types, and just changed the code to whatever the post type was for each site. I noticed it becoming a bit redundant, and finally decided to create a custom widget which could be easily insalled and configured.

1. Provide Details About the Plugin

The first thing your plugin should have is the details about it such as the name, description, version number, developer, etc. All plugins in WordPress require some kind of details about the plugin at the top of the code.

For example:

/**
 * Plugin Name: Latest Posts For Custom Types Widget
 * Plugin URI: http://new2wp.com/pro/latest-custom-post-type-posts-sidebar-widget
 * Description: A sidebar Widget for displaying the most recent posts of any post type including custom types.
 * Version: 1.0
 * Author: Jared Williams
 * Author URI: http://new2wp.com
 * Tags: custom post types, sidebar widget
 */

2. Create The Init Function

You need to make a function that can be added to the widgets using the ‘widgets_init’ hook, which is what will add the widget to the list of widgets in the dashboard.

Here’s how you create the function that will wrap all the code for making the widget:

1
2
3
4
5
6
7
8
9
/**
* Create the init function
*/
function n2wp_latest_cpt_init() {
if ( !function_exists( 'register_sidebar_widget' ))
return;

// code here
}

We will be creating two new functions within this function. You may be wondering what the IF statement in the function is for. This checks if the theme does not have a register_sidebar_widget() function call in it, which is what creates widgetized areas in your theme.

3. The Widget Output Function

The first function we are going to create within this function, after the IF statement, is going to be the function which outputs the code that creates the widget in your sidebar. This function is passed the variable $args, which contains the arguments needed to create the widget based on the settings from the widget form in the dashboard.

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
/**
* The widget output function
*/
function n2wp_latest_cpt($args) {
global $post;
extract($args);

// These are our own options
$options = get_option( 'n2wp_latest_cpt' );
$title = $options['title']; // Widget title
$phead = $options['phead']; // Heading format
$ptype = $options['ptype']; // Post type
$pshow = $options['pshow']; // Number of Tweets

$beforetitle = '';
$aftertitle = '';

// Output
echo $before_widget;

if ($title) echo $beforetitle . $title . $aftertitle;

$pq = new WP_Query(array( 'post_type' => $ptype, 'showposts' => $pshow ));
if( $pq->have_posts() ) :
?>
<ul>
<ul><?php while($pq->have_posts()) : $pq->the_post(); ?>
    <li><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></li>
</ul>
</ul>
<?php wp_reset_query();
endwhile; ?>

<?php endif; ?>

<?php
// echo widget closing tag
echo $after_widget;
}

Let’s look at what this does. We use extract($args) to get the arguments that are passed to the function. Then we set the variable $options which is an array of variables that we get the options of ‘n2wp_latest_cpt’. Then we set up variables for the title, heading, post type, and number of posts to show using the $options[] array, matching each variable to the correct part of the array.

Next we prepare the output for the heading of the widget with $beforetitle = ” and $aftertitle = ”. This is what creates the <h3></h3> or whichever HTML tag chosen in the widget form (h2,h3,h4, strong). I added this feature because not everyone’s sidebar uses the same heading tags for the titles of the widgets.

Next, you output the $beforewidget, this is whatever your register_sidebar_widget function has defined in it, usually a <ul> list. Then IF $title is set, which it should be, then output the $beforetitle and $aftertitle with the $title concatenated in between the variables.

Then you set up a new WP_Query() and query the post_type which equals whatever the posttype that is chosen in the widget form, and showposts set to the number of posts set in the widget form. Then do the normal while() loop to output the list of custom posts, and before you end the loop use wp_reset_query() to reset the loop just to be safe. And finally output the $after_widget code and close the function.

4. The Widget Form Function

The second function we need to create within our init function is the one that creates and outputs the widget form that you use in the dashboard on the widgets page. This function is what sets the defaults for the widget, and also updates the $options[] array based on the settings you make using the widget form.

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
/**
* Widget settings form function
*/
function n2wp_latest_cpt_control() {

// Get options
$options = get_option( 'n2wp_latest_cpt' );
// options exist? if not set defaults
if ( !is_array( $options ))
$options = array(
'title' => 'Latest Posts',
'phead' => 'h2',
'ptype' => 'post',
'pshow' => '5'
);
// form posted?
if ( $_POST['latest-cpt-submit'] ) {
$options['title'] = strip_tags( $_POST['latest-cpt-title'] );
$options['phead'] = $_POST['latest-cpt-phead'];
$options['ptype'] = $_POST['latest-cpt-ptype'];
$options['pshow'] = strip_tags( $_POST['latest-cpt-pshow'] );
update_option( 'n2wp_latest_cpt', $options );
}
// Get options for form fields to show
$title = $options['title'];
$phead = $options['phead'];
$ptype = $options['ptype'];
$pshow = $options['pshow'];

// The widget form fields
?>

<label for="latest-cpt-title"><?php echo __( 'Widget Title' ); ?>
<input id="latest-cpt-title" type="text" name="latest-cpt-title" size="30" value="<?php echo $title; ?>" />
</label>

<label for="latest-cpt-phead"><?php echo __( 'Widget Heading Format' ); ?></label>

<select name="latest-cpt-phead"><option selected="selected" value="h2">H2 - <h2></h2></option><option selected="selected" value="h3">H3 - <h3></h3></option><option selected="selected" value="h4">H4 - <h4></h4></option><option selected="selected" value="strong">Bold - <strong></strong></option></select><select name="latest-cpt-ptype"><option value="">- <?php echo __( 'Select Post Type' ); ?> -</option></select><?php $args = array( 'public' => true );
$post_types = get_post_types( $args, 'names' );
foreach ($post_types as $post_type ) { ?>

<select name="latest-cpt-ptype"><option selected="selected" value="<?php echo $post_type; ?>"><?php echo $post_type;?></option></select><?php } ?>

<label for="latest-cpt-pshow"><?php echo __( 'Number of posts to show' ); ?>
<input id="latest-cpt-pshow" type="text" name="latest-cpt-pshow" size="2" value="<?php echo $pshow; ?>" />
</label>

<input id="latest-cpt-submit" type="hidden" name="latest-cpt-submit" value="1" />
<?php
}

In this function you get the $options just like the previous function. Then check to see if the $options variable is not an array. If not, then set it as an array, with some default settings.

Then we check if the form was submitted, and set all the $options[] to the value of the associated form fields for each. Since the title and number of posts to show are the only fields that use a text input type we want to use strip_tags to strip any characters that might not be allowed because we only want the title and the number of posts to be text and not some crazy weird characters. Once all the $options are set we update the options with update_option( ‘n2wp_latest_cpt’, $options ).

Then we get all the $options and set variables for each according to each field in the form, and then we build the forms HTML code to be output. Within the form we want to make sure that the fields don’t reset to the default settings, so we need to output the settings from the previous code where we set up the variables for each field.

For the title and number of posts fields we just echo the $title and $pshow variables in the value attribute. For the heading format we are using a select menu so we need to do IF statements to check if the $phead variable is set to each of the options we’ve created and output the selected option according to which one the variable is set to.

We do the same thing for the post type select menu, only for that we use a foreach() loop. Before the loop we need to get all the post types that are public, and output the names of each post type. The do foreach $post_types as a single $post_type we loop through them to create each of the options for the select menu. We check if the option for the set post type is equal to each $post_type to make whichever one is set output as selected.

Finally we create a hidden input with a value of 1 that we can use to check if the form is submitted as shown before where we update each of the $options, and then close the function.

5. Register The Widget And Widget Control

Now that we have a function for displaying the widget in our sidebar, and a function for the widget form which we can use to control the output of the widget, we need to register the widget and the widget control. WordPress has functions built-in for doing this so it is fairly simple to do. This is the last peice of code that needs to go within our init function.

1
2
wp_register_sidebar_widget( 'widget_latest_cpt', __('Latest Custom Posts'), 'n2wp_latest_cpt' );
wp_register_widget_control( 'widget_latest_cpt', __('Latest Custom Posts'), 'n2wp_latest_cpt_control', 300, 200 );

The Codex explains the arguments wp_register_sidebar_widget() can take. You can find the wp_register_sidebar_widget here.

1
wp_register_sidebar_widget($id, $name, $output_callback, $options = array())

This function is defined in /wp-includes/widgets.php on line 603.

Some information on register_widget_control is here.

1
wp_register_widget_control($id, $name, $control_callback, $options = array())

This function is defined in /wp-includes/widgets.php on line 716.

Since WordPress 3.0, register_sidebar_widget() and register_widget_control() are both deprecated.
The new page for wp_register_widget_control doesn’t exist yet. I’m going to try adding what I know about it to the Codex so others learning about this have at least some information about this function.

Another great resource on these two functions can be found on wpmudev.org as well. I should mention that in making this widget, this forum thread here helped me out in understanding some things with these functions.

6. Adding The Action Init

The final step in this tutorial is adding the action to hook into WordPress. This is what will add the widget to your site for use. Once this is done, you will see the widget in the dashboard on the widgets page where you can drag it to one of your widgetized areas, and set the settings of the widget which will then be outputted in your sidebar.

1
add_action( 'widgets_init', 'n2wp_latest_cpt_init' );

The hook used is the widgets_init which is obviously the hook for WordPress widgets.

The Entire Code

Here is the entire code for this plugin. It is available for download on New2WP here as well.

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
112
113
114
115
116
<?php
/**
* Plugin Name: Latest Posts For Custom Types Widget
* Plugin URI: http://new2wp.com/pro/latest-custom-post-type-posts-sidebar-widget
* Description: A New2WP sidebar Widget for displaying the latest posts of any post type including custom types. Control the widget title formatting and the number of posts to display. Plus the widget is completely localized for other languages.
* Version: 1.1
* Author: Jared Williams
* Author URI: http://new2wp.com
* Tags: custom post types, post types, latest posts, sidebar widget, plugin
* License: GPL
*/
function n2wp_latest_cpt_init() {
if ( !function_exists( 'register_sidebar_widget' ))
return;

function n2wp_latest_cpt($args) {
global $post;
extract($args);

// These are our own options
$options = get_option( 'n2wp_latest_cpt' );
$title = $options['title']; // Widget title
$phead = $options['phead']; // Heading format
$ptype = $options['ptype']; // Post type
$pshow = $options['pshow']; // Number of Tweets

$beforetitle = '';
$aftertitle = '';

// Output
echo $before_widget;

if ($title) echo $beforetitle . $title . $aftertitle;

$pq = new WP_Query(array( 'post_type' => $ptype, 'showposts' => $pshow ));
if( $pq->have_posts() ) :
?>
<ul>
<ul><?php while($pq->have_posts()) : $pq->the_post(); ?>
    <li><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></li>
</ul>
</ul>
<?php wp_reset_query();
endwhile; ?>

<?php endif; ?>

<!-- NEEDS FIX: to display link to full list of posts page
<?php $obj = get_post_type_object($ptype); ?>
<div class="latest_cpt_icon"><a href="<?php site_url('/'.$obj->query_var); ?>" rel="bookmark"><?php _e( 'View all ' . $obj->labels->name . ' posts' ); ?>&rarr;</a></div>
//-->

<?php
// echo widget closing tag
echo $after_widget;
}

/**
* Widget settings form function
*/
function n2wp_latest_cpt_control() {

// Get options
$options = get_option( 'n2wp_latest_cpt' );
// options exist? if not set defaults
if ( !is_array( $options ))
$options = array(
'title' => 'Latest Posts',
'phead' => 'h2',
'ptype' => 'post',
'pshow' => '5'
);
// form posted?
if ( $_POST['latest-cpt-submit'] ) {
$options['title'] = strip_tags( $_POST['latest-cpt-title'] );
$options['phead'] = $_POST['latest-cpt-phead'];
$options['ptype'] = $_POST['latest-cpt-ptype'];
$options['pshow'] = $_POST['latest-cpt-pshow'];
update_option( 'n2wp_latest_cpt', $options );
}
// Get options for form fields to show
$title = $options['title'];
$phead = $options['phead'];
$ptype = $options['ptype'];
$pshow = $options['pshow'];

// The widget form fields
?>

<label for="latest-cpt-title"><?php echo __( 'Widget Title' ); ?>
<input id="latest-cpt-title" type="text" name="latest-cpt-title" size="30" value="<?php echo $title; ?>" />
</label>

<label for="latest-cpt-phead"><?php echo __( 'Widget Heading Format' ); ?></label>

<select name="latest-cpt-phead"><option selected="selected" value="h2">H2 - <h2></h2></option><option selected="selected" value="h3">H3 - <h3></h3></option><option selected="selected" value="h4">H4 - <h4></h4></option><option selected="selected" value="strong">Bold - <strong></strong></option></select><select name="latest-cpt-ptype"><option value="">- <?php echo __( 'Select Post Type' ); ?> -</option></select><?php $args = array( 'public' => true );
$post_types = get_post_types( $args, 'names' );
foreach ($post_types as $post_type ) { ?>

<select name="latest-cpt-ptype"><option selected="selected" value="<?php echo $post_type; ?>"><?php echo $post_type;?></option></select><?php } ?>

<label for="latest-cpt-pshow"><?php echo __( 'Number of posts to show' ); ?>
<input id="latest-cpt-pshow" type="text" name="latest-cpt-pshow" size="2" value="<?php echo $pshow; ?>" />
</label>

<input id="latest-cpt-submit" type="hidden" name="latest-cpt-submit" value="1" />
<?php
}

wp_register_sidebar_widget( 'widget_latest_cpt', __('Latest Custom Posts'), 'n2wp_latest_cpt' );
wp_register_widget_control( 'widget_latest_cpt', __('Latest Custom Posts'), 'n2wp_latest_cpt_control', 300, 200 );

}
add_action( 'widgets_init', 'n2wp_latest_cpt_init' );

?>

Resources For Creating Widgets

Comments (10)

  1. Thanks Justin. I agree that people should extend the WP_Widget class when making widgets. When I was creating this tutorial I actually started to rewrite the code so that it did extend the widget class, so I showed people the new, right way to make widgets. However, I just didn’t have time to create it that way, test it, and then finish this tutorial on how to make it by the time I needed to for this series.

    I plan to rewrite this plugin so it extends the widget class, and so that it allows for multiples of this widget too. Once I do that, I will write a followup tutorial to this, if I ever find the time.

  2. Hiya, I’m really glad I have found this info. Nowadays bloggers publish just about gossip and web stuff and this is actually annoying. A good website with interesting content, that is what I need. Thank you for making this web-site, and I’ll be visiting again. Do you do newsletters? I Cant find it.

  3. I’ve used:
    $obj = get_post_type_object($ptype);
    if ($obj->has_archive) : ?>
    <a href="has_archive;?>” title”labels->name; ?>” class=”widget_note”>Show all
    <?php endif;

    For this part:
    <!– NEEDS FIX: to display link to full list of posts page

    <a href="query_var); ?>” rel=”bookmark”>labels->name . ‘ posts’ ); ?>→
    //–>

Participate