From adbd3486337df9a3463e639504354fc8f0a46430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=83=C2=B3=C3=85=E2=80=9Akowski?= Date: Mon, 29 Jan 2024 11:14:22 +0000 Subject: [PATCH] Editor: Add registry for block binding sources It is part of the sync from the Gutenberg plugin that introduces the registry for block binding sources required for the new Block Bindings API: https://github.com/WordPress/gutenberg/issues/54536. See #60282. Props czapla, artemiosans, santosguillamot, sc0ttkclark, lgladdy, talldanwp, swissspidy, youknowriad, fabiankaegy. git-svn-id: https://develop.svn.wordpress.org/trunk@57373 602fd350-edb4-49c9-b593-d223f7449a82 --- .../class-wp-block-bindings-registry.php | 194 +++++++++++++ src/wp-settings.php | 1 + .../wpBlockBindingsRegistry.php | 262 ++++++++++++++++++ 3 files changed, 457 insertions(+) create mode 100644 src/wp-includes/class-wp-block-bindings-registry.php create mode 100644 tests/phpunit/tests/block-bindings/wpBlockBindingsRegistry.php diff --git a/src/wp-includes/class-wp-block-bindings-registry.php b/src/wp-includes/class-wp-block-bindings-registry.php new file mode 100644 index 0000000000..baffd2f3dc --- /dev/null +++ b/src/wp-includes/class-wp-block-bindings-registry.php @@ -0,0 +1,194 @@ +is_registered( $source_name ) ) { + _doing_it_wrong( + __METHOD__, + /* translators: %s: Block binding source name. */ + sprintf( __( 'Block binding source "%s" already registered.' ), $source_name ), + '6.5.0' + ); + return false; + } + + $source = array_merge( + array( 'name' => $source_name ), + $source_properties + ); + + $this->sources[ $source_name ] = $source; + + return $source; + } + + /** + * Unregisters a block binding source. + * + * @since 6.5.0 + * + * @param string $source_name Block binding source name including namespace. + * @return array|false The unregistred block binding source on success and `false` otherwise. + */ + public function unregister( $source_name ) { + if ( ! $this->is_registered( $source_name ) ) { + _doing_it_wrong( + __METHOD__, + /* translators: %s: Block binding source name. */ + sprintf( __( 'Block binding "%s" not found.' ), $source_name ), + '6.5.0' + ); + return false; + } + + $unregistered_source = $this->sources[ $source_name ]; + unset( $this->sources[ $source_name ] ); + + return $unregistered_source; + } + + /** + * Retrieves the list of all registered block bindings sources. + * + * @since 6.5.0 + * + * @return array The array of registered sources. + */ + public function get_all_registered() { + return $this->sources; + } + + /** + * Retrieves a registered block bindings source. + * + * @since 6.5.0 + * + * @param string $source_name The name of the source. + * @return array|null The registered block binding source, or `null` if it is not registered. + */ + public function get_registered( $source_name ) { + if ( ! $this->is_registered( $source_name ) ) { + return null; + } + + return $this->sources[ $source_name ]; + } + + /** + * Checks if a block binding source is registered. + * + * @since 6.5.0 + * + * @param string $source_name The name of the source. + * @return bool `true` if the block binding source is registered, `false` otherwise. + */ + public function is_registered( $source_name ) { + return isset( $this->sources[ $source_name ] ); + } + + /** + * Utility method to retrieve the main instance of the class. + * + * The instance will be created if it does not exist yet. + * + * @since 6.5.0 + * + * @return WP_Block_Bindings_Registry The main instance. + */ + public static function get_instance() { + if ( null === self::$instance ) { + self::$instance = new self(); + } + + return self::$instance; + } +} diff --git a/src/wp-settings.php b/src/wp-settings.php index e30eeb493b..9904bf5003 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -330,6 +330,7 @@ require ABSPATH . WPINC . '/sitemaps/providers/class-wp-sitemaps-posts.php'; require ABSPATH . WPINC . '/sitemaps/providers/class-wp-sitemaps-taxonomies.php'; require ABSPATH . WPINC . '/sitemaps/providers/class-wp-sitemaps-users.php'; require ABSPATH . WPINC . '/class-wp-block-editor-context.php'; +require ABSPATH . WPINC . '/class-wp-block-bindings-registry.php'; require ABSPATH . WPINC . '/class-wp-block-type.php'; require ABSPATH . WPINC . '/class-wp-block-pattern-categories-registry.php'; require ABSPATH . WPINC . '/class-wp-block-patterns-registry.php'; diff --git a/tests/phpunit/tests/block-bindings/wpBlockBindingsRegistry.php b/tests/phpunit/tests/block-bindings/wpBlockBindingsRegistry.php new file mode 100644 index 0000000000..deb08de351 --- /dev/null +++ b/tests/phpunit/tests/block-bindings/wpBlockBindingsRegistry.php @@ -0,0 +1,262 @@ + 'Test source', + ); + + /** + * Fake block bindings registry. + * + * @since 6.5.0 + * @var WP_Block_Bindings_Registry + */ + private $registry = null; + + /** + * Set up each test method. + * + * @since 6.5.0 + */ + public function set_up() { + parent::set_up(); + + $this->registry = new WP_Block_Bindings_Registry(); + } + + /** + * Tear down each test method. + * + * @since 6.5.0 + */ + public function tear_down() { + $this->registry = null; + + parent::tear_down(); + } + + /** + * Should reject numbers as block binding source name. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::register + * + * @expectedIncorrectUsage WP_Block_Bindings_Registry::register + */ + public function test_register_invalid_non_string_names() { + $result = $this->registry->register( 1, self::TEST_SOURCE_PROPERTIES ); + $this->assertFalse( $result ); + } + + /** + * Should reject block binding source name without a namespace. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::register + * + * @expectedIncorrectUsage WP_Block_Bindings_Registry::register + */ + public function test_register_invalid_names_without_namespace() { + $result = $this->registry->register( 'post-meta', self::TEST_SOURCE_PROPERTIES ); + $this->assertFalse( $result ); + } + + /** + * Should reject block binding source name with invalid characters. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::register + * + * @expectedIncorrectUsage WP_Block_Bindings_Registry::register + */ + public function test_register_invalid_characters() { + $result = $this->registry->register( 'still/_doing_it_wrong', array() ); + $this->assertFalse( $result ); + } + + /** + * Should reject block binding source name with uppercase characters. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::register + * + * @expectedIncorrectUsage WP_Block_Bindings_Registry::register + */ + public function test_register_invalid_uppercase_characters() { + $result = $this->registry->register( 'Core/PostMeta', self::TEST_SOURCE_PROPERTIES ); + $this->assertFalse( $result ); + } + + /** + * Should accept valid block binding source. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::register + */ + public function test_register_block_binding_source() { + $result = $this->registry->register( self::TEST_SOURCE_NAME, self::TEST_SOURCE_PROPERTIES ); + $this->assertSame( + array_merge( + array( 'name' => self::TEST_SOURCE_NAME ), + self::TEST_SOURCE_PROPERTIES + ), + $result + ); + } + + /** + * Unregistering should fail if a block binding source is not registered. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::unregister + * + * @expectedIncorrectUsage WP_Block_Bindings_Registry::unregister + */ + public function test_unregister_not_registered_block() { + $result = $this->registry->unregister( 'test/unregistered' ); + $this->assertFalse( $result ); + } + + /** + * Should unregister existing block binding source. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::unregister + */ + public function test_unregister_block_source() { + $this->registry->register( self::TEST_SOURCE_NAME, self::TEST_SOURCE_PROPERTIES ); + + $result = $this->registry->unregister( self::TEST_SOURCE_NAME ); + $this->assertSame( + array_merge( + array( 'name' => self::TEST_SOURCE_NAME ), + self::TEST_SOURCE_PROPERTIES + ), + $result + ); + } + + /** + * Should find all registered sources. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::register + * @covers WP_Block_Bindings_Registry::get_all_registered + */ + public function test_get_all_registered() { + $source_one_name = 'test/source-one'; + $source_one_properties = self::TEST_SOURCE_PROPERTIES; + $this->registry->register( $source_one_name, $source_one_properties ); + + $source_two_name = 'test/source-two'; + $source_two_properties = self::TEST_SOURCE_PROPERTIES; + $this->registry->register( $source_two_name, $source_two_properties ); + + $source_three_name = 'test/source-three'; + $source_three_properties = self::TEST_SOURCE_PROPERTIES; + $this->registry->register( $source_three_name, $source_three_properties ); + + $expected = array( + $source_one_name => array_merge( array( 'name' => $source_one_name ), $source_one_properties ), + $source_two_name => array_merge( array( 'name' => $source_two_name ), $source_two_properties ), + $source_three_name => array_merge( array( 'name' => $source_three_name ), $source_three_properties ), + ); + + $registered = $this->registry->get_all_registered(); + $this->assertSame( $expected, $registered ); + } + + /** + * Should not find source that's not registered. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::register + * @covers WP_Block_Bindings_Registry::get_registered + */ + public function test_get_registered_rejects_unknown_source_name() { + $this->registry->register( self::TEST_SOURCE_NAME, self::TEST_SOURCE_PROPERTIES ); + + $source = $this->registry->get_registered( 'test/unknown-source' ); + $this->assertNull( $source ); + } + + /** + * Should find registered block binding source by name. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::register + * @covers WP_Block_Bindings_Registry::get_registered + */ + public function test_get_registered() { + $source_one_name = 'test/source-one'; + $source_one_properties = self::TEST_SOURCE_PROPERTIES; + $this->registry->register( $source_one_name, $source_one_properties ); + + $source_two_name = 'test/source-two'; + $source_two_properties = self::TEST_SOURCE_PROPERTIES; + $this->registry->register( $source_two_name, $source_two_properties ); + + $source_three_name = 'test/source-three'; + $source_three_properties = self::TEST_SOURCE_PROPERTIES; + $this->registry->register( $source_three_name, $source_three_properties ); + + $result = $this->registry->get_registered( 'test/source-two' ); + $this->assertSame( + array_merge( + array( 'name' => $source_two_name ), + $source_two_properties + ), + $result + ); + } + + /** + * Should return false for source that's not registered. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::is_registered + */ + public function test_is_registered_for_unknown_source() { + $result = $this->registry->is_registered( 'test/one' ); + $this->assertFalse( $result ); + } + + /** + * Should return true if source is registered. + * + * @ticket 60282 + * + * @covers WP_Block_Bindings_Registry::register + * @covers WP_Block_Bindings_Registry::is_registered + */ + public function test_is_registered_for_known_source() { + $this->registry->register( self::TEST_SOURCE_NAME, self::TEST_SOURCE_PROPERTIES ); + + $result = $this->registry->is_registered( self::TEST_SOURCE_NAME ); + $this->assertTrue( $result ); + } +}