Кастомный шорткод в WordPress
Зачем мне понадобились шорткоды
Некоторое время я выводил сложные элементы на страницах блога через HTML прямо в редакторе. Это работало, но имело серьёзные минусы: код повторялся в каждом посте, а когда мне нужно было что-то поменять в выводе, приходилось править десятки записей вручную. Понятно, что такой подход не масштабируется, поэтому я задумался о механизме, который позволял бы вставлять готовый элемент одним коротким тегом.
Решение нашлось быстро — кастомные шорткоды WordPress. Это специальные метки в квадратных скобках, которые движок заменяет на нужный HTML при выводе страницы. Например, я вставляю в пост [myserv], а WordPress подставляет туда целый блок со списком моих сервисов. Одна точка управления вместо сотни правок.
Как устроен шорткод
Шорткод объявляется в файле functions.php вашей темы с помощью функции add_shortcode. Первый аргумент — это название тега, второй — функция, которая возвращает HTML, подставляемый вместо метки. Классический пример выглядит так.
add_shortcode('myserv', function() {
return '<div class="services">Мои сервисы</div>';
});
Важный нюанс: функция шорткода должна возвращать строку, а не выводить её через echo. Если сделать вывод напрямую, элемент окажется в начале страницы, а не там, где стоит шорткод. Эту ошибку я допустил в первый раз и долго не понимал, почему блок уезжает вверх.
Шорткоды с атрибутами
Через время я захотел, чтобы один шорткод умел выводить разные варианты. Для этого в WordPress предусмотрены атрибуты — параметры внутри квадратных скобок. Пример: [box type="warning"]Текст[/box]. Внутри функции атрибуты доступны во втором аргументе, а текст между открывающим и закрывающим тегами — в третьем.
add_shortcode('box', function($atts, $content = null) {
$atts = shortcode_atts(array('type' => 'info'), $atts);
return '<div class="box box-' . esc_attr($atts['type']) . '">' . $content . '</div>';
});
Здесь shortcode_atts задаёт значения по умолчанию и сливает их с переданными атрибутами. А esc_attr защищает вывод от неожиданных символов. Я использую такой шорткод для информационных и предупреждающих блоков в статьях.
Где взять данные для вывода
Чаще всего шорткод нужен не для статического блока, а для вывода данных. Например, я сделал шорткод, который показывает последние записи из определённой рубрики. Внутри функции обращаюсь к WordPress API через WP_Query, собираю HTML из результата и возвращаю его.
add_shortcode('recent_guides', function() {
$q = new WP_Query(array('posts_per_page' => 5, 'category_name' => 'guide'));
$out = '<ul class="recent">';
while ($q->have_posts()) {
$q->the_post();
$out .= '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
}
wp_reset_postdata();
$out .= '</ul>';
return $out;
});
Не забудьте вызвать wp_reset_postdata() после цикла. Без этого глобальные переменные поста останутся изменёнными, и другие части страницы могут вывести не тот контент. Это одна из тех тонкостей, на которые натыкаешься не сразу.
Шорткоды для галерей и кнопок
Со временем мой набор шорткодов расширился. Я сделал шорткод для кнопки, ведущей на скачивание, и шорткод для вставки аккуратной галереи изображений без лишних плагинов. Кнопка принимает атрибуты «текст» и «ссылка», а галерея — список ID картинок через запятую.
Такой подход позволил убрать из проекта несколько тяжёлых плагинов, которые отвечали ровно за эти же функции. Меньше плагинов — меньше потенциальных конфликтов и медленнее обновления. А ещё весь вывод находится под моим контролем, и я не завишу от настроек стороннего модуля.
Ошибки, на которые я наступил
Первая ошибка уже упоминалась — echo вместо return. Вторая — регистр шорткода: WordPress по умолчанию регистронезависим, поэтому [MyServ] и [myserv] — это одно и то же. Но в своих функциях я всё равно придерживаюсь единого нижнего регистра, чтобы не путаться.
Третья ошибка — конфликт имён. Однажды я назвал свой шорткод так же, как существующий, и получил непредсказуемый вывод. Поэтому теперь я добавляю к именам собственных шорткодов префикс, связанный с моим блогом, и проверяю в документации, что такое имя не занято.
И четвёртая: я забывал очищать кэш после правки функции. Если у вас включено кэширование страниц, изменения в шорткоде не всегда видны сразу. После обновления functions.php я всегда сбрасываю кэш, иначе теряю время на поиск несуществующей ошибки.
Альтернативы шорткодам
Стоит знать, что в современных версиях WordPress есть и более новые механизмы. Блоки Гутенберга позволяют создавать переиспользуемые элементы, а встроенный механизм синхронизированных шаблонов закрывает часть тех же задач. Но шорткоды по-прежнему остаются самым простым способом для точечной вставки динамического контента, особенно в старых постах.
Главный плюс шорткода перед блоком — его можно использовать прямо в тексте, в том числе в местах, куда редактор блоков не дотягивается. Например, в HTML-виджете или в шаблоне темы. Поэтому я считаю этот инструмент обязательным к пониманию для тех, кто работает с WordPress на уровне разработки.
Шорткод внутри блока Гутенберга
Если вы используете современный редактор блоков, вставлять шорткод можно прямо в блоке «Короткий код». Просто перетащите его в нужное место и напишите метку в квадратных скобках. При публикации WordPress заменит её на результат выполнения функции. Это работает как в классическом редакторе, так и в блочном, так что у вас нет ограничений на способ редактирования.
Важно помнить, что шорткод выполняется при выводе страницы, а не при сохранении записи. Поэтому если данные в базе меняются, вывод будет актуализироваться автоматически. Именно это делает шорткоды удобными для динамического контента вроде списков свежих постов или курсов валют.
Гнездовые шорткоды
WordPress поддерживает вложенные шорткоды. Это значит, что внутри одного шорткода может стоять другой. Например, я делаю кнопку-блок, внутри которой можно использовать шорткод со ссылкой. Главное условие — вложенность должна быть корректно закрыта, иначе парсер перестанет разбирать конструкцию.
Бывает удобно, когда один шорткод служит обёрткой для другого. Мой пример: шорткод [panel] задаёт стиль блока, а внутри я размещаю [recent_guides] для списка статей. Один вызов функции, и на странице появляется аккуратный оформленный блок с актуальным содержанием. С гнездованием нужно быть аккуратным, но в разумных пределах оно сильно упрощает жизнь.
Кэширование и производительность
Поскольку шорткоды выполняются при каждом выводе страницы, важно не делать внутри них тяжёлых операций. Я стараюсь не выполнять в функции шорткода сложные запросы к базе, если вывод можно кэшировать. Простой приём — использовать транзиенты WordPress: результат запроса складывается во временный кэш на час, и только потом пересчитывается.
add_shortcode('recent_guides', function() {
$cache = get_transient('recent_guides_html');
if ($cache !== false) return $cache;
// ... строим $out ...
set_transient('recent_guides_html', $out, HOUR_IN_SECONDS);
return $out;
});
Такой подход снижает нагрузку на базу данных и заметно ускоряет вывод страниц. Особенно это актуально, когда шорткод стоит на главной странице и выполняется при каждом визите. Я применяю транзиенты почти во всех шорткодах, которые отдают данные из базы.
Где хранить код шорткодов
Код я держу в файле темы functions.php, но для крупных проектов это не лучший вариант. Когда шорткодов много, их удобнее выносить в отдельный файл и подключать через require. Такой файл проще читать и поддерживать, а также его можно покрыть тестами. У меня файл называется shortcodes.php и подключается одной строкой.
Ещё вариант — оформить шорткоды как плагин. Это актуально, если вы меняете темы, но не хотите терять функциональность. Код плагина переживёт смену оформления, тогда как код в functions.php исчезнет вместе со старой темой. Я рекомендую сразу думать о том, насколько постоянными должны быть ваши шорткоды.
Проверка перед публикацией
Перед тем как выпустить пост с новым шорткодом, я проверяю его на черновике. Смотрю, что вывод не ломает вёрстку, что ссылки рабочие и что данные актуальные. Иногда достаточно открыть страницу в режиме предпросмотра, но для динамических данных лучше смотреть уже опубликованную версию с выключенным кэшем.
Если что-то пошло не так, первым делом проверяю логи ошибок PHP. Большинство проблем с шорткодами проявляются в виде предупреждений о том, что функция не найдена или вызывается не с теми аргументами. Чтение логов экономит кучу времени по сравнению с догадками.
Конкретные примеры из моего блога
Расскажу, какие шорткоды реально использую на этом сайте. Первый — для вывода списка сервисов в верхней части некоторых статей. Вместо того чтобы копировать один и тот же HTML в каждый пост, я вставляю короткую метку, и WordPress подставляет актуальный список с ссылками. Когда я добавил новый сервис, мне хватило одной правки в функции.
Второй шорткод — блок «Полезно знать», который оформляет заметку с серым фоном и иконкой. Он принимает атрибут типа, чтобы менять цвет рамки. Такой блок я использую, когда хочу выделить важную деталь в статье, не перегружая её оформление.
Третий — шорткод для сравнения двух версий сервиса. Он рисует таблицу из переданных аргументов. Раньше я оформлял такие таблицы вручную, и они ломались при редактировании. С шорткодом достаточно поменять данные в одном месте.
Распространённые мифы
Есть мнение, что шорткоды устарели и использовать их не стоит. На деле это не так. Да, Гутенберг даёт больше возможностей для оформления, но шорткоды остаются простым и надёжным способом переиспользовать код. Они работают во всех версиях WordPress, и сотни плагинов до сих пор используют их внутри себя.
Другой миф — что шорткоды замедляют сайт. Замедляют не сами шорткоды, а неаккуратный код внутри них. Если функция делает тяжёлые запросы без кэширования, страница будет грузиться долго. Но с транзиентами и простыми операциями вы этого даже не заметите.
Как отладить шорткод
Если шорткод не выводит ничего, проверяю три вещи в таком порядке. Сначала — что функция вообще зарегистрирована: открываю страницу, где шорткод должен сработать, и смотрю, не остался ли он в тексте в исходном виде. Если остался — значит, вызов add_shortcode не выполняется или имя не совпадает.
Потом проверяю права на файл темы. Иногда редактор сохраняет файл без разрешения на запись, и правки не применяются, хотя выглядят удачно. И наконец, добавляю временную запись в лог внутри функции, чтобы понять, вызывается ли она вообще и с какими аргументами. Этот набор действий решает подавляющее большинство проблем.
Итог
Кастомные шорткоды избавили меня от дублирования кода и сделали контент управляемым. Вместо того чтобы вставлять одинаковые HTML-блоки в десятки постов, я описываю их один раз в functions.php и вызываю по имени. Это экономит время и упрощает поддержку блога. Если вы ещё не пользовались шорткодами, начните с простого примера — уверен, быстро оцените удобство.