Skip to content

Commit ba44ffd

Browse files
authored
Merge branch 'WordPress:trunk' into trunk
2 parents 060e5e6 + 659ba67 commit ba44ffd

1 file changed

Lines changed: 262 additions & 0 deletions

File tree

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
<?php
2+
/**
3+
* Tests for _wp_apply_block_content_filters().
4+
*
5+
* @package WordPress
6+
* @subpackage Blocks
7+
*
8+
* @group blocks
9+
*
10+
* @covers ::_wp_apply_block_content_filters
11+
*/
12+
class Tests_Blocks_WpApplyBlockContentFilters extends WP_UnitTestCase {
13+
const TEST_BLOCK_NAME = 'tests/apply-block-content-filters';
14+
const TEST_EXCEPTION_BLOCK_NAME = 'tests/apply-block-content-filters-exception';
15+
const TEST_EMBED_HANDLER = 'apply_block_content_filters_embed';
16+
const TEST_SHORTCODE = 'apply_block_content_filters_shortcode';
17+
18+
/**
19+
* The original use_smilies option value.
20+
*
21+
* @var string
22+
*/
23+
private $original_use_smilies;
24+
25+
/**
26+
* Context received by the wp_content_img_tag filter.
27+
*
28+
* @var string|null
29+
*/
30+
private $filtered_image_context;
31+
32+
public function set_up() {
33+
parent::set_up();
34+
35+
$this->original_use_smilies = get_option( 'use_smilies' );
36+
$this->filtered_image_context = null;
37+
38+
update_option( 'use_smilies', 1 );
39+
smilies_init();
40+
41+
register_block_type(
42+
self::TEST_BLOCK_NAME,
43+
array(
44+
'render_callback' => static function ( $attributes ) {
45+
return sprintf(
46+
'<div class="apply-block-content-filters-block">%s</div>',
47+
esc_html( $attributes['label'] )
48+
);
49+
},
50+
)
51+
);
52+
53+
register_block_type(
54+
self::TEST_EXCEPTION_BLOCK_NAME,
55+
array(
56+
'render_callback' => static function () {
57+
throw new Exception( 'Block rendering failed.' );
58+
},
59+
)
60+
);
61+
}
62+
63+
public function tear_down() {
64+
remove_shortcode( self::TEST_SHORTCODE );
65+
wp_embed_unregister_handler( self::TEST_EMBED_HANDLER );
66+
remove_filter( 'wp_content_img_tag', array( $this, 'filter_content_image_tag' ) );
67+
68+
if ( WP_Block_Type_Registry::get_instance()->is_registered( self::TEST_BLOCK_NAME ) ) {
69+
unregister_block_type( self::TEST_BLOCK_NAME );
70+
}
71+
72+
if ( WP_Block_Type_Registry::get_instance()->is_registered( self::TEST_EXCEPTION_BLOCK_NAME ) ) {
73+
unregister_block_type( self::TEST_EXCEPTION_BLOCK_NAME );
74+
}
75+
76+
update_option( 'use_smilies', $this->original_use_smilies );
77+
78+
parent::tear_down();
79+
}
80+
81+
/**
82+
* Filters content image tags.
83+
*
84+
* @param string $filtered_image Full img tag with attributes.
85+
* @param string $context Context for the image tag.
86+
* @return string Filtered image tag.
87+
*/
88+
public function filter_content_image_tag( $filtered_image, $context ) {
89+
$this->filtered_image_context = $context;
90+
91+
if ( str_contains( $filtered_image, 'class="content-image"' ) ) {
92+
return str_replace( '<img ', '<img data-filtered="yes" ', $filtered_image );
93+
}
94+
95+
return $filtered_image;
96+
}
97+
98+
/**
99+
* Renders the test embed handler.
100+
*
101+
* @return string Embed markup.
102+
*/
103+
public function render_test_embed() {
104+
return '<div class="apply-block-content-filters-embed">Embedded content</div>';
105+
}
106+
107+
/**
108+
* Tests that each expected content filter is applied.
109+
*
110+
* @ticket 65586
111+
*/
112+
public function test_applies_content_filters() {
113+
add_filter( 'wp_content_img_tag', array( $this, 'filter_content_image_tag' ), 10, 2 );
114+
115+
wp_embed_register_handler(
116+
self::TEST_EMBED_HANDLER,
117+
'#https?://example\.com/apply-block-content-filters#i',
118+
array( $this, 'render_test_embed' )
119+
);
120+
121+
add_shortcode(
122+
self::TEST_SHORTCODE,
123+
static function () {
124+
return '<!-- wp:tests/apply-block-content-filters {"label":"Shortcode block output"} /-->';
125+
}
126+
);
127+
128+
$content = sprintf(
129+
"This shouldn't use a straight apostrophe, and this should become a smilie: :mrgreen:\n\n<p>[%s]</p>\n\n<!-- wp:tests/apply-block-content-filters {\"label\":\"Direct block output\"} /-->\n\n<img src=\"https://example.org/image.jpg\" alt=\"\" class=\"content-image\" />\n\nhttps://example.com/apply-block-content-filters",
130+
self::TEST_SHORTCODE
131+
);
132+
133+
$output = _wp_apply_block_content_filters( $content, 'test-context' );
134+
135+
$this->assertStringContainsString(
136+
'This shouldn&#8217;t use a straight apostrophe',
137+
$output,
138+
'wptexturize() should convert straight apostrophes to curly apostrophe entities.'
139+
);
140+
$this->assertStringContainsString(
141+
'class="wp-smiley"',
142+
$output,
143+
'convert_smilies() should process smilies in the filtered content.'
144+
);
145+
$this->assertStringContainsString(
146+
'<div class="apply-block-content-filters-block">Shortcode block output</div>',
147+
$output,
148+
'do_shortcode() should run before do_blocks() so block markup returned by a shortcode is rendered.'
149+
);
150+
$this->assertStringNotContainsString(
151+
'<p><div class="apply-block-content-filters-block">Shortcode block output</div></p>',
152+
$output,
153+
'shortcode_unautop() should remove paragraph wrappers around standalone shortcodes.'
154+
);
155+
$this->assertStringContainsString(
156+
'<div class="apply-block-content-filters-block">Direct block output</div>',
157+
$output,
158+
'do_blocks() should render block markup in the filtered content.'
159+
);
160+
$this->assertStringNotContainsString(
161+
'<!-- wp:tests/apply-block-content-filters',
162+
$output,
163+
'do_blocks() should remove block comments from rendered output.'
164+
);
165+
$this->assertStringContainsString(
166+
'data-filtered="yes"',
167+
$output,
168+
'wp_filter_content_tags() should filter image tags in the filtered content.'
169+
);
170+
$this->assertSame(
171+
'test-context',
172+
$this->filtered_image_context,
173+
'wp_filter_content_tags() should receive the context passed to _wp_apply_block_content_filters().'
174+
);
175+
$this->assertStringContainsString(
176+
'<div class="apply-block-content-filters-embed">Embedded content</div>',
177+
$output,
178+
'WP_Embed::autoembed() should process URLs on their own line.'
179+
);
180+
$this->assertStringNotContainsString(
181+
'https://example.com/apply-block-content-filters',
182+
$output,
183+
'WP_Embed::autoembed() should replace the original URL with embed markup.'
184+
);
185+
}
186+
187+
/**
188+
* Tests that seen IDs are set during block rendering and cleared afterward.
189+
*
190+
* @ticket 65586
191+
*/
192+
public function test_marks_and_clears_seen_id() {
193+
$seen_ids = array();
194+
$seen_ids_during_render = null;
195+
196+
unregister_block_type( self::TEST_BLOCK_NAME );
197+
register_block_type(
198+
self::TEST_BLOCK_NAME,
199+
array(
200+
'render_callback' => static function () use ( &$seen_ids, &$seen_ids_during_render ) {
201+
$seen_ids_during_render = $seen_ids;
202+
203+
return '<div class="apply-block-content-filters-block">Nested block rendered while recursion guard was active</div>';
204+
},
205+
)
206+
);
207+
208+
$output = _wp_apply_block_content_filters(
209+
'<!-- wp:tests/apply-block-content-filters /-->',
210+
'test-context',
211+
$seen_ids,
212+
'test-id'
213+
);
214+
215+
$this->assertStringContainsString(
216+
'Nested block rendered while recursion guard was active',
217+
$output,
218+
'The test block should render while the ID is marked as seen.'
219+
);
220+
$this->assertSame(
221+
array( 'test-id' => true ),
222+
$seen_ids_during_render,
223+
'The ID should be marked as seen while do_blocks() renders nested blocks.'
224+
);
225+
$this->assertSame(
226+
array(),
227+
$seen_ids,
228+
'The seen ID should be cleared after do_blocks() completes.'
229+
);
230+
}
231+
232+
/**
233+
* Tests that seen IDs are cleared when block rendering throws an exception.
234+
*
235+
* @ticket 65586
236+
*/
237+
public function test_clears_seen_id_when_block_rendering_throws() {
238+
$seen_ids = array();
239+
240+
try {
241+
_wp_apply_block_content_filters(
242+
'<!-- wp:tests/apply-block-content-filters-exception /-->',
243+
'test-context',
244+
$seen_ids,
245+
'test-id'
246+
);
247+
$this->fail( 'Expected block rendering to throw an exception.' );
248+
} catch ( Exception $exception ) {
249+
$this->assertSame(
250+
'Block rendering failed.',
251+
$exception->getMessage(),
252+
'The exception from the nested block render callback should be rethrown.'
253+
);
254+
}
255+
256+
$this->assertSame(
257+
array(),
258+
$seen_ids,
259+
'The seen ID should be cleared when do_blocks() throws.'
260+
);
261+
}
262+
}

0 commit comments

Comments
 (0)