Что такое динамические виджеты и зачем они нужны в WordPress
Виджеты в WordPress — это небольшие блоки функциональности, которые можно размещать в сайдбарах, футерах и других областях, поддерживающих виджеты. Стандартные виджеты часто статичны и ограничены по функционалу. Динамические виджеты позволяют создавать более гибкие и интерактивные блоки, которые могут менять содержимое в зависимости от условий или данных, получаемых из базы или внешних источников.
Например, динамический виджет может показывать последние записи определённой категории, выводить персональные рекомендации или отображать форму подписки с учётом текущего пользователя. Это значительно расширяет возможности кастомизации интерфейса сайта без необходимости править темы напрямую.
В этой статье мы подробно разберём, как создать свой динамический виджет в WordPress с нуля, используя собственный префикс функций для удобства поддержки кода на сайте wptemplates.ru.
Создание базового виджета в WordPress: структура и регистрация
Для создания виджета в WordPress используется класс, наследующийся от WP_Widget. Самый простой виджет содержит минимум методов: конструктор, метод отображения (widget), метод форм для настроек (form) и метод сохранения настроек (update).
Пример базового класса виджета с префиксом wptemplates_:
class wptemplates_Dynamic_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'wptemplates_dynamic_widget',
'WPT Dynamic Widget',
['description' => 'Динамический виджет для вывода данных']
);
}
public function widget($args, $instance) {
echo $args['before_widget'];
echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
echo '<p>Здесь будет динамический контент</p>';
echo $args['after_widget'];
}
public function form($instance) {
$title = !empty($instance['title']) ? $instance['title'] : 'Новый заголовок';
?>
<p>
<label for="<?php echo $this->get_field_id('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 esc_attr($title); ?>">
</p>
<?php
}
public function update($new_instance, $old_instance) {
$instance = [];
$instance['title'] = (!empty($new_instance['title'])) ? strip_tags($new_instance['title']) : '';
return $instance;
}
}
function wptemplates_register_dynamic_widget() {
register_widget('wptemplates_Dynamic_Widget');
}
add_action('widgets_init', 'wptemplates_register_dynamic_widget');Этот код создаёт простой виджет с заголовком и выводом статического текста. Мы будем расширять его функционал дальше.
Добавление динамического контента: вывод последних записей категории
Самый частый кейс для динамического виджета — вывод последних записей из определённой категории или по определённым критериям. Для этого используем класс WP_Query внутри метода widget.
Пример расширения метода wptemplates_Dynamic_Widget::widget для вывода 5 последних записей из категории, выбранной в настройках:
public function widget($args, $instance) {
echo $args['before_widget'];
if (!empty($instance['title'])) {
echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
}
$cat_id = !empty($instance['category']) ? intval($instance['category']) : 0;
$query_args = [
'posts_per_page' => 5,
'cat' => $cat_id,
'post_status' => 'publish'
];
$recent_posts = new WP_Query($query_args);
if ($recent_posts->have_posts()) {
echo '<ul>';
while ($recent_posts->have_posts()) {
$recent_posts->the_post();
echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
}
echo '</ul>';
} else {
echo '<p>Нет записей для отображения.</p>';
}
wp_reset_postdata();
echo $args['after_widget'];
}Для настройки категории необходимо доработать метод form, добавив выпадающий список с категориями:
public function form($instance) {
$title = !empty($instance['title']) ? $instance['title'] : 'Последние записи';
$category = !empty($instance['category']) ? $instance['category'] : 0;
$categories = get_categories(['hide_empty' => false]);
?>
<p>
<label for="<?php echo $this->get_field_id('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 esc_attr($title); ?>">
</p>
<p>
<label for="<?php echo $this->get_field_id('category'); ?>">Выберите категорию:</label>
<select class="widefat" id="<?php echo $this->get_field_id('category'); ?>" name="<?php echo $this->get_field_name('category'); ?>">
<option value="0">Все категории</option>
<?php foreach ($categories as $cat): ?>
<option value="<?php echo $cat->term_id; ?>" <?php selected($category, $cat->term_id); ?>><?php echo esc_html($cat->name); ?></option>
<?php endforeach; ?>
</select>
</p>
<?php
}И не забудьте обновить метод update, чтобы сохранять выбранную категорию:
public function update($new_instance, $old_instance) {
$instance = [];
$instance['title'] = (!empty($new_instance['title'])) ? strip_tags($new_instance['title']) : '';
$instance['category'] = (!empty($new_instance['category'])) ? intval($new_instance['category']) : 0;
return $instance;
}Использование хуков и фильтров для расширения функционала виджета
Чтобы сделать виджет более гибким и расширяемым, полезно добавить собственные хуки и фильтры. Например, фильтр для изменения запроса постов или вывода контента:
public function widget($args, $instance) {
echo $args['before_widget'];
$title = apply_filters('wptemplates_dynamic_widget_title', $instance['title']);
if (!empty($title)) {
echo $args['before_title'] . $title . $args['after_title'];
}
$cat_id = !empty($instance['category']) ? intval($instance['category']) : 0;
$query_args = apply_filters('wptemplates_dynamic_widget_query_args', [
'posts_per_page' => 5,
'cat' => $cat_id,
'post_status' => 'publish'
], $instance);
$recent_posts = new WP_Query($query_args);
if ($recent_posts->have_posts()) {
echo '<ul>';
while ($recent_posts->have_posts()) {
$recent_posts->the_post();
$content = '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
echo apply_filters('wptemplates_dynamic_widget_post_item', $content, get_the_ID());
}
echo '</ul>';
} else {
echo '<p>Нет записей для отображения.</p>';
}
wp_reset_postdata();
echo $args['after_widget'];
}Таким образом, другие разработчики или вы сами сможете подключать дополнительные функции для изменения поведения виджета без правки исходного кода.
Практические советы по отладке и улучшению производительности виджета
При работе с динамическими виджетами важно следить за производительностью. Запросы к базе должны быть оптимальными, а код — безопасным:
- Используйте
WP_Queryс минимально необходимыми параметрами. - Обязательно вызывайте
wp_reset_postdata()после пользовательских запросов. - Кэшируйте вывод виджета с помощью Transients API, если данные не меняются часто.
- Экранируйте все выводимые данные с помощью
esc_html()илиesc_url()для безопасности. - Проверяйте права пользователя, если виджет выводит персональные данные.
Пример использования кеширования с Transients API:
public function widget($args, $instance) {
echo $args['before_widget'];
$cache_key = 'wptemplates_widget_cache_' . $this->id;
$output = get_transient($cache_key);
if (false === $output) {
ob_start();
// Весь код вывода как в предыдущих примерах
// ...
$output = ob_get_clean();
set_transient($cache_key, $output, 3600); // кэш на 1 час
}
echo $output;
echo $args['after_widget'];
}