Включение пользовательских типов записей в виджет "Последние записи"
Я могу легко включить свои пользовательские типы записей в основной цикл, внося небольшие изменения с помощью query_posts()
, но я не уверен, как включить пользовательские типы записей в виджет "Последние записи" в сайдбаре (или в любые другие виджеты).
Как я могу расширить область действия виджета "Последние записи", чтобы он включал не только стандартный тип записей?

Вам придется отредактировать код виджета Недавние записи или создать собственную версию на основе стандартной. Код находится в файле wp-includes/default-widgets.php
примерно на строке 513. Но так как вносить изменения в ядро не рекомендуется, лучше всего скопировать код и создать собственный виджет Мои пользовательские недавние записи, который затем можно будет использовать на сайте. Просто добавьте новый класс виджета в файл темы functions.php
или используйте его в плагине.
Основное изменение, которое нужно внести, — это имя класса виджета и его инкапсулированных функций и опций (чтобы избежать конфликтов имен с оригинальным виджетом Недавние записи). После этого необходимо отредактировать вызов WP_Query
в конструкторе widget()
, чтобы он включал ваш пользовательский тип записи.
В этом примере я установил параметр post_type
равным array('post, 'page', 'custom-post-type')
... вам нужно изменить его в соответствии с вашими потребностями.
Вот полный код виджета для справки:
/**
* Класс виджета My_Custom_Recent_Posts
*
*/
class WP_Widget_My_Custom_Recent_Posts extends WP_Widget {
function __construct() {
$widget_ops = array('classname' => 'widget_my_custom_recent_entries', 'description' => __( "Последние записи на вашем сайте") );
$this->WP_Widget('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']) ? __('Мои пользовательские недавние записи') : $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
// Сброс глобальной переменной $the_post, так как запрос мог ее изменить
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('Заголовок:'); ?></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('Количество записей для отображения:'); ?></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
}
}

Вместо переименования виджета, я думаю, что лучше сначала сделать unregister_widget
для виджета по умолчанию перед регистрацией нового (это будет менее запутанно в админке).

Да, вы можете использовать unregister_widget
, но этот метод дает вам доступ к обоим, если вы хотите использовать оба (например, иметь виджет Недавние записи для отображения недавних записей блога и виджет Недавние обзоры фильмов для отображения только записей определенного пользовательского типа).

небольшое замечание для тех, кто пробует код выше: Не забудьте добавить это: register_widget('WP_Widget_My_Custom_Recent_Posts');

Спасибо за предоставление кода для пользовательского класса виджета и за объяснения. Это очень пригодилось. Однако мне интересно, есть ли способ изменить его, чтобы разрешить встроенный HTML в поле заголовка? По сути, мне нужно превратить заголовок виджета в кликабельную ссылку, но по умолчанию встроенный HTML удаляется из заголовков виджетов. Любая помощь будет очень ценной.

Иэн, пожалуйста, задайте это как отдельный вопрос, чтобы мы могли обсудить его полностью...

Я ничего не знаю о PHP, но разве нельзя просто Extend
стандартный класс и обновить необходимые переменные? Вместо полного копирования и вставки?

Начиная с версии 3.6 (как минимум), вы можете использовать следующий код для изменения запроса:
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;
}
Просто добавьте нужные типы записей в массив post_type, и они должны отображаться.
Обновление: Согласно http://core.trac.wordpress.org/ticket/16159, эта возможность доступна начиная с версии 3.4

Я только что нашел отличный плагин, где вся сложная работа уже сделана, и у него отличная документация и поддержка автора. Я действительно впечатлен.
Он позволяет переопределять WP_Query (что дает возможность фильтровать по пользовательским типам записей и всему, что вам может понадобиться), а также содержит четкие инструкции по его использованию.
Документация http://www.pjgalbraith.com/2011/08/recent-posts-plus/
Ссылка на плагин WordPress http://wordpress.org/extend/plugins/recent-posts-plus/
Это значительно упростило мою работу!

Я также создал виджет-плагин для этого, который более настраиваемый, чем стандартный виджет "Последние записи". Если вам интересно, вы можете скачать его здесь http://new2wp.com/pro/latest-custom-post-type-posts-sidebar-widget/

Этот код создает новый виджет "Последние записи", включающий ваши пользовательские типы записей (CPT)
Для расширения стандартного виджета "Последние записи" необходимо выполнить 2 шага:
i. Создать новый класс для вашего пользовательского виджета последних записей, скопировав и переименовав код виджета из файла defaults-widgets.php в папке wp-includes.
ii. Затем нужно зарегистрировать новый виджет, при этом вы можете выбрать - отменить регистрацию стандартного виджета или использовать оба.
Весь код можно просто скопировать в файл functions вашей дочерней темы или создать отдельный файл и подключить его в functions.php дочерней темы.
<?php
class WPSites_Recent_Posts extends WP_Widget {
public function __construct() {
$widget_ops = array('classname' => 'wpsites_recent_posts', 'description' => __( "Последние CPT и записи.") );
parent::__construct('wpsites-recent-posts', __('Последние записи WP Sites'), $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'] : __( 'Последние записи' );
/** Этот фильтр документирован в 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( 'Заголовок:' ); ?></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( 'Количество записей для показа:' ); ?></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( 'Показывать дату записи?' ); ?></label></p>
<?php
}
}
Регистрация нового пользовательского виджета последних записей
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 );
Код включает модифицированный WP_Query с массивом для типов записей, включая CPT portfolio, который вы можете переименовать в соответствии с вашим пользовательским типом записей.
Вот строка кода, которую нужно изменить:
'post_type' => array('post', 'portfolio'),

2020 год, и я пришел сюда найти решение для "10 самых последних записей пользовательского типа XYZ". Я нашел тот самый плагин, который делает это и даже больше.
Custom Post Type Widgets расширяет стандартные функции виджетов для обычных записей (последние записи, архивы по месяцам, используемые категории, последние комментарии, поиск, календарь) на пользовательские типы записей.
Вы выбираете нужный виджет (в моем случае "последние записи") и сначала получаете выпадающий список, где указываете пользовательский тип записей, на который должен ориентироваться виджет. По умолчанию выбран старый добрый 'post', так что этот плагин может заменять стандартные виджеты WordPress, связанные с записями.
