<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[48141] trunk: Editor: Introduce new API method that register block from `block.json` metadata file</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/48141">48141</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/48141","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>gziolo</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2020-06-23 15:43:19 +0000 (Tue, 23 Jun 2020)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Editor: Introduce new API method that register block from `block.json` metadata file

Backports changes added to Gutenberg in:
- https://github.com/WordPress/gutenberg/pull/20794
- https://github.com/WordPress/gutenberg/pull/22519
`register_block_type_from_metadata` function is going to be used to register all blocks on the server using `block.json` metadata files.

Props ocean90, azaozz, aduth, mcsf, jorgefilipecosta, spacedmonkey, nosolosw, swissspidy and noahtallen.
Fixes <a href="https://core.trac.wordpress.org/ticket/50263">#50263</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesblocksphp">trunk/src/wp-includes/blocks.php</a></li>
<li><a href="#trunktestsphpunittestsblocksregisterphp">trunk/tests/phpunit/tests/blocks/register.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>trunk/tests/phpunit/tests/blocks/fixtures/</li>
<li><a href="#trunktestsphpunittestsblocksfixturesblockassetphp">trunk/tests/phpunit/tests/blocks/fixtures/block.asset.php</a></li>
<li><a href="#trunktestsphpunittestsblocksfixturesblockcss">trunk/tests/phpunit/tests/blocks/fixtures/block.css</a></li>
<li><a href="#trunktestsphpunittestsblocksfixturesblockjs">trunk/tests/phpunit/tests/blocks/fixtures/block.js</a></li>
<li><a href="#trunktestsphpunittestsblocksfixturesblockjson">trunk/tests/phpunit/tests/blocks/fixtures/block.json</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesblocksphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/blocks.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/blocks.php  2020-06-23 13:51:03 UTC (rev 48140)
+++ trunk/src/wp-includes/blocks.php    2020-06-23 15:43:19 UTC (rev 48141)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -41,6 +41,217 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Removes the block asset's path prefix if provided.
+ *
+ * @since 5.5.0
+ *
+ * @param string $asset_handle_or_path Asset handle or prefixed path.
+ * @return string Path without the prefix or the original value.
+ */
+function remove_block_asset_path_prefix( $asset_handle_or_path ) {
+       $path_prefix = 'file:';
+       if ( 0 !== strpos( $asset_handle_or_path, $path_prefix ) ) {
+               return $asset_handle_or_path;
+       }
+       return substr(
+               $asset_handle_or_path,
+               strlen( $path_prefix )
+       );
+}
+
+/**
+ * Generates the name for an asset based on the name of the block
+ * and the field name provided.
+ *
+ * @since 5.5.0
+ *
+ * @param string $block_name Name of the block.
+ * @param string $field_name Name of the metadata field.
+ * @return string Generated asset name for the block's field.
+ */
+function generate_block_asset_handle( $block_name, $field_name ) {
+       $field_mappings = array(
+               'editorScript' => 'editor-script',
+               'script'       => 'script',
+               'editorStyle'  => 'editor-style',
+               'style'        => 'style',
+       );
+       return str_replace( '/', '-', $block_name ) .
+               '-' . $field_mappings[ $field_name ];
+}
+
+/**
+ * Finds a script handle for the selected block metadata field. It detects
+ * when a path to file was provided and finds a corresponding
+ * asset file with details necessary to register the script under
+ * automatically generated handle name. It returns unprocessed script handle
+ * otherwise.
+ *
+ * @since 5.5.0
+ *
+ * @param array  $metadata   Block metadata.
+ * @param string $field_name Field name to pick from metadata.
+ * @return string|bool Script handle provided directly or created through
+ *                     script's registration, or false on failure.
+ */
+function register_block_script_handle( $metadata, $field_name ) {
+       if ( empty( $metadata[ $field_name ] ) ) {
+               return false;
+       }
+       $script_handle = $metadata[ $field_name ];
+       $script_path   = remove_block_asset_path_prefix( $metadata[ $field_name ] );
+       if ( $script_handle === $script_path ) {
+               return $script_handle;
+       }
+
+       $script_handle     = generate_block_asset_handle( $metadata['name'], $field_name );
+       $script_asset_path = realpath(
+               dirname( $metadata['file'] ) . '/' .
+               substr_replace( $script_path, '.asset.php', - strlen( '.js' ) )
+       );
+       if ( ! file_exists( $script_asset_path ) ) {
+               $message = sprintf(
+                       /* translators: %1: field name. %2: block name */
+                       __( 'The asset file for the "%1$s" defined in "%2$s" block definition is missing.', 'default' ),
+                       $field_name,
+                       $metadata['name']
+               );
+               _doing_it_wrong( __FUNCTION__, $message, '5.5.0' );
+               return false;
+       }
+       $script_asset = require $script_asset_path;
+       $result       = wp_register_script(
+               $script_handle,
+               plugins_url( $script_path, $metadata['file'] ),
+               $script_asset['dependencies'],
+               $script_asset['version']
+       );
+       return $result ? $script_handle : false;
+}
+
+/**
+ * Finds a style handle for the block metadata field. It detects when a path
+ * to file was provided and registers the style under automatically
+ * generated handle name. It returns unprocessed style handle otherwise.
+ *
+ * @since 5.5.0
+ *
+ * @param array  $metadata Block metadata.
+ * @param string $field_name Field name to pick from metadata.
+ * @return string|boolean Style handle provided directly or created through
+ *                        style's registration, or false on failure.
+ */
+function register_block_style_handle( $metadata, $field_name ) {
+       if ( empty( $metadata[ $field_name ] ) ) {
+               return false;
+       }
+       $style_handle = $metadata[ $field_name ];
+       $style_path   = remove_block_asset_path_prefix( $metadata[ $field_name ] );
+       if ( $style_handle === $style_path ) {
+               return $style_handle;
+       }
+
+       $style_handle = generate_block_asset_handle( $metadata['name'], $field_name );
+       $block_dir    = dirname( $metadata['file'] );
+       $result       = wp_register_style(
+               $style_handle,
+               plugins_url( $style_path, $metadata['file'] ),
+               array(),
+               filemtime( realpath( "$block_dir/$style_path" ) )
+       );
+       return $result ? $style_handle : false;
+}
+
+/**
+ * Registers a block type from metadata stored in the `block.json` file.
+ *
+ * @since 5.5.0
+ *
+ * @param string $file_or_folder Path to the JSON file with metadata definition for
+ *                               the block or path to the folder where the `block.json` file is located.
+ * @param array  $args {
+ *     Optional. Array of block type arguments. Any arguments may be defined, however the
+ *     ones described below are supported by default. Default empty array.
+ *
+ *     @type callable $render_callback Callback used to render blocks of this block type.
+ * }
+ * @return WP_Block_Type|false The registered block type on success, or false on failure.
+ */
+function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
+       $filename      = 'block.json';
+       $metadata_file = ( substr( $file_or_folder, -strlen( $filename ) ) !== $filename ) ?
+               trailingslashit( $file_or_folder ) . $filename :
+               $file_or_folder;
+       if ( ! file_exists( $metadata_file ) ) {
+               return false;
+       }
+
+       $metadata = json_decode( file_get_contents( $metadata_file ), true );
+       if ( ! is_array( $metadata ) || empty( $metadata['name'] ) ) {
+               return false;
+       }
+       $metadata['file'] = $metadata_file;
+
+       $settings          = array();
+       $property_mappings = array(
+               'title'           => 'title',
+               'category'        => 'category',
+               'parent'          => 'parent',
+               'icon'            => 'icon',
+               'description'     => 'description',
+               'keywords'        => 'keywords',
+               'attributes'      => 'attributes',
+               'providesContext' => 'provides_context',
+               'usesContext'     => 'uses_context',
+               'supports'        => 'supports',
+               'styles'          => 'styles',
+               'example'         => 'example',
+       );
+
+       foreach ( $property_mappings as $key => $mapped_key ) {
+               if ( isset( $metadata[ $key ] ) ) {
+                       $settings[ $mapped_key ] = $metadata[ $key ];
+               }
+       }
+
+       if ( ! empty( $metadata['editorScript'] ) ) {
+               $settings['editor_script'] = register_block_script_handle(
+                       $metadata,
+                       'editorScript'
+               );
+       }
+
+       if ( ! empty( $metadata['script'] ) ) {
+               $settings['script'] = register_block_script_handle(
+                       $metadata,
+                       'script'
+               );
+       }
+
+       if ( ! empty( $metadata['editorStyle'] ) ) {
+               $settings['editor_style'] = register_block_style_handle(
+                       $metadata,
+                       'editorStyle'
+               );
+       }
+
+       if ( ! empty( $metadata['style'] ) ) {
+               $settings['style'] = register_block_style_handle(
+                       $metadata,
+                       'style'
+               );
+       }
+
+       return register_block_type(
+               $metadata['name'],
+               array_merge(
+                       $settings,
+                       $args
+               )
+       );
+}
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Determine whether a post or content string has blocks.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * This test optimizes for performance rather than strict accuracy, detecting
</span></span></pre></div>
<a id="trunktestsphpunittestsblocksfixturesblockassetphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/blocks/fixtures/block.asset.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/blocks/fixtures/block.asset.php                         (rev 0)
+++ trunk/tests/phpunit/tests/blocks/fixtures/block.asset.php   2020-06-23 15:43:19 UTC (rev 48141)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,6 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+return array(
+       'dependencies' => array(),
+       'version'      => 'test',
+);
</ins></span></pre></div>
<a id="trunktestsphpunittestsblocksfixturesblockcss"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/blocks/fixtures/block.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/blocks/fixtures/block.css                               (rev 0)
+++ trunk/tests/phpunit/tests/blocks/fixtures/block.css 2020-06-23 15:43:19 UTC (rev 48141)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/* Test CSS file */
</ins></span></pre></div>
<a id="trunktestsphpunittestsblocksfixturesblockjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/blocks/fixtures/block.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/blocks/fixtures/block.js                                (rev 0)
+++ trunk/tests/phpunit/tests/blocks/fixtures/block.js  2020-06-23 15:43:19 UTC (rev 48141)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/* Test JavaScript file. */
</ins></span></pre></div>
<a id="trunktestsphpunittestsblocksfixturesblockjson"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/blocks/fixtures/block.json</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/blocks/fixtures/block.json                              (rev 0)
+++ trunk/tests/phpunit/tests/blocks/fixtures/block.json        2020-06-23 15:43:19 UTC (rev 48141)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,52 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+{
+       "name": "my-plugin/notice",
+       "title": "Notice",
+       "category": "common",
+       "parent": [
+               "core/group"
+       ],
+       "providesContext": {
+               "my-plugin/message": "message"
+       },
+       "usesContext": [
+               "groupId"
+       ],
+       "icon": "star",
+       "description": "Shows warning, error or success notices…",
+       "keywords": [
+               "alert",
+               "message"
+       ],
+       "textDomain": "my-plugin",
+       "attributes": {
+               "message": {
+                       "type": "string",
+                       "source": "html",
+                       "selector": ".message"
+               }
+       },
+       "supports": {
+               "align": true,
+               "lightBlockWrapper": true
+       },
+       "styles": [
+               {
+                       "name": "default",
+                       "label": "Default",
+                       "isDefault": true
+               },
+               {
+                       "name": "other",
+                       "label": "Other"
+               }
+       ],
+       "example": {
+               "attributes": {
+                       "message": "This is a notice!"
+               }
+       },
+       "editorScript": "my-plugin-notice-editor-script",
+       "script": "my-plugin-notice-script",
+       "editorStyle": "my-plugin-notice-editor-style",
+       "style": "my-plugin-notice-style"
+}
</ins></span></pre></div>
<a id="trunktestsphpunittestsblocksregisterphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/blocks/register.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/blocks/register.php     2020-06-23 13:51:03 UTC (rev 48140)
+++ trunk/tests/phpunit/tests/blocks/register.php       2020-06-23 15:43:19 UTC (rev 48141)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -103,6 +103,248 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @ticket 50263
+        */
+       function test_does_not_remove_block_asset_path_prefix() {
+               $result = remove_block_asset_path_prefix( 'script-handle' );
+
+               $this->assertSame( 'script-handle', $result );
+       }
+
+       /**
+        * @ticket 50263
+        */
+       function test_removes_block_asset_path_prefix() {
+               $result = remove_block_asset_path_prefix( 'file:./block.js' );
+
+               $this->assertSame( './block.js', $result );
+       }
+
+       /**
+        * @ticket 50263
+        */
+       function test_generate_block_asset_handle() {
+               $block_name = 'unit-tests/my-block';
+
+               $this->assertSame(
+                       'unit-tests-my-block-editor-script',
+                       generate_block_asset_handle( $block_name, 'editorScript' )
+               );
+               $this->assertSame(
+                       'unit-tests-my-block-script',
+                       generate_block_asset_handle( $block_name, 'script' )
+               );
+               $this->assertSame(
+                       'unit-tests-my-block-editor-style',
+                       generate_block_asset_handle( $block_name, 'editorStyle' )
+               );
+               $this->assertSame(
+                       'unit-tests-my-block-style',
+                       generate_block_asset_handle( $block_name, 'style' )
+               );
+       }
+
+       /**
+        * @ticket 50263
+        */
+       function test_field_not_found_register_block_script_handle() {
+               $result = register_block_script_handle( array(), 'script' );
+
+               $this->assertFalse( $result );
+       }
+
+       /**
+        * @ticket 50263
+        */
+       function test_empty_value_register_block_script_handle() {
+               $metadata = array( 'script' => '' );
+               $result   = register_block_script_handle( $metadata, 'script' );
+
+               $this->assertFalse( $result );
+       }
+
+       /**
+        * @expectedIncorrectUsage register_block_script_handle
+        * @ticket 50263
+        */
+       function test_missing_asset_file_register_block_script_handle() {
+               $metadata = array(
+                       'file'   => __FILE__,
+                       'name'   => 'unit-tests/test-block',
+                       'script' => 'file:./fixtures/missing-asset.js',
+               );
+               $result   = register_block_script_handle( $metadata, 'script' );
+
+               $this->assertFalse( $result );
+       }
+
+       /**
+        * @ticket 50263
+        */
+       function test_handle_passed_register_block_script_handle() {
+               $metadata = array(
+                       'editorScript' => 'test-script-handle',
+               );
+               $result   = register_block_script_handle( $metadata, 'editorScript' );
+
+               $this->assertSame( 'test-script-handle', $result );
+       }
+
+       /**
+        * @ticket 50263
+        */
+       function test_success_register_block_script_handle() {
+               $metadata = array(
+                       'file'   => __FILE__,
+                       'name'   => 'unit-tests/test-block',
+                       'script' => 'file:./fixtures/block.js',
+               );
+               $result   = register_block_script_handle( $metadata, 'script' );
+
+               $this->assertSame( 'unit-tests-test-block-script', $result );
+       }
+
+       /**
+        * @ticket 50263
+        */
+       function test_field_not_found_register_block_style_handle() {
+               $result = register_block_style_handle( array(), 'style' );
+
+               $this->assertFalse( $result );
+       }
+
+       /**
+        * @ticket 50263
+        */
+       function test_empty_value_found_register_block_style_handle() {
+               $metadata = array( 'style' => '' );
+               $result   = register_block_style_handle( $metadata, 'style' );
+
+               $this->assertFalse( $result );
+       }
+
+       /**
+        * @ticket 50263
+        */
+       function test_handle_passed_register_block_style_handle() {
+               $metadata = array(
+                       'style' => 'test-style-handle',
+               );
+               $result   = register_block_style_handle( $metadata, 'style' );
+
+               $this->assertSame( 'test-style-handle', $result );
+       }
+
+       /**
+        * @ticket 50263
+        */
+       function test_success_register_block_style_handle() {
+               $metadata = array(
+                       'file'  => __FILE__,
+                       'name'  => 'unit-tests/test-block',
+                       'style' => 'file:./fixtures/block.css',
+               );
+               $result   = register_block_style_handle( $metadata, 'style' );
+
+               $this->assertSame( 'unit-tests-test-block-style', $result );
+       }
+
+       /**
+        * Tests that the function returns false when the `block.json` is not found
+        * in the WordPress core.
+        *
+        * @ticket 50263
+        */
+       function test_metadata_not_found_in_wordpress_core() {
+               $result = register_block_type_from_metadata( 'unknown' );
+
+               $this->assertFalse( $result );
+       }
+
+       /**
+        * Tests that the function returns false when the `block.json` is not found
+        * in the current directory.
+        *
+        * @ticket 50263
+        */
+       function test_metadata_not_found_in_the_current_directory() {
+               $result = register_block_type_from_metadata( __DIR__ );
+
+               $this->assertFalse( $result );
+       }
+
+       /**
+        * Tests that the function returns the registered block when the `block.json`
+        * is found in the fixtures directory.
+        *
+        * @ticket 50263
+        */
+       function test_block_registers_with_metadata_fixture() {
+               $result = register_block_type_from_metadata(
+                       __DIR__ . '/fixtures'
+               );
+
+               $this->assertInstanceOf( 'WP_Block_Type', $result );
+               $this->assertSame( 'my-plugin/notice', $result->name );
+               $this->assertSame( 'Notice', $result->title );
+               $this->assertSame( 'common', $result->category );
+               $this->assertEqualSets( array( 'core/group' ), $result->parent );
+               $this->assertSame( 'star', $result->icon );
+               $this->assertSame( 'Shows warning, error or success notices…', $result->description );
+               $this->assertEqualSets( array( 'alert', 'message' ), $result->keywords );
+               $this->assertEquals(
+                       array(
+                               'message' => array(
+                                       'type'     => 'string',
+                                       'source'   => 'html',
+                                       'selector' => '.message',
+                               ),
+                       ),
+                       $result->attributes
+               );
+               $this->assertEquals(
+                       array(
+                               'my-plugin/message' => 'message',
+                       ),
+                       $result->provides_context
+               );
+               $this->assertEqualSets( array( 'groupId' ), $result->uses_context );
+               $this->assertEquals(
+                       array(
+                               'align'             => true,
+                               'lightBlockWrapper' => true,
+                       ),
+                       $result->supports
+               );
+               $this->assertEquals(
+                       array(
+                               array(
+                                       'name'      => 'default',
+                                       'label'     => 'Default',
+                                       'isDefault' => true,
+                               ),
+                               array(
+                                       'name'  => 'other',
+                                       'label' => 'Other',
+                               ),
+                       ),
+                       $result->styles
+               );
+               $this->assertEquals(
+                       array(
+                               'attributes' => array(
+                                       'message' => 'This is a notice!',
+                               ),
+                       ),
+                       $result->example
+               );
+               $this->assertSame( 'my-plugin-notice-editor-script', $result->editor_script );
+               $this->assertSame( 'my-plugin-notice-script', $result->script );
+               $this->assertSame( 'my-plugin-notice-editor-style', $result->editor_style );
+               $this->assertSame( 'my-plugin-notice-style', $result->style );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * @ticket 45109
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        function test_get_dynamic_block_names() {
</span></span></pre>
</div>
</div>

</body>
</html>