Skip to content

Commit 0290dc3

Browse files
authored
Strip whitespace between HTML tags instead of all content (#2621)
1 parent 214acc5 commit 0290dc3

File tree

6 files changed

+140
-7
lines changed

6 files changed

+140
-7
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: fixed
3+
4+
Preserve whitespace inside preformatted elements when federating content.

includes/class-sanitize.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,4 +201,18 @@ public static function content( $content ) {
201201

202202
return $content;
203203
}
204+
205+
/**
206+
* Strip whitespace between HTML tags.
207+
*
208+
* Removes newlines, carriage returns, and tabs that appear between HTML tags,
209+
* preserving whitespace within text content and preformatted elements.
210+
*
211+
* @param string $content The content to process.
212+
*
213+
* @return string The content with whitespace between tags removed.
214+
*/
215+
public static function strip_whitespace( $content ) {
216+
return \trim( \preg_replace( '/>[\n\r\t]+</', '><', $content ) );
217+
}
204218
}

includes/class-shortcodes.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ public static function content( $attributes, $content, $tag ) {
191191
// Replace script and style elements.
192192
$content = \preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $content );
193193
$content = \strip_shortcodes( $content );
194-
$content = \trim( \preg_replace( '/[\n\r\t]/', '', $content ) );
194+
$content = Sanitize::strip_whitespace( $content );
195195

196196
add_shortcode( 'ap_content', array( 'Activitypub\Shortcodes', 'content' ) );
197197

