Skip to content
Open
95 changes: 95 additions & 0 deletions src/class-wp-import.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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'] ) ) {
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -1139,6 +1145,95 @@ protected function process_post_comment_metas( $comment_id, $commentmeta ) {
}
}

/**
* Remaps noteId references in block metadata after note-type comments are imported.
*
* @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 {
if ( empty( $this->processed_comments ) ) {
return;
}

$post = get_post( $post_id );
if ( ! $post ) {
return;
}

$is_contain_notes = strpos( $post->post_content, '"noteId"' );
Comment thread
hbhalodia marked this conversation as resolved.
Outdated
if ( false === $is_contain_notes ) {
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;
$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 ( 'block-opener' !== $token_type && 'void-block' !== $token_type ) {
continue;
}

$old_note_id = $attrs['metadata']['noteId'] ?? null;

if (
! ( is_string( $old_note_id ) || is_int( $old_note_id ) ) ||
! isset( $this->processed_comments[ $old_note_id ] )
) {
continue;
}

$attribute_string = substr( $post->post_content, $start_offset, $token_length );
$attribute_json_start = strcspn( $attribute_string, '{' );
$attribute_json_end = strrpos( $attribute_string, '}' );

if ( false === $attribute_json_end || $attribute_json_start >= $attribute_json_end ) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the parser returned these attributes then we shouldn’t need the bounds-checking. it’s already been performed.

if we leave it in for the sake of explicitness, then there’s an error where the starting bound could be false and it will fail to abort.

so I think it might be appropriate to either remove this step entirely (it should never trigger here) or add false === $attribute_json_start to the conditions.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done Thanks,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only when I linked to this as an example for another PR did I notice that $attribute_json_start can never be false, only past the length of the $attribute_string.

so you had it right before and that was a review blunder on my part. it now makes more sense why the $start >= $end check was there. sorry!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, Have reverted the same.

Probably I could have thought of more of that case and should have replied before addressing that!

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 );
Comment thread
hbhalodia marked this conversation as resolved.
Outdated

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;

// 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 );
}
Comment thread
dmsnell marked this conversation as resolved.

wp_update_post(
// Cast to object to ensure wp_update_post() will add the required slashes.
(object) array(
'ID' => $post_id,
'post_content' => $updated_content,
)
);
}

/**
* Process a single comment meta entry for an imported comment.
*
Expand Down
Loading