Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a44fafe
Icons: Override WP_Icons_Registry singleton with Gutenberg icons regi…
t-hamano Mar 12, 2026
b610839
Remove Gutenberg_REST_Icons_Controller_7_1
t-hamano Mar 12, 2026
55892ed
Remove require statement
t-hamano Mar 12, 2026
78ec29f
Remove temp code
t-hamano Mar 12, 2026
d0daaf6
Update comment
t-hamano Mar 12, 2026
491c9fb
Replay pre-registered non-core icons
t-hamano Mar 13, 2026
493d230
Merge branch 'trunk' into icons/refrection-class
t-hamano Mar 13, 2026
7d47012
Create registry and REST API controller for Gutenberg
t-hamano Mar 13, 2026
196e4b3
WP_REST_Icons_Controller_Gutenberg: Remove unnecessary ABSPATH check
t-hamano Mar 13, 2026
b3d1dae
Merge branch 'trunk' into icons/refrection-class
t-hamano Mar 19, 2026
c56e31c
Fix misplaced files
t-hamano Mar 19, 2026
6160049
Merge branch 'trunk' into icons/refrection-class
t-hamano Mar 19, 2026
a75a322
Merge branch 'trunk' into icons/refrection-class
t-hamano Mar 26, 2026
7309547
Merge branch 'trunk' into icons/refrection-class
t-hamano Mar 30, 2026
b30292f
Restore code that was accidentally deleted
t-hamano Mar 31, 2026
bdd9972
Merge branch 'trunk' into icons/refrection-class
t-hamano Mar 31, 2026
8d80eae
Merge branch 'trunk' into icons/refrection-class
t-hamano Apr 1, 2026
55b6070
Update unit test
t-hamano Apr 1, 2026
14fe750
Fix PHPCS warning
t-hamano Apr 1, 2026
a3027c6
Fix PHPCS warning take 2
t-hamano Apr 1, 2026
fdd080f
Merge branch 'trunk' into icons/refrection-class
t-hamano Apr 8, 2026
60bafaa
Add PHP version check
t-hamano Apr 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

