diff --git a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php b/lib/class-wp-icons-registry-gutenberg.php similarity index 69% rename from lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php rename to lib/class-wp-icons-registry-gutenberg.php index 727064c9b9e7a0..c652bcfb924e2d 100644 --- a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php +++ b/lib/class-wp-icons-registry-gutenberg.php @@ -1,6 +1,6 @@ is_registered( $icon_name ) ) { _doing_it_wrong( __METHOD__, - __( 'Icon is already registered.' ), + __( 'Icon is already registered.', 'gutenberg' ), '7.1.0' ); return false; @@ -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' ); + /* + * 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 ); diff --git a/lib/class-wp-rest-icons-controller-gutenberg.php b/lib/class-wp-rest-icons-controller-gutenberg.php new file mode 100644 index 00000000000000..e20c5a39e19645 --- /dev/null +++ b/lib/class-wp-rest-icons-controller-gutenberg.php @@ -0,0 +1,18 @@ +namespace, - '/' . $this->rest_base, - array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ), - true // Override the core route. - ); - - register_rest_route( - $this->namespace, - '/' . $this->rest_base . '/(?P[a-z][a-z0-9-]*/[a-z][a-z0-9-]*)', - array( - 'args' => array( - 'name' => array( - 'description' => __( 'Icon name.', 'gutenberg' ), - 'type' => 'string', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ), - true // Override the core route. - ); - } - - /** - * Modified to call Gutenberg_Icons_Registry_7_1 - */ - public function get_items( $request ) { - $response = array(); - $search = $request->get_param( 'search' ); - $icons = Gutenberg_Icons_Registry_7_1::get_instance()->get_registered_icons( $search ); - foreach ( $icons as $icon ) { - $prepared_icon = $this->prepare_item_for_response( $icon, $request ); - $response[] = $this->prepare_response_for_collection( $prepared_icon ); - } - return rest_ensure_response( $response ); - } - - /** - * Modified to call Gutenberg_Icons_Registry_7_1 - */ - public function get_icon( $name ) { - $registry = Gutenberg_Icons_Registry_7_1::get_instance(); - $icon = $registry->get_registered_icon( $name ); - - if ( null === $icon ) { - return new WP_Error( - 'rest_icon_not_found', - sprintf( - // translators: %s is the name of any user-provided name - __( 'Icon not found: "%s".', 'gutenberg' ), - $name - ), - array( 'status' => 404 ) - ); - } - - return $icon; - } -} diff --git a/lib/compat/wordpress-7.1/rest-api.php b/lib/compat/wordpress-7.1/rest-api.php index 350ef1f08cdb1a..da8acb5309f22e 100644 --- a/lib/compat/wordpress-7.1/rest-api.php +++ b/lib/compat/wordpress-7.1/rest-api.php @@ -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. */ diff --git a/lib/load.php b/lib/load.php index 88ef3408da2c90..f899d34e071d19 100644 --- a/lib/load.php +++ b/lib/load.php @@ -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. diff --git a/lib/rest-api.php b/lib/rest-api.php index 4209b950c7cb40..529cff55cbc271 100644 --- a/lib/rest-api.php +++ b/lib/rest-api.php @@ -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' ); diff --git a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php b/phpunit/experimental/class-wp-icons-registry-gutenberg-test.php similarity index 83% rename from phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php rename to phpunit/experimental/class-wp-icons-registry-gutenberg-test.php index 89696277f4720a..68f60b730ff8bc 100644 --- a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php +++ b/phpunit/experimental/class-wp-icons-registry-gutenberg-test.php @@ -1,25 +1,25 @@ 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: @@ -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). @@ -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'; @@ -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 ) {