Skip to content

Commit 4b3201c

Browse files
committed
Preserve whitespace inside pre elements when federating content
1 parent c56e9cd commit 4b3201c

File tree

4 files changed

+72
-3
lines changed

4 files changed

+72
-3
lines changed

includes/class-sanitize.php

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

202202
return $content;
203203
}
204+
205+
/**
206+
* Strip newlines, carriage returns, and tabs from content while preserving them inside pre elements.
207+
*
208+
* Code blocks require whitespace to be preserved for proper formatting.
209+
*
210+
* @param string $content The content to process.
211+
*
212+
* @return string The trimmed content with whitespace stripped except inside pre elements.
213+
*/
214+
public static function strip_whitespace( $content ) {
215+
return \trim(
216+
\preg_replace_callback(
217+
'/(<pre[^>]*>.*?<\/pre>)|[\n\r\t]+/is',
218+
static function ( $matches ) {
219+
return $matches[1] ?? '';
220+
},
221+
$content
222+
)
223+
);
224+
}
204225
}

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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Activitypub\Collection\Interactions;
1313
use Activitypub\Collection\Replies;
1414
use Activitypub\Model\Blog;
15+
use Activitypub\Sanitize;
1516
use Activitypub\Shortcodes;
1617

1718
use function Activitypub\esc_hashtag;
@@ -539,8 +540,7 @@ protected function get_content() {
539540
\wp_reset_postdata();
540541

541542
$content = \wpautop( $content );
542-
$content = \preg_replace( '/[\n\r\t]/', '', $content );
543-
$content = \trim( $content );
543+
$content = Sanitize::strip_whitespace( $content );
544544

545545
// Don't need these anymore, should never appear in a post.
546546
Shortcodes::unregister();

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,54 @@ public function test_get_post_content_template_with_scenarios( $post_data, $expe
11061106
$this->assertSame( $expected_template, $template, $description );
11071107
}
11081108

1109+
/**
1110+
* Test that code blocks preserve newlines when content is transformed.
1111+
*
1112+
* @covers ::get_content
1113+
*/
1114+
public function test_code_blocks_preserve_newlines() {
1115+
$code_content = "function test() {\n\treturn true;\n}";
1116+
$post = self::factory()->post->create_and_get(
1117+
array(
1118+
'post_title' => 'Code Example',
1119+
'post_content' => '<pre>' . $code_content . '</pre>',
1120+
'post_status' => 'publish',
1121+
)
1122+
);
1123+
1124+
$object = Post::transform( $post )->to_object();
1125+
$content = $object->get_content();
1126+
1127+
// The pre block content should preserve newlines and tabs.
1128+
$this->assertStringContainsString( '<pre>', $content, 'Content should contain pre tag' );
1129+
$this->assertStringContainsString( "\n", $content, 'Content should preserve newlines inside pre blocks' );
1130+
$this->assertStringContainsString( "\t", $content, 'Content should preserve tabs inside pre blocks' );
1131+
}
1132+
1133+
/**
1134+
* Test that regular content has whitespace stripped while code blocks are preserved.
1135+
*
1136+
* @covers ::get_content
1137+
*/
1138+
public function test_mixed_content_preserves_code_blocks() {
1139+
$post = self::factory()->post->create_and_get(
1140+
array(
1141+
'post_title' => 'Mixed Content',
1142+
'post_content' => "<p>Regular paragraph</p>\n\n<pre class=\"code\">line1\nline2\nline3</pre>\n\n<p>Another paragraph</p>",
1143+
'post_status' => 'publish',
1144+
)
1145+
);
1146+
1147+
$object = Post::transform( $post )->to_object();
1148+
$content = $object->get_content();
1149+
1150+
// Pre block should preserve newlines.
1151+
$this->assertStringContainsString( "line1\nline2\nline3", $content, 'Pre block should preserve newlines' );
1152+
1153+
// Regular paragraphs should be joined without extra newlines.
1154+
$this->assertStringNotContainsString( "</p>\n\n<p>", $content, 'Paragraphs should not have newlines between them' );
1155+
}
1156+
11091157
/**
11101158
* Data provider for get_post_content_template tests with various scenarios.
11111159
*

0 commit comments

Comments
 (0)