Гид по технологиям

Как создать виджет WordPress для случайного поста с миниатюрой

7 min read WordPress Обновлено 08 Jan 2026
Виджет случайного поста в WordPress
Виджет случайного поста в WordPress

Введение

Многие блогеры ищут готовый виджет, который сделает ровно то, что им нужно. Если у вас есть базовые навыки программирования, часто проще написать свой собственный виджет. В этой статье я покажу, как создать виджет, который выбирает один случайный пост, получает его миниатюру (featured image) и отображает в сайдбаре — визуальный «посмотрите это» блок, который помогает читателям находить дополнительный контент на сайте.

Мы также разберём важные концепты WordPress — как работают запросы и The Loop — и добавим полезные практики: безопасность, производительность и тесты.

Главная иллюстрация: пример виджета на боковой панели

Ключевые понятия: запросы WordPress и Loop

Каждая страница блога — это запрос к базе данных записей (posts). В зависимости от страницы запрос меняется: домашняя страница может запрашивать «последние 10 записей», архив категории — «последние 20 записей для категории X, отсортированные по дате». Результат запроса затем проходит через шаблонный цикл — Loop — где каждая запись выводится в соответствии с шаблоном.

На одной странице может выполняться несколько запросов — вы можете создать собственные запросы в шаблонах или виджетах для вывода связанных материалов, трендов и т. п. Для нашего виджета нужно создать отдельный запрос, который возьмёт N случайных постов (в нашем случае — 1) и их миниатюры, а затем отобразит их в боковой колонке.

Важно: query_posts() перезаписывает главный запрос страницы и обычно не рекомендуется для вторичных запросов — лучше использовать WP_Query или get_posts(). Ниже приведены оба подхода: оригинальный пример с query_posts (как в классическом туториале) и современная версия с WP_Query.

Схема: как Loop получает записи из запроса

Исходный базовый код виджета (как в источнике)

Создайте новый файл .php в папке wp-content/plugins. Можно писать локально и затем закачать через интерфейс, но удобнее отлаживать прямо в каталоге плагинов. В примере файл называется random-post-widget.php.

Ниже — исходный «скелет» виджета 그대로: вставьте в файл и сохраните. Не меняйте код сразу — сначала убедитесь, что плагин подключается и виджет появляется в списке.

  
 'RandomPostWidget', 'description' => 'Displays a random post with thumbnail' );  
    $this->WP_Widget('RandomPostWidget', 'Random Post and Thumbnail', $widget_ops);  
  }  
  function form($instance)  
  {  
    $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) );  
    $title = $instance['title'];  
?>  
  

This is my new widget!";   echo $after_widget;   }   } add_action( 'widgets_init', create_function('', 'return register_widget("RandomPostWidget");') );?>

Как видно, плагин пока просто выводит заголовок «This is my new widget!». Далее мы заменим место «// WIDGET CODE GOES HERE» на рабочий запрос и вывод миниатюры.

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

Простой запрос и базовый Loop (оригинал)

Чтобы сделать запрос, в примере используется query_posts() и while Loop. Вставьте (как в источнике) такой код туда, где написано WIDGET CODE GOES HERE:

// WIDGET CODE GOES HERE  
query_posts('');      
if (have_posts()) :   
while (have_posts()) : the_post();   
        the_title();      
endwhile;  
endif;   
wp_reset_query();  

Это самый простой пример: без параметров query_posts() вернёт записи по умолчанию (обычно 10 последних). Код просто выведет заголовки.

Чтобы добавить ссылку и HTML‑разметку, можно использовать get_the_permalink() и get_the_title():

query_posts('');  
if (have_posts()) :   
echo "";
endif; 
wp_reset_query();

Чтобы получить один случайный пост, добавьте параметры:

query_posts('posts_per_page=1&orderby=rand');

А чтобы вывести миниатюру рядом с заголовком, используйте the_post_thumbnail():

query_posts('posts_per_page=1&orderby=rand');  
if (have_posts()) :   
echo "
    "; while (have_posts()) : the_post(); echo "
  • ".get_the_title(); echo the_post_thumbnail(array(220,200)); echo "
  • "; endwhile; echo "
