From 1718294fa9b213fab3b6b166eade6c863857a857 Mon Sep 17 00:00:00 2001 From: Darin Kotter Date: Thu, 10 Oct 2024 14:48:19 -0600 Subject: [PATCH 1/7] After we download images to a site, update the URLs in the content if using the block editor and image blocks --- .../NetworkSiteConnection.php | 2 +- includes/utils.php | 88 +++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/includes/classes/InternalConnections/NetworkSiteConnection.php b/includes/classes/InternalConnections/NetworkSiteConnection.php index 0428347f7..ee3d5a98f 100644 --- a/includes/classes/InternalConnections/NetworkSiteConnection.php +++ b/includes/classes/InternalConnections/NetworkSiteConnection.php @@ -180,7 +180,7 @@ public function push( $post, $args = array() ) { */ if ( apply_filters( 'dt_push_post_media', true, $new_post_id, $post_media, $post_id, $args, $this ) ) { Utils\set_media( $new_post_id, $post_media, [ 'use_filesystem' => true ] ); - }; + } $media_errors = get_transient( 'dt_media_errors_' . $new_post_id ); diff --git a/includes/utils.php b/includes/utils.php index 3579a8d67..d4c49caa4 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -782,6 +782,11 @@ function set_media( $post_id, $media, $args = [] ) { set_meta( $image_id, $media_item['meta'] ); } + // Update media URLs in content. + if ( 'featured' !== $settings['media_handling'] ) { + update_content_image_urls( (int) $post_id, (int) $image_id, $media_item ); + } + // Transfer post properties wp_update_post( [ @@ -1031,6 +1036,89 @@ function process_media( $url, $post_id, $args = [] ) { return (int) $result; } +/** + * Update an image block with the new image information. + * + * @param array $blocks All blocks in a post. + * @param array $media_item The old media item details. + * @param int $image_id The new image ID. + * @return array + */ +function update_image_block_attributes( array $blocks, array $media_item, int $image_id ) { + // Find and update all image blocks that match the old image ID. + foreach ( $blocks as $key => $block ) { + // Recurse into inner blocks. + if ( ! empty( $block['innerBlocks'] ) ) { + $blocks[ $key ]['innerBlocks'] = update_image_block_attributes( $block['innerBlocks'], $media_item, $image_id ); + } + + // If the block is an image block and the ID matches, update the ID and URL. + if ( 'core/image' === $block['blockName'] && $media_item['id'] === $block['attrs']['id'] ) { + $blocks[ $key ]['attrs']['id'] = $image_id; + + $processor = new \WP_HTML_Tag_Processor( $blocks[ $key ]['innerHTML'] ); + + // Use the HTML API to update the image src and class. + if ( $processor->next_tag( 'img' ) ) { + $processor->set_attribute( 'src', wp_get_attachment_url( $image_id ) ); + $processor->add_class( 'wp-image-' . $image_id ); + $processor->remove_class( 'wp-image-' . $media_item['id'] ); + + $blocks[ $key ]['innerHTML'] = $processor->get_updated_html(); + $blocks[ $key ]['innerContent'][0] = $processor->get_updated_html(); + } + } + } + + return $blocks; +} + +/** + * For a specific image, update the old URL with the new one. + * + * @param int $post_id The post ID. + * @param int $image_id The new image ID. + * @param array $media_item The old media item details. + */ +function update_content_image_urls( int $post_id, int $image_id, array $media_item ) { + $dt_post = new DistributorPost( $post_id ); + + if ( ! $dt_post || ! $dt_post->has_blocks() ) { + return; + } + + /** + * Filter whether image URLS should be updated in the content. + * + * @since x.x.x + * @hook dt_update_content_image_urls + * + * @param {bool} true Whether image URLs should be updated. Default `true`. + * @param {int} $post_id The post ID. + * @param {int} $image_id The new image ID. + * @param {array} $media_item The old media item details. + * + * @return {bool} Whether image URLs should be updated. + */ + if ( ! apply_filters( 'dt_update_content_image_urls', true, $post_id, $image_id, $media_item ) ) { + return; + } + + // Parse out the blocks. + $blocks = parse_blocks( $dt_post->post->post_content ); + + // Update the image block attributes. + $blocks = update_image_block_attributes( $blocks, $media_item, $image_id ); + + // Update the post content. + wp_update_post( + [ + 'ID' => $post_id, + 'post_content' => serialize_blocks( $blocks ), + ] + ); +} + /** * Return whether a post type is compatible with the block editor. * From 414cc6817f8c665e42b999300d0b80a31588201d Mon Sep 17 00:00:00 2001 From: Darin Kotter Date: Thu, 10 Oct 2024 15:06:11 -0600 Subject: [PATCH 2/7] Update image URLs in the classic editor --- includes/utils.php | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/includes/utils.php b/includes/utils.php index d4c49caa4..967b90106 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -1083,7 +1083,7 @@ function update_image_block_attributes( array $blocks, array $media_item, int $i function update_content_image_urls( int $post_id, int $image_id, array $media_item ) { $dt_post = new DistributorPost( $post_id ); - if ( ! $dt_post || ! $dt_post->has_blocks() ) { + if ( ! $dt_post ) { return; } @@ -1104,6 +1104,29 @@ function update_content_image_urls( int $post_id, int $image_id, array $media_it return; } + // Process classic editor differently. + if ( ! $dt_post->has_blocks() ) { + $processor = new \WP_HTML_Tag_Processor( $dt_post->post->post_content ); + + while ( $processor->next_tag( 'img' ) ) { + $processor->set_attribute( 'src', wp_get_attachment_url( $image_id ) ); + $processor->add_class( 'wp-image-' . $image_id ); + $processor->remove_class( 'wp-image-' . $media_item['id'] ); + $processor->remove_attribute( 'srcset' ); + $processor->remove_attribute( 'sizes' ); + } + + // Update the post content. + wp_update_post( + [ + 'ID' => $post_id, + 'post_content' => $processor->get_updated_html(), + ] + ); + + return; + } + // Parse out the blocks. $blocks = parse_blocks( $dt_post->post->post_content ); From 0a3f6fa65613debf5781a6e045b6af5ae10a8e28 Mon Sep 17 00:00:00 2001 From: Darin Kotter Date: Thu, 10 Oct 2024 15:21:58 -0600 Subject: [PATCH 3/7] More efficient processing --- includes/utils.php | 62 +++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/includes/utils.php b/includes/utils.php index 967b90106..e54ac63de 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -1037,19 +1037,41 @@ function process_media( $url, $post_id, $args = [] ) { } /** - * Update an image block with the new image information. + * Find and update an image tag. + * + * @param string $content The post content. + * @param array $media_item The old media item details. + * @param int $image_id The new image ID. + * @return string + */ +function update_image_tag( string $content, array $media_item, int $image_id ) { + $processor = new \WP_HTML_Tag_Processor( $content ); + + while ( $processor->next_tag( 'img' ) ) { + $processor->set_attribute( 'src', wp_get_attachment_url( $image_id ) ); + $processor->add_class( 'wp-image-' . $image_id ); + $processor->remove_class( 'wp-image-' . $media_item['id'] ); + $processor->remove_attribute( 'srcset' ); + $processor->remove_attribute( 'sizes' ); + } + + return $processor->get_updated_html(); +} + +/** + * Find and update an image block. * * @param array $blocks All blocks in a post. * @param array $media_item The old media item details. * @param int $image_id The new image ID. * @return array */ -function update_image_block_attributes( array $blocks, array $media_item, int $image_id ) { +function update_image_block( array $blocks, array $media_item, int $image_id ) { // Find and update all image blocks that match the old image ID. foreach ( $blocks as $key => $block ) { // Recurse into inner blocks. if ( ! empty( $block['innerBlocks'] ) ) { - $blocks[ $key ]['innerBlocks'] = update_image_block_attributes( $block['innerBlocks'], $media_item, $image_id ); + $blocks[ $key ]['innerBlocks'] = update_image_block( $block['innerBlocks'], $media_item, $image_id ); } // If the block is an image block and the ID matches, update the ID and URL. @@ -1106,38 +1128,26 @@ function update_content_image_urls( int $post_id, int $image_id, array $media_it // Process classic editor differently. if ( ! $dt_post->has_blocks() ) { - $processor = new \WP_HTML_Tag_Processor( $dt_post->post->post_content ); - - while ( $processor->next_tag( 'img' ) ) { - $processor->set_attribute( 'src', wp_get_attachment_url( $image_id ) ); - $processor->add_class( 'wp-image-' . $image_id ); - $processor->remove_class( 'wp-image-' . $media_item['id'] ); - $processor->remove_attribute( 'srcset' ); - $processor->remove_attribute( 'sizes' ); - } + $content = update_image_tag( $dt_post->post->post_content, $media_item, $image_id ); + } else { + // Parse out the blocks. + $blocks = parse_blocks( $dt_post->post->post_content ); - // Update the post content. - wp_update_post( - [ - 'ID' => $post_id, - 'post_content' => $processor->get_updated_html(), - ] - ); + // Update the image block attributes. + $updated_blocks = update_image_block( $blocks, $media_item, $image_id ); + $content = serialize_blocks( $updated_blocks ); + } + // No need to update if the content wasn't modified. + if ( $content === $dt_post->post->post_content ) { return; } - // Parse out the blocks. - $blocks = parse_blocks( $dt_post->post->post_content ); - - // Update the image block attributes. - $blocks = update_image_block_attributes( $blocks, $media_item, $image_id ); - // Update the post content. wp_update_post( [ 'ID' => $post_id, - 'post_content' => serialize_blocks( $blocks ), + 'post_content' => $content, ] ); } From 7efd4a41b541906b044d5f3f33712b05f7ec7352 Mon Sep 17 00:00:00 2001 From: Darin Kotter Date: Fri, 11 Oct 2024 14:44:41 -0600 Subject: [PATCH 4/7] Instead of always using the full image size, try and use the same image size from the original content --- includes/utils.php | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/includes/utils.php b/includes/utils.php index e54ac63de..468faca54 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -1048,7 +1048,23 @@ function update_image_tag( string $content, array $media_item, int $image_id ) { $processor = new \WP_HTML_Tag_Processor( $content ); while ( $processor->next_tag( 'img' ) ) { - $processor->set_attribute( 'src', wp_get_attachment_url( $image_id ) ); + // Try to determine the image size from the size class WordPress adds. + $image_size = 'full'; + $classes = explode( ' ', $processor->get_attribute( 'class' ) ); + $size_classes = array_filter( + $classes, + function ( $image_class ) { + return false !== strpos( $image_class, 'size-' ); + } + ); + + if ( ! empty( $size_classes ) ) { + // If an image happens to have multiple size classes, just use the first. + $size_class = reset( $size_classes ); + $image_size = str_replace( 'size-', '', $size_class ); + } + + $processor->set_attribute( 'src', wp_get_attachment_image_url( $image_id, $image_size ) ); $processor->add_class( 'wp-image-' . $image_id ); $processor->remove_class( 'wp-image-' . $media_item['id'] ); $processor->remove_attribute( 'srcset' ); @@ -1076,13 +1092,15 @@ function update_image_block( array $blocks, array $media_item, int $image_id ) { // If the block is an image block and the ID matches, update the ID and URL. if ( 'core/image' === $block['blockName'] && $media_item['id'] === $block['attrs']['id'] ) { + $image_size = $block['attrs']['sizeSlug'] ?? 'full'; + $blocks[ $key ]['attrs']['id'] = $image_id; $processor = new \WP_HTML_Tag_Processor( $blocks[ $key ]['innerHTML'] ); // Use the HTML API to update the image src and class. if ( $processor->next_tag( 'img' ) ) { - $processor->set_attribute( 'src', wp_get_attachment_url( $image_id ) ); + $processor->set_attribute( 'src', wp_get_attachment_image_url( $image_id, $image_size ) ); $processor->add_class( 'wp-image-' . $image_id ); $processor->remove_class( 'wp-image-' . $media_item['id'] ); From 3e39ff270bf07496ec62207b4083c008b46ee3f1 Mon Sep 17 00:00:00 2001 From: Darin Kotter Date: Fri, 11 Oct 2024 15:02:54 -0600 Subject: [PATCH 5/7] Make things more efficient by only updating the post content once, after we've processed all image urls --- includes/utils.php | 51 +++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/includes/utils.php b/includes/utils.php index 468faca54..0f826ed51 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -734,6 +734,8 @@ function set_media( $post_id, $media, $args = [] ) { $media = ( false !== $featured_key ) ? array( $media[ $featured_key ] ) : array(); } + $image_urls_to_update = []; + foreach ( $media as $media_item ) { $args['source_file'] = $media_item['source_file']; @@ -782,9 +784,9 @@ function set_media( $post_id, $media, $args = [] ) { set_meta( $image_id, $media_item['meta'] ); } - // Update media URLs in content. - if ( 'featured' !== $settings['media_handling'] ) { - update_content_image_urls( (int) $post_id, (int) $image_id, $media_item ); + // Save the images that we need to try updating in the content. + if ( 'featured' !== $settings['media_handling'] ) { // TODO: do we want a new setting for this? + $image_urls_to_update[ $image_id ] = $media_item; } // Transfer post properties @@ -798,6 +800,11 @@ function set_media( $post_id, $media, $args = [] ) { ); } + // Update image URLs in content if needed. + if ( ! empty( $image_urls_to_update ) ) { + update_content_image_urls( (int) $post_id, $image_urls_to_update ); + } + if ( ! $found_featured_image ) { delete_post_meta( $post_id, '_thumbnail_id' ); } @@ -1114,13 +1121,12 @@ function update_image_block( array $blocks, array $media_item, int $image_id ) { } /** - * For a specific image, update the old URL with the new one. + * Update all old image URLs with the new ones. * * @param int $post_id The post ID. - * @param int $image_id The new image ID. - * @param array $media_item The old media item details. + * @param array $images The old image details. */ -function update_content_image_urls( int $post_id, int $image_id, array $media_item ) { +function update_content_image_urls( int $post_id, array $images ) { $dt_post = new DistributorPost( $post_id ); if ( ! $dt_post ) { @@ -1133,27 +1139,30 @@ function update_content_image_urls( int $post_id, int $image_id, array $media_it * @since x.x.x * @hook dt_update_content_image_urls * - * @param {bool} true Whether image URLs should be updated. Default `true`. - * @param {int} $post_id The post ID. - * @param {int} $image_id The new image ID. - * @param {array} $media_item The old media item details. + * @param {bool} true Whether image URLs should be updated. Default `true`. + * @param {int} $post_id The post ID. + * @param {array} $images The old image details. * * @return {bool} Whether image URLs should be updated. */ - if ( ! apply_filters( 'dt_update_content_image_urls', true, $post_id, $image_id, $media_item ) ) { + if ( ! apply_filters( 'dt_update_content_image_urls', true, $post_id, $images ) ) { return; } - // Process classic editor differently. - if ( ! $dt_post->has_blocks() ) { - $content = update_image_tag( $dt_post->post->post_content, $media_item, $image_id ); - } else { - // Parse out the blocks. - $blocks = parse_blocks( $dt_post->post->post_content ); + $content = $dt_post->post->post_content; + $has_blocks = $dt_post->has_blocks(); + + foreach ( $images as $image_id => $media_item ) { + // Process block and classic editor content differently. + if ( $has_blocks ) { + $blocks = parse_blocks( $content ); - // Update the image block attributes. - $updated_blocks = update_image_block( $blocks, $media_item, $image_id ); - $content = serialize_blocks( $updated_blocks ); + // Update the image block attributes. + $updated_blocks = update_image_block( $blocks, $media_item, $image_id ); + $content = serialize_blocks( $updated_blocks ); + } else { + $content = update_image_tag( $content, $media_item, $image_id ); + } } // No need to update if the content wasn't modified. From 49d66e6ce51998471656f1c50aa09ba1c2ac9530 Mon Sep 17 00:00:00 2001 From: Darin Kotter Date: Fri, 11 Oct 2024 15:07:54 -0600 Subject: [PATCH 6/7] Ensure we only update images in the classic editor if they match the old image ID --- includes/utils.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/includes/utils.php b/includes/utils.php index 0f826ed51..e4827912f 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -1055,9 +1055,16 @@ function update_image_tag( string $content, array $media_item, int $image_id ) { $processor = new \WP_HTML_Tag_Processor( $content ); while ( $processor->next_tag( 'img' ) ) { + $classes = explode( ' ', $processor->get_attribute( 'class' ) ?? ' ' ); + + // Only process the image that matches the old ID. + if ( ! is_array( $classes ) || ! in_array( 'wp-image-' . $media_item['id'], $classes, true ) ) { + continue; + } + // Try to determine the image size from the size class WordPress adds. $image_size = 'full'; - $classes = explode( ' ', $processor->get_attribute( 'class' ) ); + $classes = explode( ' ', $processor->get_attribute( 'class' ) ?? [] ); $size_classes = array_filter( $classes, function ( $image_class ) { From 3778154bb25da520f702a74b8266c678811237ae Mon Sep 17 00:00:00 2001 From: Darin Kotter Date: Fri, 11 Oct 2024 15:32:21 -0600 Subject: [PATCH 7/7] Don't update the image src if we don't have an image URL. Better fallback if we can't find a resized image --- includes/utils.php | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/includes/utils.php b/includes/utils.php index e4827912f..1a9ddfa5a 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -1058,7 +1058,10 @@ function update_image_tag( string $content, array $media_item, int $image_id ) { $classes = explode( ' ', $processor->get_attribute( 'class' ) ?? ' ' ); // Only process the image that matches the old ID. - if ( ! is_array( $classes ) || ! in_array( 'wp-image-' . $media_item['id'], $classes, true ) ) { + if ( + ! is_array( $classes ) || + ! in_array( 'wp-image-' . $media_item['id'], $classes, true ) + ) { continue; } @@ -1078,7 +1081,19 @@ function ( $image_class ) { $image_size = str_replace( 'size-', '', $size_class ); } - $processor->set_attribute( 'src', wp_get_attachment_image_url( $image_id, $image_size ) ); + $src = wp_get_attachment_image_url( $image_id, $image_size ); + + // If the image size can't be found, try to get the full size. + if ( ! $src ) { + $src = wp_get_attachment_image_url( $image_id, 'full' ); + + // If we still don't have an image, skip this block. + if ( ! $src ) { + continue; + } + } + + $processor->set_attribute( 'src', $src ); $processor->add_class( 'wp-image-' . $image_id ); $processor->remove_class( 'wp-image-' . $media_item['id'] ); $processor->remove_attribute( 'srcset' ); @@ -1114,7 +1129,19 @@ function update_image_block( array $blocks, array $media_item, int $image_id ) { // Use the HTML API to update the image src and class. if ( $processor->next_tag( 'img' ) ) { - $processor->set_attribute( 'src', wp_get_attachment_image_url( $image_id, $image_size ) ); + $src = wp_get_attachment_image_url( $image_id, $image_size ); + + // If the image size can't be found, try to get the full size. + if ( ! $src ) { + $src = wp_get_attachment_image_url( $image_id, 'full' ); + + // If we still don't have an image, skip this block. + if ( ! $src ) { + continue; + } + } + + $processor->set_attribute( 'src', $src ); $processor->add_class( 'wp-image-' . $image_id ); $processor->remove_class( 'wp-image-' . $media_item['id'] );