Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/changelog/2595-from-description
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fixed

Preserve newlines inside pre elements when federating content.
21 changes: 21 additions & 0 deletions includes/class-sanitize.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,25 @@ public static function content( $content ) {

return $content;
}

/**
* Strip newlines, carriage returns, and tabs from content while preserving them inside pre elements.
*
* Code blocks require whitespace to be preserved for proper formatting.
*
* @param string $content The content to process.
*
* @return string The trimmed content with whitespace stripped except inside pre elements.
*/
public static function strip_whitespace( $content ) {
return \trim(
\preg_replace_callback(
'/(<pre[^>]*>.*?<\/pre>)|[\n\r\t]+/is',
static function ( $matches ) {
return $matches[1] ?? '';
},
$content
)
);
}
}
2 changes: 1 addition & 1 deletion includes/class-shortcodes.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ public static function content( $attributes, $content, $tag ) {
// Replace script and style elements.
$content = \preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $content );
$content = \strip_shortcodes( $content );
$content = \trim( \preg_replace( '/[\n\r\t]/', '', $content ) );
$content = Sanitize::strip_whitespace( $content );

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

Expand Down
4 changes: 2 additions & 2 deletions includes/transformer/class-post.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Activitypub\Collection\Interactions;
use Activitypub\Collection\Replies;
use Activitypub\Model\Blog;
use Activitypub\Sanitize;
use Activitypub\Shortcodes;

use function Activitypub\esc_hashtag;
Expand Down Expand Up @@ -539,8 +540,7 @@ protected function get_content() {
\wp_reset_postdata();

$content = \wpautop( $content );
$content = \preg_replace( '/[\n\r\t]/', '', $content );
$content = \trim( $content );
$content = Sanitize::strip_whitespace( $content );

// Don't need these anymore, should never appear in a post.
Shortcodes::unregister();
Expand Down
48 changes: 48 additions & 0 deletions tests/phpunit/tests/includes/transformer/class-test-post.php
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,54 @@ public function test_get_post_content_template_with_scenarios( $post_data, $expe
$this->assertSame( $expected_template, $template, $description );
}

/**
* Test that code blocks preserve newlines when content is transformed.
*
* @covers ::get_content
*/
public function test_code_blocks_preserve_newlines() {
$code_content = "function test() {\n\treturn true;\n}";
$post = self::factory()->post->create_and_get(
array(
'post_title' => 'Code Example',
'post_content' => '<pre>' . $code_content . '</pre>',
'post_status' => 'publish',
)
);

$object = Post::transform( $post )->to_object();
$content = $object->get_content();

// The pre block content should preserve newlines and tabs.
$this->assertStringContainsString( '<pre>', $content, 'Content should contain pre tag' );
$this->assertStringContainsString( "\n", $content, 'Content should preserve newlines inside pre blocks' );
$this->assertStringContainsString( "\t", $content, 'Content should preserve tabs inside pre blocks' );
}

/**
* Test that regular content has whitespace stripped while code blocks are preserved.
*
* @covers ::get_content
*/
public function test_mixed_content_preserves_code_blocks() {
$post = self::factory()->post->create_and_get(
array(
'post_title' => 'Mixed Content',
'post_content' => "<p>Regular paragraph</p>\n\n<pre class=\"code\">line1\nline2\nline3</pre>\n\n<p>Another paragraph</p>",
'post_status' => 'publish',
)
);

$object = Post::transform( $post )->to_object();
$content = $object->get_content();

// Pre block should preserve newlines.
$this->assertStringContainsString( "line1\nline2\nline3", $content, 'Pre block should preserve newlines' );

// Regular paragraphs should be joined without extra newlines.
$this->assertStringNotContainsString( "</p>\n\n<p>", $content, 'Paragraphs should not have newlines between them' );
}

/**
* Data provider for get_post_content_template tests with various scenarios.
*
Expand Down