Как создать динамический виджет в WordPress с использованием PHP и хуков

Что такое динамические виджеты и зачем они нужны в 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'];
}
Как отключить редактор Gutenberg в WordPress 5.9: практические способы и примеры
08.03.2026
Создание кастомных типов записей и таксономий в WordPress с примерами кода
12.12.2025
Автоматическое удаление неактивных товаров в WooCommerce по дате последнего обновления
12.05.2026
Как создать собственный плагин для WordPress с примерами кода
02.12.2025
Как использовать фильтр pre_get_posts в WordPress для кастомизации запросов
06.12.2025