Разработка шорткодов (Shortcodes) для WordPress
Шорткод — механизм WordPress, позволяющий редактору вставить произвольный PHP-вывод прямо в содержимое поста командой вида [my_shortcode param="value"]. Редактор не знает PHP, не имеет доступа к шаблонам — но через шорткод может вставить таблицу, форму, виджет или карту в любое место контента. Реализация простого шорткода занимает несколько часов; шорткод со сложным рендером и настройками — 1–2 дня.
Регистрация шорткода
add_shortcode('my_button', 'my_button_shortcode_handler');
function my_button_shortcode_handler(array $atts, ?string $content = null): string {
$atts = shortcode_atts([
'url' => '#',
'color' => 'primary',
'target' => '_self',
'size' => 'md',
], $atts, 'my_button');
// Санитизация
$url = esc_url($atts['url']);
$color = sanitize_html_class($atts['color']);
$target = in_array($atts['target'], ['_self', '_blank']) ? $atts['target'] : '_self';
$size = in_array($atts['size'], ['sm', 'md', 'lg']) ? $atts['size'] : 'md';
$label = $content ? wp_kses_post($content) : 'Нажмите';
return sprintf(
'<a href="%s" target="%s" rel="%s" class="btn btn--%s btn--%s">%s</a>',
$url,
$target,
$target === '_blank' ? 'noopener noreferrer' : '',
esc_attr($color),
esc_attr($size),
$label
);
}
shortcode_atts() мержит переданные пользователем атрибуты с дефолтными. Третий параметр — имя шорткода — позволяет фильтровать дефолты через shortcode_atts_my_button.
Шорткод с вложенным контентом
add_shortcode('my_tabs', 'my_tabs_shortcode');
add_shortcode('my_tab', 'my_tab_shortcode');
function my_tabs_shortcode(array $atts, ?string $content = null): string {
if (!$content) return '';
// do_shortcode обрабатывает вложенные [my_tab]
$inner = do_shortcode($content);
return '<div class="my-tabs">' . $inner . '</div>';
}
function my_tab_shortcode(array $atts, ?string $content = null): string {
$atts = shortcode_atts(['title' => 'Вкладка', 'active' => 'no'], $atts, 'my_tab');
$is_active = $atts['active'] === 'yes' ? ' my-tab--active' : '';
$title = esc_html($atts['title']);
$body = $content ? do_shortcode($content) : '';
return "<div class=\"my-tab{$is_active}\" data-title=\"{$title}\">{$body}</div>";
}
Использование в редакторе:
[my_tabs]
[my_tab title="Описание" active="yes"]Текст первой вкладки[/my_tab]
[my_tab title="Характеристики"]Список характеристик[/my_tab]
[/my_tabs]
Шорткод с запросом к базе
add_shortcode('recent_projects', function (array $atts): string {
$atts = shortcode_atts([
'count' => 3,
'category' => '',
'columns' => 3,
], $atts, 'recent_projects');
$args = [
'post_type' => 'project',
'posts_per_page' => absint($atts['count']),
'post_status' => 'publish',
];
if ($atts['category']) {
$args['tax_query'] = [[
'taxonomy' => 'project_category',
'field' => 'slug',
'terms' => sanitize_title($atts['category']),
]];
}
$query = new WP_Query($args);
if (!$query->have_posts()) {
return '<p>Проекты не найдены.</p>';
}
ob_start();
echo '<div class="projects-grid projects-grid--cols-' . absint($atts['columns']) . '">';
while ($query->have_posts()) {
$query->the_post();
get_template_part('template-parts/project-card');
}
wp_reset_postdata();
echo '</div>';
return ob_get_clean();
});
ob_start() / ob_get_clean() — стандартный способ захватить вывод шаблонных частей, которые используют echo, а не return.
Кеширование результата
Шорткоды с запросами к БД или внешним API стоит кешировать через Transients API:
add_shortcode('exchange_rates', function (): string {
$cache_key = 'my_exchange_rates';
$cached = get_transient($cache_key);
if ($cached !== false) {
return $cached;
}
$response = wp_remote_get('https://api.exchangerate.host/latest?base=USD&symbols=RUB,EUR');
if (is_wp_error($response)) {
return '<p>Данные недоступны.</p>';
}
$data = json_decode(wp_remote_retrieve_body($response), true);
$html = '<ul class="rates">';
foreach ($data['rates'] as $currency => $rate) {
$html .= "<li><strong>{$currency}:</strong> " . number_format($rate, 2) . '</li>';
}
$html .= '</ul>';
set_transient($cache_key, $html, HOUR_IN_SECONDS);
return $html;
});
TTL подбирается по частоте изменения данных. Для курсов валют 1 час достаточно; для счётчика посетителей кеш вреден.
Регистрация кнопки в Gutenberg
Чтобы редактор мог вставить шорткод кнопкой, а не вводить вручную, добавляем кнопку в TinyMCE (классический редактор) или блок-обёртку для Gutenberg:
// TinyMCE plugin — добавление кнопки в редактор
(function ($) {
tinymce.create('tinymce.plugins.my_shortcodes', {
init: function (ed) {
ed.addButton('my_button_shortcode', {
title: 'Вставить кнопку',
image: myShortcodesAdmin.pluginUrl + '/icon.svg',
onclick: function () {
const url = prompt('URL кнопки:');
const label = prompt('Текст кнопки:');
if (url && label) {
ed.insertContent(`[my_button url="${url}"]${label}[/my_button]`);
}
},
});
},
});
tinymce.PluginManager.add('my_shortcodes', tinymce.plugins.my_shortcodes);
})(jQuery);
Шорткод vs блок Gutenberg
Шорткоды не устарели, но имеют ограничения: нет preview в редакторе, синтаксис непрозрачен для редактора. Для новых проектов на Gutenberg предпочтительно создавать кастомные блоки (отдельная услуга). Шорткоды остаются оптимальным выбором для Classic Editor, Elementor, WPBakery и любых сторонних конструкторов, которые умеют обрабатывать do_shortcode().







