Skip to content

IconPicker: support the WordPress 7.1 core icon store (wp/v2/icons) #411

Description

@fabiankaegy

What / Why

WordPress 7.1 introduces a first-party icon registration API (dev note):

  • PHP: wp_register_icon_collection() / wp_register_icon() / wp_get_icon(), backed by WP_Icons_Registry / WP_Icon_Collections_Registry
  • REST: read-only wp/v2/icons and wp/v2/icon-collections
  • Editor: icons are exposed as core-data root entitiesgetEntityRecords( 'root', 'icon', { collection } ) and getEntityRecords( 'root', 'iconCollection' ) (record shape: { name: 'my-collection/my-icon', label, content, collection }). There is no dedicated icon data store; the core core/icon block's inserter reads these entities directly.

Currently <IconPicker> / <Icon> / <IconPickerToolbarButton> only list icons pushed into block-components' own internal store via registerIcons(). Plugins adopting the core API end up with two parallel icon stores again — the exact problem the core registry was meant to solve — and have to bridge them manually.

Current workaround

We migrated our icon system to wp_register_icon() and kept <IconPicker> by hydrating the internal store from core-data on editor load:

import domReady from '@wordpress/dom-ready';
import { resolveSelect } from '@wordpress/data';
import { registerIcons } from '@10up/block-components/api/register-icons';

domReady( async () => {
	const [ collections, icons ] = await Promise.all( [
		resolveSelect( 'core' ).getEntityRecords( 'root', 'iconCollection' ),
		resolveSelect( 'core' ).getEntityRecords( 'root', 'icon' ),
	] );

	collections?.forEach( ( collection ) => {
		registerIcons( {
			name: collection.slug,
			label: collection.label,
			icons: icons
				?.filter( ( icon ) => icon.collection === collection.slug )
				.map( ( icon ) => ( {
					name: icon.name.split( '/' )[ 1 ],
					label: icon.label,
					source: icon.content,
				} ) ) ?? [],
		} );
	} );
} );

It works, but every consumer has to ship it, it duplicates icon state alongside the core-data cache, and registration races editor mount.

Proposal

On WP ≥ 7.1, have the icon components read the core icon store natively:

  1. <IconPicker> (and friends) list icons from getEntityRecords( 'root', 'icon' ) / getEntityRecords( 'root', 'iconCollection' ), merged with anything registered via registerIcons() for back-compat. The natural mapping is iconSet ↔ collection slug, name ↔ unqualified icon name, sourcecontent.
  2. <Icon> resolves from the same entities (falling back to the internal store).
  3. Longer term, document registerIcons() as legacy in favor of wp_register_icon() — server registration comes with kses sanitization and REST exposure for free.

Feature detection could be as simple as checking whether the root/icon entity resolves (or window.wp version), keeping WP < 7.1 behavior unchanged.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions