﻿---
title: "Icons API: SVG-иконки в WordPress 7.0 и 7.1"
description: "Регистрация и рендер SVG-иконок: коллекции, wp_register_icon(), wp_get_icon(), REST API, блок Icon и обходные пути для WordPress 7.0."
---

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](https://wordpress.org/plugins/icon-block/) (Nick Diego) — именно его код лёг в основу ядерного блока. Обход через Reflection описан ниже, но не рекомендуется для продакшена.

## Коллекции иконок (WordPress 7.1)

Каждая иконка принадлежит **коллекции** — именованной группе. Имя коллекции становится префиксом: `core/plus` и `my-plugin/plus` — разные иконки, которые не конфликтуют. Ядро регистрирует одну коллекцию `core` с бандленными иконками.

### Регистрация коллекции

Иконку можно добавить только в уже существующую коллекцию, поэтому сначала регистрируем её через `wp_register_icon_collection()`:

```php
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` с приоритетом позже регистрации:

```php
function my_plugin_unregister_icon_collection() {
	wp_unregister_icon_collection( 'my-plugin' );
}
add_action( 'init', 'my_plugin_unregister_icon_collection', 20 );
```

## Регистрация иконок (WordPress 7.1)

Имя иконки всегда имеет вид `collection/icon-name`, например `my-plugin/star`. Коллекция должна быть зарегистрирована до регистрации иконки.

### wp_register_icon()

Иконке передаём `label` и сам SVG — строкой (`content`) или абсолютным путём к `.svg`-файлу (`file_path`). Только один из двух вариантов, не оба сразу:

```php
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 прогоняется через `wp_kses` по строгому allowlist:

- Выживают только элементы `<svg>`, `<path>`, `<g>` — каждый с фиксированным набором атрибутов.
- Всё остальное вырезается: другие элементы, инлайн-стили, скрипты, обработчики событий.
- `fill` сохраняется на `<path>` и `<g>`, но **не на внешнем `<svg>`**; `stroke` не разрешён вообще — stroke-based иконки теряют обводку. Используйте fill-based формы.

Allowlist намеренно консервативен и будет расширяться: [gutenberg#75550](https://github.com/WordPress/gutenberg/pull/75550).

### Удаление иконки

```php
function my_plugin_unregister_icon() {
	wp_unregister_icon( 'my-plugin/star' );
}
add_action( 'init', 'my_plugin_unregister_icon', 20 );
```

Единственная причина отказа — иконка не зарегистрирована. Чтобы убрать все иконки коллекции разом, удалите коллекцию.

## Блок Icon

Блок `core/icon` появился в WordPress 7.0. В 7.1 пикер иконок группирует их по коллекциям: у каждой коллекции своя вкладка, плюс вкладка «Все» для поиска сразу по всем. Поиск фильтрует выбранную коллекцию, запрос сохраняется при переключении вкладок. Кастомные иконки из плагинов и тем отображаются рядом с ядерными.

Другие изменения блока в 7.1:

- **Flip и rotate** — в тулбаре появились кнопки отражения по горизонтали/вертикали и поворота на 90°.
- **Дефолтная иконка** — новый блок стартует с `core/info` вместо пустого плейсхолдера.
- **Серверный рендер через `wp_get_icon()`** — блок и ручной вывод иконки в PHP идут через один кодовый путь.

## Рендер иконки в PHP: wp_get_icon()

`wp_get_icon()` возвращает готовый SVG-маркап любой зарегистрированной иконки:

```php
// Декоративная иконка, размер по умолчанию 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

С версии `15.0.0` пакета каждая иконка несёт `fill="currentColor"` на внешнем `<svg>`, поэтому наследует цвет текста. Чтобы задать другой цвет — передавайте `color`, а не `fill`:

```jsx
import { Icon, plus } from '@wordpress/icons';

<Icon icon={ plus } style={ { color: '#e01e5a' } } />;
```

### Разметка из wp_get_icon()

Здесь `fill="currentColor"` на `<svg>` **не переживает санитизацию**, и `wp_get_icon()` его не добавляет. Следствия:

- **Внутри блока Icon** цвет работает: стили блока задают `fill: currentColor` на `.wp-block-icon svg`, иконка следует за цветом текста.
- **Отдельный вызов `wp_get_icon()`** вернёт «голую» разметку — иконка отрендерится в собственном fill (обычно чёрный), а не в цвете окружающего текста.

Два способа привязать standalone-иконку к цвету текста.

**1. Свой CSS.** Рендерим с классом и задаём `fill` — он наследуется и каскадируется на формы:

```php
echo wp_get_icon( 'my-plugin/star', array( 'class' => 'my-icon' ) );
```

```css
.my-icon {
	fill: currentColor;
}
```

**2. `fill="currentColor"` на формах при регистрации.** Allowlist сохраняет `fill` на `<path>` и `<g>`, поэтому иконка сама несёт цветовое поведение в любом месте вывода:

```php
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, и ваш код может тоже. Все роуты — только GET: смотреть можно, регистрировать и менять через REST нельзя. Эндпоинты под `wp/v2`, требуют аутентифицированного пользователя с правом `edit_posts` (или эквивалентным для любого `show_in_rest` post type).

**Коллекции:**

- `GET /wp/v2/icon-collections` — все коллекции.
- `GET /wp/v2/icon-collections/<collection>` — одна коллекция.

```json
// 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).

```json
// 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

В 7.0 публичного API регистрации нет. Варианты:

### Продакшен-путь: плагин Icon Block

[Icon Block](https://wordpress.org/plugins/icon-block/) (Nick Diego) — плагин, чей код лёг в основу ядерного блока. Позволяет загружать кастомные SVG без кода. Рекомендуемый способ для боевых сайтов на 7.0. Также подойдёт вставка SVG через блок HTML.

### Образовательный хак: 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 со случаями иконок (избавляет от «магических строк» в паттернах):

```php
<?php
declare(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`:

```php
<?php
declare(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-контейнер:

```php
( 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: добавление контента блоками](https://wpcraft.ru/kb/stacks/wordpress/block-editor/editor-blocks.md)
- [Блок Custom HTML: вставка кода и редактируемые слоты](https://wpcraft.ru/kb/stacks/wordpress/block-editor/custom-html-block.md)
- [Регистрация паттернов](https://wpcraft.ru/kb/stacks/wordpress/themes/patterns/registering.md)
- [functions.php: базовые сниппеты](https://wpcraft.ru/kb/stacks/wordpress/cheatsheet/functions-php-essentials.md)
- [theme.json — основа дизайн-системы](https://wpcraft.ru/kb/stacks/wordpress/themes/practices/theme-json.md)

## Материалы и источники

- [Make WordPress Core: Registering and rendering SVG icons in WordPress 7.1](https://make.wordpress.org/core/2026/07/24/registering-and-rendering-svg-icons-in-wordpress-7-1/)
- [Justin Tadlock: How To Register Custom Icons in WordPress 7.0](https://justintadlock.com/archives/2026/06/02/register-custom-icons-wordpress-7-0)
- [Плагин Icon Block (Nick Diego)](https://wordpress.org/plugins/icon-block/)
- [Gutenberg PR #75550: расширение allowlist SVG](https://github.com/WordPress/gutenberg/pull/75550)
- [Gutenberg Issue #75715: публичный Icons API](https://github.com/WordPress/gutenberg/issues/75715)