class Gutenberg_Icons_Registry_7_1 extends WP_Icons_Registry {
class WP_Icons_Registry_Gutenberg extends WP_Icons_Registry {
/**
* Modified to point $manifest_path to Gutenberg packages
*/
Expand Down Expand Up @@ -78,7 +78,7 @@ protected function register( $icon_name, $icon_properties ) {
if ( preg_match( '/[A-Z]/', $icon_name ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Icon names must not contain uppercase characters.' ),
__( 'Icon names must not contain uppercase characters.', 'gutenberg' ),
'7.1.0'
);
return false;
Expand All @@ -88,7 +88,7 @@ protected function register( $icon_name, $icon_properties ) {
if ( ! preg_match( $name_matcher, $icon_name ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Icon names must contain a namespace prefix. Example: my-plugin/my-custom-icon' ),
__( 'Icon names must contain a namespace prefix. Example: my-plugin/my-custom-icon', 'gutenberg' ),
'7.1.0'
);
return false;
Expand All @@ -97,7 +97,7 @@ protected function register( $icon_name, $icon_properties ) {
if ( $this->is_registered( $icon_name ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Icon is already registered.' ),
__( 'Icon is already registered.', 'gutenberg' ),
'7.1.0'
);
return false;
Expand Down Expand Up @@ -208,3 +208,55 @@ public static function get_instance() {
return self::$instance;
}
}

/**
* Forces WP_Icons_Registry_Gutenberg instantiation and overrides WP_Icons_Registry
* so that all code using WP_Icons_Registry::{method_name}() receives the Gutenberg
* registry.
*/
function gutenberg_override_wp_icons_registry() {
$reflection = new ReflectionClass( WP_Icons_Registry::class );
$property = $reflection->getProperty( 'instance' );
/*
* ReflectionProperty::setAccessible is:
* - redundant as of 8.1.0, which made all properties accessible
* - deprecated as of 8.5.0
* - needed until 8.1.0, as property `instance` is private
*/
if ( PHP_VERSION_ID < 80100 ) {
$property->setAccessible( true );
}
$original_registry = $property->getValue( null );
$gutenberg_registry = WP_Icons_Registry_Gutenberg::get_instance();

// If the original registry was already instantiated, replay any icons outside
// the `core/` namespace onto the Gutenberg registry so they are not lost.
if ( null !== $original_registry ) {
$register_method = new ReflectionMethod( WP_Icons_Registry_Gutenberg::class, 'register' );

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in commit 60bafaa

/*
* ReflectionMethod::setAccessible is:
* - redundant as of 8.1.0, which made all properties accessible
* - deprecated as of 8.5.0
* - needed until 8.1.0, as property `instance` is private
*/
if ( PHP_VERSION_ID < 80100 ) {
$register_method->setAccessible( true );
}
foreach ( $original_registry->get_registered_icons() as $icon ) {
if ( strpos( $icon['name'], 'core/' ) === 0 ) {
continue;
}
$icon_properties = array( 'label' => $icon['label'] );
if ( ! empty( $icon['content'] ) ) {
$icon_properties['content'] = $icon['content'];
} elseif ( ! empty( $icon['filePath'] ) ) {
$icon_properties['filePath'] = $icon['filePath'];
} else {
continue;
}
$register_method->invoke( $gutenberg_registry, $icon['name'], $icon_properties );
}
}
$property->setValue( null, $gutenberg_registry );
}
add_action( 'init', 'gutenberg_override_wp_icons_registry', 1 );
18 changes: 18 additions & 0 deletions lib/class-wp-rest-icons-controller-gutenberg.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
/**
* REST API: Bundle WP_Icons_Registry_Gutenberg class instead of inheriting per WordPress version class
*
* Changes to this class should be synced to the corresponding class
* in WordPress core: src/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php.
*
* @package gutenberg
* @subpackage REST_API
*/

/**
* Gutenberg Icons REST API Controller.
*
* @since 7.1.0
*/
class WP_REST_Icons_Controller_Gutenberg extends WP_REST_Icons_Controller {
}
Comment on lines +17 to +18

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, there is no need to expand the core controller, but it may be necessary in the future.

This file was deleted.

9 changes: 0 additions & 9 deletions lib/compat/wordpress-7.1/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,6 @@
* @package gutenberg
*/

/**
* Registers the Icons REST API routes.
*/
function gutenberg_register_icons_controller_endpoints() {
$icons_controller = new Gutenberg_REST_Icons_Controller_7_1();
$icons_controller->register_routes();
}
add_action( 'rest_api_init', 'gutenberg_register_icons_controller_endpoints', PHP_INT_MAX );

/**
* Registers the View Config REST API routes.
*/
Expand Down
4 changes: 2 additions & 2 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,14 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/compat/wordpress-7.0/connectors.php';

// WordPress 7.1 compat.
require __DIR__ . '/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php';
require __DIR__ . '/compat/wordpress-7.1/class-gutenberg-rest-icons-controller-7-1.php';
require __DIR__ . '/compat/wordpress-7.1/class-gutenberg-rest-view-config-controller-7-1.php';
require __DIR__ . '/compat/wordpress-7.1/rest-api.php';

// Plugin specific code.
require_once __DIR__ . '/class-wp-rest-global-styles-controller-gutenberg.php';
require_once __DIR__ . '/class-wp-rest-edit-site-export-controller-gutenberg.php';
require_once __DIR__ . '/class-wp-icons-registry-gutenberg.php';
require_once __DIR__ . '/class-wp-rest-icons-controller-gutenberg.php';
require_once __DIR__ . '/rest-api.php';

// Experimental autosaves controller override for real-time collaboration.
Expand Down
4 changes: 2 additions & 2 deletions lib/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function gutenberg_register_edit_site_export_controller_endpoints() {
* Registers the Icons Registry REST API routes.
*/
function gutenberg_register_icon_controller_endpoints() {
$icons_registry = new WP_REST_Icons_Controller();
$icons_registry->register_routes();
$icons_controller = new WP_REST_Icons_Controller_Gutenberg();
$icons_controller->register_routes();
}
add_action( 'rest_api_init', 'gutenberg_register_icon_controller_endpoints' );
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
<?php
/**
* Unit tests covering Gutenberg_Icons_Registry_7_1::register functionality.
* Unit tests covering WP_Icons_Registry_Gutenberg::register functionality.
*
* @package Gutenberg
*/
class Gutenberg_Icons_Registry_7_1_Test extends WP_UnitTestCase {
class WP_Test_Icons_Registry_Gutenberg extends WP_UnitTestCase {

/**
* Registry instance for testing.
*
* @var Gutenberg_Icons_Registry_7_1
* @var WP_Icons_Registry_Gutenberg
*/
private $registry;

public function set_up() {
parent::set_up();
$this->registry = Gutenberg_Icons_Registry_7_1::get_instance();
$this->registry = WP_Icons_Registry_Gutenberg::get_instance();
}

public function tear_down() {
$instance_property = new ReflectionProperty( Gutenberg_Icons_Registry_7_1::class, 'instance' );
$instance_property = new ReflectionProperty( WP_Icons_Registry_Gutenberg::class, 'instance' );

/*
* ReflectionProperty::setAccessible is:
Expand All @@ -38,7 +38,7 @@ public function tear_down() {
}

/**
* Invokes Gutenberg_Icons_Registry_7_1::register despite it being private
* Invokes WP_Icons_Registry_Gutenberg::register despite it being private
*
* @param string $icon_name Icon name including namespace.
* @param array $icon_properties Icon properties (label, content, filePath).
Expand Down Expand Up @@ -92,7 +92,7 @@ public function data_invalid_icon_names() {
/**
* Should fail to re-register the same icon.
*
* @expectedIncorrectUsage Gutenberg_Icons_Registry_7_1::register
* @expectedIncorrectUsage WP_Icons_Registry_Gutenberg::register
*/
public function test_register_icon_twice() {
$name = 'test-plugin/duplicate';
Expand All @@ -111,7 +111,7 @@ public function test_register_icon_twice() {
* Should fail to register icon with invalid names.
*
* @dataProvider data_invalid_icon_names
* @expectedIncorrectUsage Gutenberg_Icons_Registry_7_1::register
* @expectedIncorrectUsage WP_Icons_Registry_Gutenberg::register
*/
public function test_register_invalid_name() {
foreach ( $this->data_invalid_icon_names() as $name ) {
Expand Down
Loading