Skip to content

Commit 6a7c802

Browse files
committed
Allow PHP-Only Block Registration
1 parent 6710308 commit 6a7c802

File tree

5 files changed

+210
-3
lines changed

5 files changed

+210
-3
lines changed

src/wp-includes/block-editor.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -497,10 +497,16 @@ function get_block_editor_settings( array $custom_settings, $block_editor_contex
497497
);
498498

499499
$editor_settings['__experimentalBlockBindingsSupportedAttributes'] = array();
500-
foreach ( array_keys( WP_Block_Type_Registry::get_instance()->get_all_registered() ) as $block_type ) {
501-
$supported_block_attributes = get_block_bindings_supported_attributes( $block_type );
500+
$editor_settings['autoRegisterBlocks'] = array();
501+
$registered_blocks = WP_Block_Type_Registry::get_instance()->get_all_registered();
502+
503+
foreach ( $registered_blocks as $block_name => $block_type ) {
504+
$supported_block_attributes = get_block_bindings_supported_attributes( $block_name );
502505
if ( ! empty( $supported_block_attributes ) ) {
503-
$editor_settings['__experimentalBlockBindingsSupportedAttributes'][ $block_type ] = $supported_block_attributes;
506+
$editor_settings['__experimentalBlockBindingsSupportedAttributes'][ $block_name ] = $supported_block_attributes;
507+
}
508+
if ( ! empty( $block_type->supports['auto_register'] ) && ! empty( $block_type->render_callback ) ) {
509+
$editor_settings['autoRegisterBlocks'][] = $block_name;
504510
}
505511
}
506512

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
/**
3+
* Auto-register block support.
4+
*
5+
* @package WordPress
6+
* @since 7.0.0
7+
*/
8+
9+
/**
10+
* Mark user-defined attributes for auto-generated inspector controls.
11+
*
12+
* This filter runs during block type registration, before the WP_Block_Type
13+
* is instantiated. Block supports add their attributes AFTER the block type
14+
* is created (via WP_Block_Supports::register_attributes()), so any attributes
15+
* present at this stage are user-defined.
16+
*
17+
* The marker tells generateFieldsFromAttributes() which attributes should
18+
* get auto-generated inspector controls. Attributes are excluded if they:
19+
* - Have a 'source' (HTML-derived, edited inline not via inspector)
20+
* - Have role 'local' (internal state, not user-configurable)
21+
* - Were added by block supports (added after this filter runs)
22+
*
23+
* @since 7.0.0
24+
* @access private
25+
*
26+
* @param array $args Array of arguments for registering a block type.
27+
* @param string $block_type Block type name including namespace.
28+
* @return array Modified block type arguments.
29+
*/
30+
function wp_mark_auto_generate_control_attributes( array $args, string $block_type ): array {
31+
if ( empty( $args['attributes'] ) || ! is_array( $args['attributes'] ) ) {
32+
return $args;
33+
}
34+
35+
$has_auto_register = ! empty( $args['supports']['auto_register'] );
36+
if ( ! $has_auto_register ) {
37+
return $args;
38+
}
39+
40+
foreach ( $args['attributes'] as $name => $def ) {
41+
// Skip HTML-derived attributes (edited inline, not via inspector).
42+
if ( ! empty( $def['source'] ) ) {
43+
continue;
44+
}
45+
// Skip internal attributes (not user-configurable).
46+
if ( isset( $def['role'] ) && 'local' === $def['role'] ) {
47+
continue;
48+
}
49+
$args['attributes'][ $name ]['autoGenerateControl'] = true;
50+
}
51+
52+
return $args;
53+
}
54+
55+
// Priority 5 to mark original attributes before other filters (priority 10+) might add their own.
56+
add_filter( 'register_block_type_args', 'wp_mark_auto_generate_control_attributes', 5, 2 );

src/wp-settings.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@
410410
require ABSPATH . WPINC . '/block-supports/background.php';
411411
require ABSPATH . WPINC . '/block-supports/block-style-variations.php';
412412
require ABSPATH . WPINC . '/block-supports/aria-label.php';
413+
require ABSPATH . WPINC . '/block-supports/auto-register.php';
413414
require ABSPATH . WPINC . '/block-supports/anchor.php';
414415
require ABSPATH . WPINC . '/block-supports/block-visibility.php';
415416
require ABSPATH . WPINC . '/style-engine.php';
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
/**
3+
* @group block-supports
4+
*
5+
* @covers ::wp_mark_auto_generate_control_attributes
6+
*/
7+
class Tests_Block_Supports_Auto_Register extends WP_UnitTestCase {
8+
9+
/**
10+
* Tests that attributes are marked when auto_register is enabled.
11+
*
12+
* @ticket 64639
13+
*/
14+
public function test_marks_attributes_with_auto_register_flag() {
15+
$settings = array(
16+
'supports' => array( 'auto_register' => true ),
17+
'attributes' => array(
18+
'title' => array( 'type' => 'string' ),
19+
'count' => array( 'type' => 'integer' ),
20+
),
21+
);
22+
23+
$result = wp_mark_auto_generate_control_attributes( $settings, 'test/block' );
24+
25+
$this->assertTrue( $result['attributes']['title']['autoGenerateControl'] );
26+
$this->assertTrue( $result['attributes']['count']['autoGenerateControl'] );
27+
}
28+
29+
/**
30+
* Tests that attributes are not marked without auto_register flag.
31+
*
32+
* @ticket 64639
33+
*/
34+
public function test_does_not_mark_attributes_without_auto_register() {
35+
$settings = array(
36+
'attributes' => array(
37+
'title' => array( 'type' => 'string' ),
38+
),
39+
);
40+
41+
$result = wp_mark_auto_generate_control_attributes( $settings, 'test/block' );
42+
43+
$this->assertArrayNotHasKey( 'autoGenerateControl', $result['attributes']['title'] );
44+
}
45+
46+
/**
47+
* Tests that attributes with source are excluded.
48+
*
49+
* @ticket 64639
50+
*/
51+
public function test_excludes_attributes_with_source() {
52+
$settings = array(
53+
'supports' => array( 'auto_register' => true ),
54+
'attributes' => array(
55+
'title' => array( 'type' => 'string' ),
56+
'content' => array(
57+
'type' => 'string',
58+
'source' => 'html',
59+
),
60+
),
61+
);
62+
63+
$result = wp_mark_auto_generate_control_attributes( $settings, 'test/block' );
64+
65+
$this->assertTrue( $result['attributes']['title']['autoGenerateControl'] );
66+
$this->assertArrayNotHasKey( 'autoGenerateControl', $result['attributes']['content'] );
67+
}
68+
69+
/**
70+
* Tests that attributes with role: local are excluded.
71+
*
72+
* Example: The 'blob' attribute in media blocks (image, video, file, audio)
73+
* stores a temporary blob URL during file upload. This is internal state
74+
* that shouldn't be shown in the inspector or saved to the database.
75+
*
76+
* @ticket 64639
77+
*/
78+
public function test_excludes_attributes_with_role_local() {
79+
$settings = array(
80+
'supports' => array( 'auto_register' => true ),
81+
'attributes' => array(
82+
'title' => array( 'type' => 'string' ),
83+
'blob' => array(
84+
'type' => 'string',
85+
'role' => 'local',
86+
),
87+
),
88+
);
89+
90+
$result = wp_mark_auto_generate_control_attributes( $settings, 'test/block' );
91+
92+
$this->assertTrue( $result['attributes']['title']['autoGenerateControl'] );
93+
$this->assertArrayNotHasKey( 'autoGenerateControl', $result['attributes']['blob'] );
94+
}
95+
96+
/**
97+
* Tests that empty attributes are handled gracefully.
98+
*/
99+
public function test_handles_empty_attributes() {
100+
$settings = array(
101+
'supports' => array( 'auto_register' => true ),
102+
);
103+
104+
$result = wp_mark_auto_generate_control_attributes( $settings, 'test/block' );
105+
106+
$this->assertSame( $settings, $result );
107+
}
108+
}

tests/phpunit/tests/blocks/editor.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,42 @@ public function test_get_classic_theme_supports_block_editor_settings() {
709709
);
710710
}
711711

712+
/**
713+
* @ticket 64639
714+
*/
715+
public function test_get_block_editor_settings_auto_register_blocks() {
716+
$block_default = 'test/default';
717+
$block_with_render = 'test/auto-register-with-render';
718+
$block_without_render = 'test/auto-register-without-render';
719+
720+
register_block_type(
721+
$block_default,
722+
array()
723+
);
724+
register_block_type(
725+
$block_with_render,
726+
array(
727+
'supports' => array( 'auto_register' => true ),
728+
'render_callback' => '__return_empty_string',
729+
)
730+
);
731+
register_block_type(
732+
$block_without_render,
733+
array(
734+
'supports' => array( 'auto_register' => true ),
735+
)
736+
);
737+
738+
$post_editor_context = new WP_Block_Editor_Context( array( 'post' => get_post() ) );
739+
$settings = get_block_editor_settings( array(), $post_editor_context );
740+
741+
unregister_block_type( $block_default );
742+
unregister_block_type( $block_with_render );
743+
unregister_block_type( $block_without_render );
744+
745+
$this->assertSame( array( $block_with_render ), $settings['autoRegisterBlocks'] );
746+
}
747+
712748
/**
713749
* Data provider.
714750
*

0 commit comments

Comments
 (0)