From 0e19c1414d91b7f838600eb6e191a0c2be1476cc Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Thu, 26 Feb 2026 11:31:46 +0530 Subject: [PATCH 01/12] Add option to map the comments for comment type note with blocks --- src/class-wp-import.php | 74 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/class-wp-import.php b/src/class-wp-import.php index 6b179432..b356b35c 100644 --- a/src/class-wp-import.php +++ b/src/class-wp-import.php @@ -33,6 +33,7 @@ class WP_Import extends WP_Importer { public $author_mapping = array(); public $processed_terms = array(); public $processed_posts = array(); + public $processed_comments = array(); public $post_orphans = array(); public $processed_menu_items = array(); public $menu_item_orphans = array(); @@ -818,6 +819,7 @@ public function process_posts() { if ( ! empty( $post['comments'] ) ) { $this->process_post_comments( $post['comments'], (bool) $post_exists, $comment_post_id, $post ); unset( $post['comments'] ); + $this->update_block_note_ids( $post_id ); } if ( ! isset( $post['postmeta'] ) ) { @@ -1095,6 +1097,10 @@ protected function process_post_comments( $comments, $post_exists, $comment_post do_action( 'wp_import_insert_comment', $inserted_comment_id, $comment, $comment_post_id, $post ); $this->process_post_comment_metas( $inserted_comment_id, $comment['commentmeta'] ); $inserted_comments[ $key ] = $inserted_comment_id; + // Store comment ID mapping for note-type comments to update noteId references in blocks. + if ( isset( $comment['comment_type'] ) && 'note' === $comment['comment_type'] ) { + $this->processed_comments[ $key ] = $inserted_comment_id; + } ++$num_comments; } } @@ -1139,6 +1145,74 @@ protected function process_post_comment_metas( $comment_id, $commentmeta ) { } } + /** + * Update noteId references in block metadata to reflect new note-type comment IDs. + * + * Scans post content for Gutenberg blocks with noteId in metadata and updates + * them to match the new comment IDs assigned during import. Only processes + * comments with type 'note'. + * + * @param int $post_id The ID of the post being processed. + */ + protected function update_block_note_ids( $post_id ) { + if ( empty( $this->processed_comments ) ) { + return; + } + + $post = get_post( $post_id ); + + if ( ! $post ) { + return; + } + + $content = $post->post_content; + $updated = false; + + // Pattern to match Gutenberg block comments with noteId in metadata. + // Example: + preg_match_all( + '//i', + $content, + $matches, + PREG_SET_ORDER | PREG_OFFSET_CAPTURE + ); + + if ( empty( $matches ) ) { + return; + } + + foreach ( $matches as $match ) { + $full_match = $match[0][0]; + $block_name = $match[1][0]; + $attributes = $match[2][0]; + $old_note_id = (int) $match[3][0]; + $offset = $match[0][1]; + + // Check if we have a mapping for this comment ID. + if ( isset( $this->processed_comments[ $old_note_id ] ) ) { + $new_note_id = $this->processed_comments[ $old_note_id ]; + $new_attributes = preg_replace( + '/"noteId"\s*:\s*' . $old_note_id . '\b/', + '"noteId":' . $new_note_id, + $attributes + ); + + $new_match = ''; + $content = substr_replace( $content, $new_match, $offset, strlen( $full_match ) ); + $updated = true; + } + } + + if ( $updated ) { + wp_update_post( + array( + 'ID' => $post_id, + 'post_content' => $content, + ) + ); + } + } + /** * Process a single comment meta entry for an imported comment. * From d59679dd375916e55cfe4ed40ab81606c90e186e Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Thu, 26 Feb 2026 11:42:48 +0530 Subject: [PATCH 02/12] Update the replace logic with shorter logic --- src/class-wp-import.php | 37 +++++++------------------------------ 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/src/class-wp-import.php b/src/class-wp-import.php index b356b35c..1004262a 100644 --- a/src/class-wp-import.php +++ b/src/class-wp-import.php @@ -1168,38 +1168,15 @@ protected function update_block_note_ids( $post_id ) { $content = $post->post_content; $updated = false; - // Pattern to match Gutenberg block comments with noteId in metadata. - // Example: - preg_match_all( - '//i', - $content, - $matches, - PREG_SET_ORDER | PREG_OFFSET_CAPTURE - ); + foreach ( $this->processed_comments as $old_note_id => $new_note_id ) { + $search = '"noteId":' . $old_note_id; + $replace = '"noteId":' . $new_note_id; - if ( empty( $matches ) ) { - return; - } - - foreach ( $matches as $match ) { - $full_match = $match[0][0]; - $block_name = $match[1][0]; - $attributes = $match[2][0]; - $old_note_id = (int) $match[3][0]; - $offset = $match[0][1]; - - // Check if we have a mapping for this comment ID. - if ( isset( $this->processed_comments[ $old_note_id ] ) ) { - $new_note_id = $this->processed_comments[ $old_note_id ]; - $new_attributes = preg_replace( - '/"noteId"\s*:\s*' . $old_note_id . '\b/', - '"noteId":' . $new_note_id, - $attributes - ); + $new_content = str_replace( $search, $replace, $content ); - $new_match = ''; - $content = substr_replace( $content, $new_match, $offset, strlen( $full_match ) ); - $updated = true; + if ( $new_content !== $content ) { + $content = $new_content; + $updated = true; } } From d7bc6768240a88e8dd229f5de5252a344b48ff4e Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Thu, 26 Feb 2026 11:46:38 +0530 Subject: [PATCH 03/12] Add return type --- src/class-wp-import.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/class-wp-import.php b/src/class-wp-import.php index 1004262a..2974a21d 100644 --- a/src/class-wp-import.php +++ b/src/class-wp-import.php @@ -1153,8 +1153,9 @@ protected function process_post_comment_metas( $comment_id, $commentmeta ) { * comments with type 'note'. * * @param int $post_id The ID of the post being processed. + * @return void */ - protected function update_block_note_ids( $post_id ) { + protected function update_block_note_ids( int $post_id = 0 ): void { if ( empty( $this->processed_comments ) ) { return; } From 039fc9b8404d07acc0e10e1905afc329cef70022 Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Thu, 26 Feb 2026 14:09:02 +0530 Subject: [PATCH 04/12] Use WP_Block_Processor to update attributes metadata for noteId --- src/class-wp-import.php | 55 ++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/class-wp-import.php b/src/class-wp-import.php index 2974a21d..c0250f3b 100644 --- a/src/class-wp-import.php +++ b/src/class-wp-import.php @@ -1160,37 +1160,68 @@ protected function update_block_note_ids( int $post_id = 0 ): void { return; } + if ( ! class_exists( 'WP_Block_Processor' ) ) { + return; + } + $post = get_post( $post_id ); if ( ! $post ) { return; } - $content = $post->post_content; - $updated = false; - - foreach ( $this->processed_comments as $old_note_id => $new_note_id ) { - $search = '"noteId":' . $old_note_id; - $replace = '"noteId":' . $new_note_id; + $new_content = ''; + $has_updates = false; + $block_processor = new WP_Block_Processor( $post->post_content ); - $new_content = str_replace( $search, $replace, $content ); + while ( $block_processor->next_block() ) { + $block = $block_processor->extract_full_block_and_advance(); - if ( $new_content !== $content ) { - $content = $new_content; - $updated = true; + if ( $this->update_note_ids_in_block_tree( $block ) ) { + $has_updates = true; } + + $new_content .= serialize_block( $block ); } - if ( $updated ) { + if ( $has_updates ) { wp_update_post( array( 'ID' => $post_id, - 'post_content' => $content, + 'post_content' => $new_content, ) ); } } + /** + * Recursively updates noteId references in a block tree. + * + * @param array $block A single block from the parsed block tree. + * @return bool Whether any block was updated. + */ + private function update_note_ids_in_block_tree( array &$block ) { + $updated = false; + + if ( isset( $block['attrs']['metadata']['noteId'] ) ) { + $old_note_id = $block['attrs']['metadata']['noteId']; + if ( isset( $this->processed_comments[ $old_note_id ] ) ) { + $block['attrs']['metadata']['noteId'] = $this->processed_comments[ $old_note_id ]; + $updated = true; + } + } + + if ( ! empty( $block['innerBlocks'] ) ) { + foreach ( $block['innerBlocks'] as &$inner_block ) { + if ( $this->update_note_ids_in_block_tree( $inner_block ) ) { + $updated = true; + } + } + } + + return $updated; + } + /** * Process a single comment meta entry for an imported comment. * From 3f1980e4161417be18576a4107514cf802ae2a34 Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Fri, 27 Feb 2026 11:58:34 +0530 Subject: [PATCH 05/12] Update to use WP_Block_Processor and use span and noteId check to update --- src/class-wp-import.php | 97 +++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/src/class-wp-import.php b/src/class-wp-import.php index c0250f3b..7d1d1eeb 100644 --- a/src/class-wp-import.php +++ b/src/class-wp-import.php @@ -1146,13 +1146,23 @@ protected function process_post_comment_metas( $comment_id, $commentmeta ) { } /** - * Update noteId references in block metadata to reflect new note-type comment IDs. + * Remaps noteId references in block metadata after note-type comments are imported. * - * Scans post content for Gutenberg blocks with noteId in metadata and updates - * them to match the new comment IDs assigned during import. Only processes - * comments with type 'note'. + * During import, note-type comments receive new auto-incremented IDs on the destination + * site. Block metadata may reference those comment IDs via a `noteId` attribute, e.g.: * - * @param int $post_id The ID of the post being processed. + * + * + * This method uses WP_Block_Processor to walk every block opener in the post content, + * checks whether its `metadata.noteId` matches an old comment ID recorded in + * `$this->processed_comments`, and — if so — replaces it with the new ID. Updated + * blocks are collected as WP_HTML_Text_Replacement objects and applied back to the + * raw post content in one pass before saving. + * + * Skips the post entirely when no `"noteId"` string is present in the content, or + * when WP_Block_Processor is unavailable. + * + * @param int $post_id ID of the post whose block content should be updated. * @return void */ protected function update_block_note_ids( int $post_id = 0 ): void { @@ -1165,61 +1175,64 @@ protected function update_block_note_ids( int $post_id = 0 ): void { } $post = get_post( $post_id ); - if ( ! $post ) { return; } - $new_content = ''; - $has_updates = false; + $next_note_id_at = strpos( $post->post_content, '"noteId"' ); + if ( false === $next_note_id_at ) { + return; + } + + $replacements = array(); $block_processor = new WP_Block_Processor( $post->post_content ); while ( $block_processor->next_block() ) { - $block = $block_processor->extract_full_block_and_advance(); + $span = $block_processor->get_span(); - if ( $this->update_note_ids_in_block_tree( $block ) ) { - $has_updates = true; + if ( $next_note_id_at > ( $span->start + $span->length ) ) { + continue; } - $new_content .= serialize_block( $block ); - } + $next_note_id_at = strpos( $post->post_content, '"noteId"', $next_note_id_at + 1 ); + $attributes = $block_processor->allocate_and_return_parsed_attributes(); + $old_note_id = $attributes['metadata']['noteId'] ?? null; - if ( $has_updates ) { - wp_update_post( - array( - 'ID' => $post_id, - 'post_content' => $new_content, - ) + if ( + ! ( is_string( $old_note_id ) || is_int( $old_note_id ) ) || + ! isset( $this->processed_comments[ $old_note_id ] ) + ) { + continue; + } + + $attributes['metadata']['noteId'] = $this->processed_comments[ $old_note_id ]; + $json_string = wp_json_encode( $attributes ); + $void = 'void' === $block_processor->get_delimiter_type() ? '/' : ''; + + $replacements[] = new WP_HTML_Text_Replacement( + $span->start, + $span->length, + "" ); } - } - /** - * Recursively updates noteId references in a block tree. - * - * @param array $block A single block from the parsed block tree. - * @return bool Whether any block was updated. - */ - private function update_note_ids_in_block_tree( array &$block ) { - $updated = false; - - if ( isset( $block['attrs']['metadata']['noteId'] ) ) { - $old_note_id = $block['attrs']['metadata']['noteId']; - if ( isset( $this->processed_comments[ $old_note_id ] ) ) { - $block['attrs']['metadata']['noteId'] = $this->processed_comments[ $old_note_id ]; - $updated = true; - } + if ( empty( $replacements ) ) { + return; } - if ( ! empty( $block['innerBlocks'] ) ) { - foreach ( $block['innerBlocks'] as &$inner_block ) { - if ( $this->update_note_ids_in_block_tree( $inner_block ) ) { - $updated = true; - } + $stitcher_class = new class ( $post->post_content ) extends WP_HTML_Tag_Processor { + public function stitch( $updates ) { + $this->lexical_updates = $updates; + return $this->get_updated_html(); } - } + }; - return $updated; + wp_update_post( + array( + 'ID' => $post_id, + 'post_content' => $stitcher_class->stitch( $replacements ) + ) + ); } /** From 10334083a3464888106ad9612a8b757865dec7c2 Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Mon, 2 Mar 2026 11:16:26 +0530 Subject: [PATCH 06/12] Shorten the function doc comment --- src/class-wp-import.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/class-wp-import.php b/src/class-wp-import.php index 7d1d1eeb..50caeda3 100644 --- a/src/class-wp-import.php +++ b/src/class-wp-import.php @@ -1148,20 +1148,6 @@ protected function process_post_comment_metas( $comment_id, $commentmeta ) { /** * Remaps noteId references in block metadata after note-type comments are imported. * - * During import, note-type comments receive new auto-incremented IDs on the destination - * site. Block metadata may reference those comment IDs via a `noteId` attribute, e.g.: - * - * - * - * This method uses WP_Block_Processor to walk every block opener in the post content, - * checks whether its `metadata.noteId` matches an old comment ID recorded in - * `$this->processed_comments`, and — if so — replaces it with the new ID. Updated - * blocks are collected as WP_HTML_Text_Replacement objects and applied back to the - * raw post content in one pass before saving. - * - * Skips the post entirely when no `"noteId"` string is present in the content, or - * when WP_Block_Processor is unavailable. - * * @param int $post_id ID of the post whose block content should be updated. * @return void */ From 8db9ccff672e9c053c40665bd1c7175a904171c6 Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Wed, 4 Mar 2026 11:30:58 +0530 Subject: [PATCH 07/12] Update remapping notes function to use block_parser and use string operations --- src/class-wp-import.php | 76 ++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/src/class-wp-import.php b/src/class-wp-import.php index 50caeda3..88705b66 100644 --- a/src/class-wp-import.php +++ b/src/class-wp-import.php @@ -1156,33 +1156,38 @@ protected function update_block_note_ids( int $post_id = 0 ): void { return; } - if ( ! class_exists( 'WP_Block_Processor' ) ) { - return; - } - $post = get_post( $post_id ); if ( ! $post ) { return; } - $next_note_id_at = strpos( $post->post_content, '"noteId"' ); - if ( false === $next_note_id_at ) { + $is_contain_notes = strpos( $post->post_content, '"noteId"' ); + if ( false === $is_contain_notes ) { return; } - $replacements = array(); - $block_processor = new WP_Block_Processor( $post->post_content ); - while ( $block_processor->next_block() ) { - $span = $block_processor->get_span(); + // @todo Replace with WP_HTML_Tag_Processor or WP_Block_Processor once minimum version support is 6.2 or 6.9 respectively. + $parser = new WP_Block_Parser(); + $parser->document = $post->post_content; + $parser->offset = 0; + $replacements = array(); + + do { + $next_token = $parser->next_token(); + list( $token_type, $block_name, $attrs, $start_offset, $token_length ) = $next_token; + + if ( 'no-more-tokens' === $token_type ) { + break; + } + + $parser->offset = $start_offset + $token_length; - if ( $next_note_id_at > ( $span->start + $span->length ) ) { + if ( 'block-opener' !== $token_type && 'void-block' !== $token_type ) { continue; } - $next_note_id_at = strpos( $post->post_content, '"noteId"', $next_note_id_at + 1 ); - $attributes = $block_processor->allocate_and_return_parsed_attributes(); - $old_note_id = $attributes['metadata']['noteId'] ?? null; + $old_note_id = $attrs['metadata']['noteId'] ?? null; if ( ! ( is_string( $old_note_id ) || is_int( $old_note_id ) ) || @@ -1191,32 +1196,41 @@ protected function update_block_note_ids( int $post_id = 0 ): void { continue; } - $attributes['metadata']['noteId'] = $this->processed_comments[ $old_note_id ]; - $json_string = wp_json_encode( $attributes ); - $void = 'void' === $block_processor->get_delimiter_type() ? '/' : ''; + $attribute_string = substr( $post->post_content, $start_offset, $token_length ); + $attribute_json_start = strcspn( $attribute_string, '{' ); + $attribute_json_end = strrpos( $attribute_string, '}' ); - $replacements[] = new WP_HTML_Text_Replacement( - $span->start, - $span->length, - "" - ); - } + if ( false === $attribute_json_end || $attribute_json_start >= $attribute_json_end ) { + continue; + } + + $json_start = $start_offset + $attribute_json_start; + $json_length = $attribute_json_end - $attribute_json_start + 1; + + $attrs['metadata']['noteId'] = $this->processed_comments[ $old_note_id ]; + $replacements[] = array( $json_start, $json_length, serialize_block_attributes( $attrs ) ); + + } while ( 'no-more-tokens' !== $token_type ); if ( empty( $replacements ) ) { return; } - $stitcher_class = new class ( $post->post_content ) extends WP_HTML_Tag_Processor { - public function stitch( $updates ) { - $this->lexical_updates = $updates; - return $this->get_updated_html(); - } - }; + // Apply replacements in reverse order to avoid affecting offsets of later replacements. + $replacements = array_reverse( $replacements ); + $updated_content = $post->post_content; + + // Loop through each replacement and update the content string with the new JSON attributes. + foreach ( $replacements as $replacement ) { + list( $offset, $length, $new_json ) = $replacement; + $updated_content = substr_replace( $updated_content, $new_json, $offset, $length ); + } wp_update_post( - array( + // Cast to object to ensure wp_update_post() will add the required slashes. + (object) array( 'ID' => $post_id, - 'post_content' => $stitcher_class->stitch( $replacements ) + 'post_content' => $updated_content, ) ); } From ba2fdc8112decefd8f4cf8a54121c91222642ad3 Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Wed, 4 Mar 2026 11:31:55 +0530 Subject: [PATCH 08/12] Remove extra line --- src/class-wp-import.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/class-wp-import.php b/src/class-wp-import.php index 88705b66..b3c0d400 100644 --- a/src/class-wp-import.php +++ b/src/class-wp-import.php @@ -1166,7 +1166,6 @@ protected function update_block_note_ids( int $post_id = 0 ): void { return; } - // @todo Replace with WP_HTML_Tag_Processor or WP_Block_Processor once minimum version support is 6.2 or 6.9 respectively. $parser = new WP_Block_Parser(); $parser->document = $post->post_content; From dccc96b8c5d8c3eed4a7f59b29022d872aec0b53 Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Mon, 23 Mar 2026 13:02:59 +0530 Subject: [PATCH 09/12] Address feedbacks and build replacements --- src/class-wp-import.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/class-wp-import.php b/src/class-wp-import.php index b3c0d400..f4e900e4 100644 --- a/src/class-wp-import.php +++ b/src/class-wp-import.php @@ -1170,9 +1170,10 @@ protected function update_block_note_ids( int $post_id = 0 ): void { $parser = new WP_Block_Parser(); $parser->document = $post->post_content; $parser->offset = 0; + $end = strlen( $post->post_content ); $replacements = array(); - do { + while ( $parser->offset < $end ) { $next_token = $parser->next_token(); list( $token_type, $block_name, $attrs, $start_offset, $token_length ) = $next_token; @@ -1208,23 +1209,26 @@ protected function update_block_note_ids( int $post_id = 0 ): void { $attrs['metadata']['noteId'] = $this->processed_comments[ $old_note_id ]; $replacements[] = array( $json_start, $json_length, serialize_block_attributes( $attrs ) ); - - } while ( 'no-more-tokens' !== $token_type ); + } if ( empty( $replacements ) ) { return; } - // Apply replacements in reverse order to avoid affecting offsets of later replacements. - $replacements = array_reverse( $replacements ); - $updated_content = $post->post_content; + $post_content = $post->post_content; + $updated_content = ''; + $was_at = 0; - // Loop through each replacement and update the content string with the new JSON attributes. foreach ( $replacements as $replacement ) { list( $offset, $length, $new_json ) = $replacement; - $updated_content = substr_replace( $updated_content, $new_json, $offset, $length ); + + $pre_length = $offset - $was_at; + $updated_content .= substr( $post_content, $was_at, $pre_length ) . $new_json; + $was_at = $offset + $length; } + $updated_content .= substr( $post_content, $was_at ); + wp_update_post( // Cast to object to ensure wp_update_post() will add the required slashes. (object) array( From 91880cd4f59ff216ffb8f95194ab69e134f40d7f Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Tue, 24 Mar 2026 14:56:39 +0530 Subject: [PATCH 10/12] Address feedbacks --- src/class-wp-import.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/class-wp-import.php b/src/class-wp-import.php index f4e900e4..c475de1d 100644 --- a/src/class-wp-import.php +++ b/src/class-wp-import.php @@ -1161,8 +1161,7 @@ protected function update_block_note_ids( int $post_id = 0 ): void { return; } - $is_contain_notes = strpos( $post->post_content, '"noteId"' ); - if ( false === $is_contain_notes ) { + if ( ! str_contains( $post->post_content, '"noteId"' ) ) { return; } @@ -1200,7 +1199,7 @@ protected function update_block_note_ids( int $post_id = 0 ): void { $attribute_json_start = strcspn( $attribute_string, '{' ); $attribute_json_end = strrpos( $attribute_string, '}' ); - if ( false === $attribute_json_end || $attribute_json_start >= $attribute_json_end ) { + if ( false === $attribute_json_start || false === $attribute_json_end || $attribute_json_start >= $attribute_json_end ) { continue; } From e86f18575d954ce30649d4d2eeb53890c04201fc Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Tue, 24 Mar 2026 17:16:11 +0530 Subject: [PATCH 11/12] Add unit test case for functionality --- phpunit/data/wxr-with-note-comments.xml | 114 ++++++++++++++++++++++++ phpunit/tests/import.php | 37 ++++++++ 2 files changed, 151 insertions(+) create mode 100644 phpunit/data/wxr-with-note-comments.xml diff --git a/phpunit/data/wxr-with-note-comments.xml b/phpunit/data/wxr-with-note-comments.xml new file mode 100644 index 00000000..294c2db4 --- /dev/null +++ b/phpunit/data/wxr-with-note-comments.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + My WordPress Website + https://playground.wordpress.net/scope:creative-busy-garden + + Tue, 24 Mar 2026 10:39:41 +0000 + en-US + 1.2 + https://playground.wordpress.net/scope:creative-busy-garden + https://playground.wordpress.net/scope:creative-busy-garden + + 1 + https://wordpress.org/?v=6.9.4 + + + <![CDATA[Page with notes and comments]]> + https://playground.wordpress.net/scope:creative-busy-garden/page-with-notes-and-comments/ + Tue, 24 Mar 2026 10:38:09 +0000 + + https://playground.wordpress.net/scope:creative-busy-garden/?page_id=10 + + +

Note on heading 1

+ + + +

Paragraph with note 1

+]]>
+ + 10 + + + + + + + + + 0 + 0 + + + 0 + + 2 + + + http://127.0.0.1:34717 + + + + + + + 0 + 1 + + + 3 + + + http://127.0.0.1:34717 + + + + + + + 0 + 1 + + + 4 + + + http://127.0.0.1:34717 + + + + + + + 0 + 1 + +
+
+
diff --git a/phpunit/tests/import.php b/phpunit/tests/import.php index 3f037964..3b091d98 100644 --- a/phpunit/tests/import.php +++ b/phpunit/tests/import.php @@ -374,6 +374,43 @@ public static function data_flat_attachment_import_rewrites_attachment_url() { ); } + /** + * Test that note comment IDs are correctly remapped in block content. + * + * @covers WP_Import::update_block_note_ids + * @covers WP_Import::process_post_comments + */ + public function test_note_comment_ids_are_remapped_in_block_content() { + $authors = array( + 'admin' => 1, + ); + $this->_import_wp( DIR_TESTDATA_WP_IMPORTER . '/wxr-with-note-comments.xml', $authors ); + + $posts = get_posts( + array( + 'post_type' => 'page', + 'post_status' => 'publish', + 'title' => 'Page with notes and comments', + ) + ); + $post = $posts[0]; + $comments = get_comments( + array( + 'post_id' => $post->ID, + 'type' => 'note', + ) + ); + + $new_comment_ids = array_map( 'intval', wp_list_pluck( $comments, 'comment_ID' ) ); + + $this->assertStringNotContainsString( '{"noteId":2}', $post->post_content, 'Old noteId 2 should have been remapped.' ); + $this->assertStringNotContainsString( '{"noteId":3}', $post->post_content, 'Old noteId 3 should have been remapped.' ); + + foreach ( $new_comment_ids as $new_id ) { + $this->assertStringContainsString( '{"noteId":' . $new_id . '}', $post->post_content, "New noteId $new_id should be present in block content." ); + } + } + /** * Provides a mocked HTTP response when the importer downloads attachments. * From 244e6273b674d0dca65283335755eb4be4c56d88 Mon Sep 17 00:00:00 2001 From: hbhalodia Date: Tue, 24 Mar 2026 22:42:25 +0530 Subject: [PATCH 12/12] Revert condition check for attribute_start --- src/class-wp-import.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class-wp-import.php b/src/class-wp-import.php index c475de1d..9d01f4b8 100644 --- a/src/class-wp-import.php +++ b/src/class-wp-import.php @@ -1199,7 +1199,7 @@ protected function update_block_note_ids( int $post_id = 0 ): void { $attribute_json_start = strcspn( $attribute_string, '{' ); $attribute_json_end = strrpos( $attribute_string, '}' ); - if ( false === $attribute_json_start || false === $attribute_json_end || $attribute_json_start >= $attribute_json_end ) { + if ( false === $attribute_json_end || $attribute_json_start >= $attribute_json_end ) { continue; }