Icons API: SVG-иконки в WordPress 7.0 и 7.1
Icons API — система регистрации и вывода SVG-иконок в ядре WordPress. Иконка регистрируется один раз и дальше доступна везде: в редакторе (блок Icon), в PHP-шаблонах и паттернах, через REST API.
История и доступность по версиям
Заголовок раздела «История и доступность по версиям»| Версия | Что появилось |
|---|---|
| WordPress 7.0 | Встроенный набор SVG-иконок (коллекция core), блок core/icon, REST-эндпоинт /wp/v2/icons. Публичного API регистрации нет — метод WP_Icons_Registry::register() объявлен protected. |
| WordPress 7.1 | Полноценный публичный API: регистрация коллекций и иконок, wp_get_icon() для серверного рендера, группировка иконок по коллекциям в пикере блока Icon. |
До 7.1 кастомные иконки добавляются через плагин Icon Block (Nick Diego) — именно его код лёг в основу ядерного блока. Обход через Reflection описан ниже, но не рекомендуется для продакшена.
Коллекции иконок (WordPress 7.1)
Заголовок раздела «Коллекции иконок (WordPress 7.1)»Каждая иконка принадлежит коллекции — именованной группе. Имя коллекции становится префиксом: core/plus и my-plugin/plus — разные иконки, которые не конфликтуют. Ядро регистрирует одну коллекцию core с бандленными иконками.
Регистрация коллекции
Заголовок раздела «Регистрация коллекции»Иконку можно добавить только в уже существующую коллекцию, поэтому сначала регистрируем её через wp_register_icon_collection():
function my_plugin_register_icon_collection() { wp_register_icon_collection( 'my-plugin', array( 'label' => __( 'My Plugin Icons', 'my-plugin' ), 'description' => __( 'Icons provided by My Plugin.', 'my-plugin' ), ) );}add_action( 'init', 'my_plugin_register_icon_collection' );- Первый аргумент — имя коллекции: начинается и заканчивается строчной буквой или цифрой, внутри допустимы строчные буквы, цифры, дефисы и подчёркивания.
- Второй аргумент — массив с обязательным
labelи опциональнымdescription.
Удаление коллекции
Заголовок раздела «Удаление коллекции»wp_unregister_icon_collection() удаляет коллекцию вместе со всеми её иконками — по одной удалять не нужно. Запускаем на init с приоритетом позже регистрации:
function my_plugin_unregister_icon_collection() { wp_unregister_icon_collection( 'my-plugin' );}add_action( 'init', 'my_plugin_unregister_icon_collection', 20 );Регистрация иконок (WordPress 7.1)
Заголовок раздела «Регистрация иконок (WordPress 7.1)»Имя иконки всегда имеет вид collection/icon-name, например my-plugin/star. Коллекция должна быть зарегистрирована до регистрации иконки.
wp_register_icon()
Заголовок раздела «wp_register_icon()»Иконке передаём label и сам SVG — строкой (content) или абсолютным путём к .svg-файлу (file_path). Только один из двух вариантов, не оба сразу:
function my_plugin_register_icons() { // Сначала коллекция. wp_register_icon_collection( 'my-plugin', array( 'label' => __( 'My Plugin Icons', 'my-plugin' ) ) );
// Иконка из инлайн-строки SVG. wp_register_icon( 'my-plugin/star', array( 'label' => __( 'Star', 'my-plugin' ), 'content' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2l2.9 6.3 6.6.6-5 4.4 1.5 6.4L12 16.9 6 19.7l1.5-6.4-5-4.4 6.6-.6L12 2z"/></svg>', ) );
// Иконка из .svg-файла, поставляемого с плагином. wp_register_icon( 'my-plugin/heart', array( 'label' => __( 'Heart', 'my-plugin' ), 'file_path' => plugin_dir_path( __FILE__ ) . 'icons/heart.svg', ) );}add_action( 'init', 'my_plugin_register_icons' );Функция возвращает true при успехе и false при ошибке с _doing_it_wrong(). Причины отказа: невалидное имя, имя без неймспейса collection/icon-name, незарегистрированная коллекция, дубликат иконки, отсутствующий label, лишние ключи аргументов, отсутствие (или одновременное указание) content и file_path.
file_pathчитается лениво. Файл не открывается при регистрации — только при первом обращении к содержимому (рендер или REST). Поэтому регистрация пройдёт даже с неверным путём, а проблема всплывёт позже как пустой контент. Проверяйте, что путь резолвится на том окружении, где иконка используется.
Санитизация SVG
Заголовок раздела «Санитизация SVG»SVG прогоняется через wp_kses по строгому allowlist:
- Выживают только элементы
<svg>,<path>,<g>— каждый с фиксированным набором атрибутов. - Всё остальное вырезается: другие элементы, инлайн-стили, скрипты, обработчики событий.
fillсохраняется на<path>и<g>, но не на внешнем<svg>;strokeне разрешён вообще — stroke-based иконки теряют обводку. Используйте fill-based формы.
Allowlist намеренно консервативен и будет расширяться: gutenberg#75550.
Удаление иконки
Заголовок раздела «Удаление иконки»function my_plugin_unregister_icon() { wp_unregister_icon( 'my-plugin/star' );}add_action( 'init', 'my_plugin_unregister_icon', 20 );Единственная причина отказа — иконка не зарегистрирована. Чтобы убрать все иконки коллекции разом, удалите коллекцию.
Блок Icon
Заголовок раздела «Блок Icon»Блок core/icon появился в WordPress 7.0. В 7.1 пикер иконок группирует их по коллекциям: у каждой коллекции своя вкладка, плюс вкладка «Все» для поиска сразу по всем. Поиск фильтрует выбранную коллекцию, запрос сохраняется при переключении вкладок. Кастомные иконки из плагинов и тем отображаются рядом с ядерными.
Другие изменения блока в 7.1:
- Flip и rotate — в тулбаре появились кнопки отражения по горизонтали/вертикали и поворота на 90°.
- Дефолтная иконка — новый блок стартует с
core/infoвместо пустого плейсхолдера. - Серверный рендер через
wp_get_icon()— блок и ручной вывод иконки в PHP идут через один кодовый путь.
Рендер иконки в PHP: wp_get_icon()
Заголовок раздела «Рендер иконки в PHP: wp_get_icon()»wp_get_icon() возвращает готовый SVG-маркап любой зарегистрированной иконки:
// Декоративная иконка, размер по умолчанию 24px.echo wp_get_icon( 'core/plus' );
// Иконка 32px с доступным лейблом и дополнительным CSS-классом.echo wp_get_icon( 'my-plugin/star', array( 'size' => 32, 'label' => __( 'Featured', 'my-plugin' ), 'class' => 'my-plugin-star', ));- Первый аргумент — имя иконки; если не зарегистрирована, вернётся пустая строка.
size— ширина и высота в пикселях, по умолчанию24;nullсохраняет исходный размер SVG.class— дополнительные CSS-классы на<svg>.label— доступный лейбл: с ним иконка озвучивается скринридерами, без него — считается декоративной и скрывается от них.
В паттернах и PHP-шаблонах блочной темы это основной способ вставить иконку вне блока Icon.
Стилизация иконок
Заголовок раздела «Стилизация иконок»React-иконки из @wordpress/icons
Заголовок раздела «React-иконки из @wordpress/icons»С версии 15.0.0 пакета каждая иконка несёт fill="currentColor" на внешнем <svg>, поэтому наследует цвет текста. Чтобы задать другой цвет — передавайте color, а не fill:
import { Icon, plus } from '@wordpress/icons';
<Icon icon={ plus } style={ { color: '#e01e5a' } } />;Разметка из wp_get_icon()
Заголовок раздела «Разметка из wp_get_icon()»Здесь fill="currentColor" на <svg> не переживает санитизацию, и wp_get_icon() его не добавляет. Следствия:
- Внутри блока Icon цвет работает: стили блока задают
fill: currentColorна.wp-block-icon svg, иконка следует за цветом текста. - Отдельный вызов
wp_get_icon()вернёт «голую» разметку — иконка отрендерится в собственном fill (обычно чёрный), а не в цвете окружающего текста.
Два способа привязать standalone-иконку к цвету текста.
1. Свой CSS. Рендерим с классом и задаём fill — он наследуется и каскадируется на формы:
echo wp_get_icon( 'my-plugin/star', array( 'class' => 'my-icon' ) );.my-icon { fill: currentColor;}2. fill="currentColor" на формах при регистрации. Allowlist сохраняет fill на <path> и <g>, поэтому иконка сама несёт цветовое поведение в любом месте вывода:
wp_register_icon( 'my-plugin/star', array( 'label' => __( 'Star', 'my-plugin' ), 'content' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M12 2l2.9 6.3 6.6.6-5 4.4 1.5 6.4L12 16.9 6 19.7l1.5-6.4-5-4.4 6.6-.6L12 2z"/></svg>', ));REST API
Заголовок раздела «REST API»Редактор читает иконки через REST API, и ваш код может тоже. Все роуты — только GET: смотреть можно, регистрировать и менять через REST нельзя. Эндпоинты под wp/v2, требуют аутентифицированного пользователя с правом edit_posts (или эквивалентным для любого show_in_rest post type).
Коллекции:
GET /wp/v2/icon-collections— все коллекции.GET /wp/v2/icon-collections/<collection>— одна коллекция.
// GET /wp/v2/icon-collections/core{ "slug": "core", "label": "WordPress", "description": "Default icon collection."}Иконки:
GET /wp/v2/icons— все иконки (с 7.0: поляname,label,contentи параметрsearch; 7.1 добавил поле и параметрcollection).GET /wp/v2/icons/<collection>— иконки одной коллекции (новое в 7.1).GET /wp/v2/icons/<collection>/<icon-name>— одна иконка (с 7.0).
// GET /wp/v2/icons/core/plus{ "name": "core/plus", "label": "Plus", "content": "<svg ...>...</svg>", "collection": "core"}Список иконок принимает параметры search (фильтр по name или label) и collection:
GET /wp/v2/icons?collection=my-plugin&search=starКастомные иконки в WordPress 7.0
Заголовок раздела «Кастомные иконки в WordPress 7.0»В 7.0 публичного API регистрации нет. Варианты:
Продакшен-путь: плагин Icon Block
Заголовок раздела «Продакшен-путь: плагин Icon Block»Icon Block (Nick Diego) — плагин, чей код лёг в основу ядерного блока. Позволяет загружать кастомные SVG без кода. Рекомендуемый способ для боевых сайтов на 7.0. Также подойдёт вставка SVG через блок HTML.
Образовательный хак: Reflection
Заголовок раздела «Образовательный хак: Reflection»Метод WP_Icons_Registry::register() в 7.0 объявлен protected, но доступен через PHP Reflection. Только для экспериментов, не для продакшена — protected API может измениться в любой минорной версии.
Сигнатура метода: register( string $icon_name, array $icon_properties ): bool, где $icon_properties — label плюс content или filePath.
Пример организации кода в теме — enum со случаями иконок (избавляет от «магических строк» в паттернах):
<?phpdeclare(strict_types=1);
namespace ThemeSlug\Icon;
enum Icon: string { case SEALED_KEY = 'theme-slug/sealed-key';
private const NAMESPACE = 'theme-slug'; private const ICONS_PATH = 'public/media/svg';
public function label(): string { return match ( $this ) { self::SEALED_KEY => __( 'Sealed Key', 'theme-slug' ), }; }
public function slug(): string { return substr( $this->value, strlen( self::NAMESPACE . '/' ) ); }
public function filePath(): string { return get_parent_theme_file_path( self::ICONS_PATH . '/' . $this->slug() . '.svg' ); }}Регистратор, вызывающий protected-метод через ReflectionMethod:
<?phpdeclare(strict_types=1);
namespace ThemeSlug\Icon;
use ReflectionException;use ReflectionMethod;use WP_Icons_Registry;
final class IconRegistrar { public function boot(): void { add_action( 'init', $this->register( ... ) ); }
private function register(): void { $registry = WP_Icons_Registry::get_instance();
try { $method = new ReflectionMethod( $registry, 'register' ); } catch ( ReflectionException ) { return; }
foreach ( Icon::cases() as $icon ) { $method->invoke( $registry, $icon->value, [ 'label' => $icon->label(), 'filePath' => $icon->filePath(), ] ); } }}Запуск — в functions.php или через DI-контейнер:
( new \ThemeSlug\Icon\IconRegistrar() )->boot();try/catch защищает от изменения protected API в будущих версиях. Иконки кладутся в public/media/svg/ темы; в 7.0 санитизатор так же пропускает только <svg>, <path>, <g>.
Правильный путь — дождаться 7.1 и переписать регистрацию на публичный API:
wp_register_icon_collection()+wp_register_icon()вместо Reflection.
Связанные страницы
Заголовок раздела «Связанные страницы»- Блочный редактор WordPress: добавление контента блоками
- Блок Custom HTML: вставка кода и редактируемые слоты
- Регистрация паттернов
- functions.php: базовые сниппеты
- theme.json — основа дизайн-системы