includes/transformer/class-post.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -603,10 +603,6 @@ protected function get_content() {
603603
$content = \do_shortcode( $content );
604604
\wp_reset_postdata();
605605

606-
$content = \wpautop( $content );
607-
$content = \preg_replace( '/[\n\r\t]/', '', $content );
608-
$content = \trim( $content );
609-
610606
// Don't need these anymore, should never appear in a post.
611607
Shortcodes::unregister();
612608

@@ -992,7 +988,7 @@ protected function get_post_content_template() {
992988
&& empty( $this->get_in_reply_to() )
993989
&& empty( $this->get_mentions() )
994990
) {
995-
$template .= "[ap_title type=\"html\"]\n\n";
991+
$template .= '[ap_title type="html"]';
996992
}
997993

998994
$template .= '[ap_content]';

tests/phpunit/tests/includes/class-test-sanitize.php

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,4 +266,123 @@ public function test_content_preserves_safe_html() {
266266
$this->assertStringContainsString( '<strong>Bold</strong>', $result );
267267
$this->assertStringContainsString( '<em>italic</em>', $result );
268268
}
269+
270+
/**
271+
* Data provider for strip_whitespace tests.
272+
*
273+
* @return array Test data with input and expected output.
274+
*/
275+
public function strip_whitespace_provider() {
276+
return array(
277+
'removes_newlines_between_tags' => array(
278+
"<p>Hello</p>\n<p>World</p>",
279+
'<p>Hello</p><p>World</p>',
280+
),
281+
'removes_tabs_between_tags' => array(
282+
"<p>Hello</p>\t\t<p>World</p>",
283+
'<p>Hello</p><p>World</p>',
284+
),
285+
'removes_carriage_returns' => array(
286+
"<p>Hello</p>\r\n<p>World</p>",
287+
'<p>Hello</p><p>World</p>',
288+
),
289+
'removes_mixed_whitespace' => array(
290+
"<div>\n\t<p>Text</p>\n</div>",
291+
'<div><p>Text</p></div>',
292+
),
293+
'preserves_spaces_between_tags' => array(
294+
'<span>Hello</span> <span>World</span>',
295+
'<span>Hello</span> <span>World</span>',
296+
),
297+
'preserves_whitespace_in_text' => array(
298+
"<p>Hello\nWorld</p>",
299+
"<p>Hello\nWorld</p>",
300+
),
301+
'preserves_pre_content' => array(
302+
"<pre>function test() {\n return true;\n}</pre>",
303+
"<pre>function test() {\n return true;\n}</pre>",
304+
),
305+
'preserves_code_content' => array(
306+
"<code>const x = 1;\nconst y = 2;</code>",
307+
"<code>const x = 1;\nconst y = 2;</code>",
308+
),
309+
'complex_html_with_pre' => array(
310+
"<p>Some text</p>\n<pre>code line 1\ncode line 2</pre>\n<p>More text</p>",
311+
"<p>Some text</p><pre>code line 1\ncode line 2</pre><p>More text</p>",
312+
),
313+
'trims_leading_trailing_whitespace' => array(
314+
"\n\n<p>Hello</p>\n\n",
315+
'<p>Hello</p>',
316+
),
317+
'empty_string' => array(
318+
'',
319+
'',
320+
),
321+
'whitespace_only' => array(
322+
"\n\t\r\n",
323+
'',
324+
),
325+
'nested_tags_with_whitespace' => array(
326+
"<div>\n\t<ul>\n\t\t<li>Item</li>\n\t</ul>\n</div>",
327+
'<div><ul><li>Item</li></ul></div>',
328+
),
329+
'self_closing_hr_between_tags' => array(
330+
"<p>Before</p>\n<hr />\n<p>After</p>",
331+
'<p>Before</p><hr /><p>After</p>',
332+
),
333+
'self_closing_br_between_tags' => array(
334+
"<p>Line 1</p>\n<br>\n<p>Line 2</p>",
335+
'<p>Line 1</p><br><p>Line 2</p>',
336+
),
337+
'br_inside_paragraph' => array(
338+
"<p>Line 1<br>\nLine 2</p>",
339+
"<p>Line 1<br>\nLine 2</p>",
340+
),
341+
'hr_with_xhtml_syntax' => array(
342+
"<div>\n<hr/>\n</div>",
343+
'<div><hr/></div>',
344+
),
345+
'deeply_nested_divs' => array(
346+
"<div>\n\t<div>\n\t\t<div>\n\t\t\t<p>Deep</p>\n\t\t</div>\n\t</div>\n</div>",
347+
'<div><div><div><p>Deep</p></div></div></div>',
348+
),
349+
'mixed_self_closing_and_nested' => array(
350+
"<div>\n\t<p>Text</p>\n\t<hr />\n\t<p>More</p>\n</div>",
351+
'<div><p>Text</p><hr /><p>More</p></div>',
352+
),
353+
'img_self_closing' => array(
354+
"<p>Text</p>\n<img src=\"test.jpg\" />\n<p>More</p>",
355+
'<p>Text</p><img src="test.jpg" /><p>More</p>',
356+
),
357+
'preserves_spaces_with_newlines' => array(
358+
"<p>Hello</p> \n <p>World</p>",
359+
"<p>Hello</p> \n <p>World</p>",
360+
),
361+
'preserves_space_after_newline' => array(
362+
"<span>A</span>\n <span>B</span>",
363+
"<span>A</span>\n <span>B</span>",
364+
),
365+
'preserves_space_before_newline' => array(
366+
"<span>A</span> \n<span>B</span>",
367+
"<span>A</span> \n<span>B</span>",
368+
),
369+
'multiple_spaces_with_newlines' => array(
370+
"<div>A</div> \n\t <div>B</div>",
371+
"<div>A</div> \n\t <div>B</div>",
372+
),
373+
);
374+
}
375+
376+
/**
377+
* Test strip_whitespace with various inputs.
378+
*
379+
* @dataProvider strip_whitespace_provider
380+
* @covers ::strip_whitespace
381+
*
382+
* @param string $input Input value.
383+
* @param string $expected Expected output.
384+
*/
385+
public function test_strip_whitespace( $input, $expected ) {
386+
$this->assertSame( $expected, Sanitize::strip_whitespace( $input ) );
387+
}
269388
}

tests/phpunit/tests/includes/transformer/class-test-post.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,7 @@ public function wordpress_post_format_template_provider() {
11371137
'post_content' => 'Short note',
11381138
'post_status' => 'publish',
11391139
),
1140-
"[ap_title type=\"html\"]\n\n[ap_content]",
1140+
'[ap_title type="html"][ap_content]',
11411141
'wordpress-post-format',
11421142
'[ap_title]\n\n[ap_content]',
11431143
'wordpress-post-format should add title for Note type without reply.',

0 commit comments

Comments
 (0)