"; endif; wp_reset_query();

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

Иллюстрация миниатюры поста, выводимой виджетом

Современная реализация: WP_Query и безопасный вывод

Рекомендуется не использовать query_posts() во вторичных запросах. Ниже — современная и безопасная версия для виджета, которая:

  • использует WP_Query, не ломая главный запрос;
  • кеширует результат во временной опции transient для снижения числа запросов к БД;
  • экранирует вывод (esc_url, esc_attr, esc_html);
  • использует безопасный регистр конструктора класса (PHP7+ совместимость).

Пример кода (фрагмент) для вставки в функцию widget():

// Пример: современный WP_Query и безопасный вывод
$cache_key = 'rpw_random_post_widget';
$cached = get_transient($cache_key);
if ($cached !== false) {
  echo $cached; // уже безопасно закешировано и содержит HTML
} else {
  $args = array(
    'posts_per_page' => 1,
    'orderby' => 'rand',
    'post_status' => 'publish'
  );
  $q = new WP_Query($args);
  ob_start();
  if ($q->have_posts()) {
    echo '
'; while ($q->have_posts()) { $q->the_post(); $permalink = esc_url(get_permalink()); $title = esc_html(get_the_title()); echo ''; if (has_post_thumbnail()) { echo get_the_post_thumbnail(null, array(220,200), array('alt' => esc_attr($title))); } echo '' . $title . ''; echo ''; } echo '
'; } wp_reset_postdata(); $html = ob_get_clean(); set_transient($cache_key, $html, HOUR_IN_SECONDS * 6); // кэш 6 часов echo $html; }

Важно: пример использует set_transient/get_transient — кэширование снижает нагрузку БД, особенно на популярных сайтах. Подберите TTL (time to live) по нагрузке и обновляемости контента.

Отображение миниатюры и заголовка внутри виджета

Советы по безопасности и качественному коду

  • Экранируйте все данные при выводе: esc_html для текста, esc_attr для атрибутов, esc_url для URL.
  • Используйте wp_reset_postdata() после WP_Query, чтобы вернуть глобальную $post в исходное состояние.
  • Для опций виджета и форм в админке используйте sanitize_text_field и соответствующие функции в update().
  • Ограничьте доступ к админским контролам по capability, если добавляете расширенные настройки.

Производительность и кэширование

  • WP_Query с параметром orderby=rand может быть дорогим на больших таблицах posts. Для очень больших сайтов рассмотрите альтернативы (см. раздел «Альтернативные подходы»).
  • Кэшируйте вывод (transients), особенно если набор случайных постов можно обновлять не чаще раза в несколько часов.
  • Для мультисайтов и масштабируемых систем используйте объектный кеш (Redis, Memcached) если доступно.

Альтернативные подходы

  1. get_posts(): возвращает массив объектов WP_Post и удобен для простых задач.
  2. Крайне эффективный метод для больших баз: сначала получить случайный ID через SQL выборку ограниченного набора ID, затем запросить посты по ID (двухэтапный подход уменьшает дерево сортировки).
  3. REST API: для динамических одностраничных приложений можно получить случайный пост через REST и рендерить виджет на фронте.
  4. Плагин‑решения: если вы не хотите кодить, используйте готовые плагины, но будьте внимательны к безопасности и производительности.

Когда подход с миниатюрой не сработает (ограничения)

  • У записи нет миниатюры: обработайте has_post_thumbnail() и выведите fallback‑картинку.
  • Большая нагрузка базы данных при orderby=rand на миллионах записей.
  • Кэширование на уровне CDN или прокси может показывать одинаковый пост разным посетителям — если хотите персонализацию, кэш нужно настраивать аккуратно.

Ментальные модели и эвристики

  • «Не ломай главный запрос»: если вам нужен вторичный запрос — используйте WP_Query или get_posts.
  • «Кэшируй горячее» — медленные операции (orderby=rand, тяжелые JOIN) лучше делать реже и кешировать результат.
  • «Безопасный вывод» — любое внешнее или динамическое содержимое должно быть экранировано.

Чеклист по ролям

Разработчик:

  • Использовать WP_Query или get_posts, не query_posts.
  • Экранировать вывод (esc_*).
  • Добавить transient‑кэширование.
  • Добавить fallback для постов без миниатюр.

Контент‑менеджер:

  • Убедиться, что важные посты имеют featured image.
  • Настроить размеры миниатюр через add_image_size при необходимости.

Сайт‑админ:

  • Включить объектный кэш (если доступно) для ускорения транзиентов.
  • Проверить память PHP и время выполнения при больших выборках.

Критерии приёмки

  • Виджет отображается в списке виджетов в админке.
  • На передней части сайта виджет выводит одну ссылку на пост с миниатюрой.
  • Вывод корректно экранирован (нет XSS при злонамеренных заголовках).
  • Если у записи нет миниатюры, отображается заменяющая картинка или текст.
  • Кэш работает: нагрузка БД снижается при повторных загрузках страницы.

Тесты и приёмочные сценарии

  1. Функциональность: при нескольких обновлениях страницы виджет показывает разные посты (в пределах кэша).
  2. Без миниатюры: запись без featured image корректно обрабатывается (fallback).
  3. Права доступа: только пользователи с нужными правами видят настройку в админке.
  4. Производительность: на тестовом стенде замерить время отклика до и после включения кэша.

Полезная шпаргалка: аргументы запроса

  • posts_per_page — число записей; для виджета обычно 1.
  • orderby — rand, date, title и т.д.
  • post_status — publish (рекомендуется).
  • category_name / cat — ограничение по категории.
  • tag — ограничение по метке.

Применение и миграция

  • Совместимость: код работает на современных версиях WP, но старый конструктор виджета (в примере) устарел. Для PHP7+ и новых WP используйте construct и parent::construct().
  • При переносе на другой сайт проверьте размеры миниатюр и наличие нужных image sizes, регенерируйте миниатюры при необходимости.

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

class Random_Post_Widget extends WP_Widget {
  public function __construct() {
    parent::__construct(
      'random_post_widget',
      __('Random Post and Thumbnail', 'text-domain'),
      array('description' => __('Displays a random post with thumbnail', 'text-domain'))
    );
  }

  public function widget($args, $instance) {
    echo $args['before_widget'];
    $title = apply_filters('widget_title', $instance['title'] ?? '');
    if (!empty($title)) {
      echo $args['before_title'] . esc_html($title) . $args['after_title'];
    }
    // Здесь можно вызвать безопасную функцию, которую мы показывали выше
    echo $args['after_widget'];
  }

  public function form($instance) { /* форма настроек */ }
  public function update($new_instance, $old_instance) { /* обновление */ }
}
add_action('widgets_init', function() { register_widget('Random_Post_Widget'); });

Настройка размеров миниатюры и fallback

  • Зарегистрируйте нужный размер через add_image_size(‘rpw-thumb’, 220, 200, true);
  • При отсутствии миниатюры выводите статическое изображение из темы: get_template_directory_uri() . ‘/images/fallback-thumb.png’

Риски и способы их снижения

  • Нагрузка на БД при orderby=rand — использовать кэш или альтернативные выборки.
  • Уязвимости XSS — строго экранировать весь вывод.
  • Конфликты имён — префиксируйте функции и классы уникальным префиксом (например, rpw_).

Краткое резюме

Создать собственный виджет для WordPress несложно: достаточно знаний базового PHP и понимания WP_Query/Loop. Лучше использовать WP_Query, кешировать результат и экранировать вывод. Для больших сайтов подход с orderby=rand требует аккуратности: применяйте кэш и альтернативные алгоритмы выборки.

Важные заметки

  • Если вы используете старую реализацию виджета из примера, обновите конструктор до __construct и применяйте экранирование.
  • Тестируйте на копии сайта перед выкладкой на прод.

Иллюстрация: итоговый виджет в теме

Краткое итоговое резюме:

  • Написать виджет можно в пару десятков строк; лучше использовать WP_Query и кэш.
  • Экранируйте вывод и обрабатывайте посты без миниатюр.
  • Для больших сайтов избегайте прямого использования orderby=rand без кэширования.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство