Как создать и использовать собственные виджеты в WordPress

Виджеты — важная часть функционала WordPress, позволяющая добавлять различные блоки с контентом и функционалом в боковые панели, футеры и другие области темы. Несмотря на большое количество готовых виджетов и плагинов, часто возникает необходимость создать собственный виджет, который будет решать конкретную задачу или отображать уникальную информацию.

Что такое виджет в WordPress и зачем создавать свои собственные

Виджет — это модуль, который можно добавлять в виджетные области темы. По умолчанию WordPress предлагает стандартные виджеты, например, поиск, категории, календарь и другие. Но если вам нужно вывести специфическую информацию, например, кастомный список постов, форму с нестандартными полями или динамический контент, готовые виджеты могут не подойти.

Создание собственного виджета позволяет:

  • Добавить уникальный функционал, который не доступен в стандартных виджетах.
  • Упростить управление контентом для пользователей сайта через административный интерфейс.
  • Интегрировать сторонние сервисы или API прямо в блоки сайта.

Создание виджета — это удобный способ расширить возможности темы или плагина, сохраняя управление через стандартный интерфейс WordPress.

Основные шаги создания собственного виджета в WordPress

Для создания виджета нужно создать класс, который наследует WP_Widget, и зарегистрировать этот класс в системе. Рассмотрим по шагам:

1. Создание класса виджета

Ваш класс должен наследовать WP_Widget и реализовывать минимум три метода:

  • __construct() — инициализация виджета (название, описание и т.п.)
  • widget($args, $instance) — вывод содержимого виджета на сайте
  • form($instance) — форма настроек виджета в админке
  • update($new_instance, $old_instance) — обработка и сохранение настроек

Пример простого виджета, который выводит приветствие и настраиваемый текст:

class Wp0_Custom_Widget extends WP_Widget {
    public function __construct() {
        parent::__construct(
            'wp0_custom_widget',
            'Wp0: Приветственный виджет',
            ['description' => 'Выводит приветствие с настраиваемым текстом']
        );
    }

    public function widget($args, $instance) {
        echo $args['before_widget'];
        $title = !empty($instance['title']) ? $instance['title'] : 'Привет!';
        $text = !empty($instance['text']) ? $instance['text'] : 'Добро пожаловать на сайт!';
        echo $args['before_title'] . apply_filters('widget_title', $title) . $args['after_title'];
        echo '<p>' . esc_html($text) . '</p>';
        echo $args['after_widget'];
    }

    public function form($instance) {
        $title = !empty($instance['title']) ? $instance['title'] : '';
        $text = !empty($instance['text']) ? $instance['text'] : '';
        ?>
        <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('text'); ?>">Текст приветствия:</label>
            <textarea class="widefat" id="<?php echo $this->get_field_id('text'); ?>" name="<?php echo $this->get_field_name('text'); ?>" rows="4"><?php echo esc_textarea($text); ?></textarea>
        </p>
        <?php
    }

    public function update($new_instance, $old_instance) {
        $instance = [];
        $instance['title'] = sanitize_text_field($new_instance['title']);
        $instance['text'] = sanitize_textarea_field($new_instance['text']);
        return $instance;
    }
}

2. Регистрация виджета

Чтобы WordPress мог использовать ваш виджет, его нужно зарегистрировать. Добавьте следующий код в файл плагина или functions.php темы:

function wp0_register_custom_widget() {
    register_widget('Wp0_Custom_Widget');
}
add_action('widgets_init', 'wp0_register_custom_widget');

После этого виджет появится в списке доступных и его можно будет добавить в любую виджетную область.

Расширение возможностей виджета: динамический вывод и настройки

Описанный выше пример — базовый. На практике виджеты часто выводят динамический контент, например, последние записи из определённой категории, контакты из настроек сайта или интеграцию с внешними API.

Пример: виджет с последними постами из категории

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

class Wp0_Recent_Category_Posts_Widget extends WP_Widget {
    public function __construct() {
        parent::__construct(
            'wp0_recent_category_posts',
            'Wp0: Последние посты из категории',
            ['description' => 'Выводит последние записи из выбранной категории']
        );
    }

    public function widget($args, $instance) {
        echo $args['before_widget'];

        $title = !empty($instance['title']) ? $instance['title'] : 'Последние записи';
        $cat_id = !empty($instance['cat_id']) ? intval($instance['cat_id']) : 0;
        $posts_count = !empty($instance['posts_count']) ? intval($instance['posts_count']) : 5;

        echo $args['before_title'] . apply_filters('widget_title', $title) . $args['after_title'];

        if ($cat_id) {
            $query = new WP_Query([
                'cat' => $cat_id,
                'posts_per_page' => $posts_count,
                'post_status' => 'publish'
            ]);

            if ($query->have_posts()) {
                echo '<ul>';
                while ($query->have_posts()) {
                    $query->the_post();
                    echo '<li><a href="' . esc_url(get_permalink()) . '">' . esc_html(get_the_title()) . '</a></li>';
                }
                echo '</ul>';
                wp_reset_postdata();
            } else {
                echo '<p>Нет записей в этой категории.</p>';
            }
        } else {
            echo '<p>Категория не выбрана.</p>';
        }

        echo $args['after_widget'];
    }

    public function form($instance) {
        $title = !empty($instance['title']) ? $instance['title'] : '';
        $cat_id = !empty($instance['cat_id']) ? intval($instance['cat_id']) : 0;
        $posts_count = !empty($instance['posts_count']) ? intval($instance['posts_count']) : 5;

        $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('cat_id'); ?>">Выберите категорию:</label>
            <select id="<?php echo $this->get_field_id('cat_id'); ?>" name="<?php echo $this->get_field_name('cat_id'); ?>" class="widefat">
                <option value="0">- Выберите -</option>
                <?php foreach ($categories as $cat) : ?>
                    <option value="<?php echo $cat->term_id; ?>" <?php selected($cat_id, $cat->term_id); ?>><?php echo esc_html($cat->name); ?></option>
                <?php endforeach; ?>
            </select>
        </p>
        <p>
            <label for="<?php echo $this->get_field_id('posts_count'); ?>">Количество записей:</label>
            <input id="<?php echo $this->get_field_id('posts_count'); ?>" name="<?php echo $this->get_field_name('posts_count'); ?>" type="number" value="<?php echo esc_attr($posts_count); ?>" min="1" max="20">
        </p>
        <?php
    }

    public function update($new_instance, $old_instance) {
        $instance = [];
        $instance['title'] = sanitize_text_field($new_instance['title']);
        $instance['cat_id'] = intval($new_instance['cat_id']);
        $instance['posts_count'] = intval($new_instance['posts_count']);
        if ($instance['posts_count'] < 1) {
            $instance['posts_count'] = 5;
        } elseif ($instance['posts_count'] > 20) {
            $instance['posts_count'] = 20;
        }
        return $instance;
    }
}

function wp0_register_recent_category_posts_widget() {
    register_widget('Wp0_Recent_Category_Posts_Widget');
}
add_action('widgets_init', 'wp0_register_recent_category_posts_widget');

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

Практические советы по разработке виджетов

Используйте встроенные функции WordPress для безопасности

Обязательно экранируйте вывод с помощью esc_html, esc_url и другие функции безопасности. Для данных из формы используйте функции очистки, например, sanitize_text_field или sanitize_textarea_field в методе update.

Оптимизируйте запросы

Если виджет делает запросы к базе, старайтесь использовать WP_Query с минимальным набором параметров и сбрасывать данные после работы с помощью wp_reset_postdata(), чтобы избежать конфликтов.

Делайте виджет понятным для пользователя

Добавляйте в форму виджета понятные поля и описания. По возможности используйте выпадающие списки и валидацию данных.

Заключение

Создание собственных виджетов в WordPress — это мощный инструмент для расширения функционала сайта без изменения темы или ядра. С помощью простого класса и базовых методов вы можете создавать уникальные блоки с динамическим содержимым, гибкими настройками и удобным управлением через админку.

Приведённые примеры помогут быстро начать работу и понять основные принципы. Рекомендуется использовать этот подход для создания кастомных элементов интерфейса, которые можно легко интегрировать с любой темой WordPress на вашем сайте wp0.ru.

Наш каталог плагинов WordPress