Skip to content

Commit 68519eb

Browse files
danielbachhuberpento
authored andcommitted
Maintain backwards compatible behaviour post_content (#8077)
When transforming classic content to a shortcode block, or having a post with a single freeform block in it, `post_content` ended up in a state that wasn't backward compatible. This change ensures that un-blockified posts can continue to be used in the Classic Editor as expected, and that the shortcode block both renders in Gutenberg correctly, and on the front end. Fixes #3900.
1 parent 1a0b22a commit 68519eb

10 files changed

+104
-11
lines changed

core-blocks/shortcode/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* WordPress dependencies
33
*/
4+
import { removep, autop } from '@wordpress/autop';
45
import { RawHTML } from '@wordpress/element';
56
import { __ } from '@wordpress/i18n';
67
import { Dashicon } from '@wordpress/components';
@@ -46,7 +47,7 @@ export const settings = {
4647
text: {
4748
type: 'string',
4849
shortcode: ( attrs, { content } ) => {
49-
return content;
50+
return removep( autop( content ) );
5051
},
5152
},
5253
},

core-blocks/shortcode/index.php

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
/**
3+
* Server-side rendering of the `core/shortcode` block.
4+
*
5+
* @package gutenberg
6+
*/
7+
8+
/**
9+
* Performs wpautop() on the shortcode block content.
10+
*
11+
* @param array $attributes The block attributes.
12+
* @param string $content The block content.
13+
*
14+
* @return string Returns the block content.
15+
*/
16+
function render_block_core_shortcode( $attributes, $content ) {
17+
return wpautop( $content );
18+
}
19+
20+
/**
21+
* Registers the `core/shortcode` block on server.
22+
*/
23+
function register_block_core_shortcode() {
24+
register_block_type( 'core/shortcode', array(
25+
'render_callback' => 'render_block_core_shortcode',
26+
) );
27+
}
28+
29+
add_action( 'init', 'register_block_core_shortcode' );

docs/blocks/creating-dynamic-blocks.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Because it is a dynamic block it also needs a server component. The rendering ca
8989
<?php
9090
// block.php
9191

92-
function my_plugin_render_block_latest_post( $attributes ) {
92+
function my_plugin_render_block_latest_post( $attributes, $content ) {
9393
$recent_posts = wp_get_recent_posts( array(
9494
'numberposts' => 1,
9595
'post_status' => 'publish',
@@ -115,7 +115,7 @@ There are a few things to notice:
115115

116116
* The edit function still shows a representation of the block in the editor's context (this could be very different from the rendered version, it's up to the block's author)
117117
* The save function just returns null because the rendering is performed server-side.
118-
* The server-side rendering is a function taking the block attributes as an argument and returning the markup (quite similar to shortcodes)
118+
* The server-side rendering is a function taking the block attributes and the block inner content as arguments, and returning the markup (quite similar to shortcodes)
119119

120120
## Live rendering in Gutenberg editor
121121

editor/store/selectors.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ import createSelector from 'rememo';
2222
/**
2323
* WordPress dependencies
2424
*/
25-
import { serialize, getBlockType, getBlockTypes, hasBlockSupport, hasChildBlocks } from '@wordpress/blocks';
25+
import { serialize, getBlockType, getBlockTypes, hasBlockSupport, hasChildBlocks, getUnknownTypeHandlerName } from '@wordpress/blocks';
2626
import { __ } from '@wordpress/i18n';
2727
import { moment } from '@wordpress/date';
2828
import deprecated from '@wordpress/deprecated';
29+
import { removep } from '@wordpress/autop';
2930

3031
/***
3132
* Module constants
@@ -1352,7 +1353,13 @@ export const getEditedPostContent = createSelector(
13521353
return edits.content;
13531354
}
13541355

1355-
return serialize( getBlocks( state ) );
1356+
const blocks = getBlocks( state );
1357+
1358+
if ( blocks.length === 1 && blocks[ 0 ].name === getUnknownTypeHandlerName() ) {
1359+
return removep( serialize( blocks ) );
1360+
}
1361+
1362+
return serialize( blocks );
13561363
},
13571364
( state ) => [
13581365
state.editor.present.edits.content,

lib/blocks.php

+6-3
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,7 @@ function do_blocks( $content ) {
177177
}
178178
}
179179

180-
// Replace dynamic block with server-rendered output.
181-
$rendered_content .= $block_type->render( $attributes );
180+
$inner_content = '';
182181

183182
if ( ! $is_self_closing ) {
184183
$end_tag_pattern = '/<!--\s+\/wp:' . str_replace( '/', '\/', preg_quote( $block_name ) ) . '\s+-->/';
@@ -192,8 +191,12 @@ function do_blocks( $content ) {
192191
$end_tag = $block_match_end[0][0];
193192
$end_offset = $block_match_end[0][1];
194193

195-
$content = substr( $content, $end_offset + strlen( $end_tag ) );
194+
$inner_content = substr( $content, 0, $end_offset );
195+
$content = substr( $content, $end_offset + strlen( $end_tag ) );
196196
}
197+
198+
// Replace dynamic block with server-rendered output.
199+
$rendered_content .= $block_type->render( $attributes, $inner_content );
197200
}
198201

199202
// Append remaining unmatched content.

lib/class-wp-block-type.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,18 @@ public function __construct( $block_type, $args = array() ) {
9494
*
9595
* @since 0.6.0
9696
*
97-
* @param array $attributes Optional. Block attributes. Default empty array.
97+
* @param array $attributes Optional. Block attributes. Default empty array.
98+
* @param string $content Optional. Block content. Default empty string.
9899
* @return string Rendered block type output.
99100
*/
100-
public function render( $attributes = array() ) {
101+
public function render( $attributes = array(), $content = '' ) {
101102
if ( ! $this->is_dynamic() ) {
102103
return '';
103104
}
104105

105106
$attributes = $this->prepare_attributes_for_render( $attributes );
106107

107-
return (string) call_user_func( $this->render_callback, $attributes );
108+
return (string) call_user_func( $this->render_callback, $attributes, $content );
108109
}
109110

110111
/**

phpunit/class-block-type-test.php

+17
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,23 @@ function test_render() {
3636
$this->assertEquals( $attributes, json_decode( $output, true ) );
3737
}
3838

39+
function test_render_with_content() {
40+
$attributes = array(
41+
'foo' => 'bar',
42+
'bar' => 'foo',
43+
);
44+
45+
$content = 'baz';
46+
47+
$expected = array_merge( $attributes, array( '_content' => $content ) );
48+
49+
$block_type = new WP_Block_Type( 'core/dummy', array(
50+
'render_callback' => array( $this, 'render_dummy_block_with_content' ),
51+
) );
52+
$output = $block_type->render( $attributes, $content );
53+
$this->assertEquals( $expected, json_decode( $output, true ) );
54+
}
55+
3956
function test_render_for_static_block() {
4057
$block_type = new WP_Block_Type( 'core/dummy', array() );
4158
$output = $block_type->render();

phpunit/class-do-blocks-test.php

+22
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,26 @@ function test_do_blocks_removes_comments() {
2222

2323
$this->assertEquals( $expected_html, $actual_html );
2424
}
25+
26+
/**
27+
* Test that shortcode blocks get the same HTML as shortcodes in Classic content.
28+
*/
29+
function test_the_content() {
30+
add_shortcode( 'someshortcode', array( $this, 'handle_shortcode' ) );
31+
32+
$classic_content = "Foo\n\n[someshortcode]\n\nBar\n\n[/someshortcode]\n\nBaz";
33+
$block_content = "<!-- wp:core/paragraph -->\n<p>Foo</p>\n<!-- /wp:core/paragraph -->\n\n<!-- wp:core/shortcode -->[someshortcode]\n\nBar\n\n[/someshortcode]<!-- /wp:core/shortcode -->\n\n<!-- wp:core/paragraph -->\n<p>Baz</p>\n<!-- /wp:core/paragraph -->";
34+
35+
$classic_filtered_content = apply_filters( 'the_content', $classic_content );
36+
$block_filtered_content = apply_filters( 'the_content', $block_content );
37+
38+
// Block rendering add some extra blank lines, but we're not worried about them.
39+
$block_filtered_content = preg_replace( "/\n{2,}/", "\n", $block_filtered_content );
40+
41+
$this->assertEquals( $classic_filtered_content, $block_filtered_content );
42+
}
43+
44+
function handle_shortcode( $atts, $content ) {
45+
return $content;
46+
}
2547
}

phpunit/fixtures/do-blocks-expected.html

+5
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,8 @@
1010
<p>Third Gutenberg Paragraph</p>
1111

1212
<p>Third Auto Paragraph</p>
13+
14+
<p>[someshortcode]</p>
15+
<p>And some content?!</p>
16+
<p>[/someshortcode]</p>
17+

phpunit/fixtures/do-blocks-original.html

+8
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,11 @@
1515
<!-- /wp:core/paragraph -->
1616

1717
<p>Third Auto Paragraph</p>
18+
19+
<!-- wp:core/shortcode -->
20+
[someshortcode]
21+
22+
And some content?!
23+
24+
[/someshortcode]
25+
<!-- /wp:core/shortcode -->

0 commit comments

Comments
 (0)