I'm able to easily include my custom post types into my main loop by making small adjustments with query_posts()
, but I'm not sure how I would go about including custom post types in the "Recent Posts" sidebar widget (or any of the other widgets, for that matter).
How should I go about expanding "Recent Posts" scope to include more than just the native post type?
I'm able to easily include my custom post types into my main loop by making small adjustments with query_posts()
, but I'm not sure how I would go about including custom post types in the "Recent Posts" sidebar widget (or any of the other widgets, for that matter).
How should I go about expanding "Recent Posts" scope to include more than just the native post type?
Share Improve this question asked Sep 30, 2010 at 14:36 SampsonSampson 2,9495 gold badges30 silver badges38 bronze badges 1- 1 Never use query_posts() – Brad Dalton Commented Jul 24, 2014 at 22:17
7 Answers
Reset to default 9You'll have to edit the code for the Recent Posts widget or create your own version based on the default. The code is in the wp-includes/default-widgets.php
file around line 513. But since you should never make modifications to core, my recommendation would be to copy the code to create your own My Custom Recent Posts widget and use that on your site. Just drop the new widget class into your theme's functions.php
file or use it in a plugin.
The only real modification you need to make are to the widget's class name and encapuslated functions and options (so that there aren't any naming conflicts with the original Recent Posts widget. After that, you'll need to edit the call to WP_Query
in the widget()
constructor so that it includes your custom post type.
For this example, I've set post_type
equal to array('post, 'page', 'custom-post-type')
... you'll need to modify that to fit your specific use case.
Here's the widget's full code for reference:
/**
* My_Custom_Recent_Posts widget class
*
*/
class WP_Widget_My_Custom_Recent_Posts extends WP_Widget {
function __construct() {
$widget_ops = array('classname' => 'widget_my_custom_recent_entries', 'description' => __( "The most recent posts on your site") );
$this->WP_Widget('my-custom-recent-posts', __('My Custom Recent Posts'), $widget_ops);
$this->alt_option_name = 'widget_my_custom_recent_entries';
add_action( 'save_post', array(&$this, 'flush_widget_cache') );
add_action( 'deleted_post', array(&$this, 'flush_widget_cache') );
add_action( 'switch_theme', array(&$this, 'flush_widget_cache') );
}
function widget($args, $instance) {
$cache = wp_cache_get('widget_my_custom_recent_posts', 'widget');
if ( !is_array($cache) )
$cache = array();
if ( isset($cache[$args['widget_id']]) ) {
echo $cache[$args['widget_id']];
return;
}
ob_start();
extract($args);
$title = apply_filters('widget_title', empty($instance['title']) ? __('My Custom Recent Posts') : $instance['title'], $instance, $this->id_base);
if ( !$number = (int) $instance['number'] )
$number = 10;
else if ( $number < 1 )
$number = 1;
else if ( $number > 15 )
$number = 15;
$r = new WP_Query(array('showposts' => $number, 'nopaging' => 0, 'post_status' => 'publish', 'ignore_sticky_posts' => true, 'post_type' => array('post', 'page', 'custom-post-type')));
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
// Reset the global $the_post as this query will have stomped on it
wp_reset_postdata();
endif;
$cache[$args['widget_id']] = ob_get_flush();
wp_cache_set('widget_my_custom_recent_posts', $cache, 'widget');
}
function update( $new_instance, $old_instance ) {
$instance = $old_instance;
$instance['title'] = strip_tags($new_instance['title']);
$instance['number'] = (int) $new_instance['number'];
$this->flush_widget_cache();
$alloptions = wp_cache_get( 'alloptions', 'options' );
if ( isset($alloptions['widget_my_custom_recent_entries']) )
delete_option('widget_my_custom_recent_entries');
return $instance;
}
function flush_widget_cache() {
wp_cache_delete('widget_my_custom_recent_posts', 'widget');
}
function form( $instance ) {
$title = isset($instance['title']) ? esc_attr($instance['title']) : '';
if ( !isset($instance['number']) || !$number = (int) $instance['number'] )
$number = 5;
?>
<p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label>
<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; ?>" /></p>
<p><label for="<?php echo $this->get_field_id('number'); ?>"><?php _e('Number of posts to show:'); ?></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" /></p>
<?php
}
}
As of at least 3.6, you can use the following code to modify the query used:
add_filter('widget_posts_args', 'widget_posts_args_add_custom_type');
function widget_posts_args_add_custom_type($params) {
$params['post_type'] = array('post','custom_type');
return $params;
}
Just add the types you want in the array for post_type and they should appear.
Update: According to http://core.trac.wordpress/ticket/16159, this has been available since 3.4
I just came across a great plugin where the heavy lifting is already done, and it has great documentation and author support. I've really been impressed.
It allows WP_Query overrides (allowing you to filter by custom post types and anything else you would want) and some clear instructions on how to use it.
Documentation http://www.pjgalbraith/2011/08/recent-posts-plus/
Wordpress Plugin URL http://wordpress/extend/plugins/recent-posts-plus/
Made my work just that much shorter!
You can copy the widget code (see /wp-includes/default-widgets.php) and modify the query line.
I have also create a widget plugin for this that's more customizable than the Recent Posts widget. If interested you can download it here http://new2wp/pro/latest-custom-post-type-posts-sidebar-widget/
This Code Creates a New Recent Posts Widget Which Includes Your CPT's
There's 2 steps involved when extending the native recent posts widget:
i. Create a new class for your custom recent posts widget which you can do by copying and renaming the recent posts widget code from the defaults-widgets.php in wp-includes folder.
ii. Then you will need to register the new widget as well and you may choose to de-register the native recent posts widget or use both.
All the code can simply be copied into your functions file using a child theme or create another file and include it in your child themes functions file.
<?php
class WPSites_Recent_Posts extends WP_Widget {
public function __construct() {
$widget_ops = array('classname' => 'wpsites_recent_posts', 'description' => __( "Latest CPT's & Posts.") );
parent::__construct('wpsites-recent-posts', __('WP Sites Recent Posts'), $widget_ops);
$this->alt_option_name = 'wpsites_recent_posts';
add_action( 'save_post', array($this, 'flush_widget_cache') );
add_action( 'deleted_post', array($this, 'flush_widget_cache') );
add_action( 'switch_theme', array($this, 'flush_widget_cache') );
}
public function widget($args, $instance) {
$cache = array();
if ( ! $this->is_preview() ) {
$cache = wp_cache_get( 'wpsites_widget_recent_posts', 'widget' );
}
if ( ! is_array( $cache ) ) {
$cache = array();
}
if ( ! isset( $args['widget_id'] ) ) {
$args['widget_id'] = $this->id;
}
if ( isset( $cache[ $args['widget_id'] ] ) ) {
echo $cache[ $args['widget_id'] ];
return;
}
ob_start();
$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'Recent Posts' );
/** This filter is documented in wp-includes/default-widgets.php */
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
$number = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 5;
if ( ! $number )
$number = 5;
$show_date = isset( $instance['show_date'] ) ? $instance['show_date'] : false;
$r = new WP_Query( apply_filters( 'widget_posts_args', array(
'posts_per_page' => $number,
'no_found_rows' => true,
'post_status' => 'publish',
'post_type' => array('post', 'portfolio',
'ignore_sticky_posts' => true
) ) ) );
if ($r->have_posts()) :
?>
<?php echo $args['before_widget']; ?>
<?php if ( $title ) {
echo $args['before_title'] . $title . $args['after_title'];
} ?>
<ul>
<?php while ( $r->have_posts() ) : $r->the_post(); ?>
<li>
<a href="<?php the_permalink(); ?>"><?php get_the_title() ? the_title() : the_ID(); ?></a>
<?php if ( $show_date ) : ?>
<span class="post-date"><?php echo get_the_date(); ?></span>
<?php endif; ?>
</li>
<?php endwhile; ?>
</ul>
<?php echo $args['after_widget']; ?>
<?php
wp_reset_postdata();
endif;
if ( ! $this->is_preview() ) {
$cache[ $args['widget_id'] ] = ob_get_flush();
wp_cache_set( 'wpsites_widget_recent_posts', $cache, 'widget' );
} else {
ob_end_flush();
}
}
public function update( $new_instance, $old_instance ) {
$instance = $old_instance;
$instance['title'] = strip_tags($new_instance['title']);
$instance['number'] = (int) $new_instance['number'];
$instance['show_date'] = isset( $new_instance['show_date'] ) ? (bool) $new_instance['show_date'] : false;
$this->flush_widget_cache();
$alloptions = wp_cache_get( 'alloptions', 'options' );
if ( isset($alloptions['wpsites_recent_posts']) )
delete_option('wpsites_recent_posts');
return $instance;
}
public function flush_widget_cache() {
wp_cache_delete('wpsites_widget_recent_posts', 'widget');
}
public function form( $instance ) {
$title = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
$number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5;
$show_date = isset( $instance['show_date'] ) ? (bool) $instance['show_date'] : false;
?>
<p><label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
<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; ?>" /></p>
<p><label for="<?php echo $this->get_field_id( 'number' ); ?>"><?php _e( 'Number of posts to show:' ); ?></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" /></p>
<p><input class="checkbox" type="checkbox" <?php checked( $show_date ); ?> id="<?php echo $this->get_field_id( 'show_date' ); ?>" name="<?php echo $this->get_field_name( 'show_date' ); ?>" />
<label for="<?php echo $this->get_field_id( 'show_date' ); ?>"><?php _e( 'Display post date?' ); ?></label></p>
<?php
}
}
Register the new custom recent posts widget
function wpsites_widgets_init() {
if ( !is_blog_installed() )
return;
register_widget('WPSites_Recent_Posts');
do_action( 'widgets_init' );
}
add_action( 'init', 'wpsites_widgets_init', 2 );
The code includes a modified WP_Query which includes an array for post types including the portfolio CPT which you can rename to match your custom post type.
Here's the line of code that needs to be modified:
'post_type' => array('post', 'portfolio',
It's 2020 and I came here to find a solution to the "10 most recent custom post type XYZ". I found the plugin that does that, and more.
Custom Post Type Widgets extends the usual widget standard post functionalities (most recent, monthly archives, used categories, recent comments, search, calendar) to custom post types.
You select the widget you need (in my case "most recent") and you get first a select where you specify the custom post type the widget must target. Default choice is good old 'post', so this plugin is a substitute of the vanilla WP post-related widgets.