From a51f22e45cdc42459468ace6bd895b993d851137 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Thu, 11 Jun 2026 15:42:48 +0900 Subject: [PATCH 1/4] Icons: Use snake_case file_path internally in the icon registry. Align the icon registry's internal property with WordPress core's snake_case array-key convention by renaming the registered icon property from filePath to file_path. The conversion now happens only at the registration/mapping boundary in the constructor: the generated manifest keeps the upstream camelCase `filePath` key (as produced by Gutenberg), which is read and mapped to the internal `file_path` property when each icon is registered. This updates the registry validation, allowed property keys, `get_content()` lookup, and the related docblocks and error messages, while leaving the manifest and the copy:icon-library-manifest Grunt task untouched. Co-Authored-By: Claude --- src/wp-includes/class-wp-icons-registry.php | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/wp-includes/class-wp-icons-registry.php b/src/wp-includes/class-wp-icons-registry.php index f82739fc5d91d..a442a2f99af94 100644 --- a/src/wp-includes/class-wp-icons-registry.php +++ b/src/wp-includes/class-wp-icons-registry.php @@ -81,8 +81,8 @@ protected function __construct() { $this->register( 'core/' . $icon_name, array( - 'label' => $icon_data['label'], - 'filePath' => $icons_directory . $icon_data['filePath'], + 'label' => $icon_data['label'], + 'file_path' => $icons_directory . $icon_data['filePath'], ) ); } @@ -97,11 +97,11 @@ protected function __construct() { * @param array $icon_properties { * List of properties for the icon. * - * @type string $label Required. A human-readable label for the icon. - * @type string $content Optional. SVG markup for the icon. - * If not provided, the content will be retrieved from the `filePath` if set. - * If both `content` and `filePath` are not set, the icon will not be registered. - * @type string $filePath Optional. The full path to the file containing the icon content. + * @type string $label Required. A human-readable label for the icon. + * @type string $content Optional. SVG markup for the icon. + * If not provided, the content will be retrieved from the `file_path` if set. + * If both `content` and `file_path` are not set, the icon will not be registered. + * @type string $file_path Optional. The full path to the file containing the icon content. * } * @return bool True if the icon was registered with success and false otherwise. */ @@ -115,7 +115,7 @@ protected function register( $icon_name, $icon_properties ) { return false; } - $allowed_keys = array_fill_keys( array( 'label', 'content', 'filePath' ), 1 ); + $allowed_keys = array_fill_keys( array( 'label', 'content', 'file_path' ), 1 ); foreach ( array_keys( $icon_properties ) as $key ) { if ( ! array_key_exists( $key, $allowed_keys ) ) { _doing_it_wrong( @@ -141,12 +141,12 @@ protected function register( $icon_name, $icon_properties ) { } if ( - ( ! isset( $icon_properties['content'] ) && ! isset( $icon_properties['filePath'] ) ) || - ( isset( $icon_properties['content'] ) && isset( $icon_properties['filePath'] ) ) + ( ! isset( $icon_properties['content'] ) && ! isset( $icon_properties['file_path'] ) ) || + ( isset( $icon_properties['content'] ) && isset( $icon_properties['file_path'] ) ) ) { _doing_it_wrong( __METHOD__, - __( 'Icons must provide either `content` or `filePath`.' ), + __( 'Icons must provide either `content` or `file_path`.' ), '7.0.0' ); return false; @@ -234,7 +234,7 @@ protected function sanitize_icon_content( $icon_content ) { protected function get_content( $icon_name ) { if ( ! isset( $this->registered_icons[ $icon_name ]['content'] ) ) { $content = file_get_contents( - $this->registered_icons[ $icon_name ]['filePath'] + $this->registered_icons[ $icon_name ]['file_path'] ); $content = $this->sanitize_icon_content( $content ); From 205cea8b167047c461e3bb2b0a1370b6592680c0 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Mon, 15 Jun 2026 17:02:07 +0900 Subject: [PATCH 2/4] Icons: Add tests for file_path registration in the icon registry. Add unit tests covering WP_Icons_Registry::register() to verify the snake_case file_path handling: that an icon can be registered via file_path and have its content read from the file, and that registration fails when both content and file_path are provided or when neither is. This mirrors the equivalent tests added on the Gutenberg side and locks in the file_path behavior introduced in the preceding commit. Co-Authored-By: Claude --- tests/phpunit/tests/icons/wpIconsRegistry.php | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 tests/phpunit/tests/icons/wpIconsRegistry.php diff --git a/tests/phpunit/tests/icons/wpIconsRegistry.php b/tests/phpunit/tests/icons/wpIconsRegistry.php new file mode 100644 index 0000000000000..52f97ed78e3e5 --- /dev/null +++ b/tests/phpunit/tests/icons/wpIconsRegistry.php @@ -0,0 +1,137 @@ +registry = WP_Icons_Registry::get_instance(); + } + + public function tear_down() { + $instance_property = new ReflectionProperty( WP_Icons_Registry::class, '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 ) { + $instance_property->setAccessible( true ); + } + + $instance_property->setValue( null, null ); + + $this->registry = null; + parent::tear_down(); + } + + /** + * Invokes WP_Icons_Registry::register despite it being private + * + * @param string $icon_name Icon name including namespace. + * @param array $icon_properties Icon properties (label, content, filePath). + * @return bool True if the icon was registered successfully. + */ + private function register( $icon_name, $icon_properties ) { + $method = new ReflectionMethod( $this->registry, 'register' ); + + /* + * 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 ) { + $method->setAccessible( true ); + } + + return $method->invoke( $this->registry, $icon_name, $icon_properties ); + } + + /** + * Should register an icon that provides its content through `file_path`. + * + * @ticket 64847 + * + * @covers ::register + */ + public function test_register_icon_with_file_path() { + $file_path = tempnam( get_temp_dir(), 'wp-icon-' ); + file_put_contents( $file_path, '' ); + + $name = 'test-plugin/file-path-icon'; + $settings = array( + 'label' => 'Icon', + 'file_path' => $file_path, + ); + + $result = $this->register( $name, $settings ); + $this->assertTrue( $result ); + $this->assertTrue( $this->registry->is_registered( $name ) ); + + $registered_icons = $this->registry->get_registered_icons( $name ); + $this->assertCount( 1, $registered_icons ); + $this->assertStringContainsString( ' 'Icon', + 'content' => '', + 'file_path' => '/path/to/icon.svg', + ); + + $result = $this->register( $name, $settings ); + $this->assertFalse( $result ); + $this->assertFalse( $this->registry->is_registered( $name ) ); + } + + /** + * Should fail to register an icon that provides neither `content` nor `file_path`. + * + * @ticket 64847 + * + * @covers ::register + * + * @expectedIncorrectUsage WP_Icons_Registry::register + */ + public function test_register_icon_without_content_or_file_path() { + $name = 'test-plugin/no-content'; + $settings = array( + 'label' => 'Icon', + ); + + $result = $this->register( $name, $settings ); + $this->assertFalse( $result ); + $this->assertFalse( $this->registry->is_registered( $name ) ); + } +} From 751479d3d993785fc272d3d8a4096d431e8c8214 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Tue, 16 Jun 2026 20:48:41 +0900 Subject: [PATCH 3/4] Icons: rename `filePath` property to `file_path` for naming consistency Rename the icon property key from camelCase `filePath` to snake_case `file_path` in WP_Icons_Registry, matching WordPress array key naming conventions. Add PHPUnit tests covering registration via `file_path`, and the failure cases for providing both or neither `content`/`file_path`. Co-Authored-By: Claude --- tests/phpunit/tests/icons/wpIconsRegistry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/icons/wpIconsRegistry.php b/tests/phpunit/tests/icons/wpIconsRegistry.php index 52f97ed78e3e5..2155327f103c5 100644 --- a/tests/phpunit/tests/icons/wpIconsRegistry.php +++ b/tests/phpunit/tests/icons/wpIconsRegistry.php @@ -46,7 +46,7 @@ public function tear_down() { * Invokes WP_Icons_Registry::register despite it being private * * @param string $icon_name Icon name including namespace. - * @param array $icon_properties Icon properties (label, content, filePath). + * @param array $icon_properties Icon properties (label, content, file_path). * @return bool True if the icon was registered successfully. */ private function register( $icon_name, $icon_properties ) { From c99989c4437920f8aec83f0833bac2a1b69cca02 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Wed, 17 Jun 2026 19:44:17 +0900 Subject: [PATCH 4/4] Icons: Align test helper style with trunk after merge. Remove the redundant `setAccessible` explanatory comments and an extra blank line so the merged test file matches the conventions already used on trunk, keeping the icon registry tests consistent. Co-Authored-By: Claude --- tests/phpunit/tests/icons/wpIconsRegistry.php | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/tests/phpunit/tests/icons/wpIconsRegistry.php b/tests/phpunit/tests/icons/wpIconsRegistry.php index 998b33273287d..23352964db0f5 100644 --- a/tests/phpunit/tests/icons/wpIconsRegistry.php +++ b/tests/phpunit/tests/icons/wpIconsRegistry.php @@ -26,12 +26,6 @@ public function set_up() { public function tear_down() { $instance_property = new ReflectionProperty( WP_Icons_Registry::class, '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 ) { $instance_property->setAccessible( true ); } @@ -52,12 +46,6 @@ public function tear_down() { private function register( $icon_name, $icon_properties ) { $method = new ReflectionMethod( $this->registry, 'register' ); - /* - * 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 ) { $method->setAccessible( true ); } @@ -95,7 +83,6 @@ public function test_register_icon_twice() { $result = $this->register( $name, $settings ); $this->assertTrue( $result ); - $result2 = $this->register( $name, $settings ); $this->assertFalse( $result2 ); }