Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions backport-changelog/7.1/11245.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
https://github.com/WordPress/wordpress-develop/pull/11245

* https://github.com/WordPress/gutenberg/pull/76079
121 changes: 121 additions & 0 deletions lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,127 @@ protected function __construct() {
}
}

/**
* Registers an icon.
*
* @param string $icon_name Icon name including namespace.
* @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.
* }
* @return bool True if the icon was registered with success and false otherwise.
*/
protected function register( $icon_name, $icon_properties ) {
if ( ! isset( $icon_name ) || ! is_string( $icon_name ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Icon name must be a string.', 'gutenberg' ),
'7.0.0'
);
return false;
}

if ( preg_match( '/[A-Z]/', $icon_name ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Icon names must not contain uppercase characters.' ),
'7.1.0'
);
return false;
}

$name_matcher = '/^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/';
if ( ! preg_match( $name_matcher, $icon_name ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Icon names must contain a namespace prefix. Example: my-plugin/my-custom-icon' ),
'7.1.0'
);
return false;
}

if ( $this->is_registered( $icon_name ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Icon is already registered.' ),
'7.1.0'
);
return false;
}

$allowed_keys = array_fill_keys( array( 'label', 'content', 'filePath' ), 1 );
foreach ( array_keys( $icon_properties ) as $key ) {
if ( ! array_key_exists( $key, $allowed_keys ) ) {
_doing_it_wrong(
__METHOD__,
sprintf(
// translators: %s is the name of any user-provided key
__( 'Invalid icon property: "%s".', 'gutenberg' ),
$key
),
'7.0.0'
);
return false;
}
}

if ( ! isset( $icon_properties['label'] ) || ! is_string( $icon_properties['label'] ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Icon label must be a string.', 'gutenberg' ),
'7.0.0'
);
return false;
}

if (
( ! isset( $icon_properties['content'] ) && ! isset( $icon_properties['filePath'] ) ) ||
( isset( $icon_properties['content'] ) && isset( $icon_properties['filePath'] ) )
) {
_doing_it_wrong(
__METHOD__,
__( 'Icons must provide either `content` or `filePath`.', 'gutenberg' ),
'7.0.0'
);
return false;
}

if ( isset( $icon_properties['content'] ) ) {
if ( ! is_string( $icon_properties['content'] ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Icon content must be a string.', 'gutenberg' ),
'7.0.0'
);
return false;
}

$sanitized_icon_content = $this->sanitize_icon_content( $icon_properties['content'] );
if ( empty( $sanitized_icon_content ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Icon content does not contain valid SVG markup.', 'gutenberg' ),
'7.0.0'
);
return false;
}
}

$icon = array_merge(
$icon_properties,
array( 'name' => $icon_name )
);

$this->registered_icons[ $icon_name ] = $icon;

return true;
}

/**
* Modified to also search in icon labels
*/
Expand Down
127 changes: 127 additions & 0 deletions phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php

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.

I am not sure if this is the best filename. Please guide me in naming this correctly; I will update it.

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.

This looks fine, thanks. :)

Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<?php
/**
* Unit tests covering Gutenberg_Icons_Registry_7_1::register functionality.
*
* @package Gutenberg
*/
class Gutenberg_Icons_Registry_7_1_Test extends WP_UnitTestCase {

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

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

public function tear_down() {
$instance_property = new ReflectionProperty( Gutenberg_Icons_Registry_7_1::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 Gutenberg_Icons_Registry_7_1::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 accept valid icon names.
*/
public function test_register_icon() {
$name = 'test-plugin/my-icon';
$settings = array(
'label' => 'My Icon',
'content' => '<svg></svg>',
);

$result = $this->register( $name, $settings );
$this->assertTrue( $result );
$this->assertTrue( $this->registry->is_registered( $name ) );
}

/**
* Provides invalid icon names.
*
* @return array[]
*/
public function data_invalid_icon_names() {
return array(
'non-string name' => array( 1 ),
'no namespace' => array( 'plus' ),
'uppercase characters' => array( 'Test/Plus' ),
'invalid characters' => array( 'test/_doing_it_wrong' ),
);
}

/**
* Should fail to re-register the same icon.
*
* @expectedIncorrectUsage Gutenberg_Icons_Registry_7_1::register
*/
public function test_register_icon_twice() {
$name = 'test-plugin/duplicate';
$settings = array(
'label' => 'Icon',
'content' => '<svg></svg>',
);

$result = $this->register( $name, $settings );
$this->assertTrue( $result );
$result2 = $this->register( $name, $settings );
$this->assertFalse( $result2 );
}

/**
* Should fail to register icon with invalid names.
*
* @dataProvider data_invalid_icon_names
* @expectedIncorrectUsage Gutenberg_Icons_Registry_7_1::register
*/
public function test_register_invalid_name() {
foreach ( $this->data_invalid_icon_names() as $name ) {
$settings = array(
'label' => 'Icon',
'content' => '<svg></svg>',
);

$result = $this->register( $name, $settings );
$this->assertFalse( $result );
}
}
}
Loading