diff --git a/packages/block-library/src/paragraph/index.php b/packages/block-library/src/paragraph/index.php new file mode 100644 index 00000000000000..f72ca085a2048f --- /dev/null +++ b/packages/block-library/src/paragraph/index.php @@ -0,0 +1,48 @@ +Hello World
+ * + * Would be transformed to: + *Hello World
+ * + * @since 7.0.0 + * + * @param string $block_content The block content. + * + * @return string Filtered block content. + */ +function block_core_paragraph_add_class( $block_content ) { + if ( ! $block_content ) { + return $block_content; + } + + $processor = new WP_HTML_Tag_Processor( $block_content ); + + if ( $processor->next_tag( 'p' ) ) { + $processor->add_class( 'wp-block-paragraph' ); + } + + return $processor->get_updated_html(); +} + +add_filter( 'render_block_core/paragraph', 'block_core_paragraph_add_class' ); + +/** + * Registers the `core/paragraph` block on server. + * + * @since 7.0.0 + */ +function register_block_core_paragraph() { + register_block_type_from_metadata( __DIR__ . '/paragraph' ); +} +add_action( 'init', 'register_block_core_paragraph' ); diff --git a/phpunit/block-bindings-test.php b/phpunit/block-bindings-test.php index c122861158258b..9517c425bcd191 100644 --- a/phpunit/block-bindings-test.php +++ b/phpunit/block-bindings-test.php @@ -85,7 +85,7 @@ public function data_update_block_with_value_from_source() { HTML , - 'test source value
', + 'test source value
', ), 'button block' => array( 'text', @@ -162,19 +162,19 @@ function ( $source_args, $block_instance, $attribute_name ) { $value = $source_args['key']; return "The attribute name is '$attribute_name' and its binding has argument 'key' with value '$value'."; }, - "The attribute name is 'content' and its binding has argument 'key' with value 'test'.
", + "The attribute name is 'content' and its binding has argument 'key' with value 'test'.
", ), 'unsafe HTML should be sanitized' => array( function () { return ''; }, - 'alert("Unsafe HTML")
', + 'alert("Unsafe HTML")
', ), 'symbols and numbers should be rendered correctly' => array( function () { return '$12.50'; }, - '$12.50
', + '$12.50
', ), ); } @@ -386,7 +386,7 @@ public function test_filter_block_bindings_source_value() { remove_filter( 'block_bindings_source_value', $filter_value ); $this->assertSame( - 'Filtered value: test_arg. Block instance: core/paragraph. Attribute name: content.
', + 'Filtered value: test_arg. Block instance: core/paragraph. Attribute name: content.
', trim( $result ), 'The block content should show the filtered value.' ); diff --git a/phpunit/blocks/render-block-paragraph-test.php b/phpunit/blocks/render-block-paragraph-test.php new file mode 100644 index 00000000000000..c65b12901b71ab --- /dev/null +++ b/phpunit/blocks/render-block-paragraph-test.php @@ -0,0 +1,89 @@ +' . $input . '' ); + $block = new WP_Block( $parsed_blocks[0] ); + $actual = $block->render(); + $this->assertEquals( $expected_result, $actual ); + } + + public function data_css_class_examples() { + return array( + 'should add a class name to a vanilla p element' => array( + 'Hello World
', + 'Hello World
', + ), + 'should not add a class name to a div element' => array( + 'Hello World
', + 'Hello World
', + ), + 'should handle single quotes' => array( + "Hello World
", + 'Hello World
', + ), + 'should handle single quotes with double quotes inside' => array( + "Hello World
", + 'Hello World
', + ), + 'should not add a class name even when it is already defined' => array( + 'Hello World
', + 'Hello World
', + ), + 'should add a class name even when there are other HTML attributes present' => array( + 'Hello World
', + 'Hello World
', + ), + 'should add a class name even when the class attribute is already defined and has many entries' => array( + 'Hello World
', + 'Hello World
', + ), + 'should not add a class name to a nested p' => array( + 'Hello World
', + 'Hello World
', + ), + 'should not add a class name to a nested p when the parent has another attribute' => array( + 'Hello World
', + 'Hello World
', + ), + 'should add a class name even when the class attribute is surrounded by other attributes' => array( + 'Hello World
', + 'Hello World
', + ), + 'should add a class name without getting confused when there is a tricky data-class attribute present' => array( + 'Hello World
', + 'Hello World
', + ), + ); + } +} diff --git a/phpunit/blocks/renderReusable.php b/phpunit/blocks/renderReusable.php index 74c2bea127e363..91dbe37f774bc6 100644 --- a/phpunit/blocks/renderReusable.php +++ b/phpunit/blocks/renderReusable.php @@ -63,6 +63,6 @@ public function test_render_respects_custom_context() { ); $output = $synced_pattern_block_instance->render(); - $this->assertSame( 'Custom content set from block context
', $output ); + $this->assertSame( 'Custom content set from block context
', $output ); } } diff --git a/test/e2e/specs/editor/plugins/block-hooks.spec.js b/test/e2e/specs/editor/plugins/block-hooks.spec.js index b0dba8287cafad..971dc5d764fd70 100644 --- a/test/e2e/specs/editor/plugins/block-hooks.spec.js +++ b/test/e2e/specs/editor/plugins/block-hooks.spec.js @@ -10,7 +10,7 @@ const dummyBlocksContent = `This is a dummy paragraph.
`; const dummyClassicContent = - 'This is a dummy paragraph.
'; + 'This is a dummy paragraph.
'; const getHookedBlockClassName = ( relativePosition, anchorBlock ) => `hooked-block-${ relativePosition }-${ anchorBlock.replace( @@ -84,9 +84,11 @@ test.describe( 'Block Hooks API', () => { page.locator( '.entry-content > *' ) ).toHaveClass( [ 'wp-block-heading', - getHookedBlockClassName( 'after', 'core/heading' ), - 'dummy-paragraph', - getHookedBlockClassName( 'last_child', blockType ), + getHookedBlockClassName( 'after', 'core/heading' ) + + ' wp-block-paragraph', + 'dummy-paragraph wp-block-paragraph', + getHookedBlockClassName( 'last_child', blockType ) + + ' wp-block-paragraph', ] ); } ); @@ -158,9 +160,11 @@ test.describe( 'Block Hooks API', () => { page.locator( '.entry-content > *' ) ).toHaveClass( [ 'wp-block-heading', - getHookedBlockClassName( 'after', 'core/heading' ), - getHookedBlockClassName( 'last_child', blockType ), - 'dummy-paragraph', + getHookedBlockClassName( 'after', 'core/heading' ) + + ' wp-block-paragraph', + getHookedBlockClassName( 'last_child', blockType ) + + ' wp-block-paragraph', + 'dummy-paragraph wp-block-paragraph', ] ); } ); } ); @@ -212,9 +216,10 @@ test.describe( 'Block Hooks API', () => { await expect( page.locator( '.entry-content > *' ) ).toHaveClass( [ - 'dummy-heading', - 'dummy-paragraph', - getHookedBlockClassName( 'last_child', blockType ), + 'dummy-classic-heading', + 'dummy-classic-paragraph', + getHookedBlockClassName( 'last_child', blockType ) + + ' wp-block-paragraph', ] ); } ); @@ -271,9 +276,10 @@ test.describe( 'Block Hooks API', () => { await expect( page.locator( '.entry-content > *' ) ).toHaveClass( [ - getHookedBlockClassName( 'last_child', blockType ), - 'dummy-heading', - 'dummy-paragraph', + getHookedBlockClassName( 'last_child', blockType ) + + ' wp-block-paragraph', + 'dummy-classic-heading', + 'dummy-classic-paragraph', ] ); } ); } );