Commit 743c6e3444 for woocommerce

commit 743c6e34440a071b7fba05e5a24d5cd418e3bb0e
Author: Jan Lysý <lysyjan@users.noreply.github.com>
Date:   Tue Nov 18 07:20:04 2025 +0100

    Ensure `Post_Content` compatibility with non-email contexts (#61874)

    * Ensure `Post_Content` compatibility with non-email contexts and add test coverage

    * Add changelog

    * Ensure `Post_Content` renderer uses stateless logic only in email contexts and swap callback dynamically to prevent conflicts with other plugins

diff --git a/packages/php/email-editor/changelog/fix-post-content-context-aware-rendering b/packages/php/email-editor/changelog/fix-post-content-context-aware-rendering
new file mode 100644
index 0000000000..c3b44b3d77
--- /dev/null
+++ b/packages/php/email-editor/changelog/fix-post-content-context-aware-rendering
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Swap core/post-content render callback only during email rendering to prevent conflicts with other plugins like MailPoet.
diff --git a/packages/php/email-editor/src/Engine/Renderer/ContentRenderer/class-content-renderer.php b/packages/php/email-editor/src/Engine/Renderer/ContentRenderer/class-content-renderer.php
index 2922e5c38f..3c0e3d7741 100644
--- a/packages/php/email-editor/src/Engine/Renderer/ContentRenderer/class-content-renderer.php
+++ b/packages/php/email-editor/src/Engine/Renderer/ContentRenderer/class-content-renderer.php
@@ -12,6 +12,7 @@ use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger;
 use Automattic\WooCommerce\EmailEditor\Engine\Renderer\Css_Inliner;
 use Automattic\WooCommerce\EmailEditor\Engine\Theme_Controller;
 use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Fallback;
+use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Post_Content;
 use WP_Block_Template;
 use WP_Block_Type_Registry;
 use WP_Post;
@@ -92,6 +93,13 @@ class Content_Renderer {
 	 */
 	private Email_Editor_Logger $logger;

+	/**
+	 * Backup of the original core/post-content render callback.
+	 *
+	 * @var callable|null
+	 */
+	private $backup_post_content_callback;
+
 	/**
 	 * Content_Renderer constructor.
 	 *
@@ -123,6 +131,19 @@ class Content_Renderer {
 		add_filter( 'render_block', array( $this, 'render_block' ), 10, 2 );
 		add_filter( 'block_parser_class', array( $this, 'block_parser' ) );
 		add_filter( 'woocommerce_email_blocks_renderer_parsed_blocks', array( $this, 'preprocess_parsed_blocks' ) );
+
+		// Swap core/post-content render callback for email rendering.
+		// This prevents issues with WordPress's static $seen_ids array when rendering
+		// multiple emails in a single request (e.g., MailPoet batch processing).
+		$post_content_type = $this->block_type_registry->get_registered( 'core/post-content' );
+		if ( $post_content_type ) {
+			// Save the original callback (may be null or WordPress's default).
+			$this->backup_post_content_callback = $post_content_type->render_callback;
+
+			// Replace with our stateless renderer.
+			$post_content_renderer              = new Post_Content();
+			$post_content_type->render_callback = array( $post_content_renderer, 'render_stateless' );
+		}
 	}

 	/**
@@ -247,6 +268,14 @@ class Content_Renderer {
 		remove_filter( 'block_parser_class', array( $this, 'block_parser' ) );
 		remove_filter( 'woocommerce_email_blocks_renderer_parsed_blocks', array( $this, 'preprocess_parsed_blocks' ) );

+		// Restore the original core/post-content render callback.
+		// Note: We always restore it, even if it was null originally.
+		$post_content_type = $this->block_type_registry->get_registered( 'core/post-content' );
+		if ( $post_content_type ) {
+			// @phpstan-ignore-next-line -- WordPress core allows null for render_callback despite type definition.
+			$post_content_type->render_callback = $this->backup_post_content_callback;
+		}
+
 		// Restore globals to their original values.
 		global $_wp_current_template_content, $_wp_current_template_id, $wp_query, $post;

diff --git a/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-post-content.php b/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-post-content.php
index 22963b97cd..7601bc6355 100644
--- a/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-post-content.php
+++ b/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-post-content.php
@@ -32,12 +32,17 @@ class Post_Content {
 	 * - Uses direct post content access instead of get_the_content()
 	 * - Properly backs up and restores global state
 	 *
+	 * IMPORTANT: This method is only set as the render_callback during email rendering.
+	 * Outside of email rendering, the original callback is restored, so this method
+	 * will never be called in non-email contexts.
+	 *
 	 * @param array     $attributes Block attributes.
 	 * @param string    $content    Block content.
 	 * @param \WP_Block $block      Block instance.
 	 * @return string Rendered post content HTML.
 	 */
 	public function render_stateless( $attributes, $content, $block ): string {
+		// This method is only called during email rendering, so we always use stateless logic.
 		$post_id = $block->context['postId'] ?? null;

 		if ( ! $post_id ) {
diff --git a/packages/php/email-editor/src/Integrations/Core/class-initializer.php b/packages/php/email-editor/src/Integrations/Core/class-initializer.php
index 5e6232a95f..e402e0f1de 100644
--- a/packages/php/email-editor/src/Integrations/Core/class-initializer.php
+++ b/packages/php/email-editor/src/Integrations/Core/class-initializer.php
@@ -150,14 +150,6 @@ class Initializer {
 			$settings['render_email_callback'] = array( $this, 'render_block' );
 		}

-		// Special handling for core/post-content to use stateless renderer.
-		// This prevents issues with WordPress's static $seen_ids array when rendering
-		// multiple emails in a single request (e.g., MailPoet batch processing).
-		if ( 'core/post-content' === $settings['name'] ) {
-			$post_content_renderer       = new Post_Content();
-			$settings['render_callback'] = array( $post_content_renderer, 'render_stateless' );
-		}
-
 		return $settings;
 	}

diff --git a/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Post_Content_Test.php b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Post_Content_Test.php
index dd5e5da5d2..b460b73013 100644
--- a/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Post_Content_Test.php
+++ b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Post_Content_Test.php
@@ -35,15 +35,14 @@ class Post_Content_Test extends \Email_Editor_Integration_Test_Case {
 		$this->initializer = $this->di_container->get( Initializer::class );
 		$this->initializer->initialize();

-		// Manually trigger block settings update for core/post-content
-		// This simulates what the block_type_metadata_settings filter does in Bootstrap.
+		// Manually swap the core/post-content render callback to simulate email rendering.
+		// In production, this is done by Content_Renderer::initialize() when rendering emails.
 		$registry   = \WP_Block_Type_Registry::get_instance();
 		$block_type = $registry->get_registered( 'core/post-content' );
 		if ( $block_type ) {
-			$settings                    = (array) $block_type;
-			$settings['name']            = 'core/post-content';
-			$updated_settings            = $this->initializer->update_block_settings( $settings );
-			$block_type->render_callback = $updated_settings['render_callback'] ?? null;
+			// Replace with our stateless renderer.
+			$post_content_renderer       = new Post_Content();
+			$block_type->render_callback = array( $post_content_renderer, 'render_stateless' );
 		}
 	}