Skip to content

Commit cc2133f

Browse files
Blocks: Parse the arguments earlier in register_block_type_from_metadata().
This makes it possible to register a block by passing an array of arguments, without the presence of a `block.json` file. Follow-up to [48141], [49948]. Props aristath, spacedmonkey, mukesh27, costdev, audrasjb, oglekler, felipeelia, hellofromTonya. Fixes #56865. git-svn-id: https://develop.svn.wordpress.org/trunk@57026 602fd350-edb4-49c9-b593-d223f7449a82
1 parent d571da5 commit cc2133f

2 files changed

Lines changed: 168 additions & 42 deletions

File tree

src/wp-includes/blocks.php

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -352,13 +352,14 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
352352
$file_or_folder;
353353

354354
$is_core_block = str_starts_with( $file_or_folder, ABSPATH . WPINC );
355-
356-
if ( ! $is_core_block && ! file_exists( $metadata_file ) ) {
355+
// If the block is not a core block, the metadata file must exist.
356+
$metadata_file_exists = $is_core_block || file_exists( $metadata_file );
357+
if ( ! $metadata_file_exists && empty( $args['name'] ) ) {
357358
return false;
358359
}
359360

360361
// Try to get metadata from the static cache for core blocks.
361-
$metadata = false;
362+
$metadata = array();
362363
if ( $is_core_block ) {
363364
$core_block_name = str_replace( ABSPATH . WPINC . '/blocks/', '', $file_or_folder );
364365
if ( ! empty( $core_blocks_meta[ $core_block_name ] ) ) {
@@ -367,14 +368,15 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
367368
}
368369

369370
// If metadata is not found in the static cache, read it from the file.
370-
if ( ! $metadata ) {
371+
if ( $metadata_file_exists && empty( $metadata ) ) {
371372
$metadata = wp_json_file_decode( $metadata_file, array( 'associative' => true ) );
372373
}
373374

374-
if ( ! is_array( $metadata ) || empty( $metadata['name'] ) ) {
375+
if ( ! is_array( $metadata ) || ( empty( $metadata['name'] ) && empty( $args['name'] ) ) ) {
375376
return false;
376377
}
377-
$metadata['file'] = wp_normalize_path( realpath( $metadata_file ) );
378+
379+
$metadata['file'] = $metadata_file_exists ? wp_normalize_path( realpath( $metadata_file ) ) : null;
378380

379381
/**
380382
* Filters the metadata provided for registering a block type.
@@ -404,6 +406,7 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
404406
$settings = array();
405407
$property_mappings = array(
406408
'apiVersion' => 'api_version',
409+
'name' => 'name',
407410
'title' => 'title',
408411
'category' => 'category',
409412
'parent' => 'parent',
@@ -426,18 +429,50 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
426429
foreach ( $property_mappings as $key => $mapped_key ) {
427430
if ( isset( $metadata[ $key ] ) ) {
428431
$settings[ $mapped_key ] = $metadata[ $key ];
429-
if ( $textdomain && isset( $i18n_schema->$key ) ) {
432+
if ( $metadata_file_exists && $textdomain && isset( $i18n_schema->$key ) ) {
430433
$settings[ $mapped_key ] = translate_settings_using_i18n_schema( $i18n_schema->$key, $settings[ $key ], $textdomain );
431434
}
432435
}
433436
}
434437

438+
if ( ! empty( $metadata['render'] ) ) {
439+
$template_path = wp_normalize_path(
440+
realpath(
441+
dirname( $metadata['file'] ) . '/' .
442+
remove_block_asset_path_prefix( $metadata['render'] )
443+
)
444+
);
445+
if ( $template_path ) {
446+
/**
447+
* Renders the block on the server.
448+
*
449+
* @since 6.1.0
450+
*
451+
* @param array $attributes Block attributes.
452+
* @param string $content Block default content.
453+
* @param WP_Block $block Block instance.
454+
*
455+
* @return string Returns the block content.
456+
*/
457+
$settings['render_callback'] = static function ( $attributes, $content, $block ) use ( $template_path ) {
458+
ob_start();
459+
require $template_path;
460+
return ob_get_clean();
461+
};
462+
}
463+
}
464+
465+
$settings = array_merge( $settings, $args );
466+
435467
$script_fields = array(
436468
'editorScript' => 'editor_script_handles',
437469
'script' => 'script_handles',
438470
'viewScript' => 'view_script_handles',
439471
);
440472
foreach ( $script_fields as $metadata_field_name => $settings_field_name ) {
473+
if ( ! empty( $settings[ $metadata_field_name ] ) ) {
474+
$metadata[ $metadata_field_name ] = $settings[ $metadata_field_name ];
475+
}
441476
if ( ! empty( $metadata[ $metadata_field_name ] ) ) {
442477
$scripts = $metadata[ $metadata_field_name ];
443478
$processed_scripts = array();
@@ -470,6 +505,9 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
470505
'style' => 'style_handles',
471506
);
472507
foreach ( $style_fields as $metadata_field_name => $settings_field_name ) {
508+
if ( ! empty( $settings[ $metadata_field_name ] ) ) {
509+
$metadata[ $metadata_field_name ] = $settings[ $metadata_field_name ];
510+
}
473511
if ( ! empty( $metadata[ $metadata_field_name ] ) ) {
474512
$styles = $metadata[ $metadata_field_name ];
475513
$processed_styles = array();
@@ -530,33 +568,6 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
530568
}
531569
}
532570

533-
if ( ! empty( $metadata['render'] ) ) {
534-
$template_path = wp_normalize_path(
535-
realpath(
536-
dirname( $metadata['file'] ) . '/' .
537-
remove_block_asset_path_prefix( $metadata['render'] )
538-
)
539-
);
540-
if ( $template_path ) {
541-
/**
542-
* Renders the block on the server.
543-
*
544-
* @since 6.1.0
545-
*
546-
* @param array $attributes Block attributes.
547-
* @param string $content Block default content.
548-
* @param WP_Block $block Block instance.
549-
*
550-
* @return string Returns the block content.
551-
*/
552-
$settings['render_callback'] = static function ( $attributes, $content, $block ) use ( $template_path ) {
553-
ob_start();
554-
require $template_path;
555-
return ob_get_clean();
556-
};
557-
}
558-
}
559-
560571
/**
561572
* Filters the settings determined from the block type metadata.
562573
*
@@ -565,14 +576,9 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
565576
* @param array $settings Array of determined settings for registering a block type.
566577
* @param array $metadata Metadata provided for registering a block type.
567578
*/
568-
$settings = apply_filters(
569-
'block_type_metadata_settings',
570-
array_merge(
571-
$settings,
572-
$args
573-
),
574-
$metadata
575-
);
579+
$settings = apply_filters( 'block_type_metadata_settings', $settings, $metadata );
580+
581+
$metadata['name'] = ! empty( $settings['name'] ) ? $settings['name'] : $metadata['name'];
576582

577583
return WP_Block_Type_Registry::get_instance()->register(
578584
$metadata['name'],

tests/phpunit/tests/blocks/register.php

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,126 @@ public function test_metadata_not_found_in_the_current_directory() {
599599
$this->assertFalse( $result );
600600
}
601601

602+
/**
603+
* Tests registering a block using arguments instead of a block.json file.
604+
*
605+
* @ticket 56865
606+
*
607+
* @covers ::register_block_type_from_metadata
608+
*/
609+
public function test_register_block_type_from_metadata_with_arguments() {
610+
$result = register_block_type_from_metadata(
611+
'',
612+
array(
613+
'api_version' => 2,
614+
'name' => 'tests/notice-from-array',
615+
'title' => 'Notice from array',
616+
'category' => 'common',
617+
'icon' => 'star',
618+
'description' => 'Shows warning, error or success notices… (registered from an array)',
619+
'keywords' => array(
620+
'alert',
621+
'message',
622+
),
623+
'textdomain' => 'notice-from-array',
624+
)
625+
);
626+
627+
$this->assertInstanceOf( 'WP_Block_Type', $result, 'The block was not registered' );
628+
$this->assertSame( 2, $result->api_version, 'The API version is incorrect' );
629+
$this->assertSame( 'tests/notice-from-array', $result->name, 'The block name is incorrect' );
630+
$this->assertSame( 'Notice from array', $result->title, 'The block title is incorrect' );
631+
$this->assertSame( 'common', $result->category, 'The block category is incorrect' );
632+
$this->assertSame( 'star', $result->icon, 'The block icon is incorrect' );
633+
$this->assertSame(
634+
'Shows warning, error or success notices… (registered from an array)',
635+
$result->description,
636+
'The block description is incorrect'
637+
);
638+
$this->assertSameSets( array( 'alert', 'message' ), $result->keywords, 'The block keywords are incorrect' );
639+
}
640+
641+
/**
642+
* Tests that defined $args can properly override the block.json file.
643+
*
644+
* @ticket 56865
645+
*
646+
* @covers ::register_block_type_from_metadata
647+
*/
648+
public function test_block_registers_with_args_override() {
649+
$result = register_block_type_from_metadata(
650+
DIR_TESTDATA . '/blocks/notice',
651+
array(
652+
'name' => 'tests/notice-with-overrides',
653+
'title' => 'Overriden title',
654+
'style' => array( 'tests-notice-style-overridden' ),
655+
)
656+
);
657+
658+
$this->assertInstanceOf( 'WP_Block_Type', $result, 'The block was not registered' );
659+
$this->assertSame( 2, $result->api_version, 'The API version is incorrect' );
660+
$this->assertSame( 'tests/notice-with-overrides', $result->name, 'The block name was not overridden' );
661+
$this->assertSame( 'Overriden title', $result->title, 'The block title was not overridden' );
662+
$this->assertSameSets(
663+
array( 'tests-notice-editor-script' ),
664+
$result->editor_script_handles,
665+
'The block editor script is incorrect'
666+
);
667+
$this->assertSameSets(
668+
array( 'tests-notice-style-overridden' ),
669+
$result->style_handles,
670+
'The block style was not overridden'
671+
);
672+
$this->assertIsCallable( $result->render_callback );
673+
}
674+
675+
/**
676+
* Tests that when the `name` is missing, `register_block_type_from_metadata()`
677+
* will return `false`.
678+
*
679+
* @ticket 56865
680+
*
681+
* @covers ::register_block_type_from_metadata
682+
*
683+
* @dataProvider data_register_block_registers_with_args_override_returns_false_when_name_is_missing
684+
*
685+
* @param string $file The metadata file.
686+
* @param array $args Array of block type arguments.
687+
*/
688+
public function test_block_registers_with_args_override_returns_false_when_name_is_missing( $file, $args ) {
689+
$this->assertFalse( register_block_type_from_metadata( $file, $args ) );
690+
}
691+
692+
/**
693+
* Data provider.
694+
*
695+
* @return array[]
696+
*/
697+
public function data_register_block_registers_with_args_override_returns_false_when_name_is_missing() {
698+
return array(
699+
'no block.json file and no name argument' => array(
700+
'file' => '', // No block.json file.
701+
'args' => array(
702+
'title' => 'Overriden title',
703+
'style' => array( 'tests-notice-style-overridden' ),
704+
),
705+
),
706+
'existing file and args not an array' => array(
707+
// A file that exists but is empty. This will bypass the file_exists() check.
708+
'file' => DIR_TESTDATA . '/blocks/notice/block.js',
709+
'args' => false,
710+
),
711+
'existing file and args[name] missing' => array(
712+
// A file that exists but is empty. This will bypass the file_exists() check.
713+
'file' => DIR_TESTDATA . '/blocks/notice/block.js',
714+
'args' => array(
715+
'title' => 'Overriden title',
716+
'style' => array( 'tests-notice-style-overridden' ),
717+
),
718+
),
719+
);
720+
}
721+
602722
/**
603723
* Tests that the function returns the registered block when the `block.json`
604724
* is found in the fixtures directory.

0 commit comments

Comments
 (0)