diff --git a/CHANGELOG.md b/CHANGELOG.md
index e1128d138..6097d2748 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Undefined array key warnings in various places
* Fetching replies from the same instance for Enable Mastodon Apps
+* Image captions not being included in the ActivityPub representation when the image is attached to the post
## [4.6.0] - 2024-12-20
diff --git a/includes/transformer/class-post.php b/includes/transformer/class-post.php
index 894012320..f3cbcf960 100644
--- a/includes/transformer/class-post.php
+++ b/includes/transformer/class-post.php
@@ -454,10 +454,21 @@ protected function get_media_from_blocks( $blocks, $media ) {
$alt = $match[2];
}
- $media['image'][] = array(
- 'id' => $block['attrs']['id'],
- 'alt' => $alt,
- );
+ $found = false;
+ foreach ( $media['image'] as $i => $image ) {
+ if ( $image['id'] === $block['attrs']['id'] ) {
+ $media['image'][ $i ]['alt'] = $alt;
+ $found = true;
+ break;
+ }
+ }
+
+ if ( ! $found ) {
+ $media['image'][] = array(
+ 'id' => $block['attrs']['id'],
+ 'alt' => $alt,
+ );
+ }
}
break;
case 'core/audio':
diff --git a/readme.txt b/readme.txt
index 19675da99..88bd189a3 100644
--- a/readme.txt
+++ b/readme.txt
@@ -138,6 +138,7 @@ For reasons of data protection, it is not possible to see the followers of other
* Changed: Hide ActivityPub post meta keys from the custom Fields UI
* Fixed: Undefined array key warnings in various places
* Fixed: Fetching replies from the same instance for Enable Mastodon Apps
+* Fixed: Image captions not being included in the ActivityPub representation when the image is attached to the post
= 4.6.0 =
diff --git a/tests/includes/transformer/class-test-post.php b/tests/includes/transformer/class-test-post.php
index 6feb0fc22..a6a07202c 100644
--- a/tests/includes/transformer/class-test-post.php
+++ b/tests/includes/transformer/class-test-post.php
@@ -387,56 +387,105 @@ public function test_block_attachments_with_fallback() {
}
/**
- * Saves an attachment.
- *
- * @param string $file The file name to create attachment object for.
- * @param int $parent_id ID of the post to attach the file to.
+ * Test get_media_from_blocks adds alt text to existing images.
*
- * @return int|WP_Error The attachment ID on success. The value 0 or WP_Error on failure.
+ * @covers ::get_media_from_blocks
*/
- public function create_upload_object( $file, $parent_id = 0 ) {
- if ( ! class_exists( 'WP_Filesystem_Direct' ) ) {
- require ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
- require ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
- }
+ public function test_get_media_from_blocks_adds_alt_text_to_existing_images() {
+ $post_id = self::factory()->post->create(
+ array(
+ 'post_content' => '',
+ )
+ );
+ $post = get_post( $post_id );
- $dest = dirname( $file ) . DIRECTORY_SEPARATOR . 'test-temp.jpg';
- $fs = new \WP_Filesystem_Direct( array() );
- $fs->copy( $file, $dest );
+ $transformer = new Post( $post );
+ $media = array(
+ 'image' => array(
+ array(
+ 'id' => 123,
+ 'alt' => '',
+ ),
+ ),
+ 'audio' => array(),
+ 'video' => array(),
+ );
- $file = $dest;
+ $reflection = new \ReflectionClass( Post::class );
+ $method = $reflection->getMethod( 'get_media_from_blocks' );
+ $method->setAccessible( true );
- $file_array = array(
- 'name' => wp_basename( $file ),
- 'tmp_name' => $file,
+ $blocks = parse_blocks( $post->post_content );
+ $result = $method->invoke( $transformer, $blocks, $media );
+
+ $this->assertSame( 'Test alt text', $result['image'][0]['alt'] );
+ $this->assertSame( 123, $result['image'][0]['id'] );
+ }
+
+ /**
+ * Test get_media_from_blocks adds new image when none exist.
+ *
+ * @covers ::get_media_from_blocks
+ */
+ public function test_get_media_from_blocks_adds_new_image() {
+ $post_id = self::factory()->post->create(
+ array(
+ 'post_content' => '',
+ )
);
+ $post = get_post( $post_id );
- $upload = wp_handle_sideload( $file_array, array( 'test_form' => false ) );
+ $transformer = new Post( $post );
+ $media = array(
+ 'image' => array(),
+ 'audio' => array(),
+ 'video' => array(),
+ );
- $type = '';
- if ( ! empty( $upload['type'] ) ) {
- $type = $upload['type'];
- } else {
- $mime = wp_check_filetype( $upload['file'] );
- if ( $mime ) {
- $type = $mime['type'];
- }
- }
+ $reflection = new \ReflectionClass( Post::class );
+ $method = $reflection->getMethod( 'get_media_from_blocks' );
+ $method->setAccessible( true );
- $attachment = array(
- 'post_title' => wp_basename( $upload['file'] ),
- 'post_content' => '',
- 'post_type' => 'attachment',
- 'post_parent' => $parent_id,
- 'post_mime_type' => $type,
- 'guid' => $upload['url'],
+ $blocks = parse_blocks( $post->post_content );
+ $result = $method->invoke( $transformer, $blocks, $media );
+
+ $this->assertCount( 1, $result['image'] );
+ $this->assertSame( 123, $result['image'][0]['id'] );
+ $this->assertSame( 'Test alt text', $result['image'][0]['alt'] );
+ }
+
+ /**
+ * Test get_media_from_blocks handles multiple blocks correctly.
+ *
+ * @covers ::get_media_from_blocks
+ */
+ public function test_get_media_from_blocks_handles_multiple_blocks() {
+ $post_id = self::factory()->post->create(
+ array(
+ 'post_content' => '',
+ )
);
+ $post = get_post( $post_id );
- // Save the data.
- $id = wp_insert_attachment( $attachment, $upload['file'], $parent_id );
- wp_update_attachment_metadata( $id, @wp_generate_attachment_metadata( $id, $upload['file'] ) ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
+ $transformer = new Post( $post );
+ $media = array(
+ 'image' => array(),
+ 'audio' => array(),
+ 'video' => array(),
+ );
- return $id;
+ $reflection = new \ReflectionClass( Post::class );
+ $method = $reflection->getMethod( 'get_media_from_blocks' );
+ $method->setAccessible( true );
+
+ $blocks = parse_blocks( $post->post_content );
+ $result = $method->invoke( $transformer, $blocks, $media );
+
+ $this->assertCount( 2, $result['image'] );
+ $this->assertSame( 123, $result['image'][0]['id'] );
+ $this->assertSame( 'Test alt 1', $result['image'][0]['alt'] );
+ $this->assertSame( 456, $result['image'][1]['id'] );
+ $this->assertSame( 'Test alt 2', $result['image'][1]['alt'] );
}
/**
@@ -457,7 +506,7 @@ public function test_get_icon() {
$attachment_id = $this->create_upload_object( dirname( __DIR__, 2 ) . '/assets/test.jpg' );
// Set up reflection method.
- $reflection = new ReflectionClass( Post::class );
+ $reflection = new \ReflectionClass( Post::class );
$method = $reflection->getMethod( 'get_icon' );
$method->setAccessible( true );
@@ -513,4 +562,56 @@ public function test_get_icon() {
wp_delete_post( $post_id, true );
wp_delete_attachment( $attachment_id, true );
}
+
+ /**
+ * Saves an attachment.
+ *
+ * @param string $file The file name to create attachment object for.
+ * @param int $parent_id ID of the post to attach the file to.
+ * @return int|\WP_Error The attachment ID on success. The value 0 or WP_Error on failure.
+ */
+ public function create_upload_object( $file, $parent_id = 0 ) {
+ if ( ! class_exists( 'WP_Filesystem_Direct' ) ) {
+ require ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
+ require ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
+ }
+
+ $dest = dirname( $file ) . DIRECTORY_SEPARATOR . 'test-temp.jpg';
+ $fs = new \WP_Filesystem_Direct( array() );
+ $fs->copy( $file, $dest );
+
+ $file = $dest;
+
+ $file_array = array(
+ 'name' => wp_basename( $file ),
+ 'tmp_name' => $file,
+ );
+
+ $upload = wp_handle_sideload( $file_array, array( 'test_form' => false ) );
+
+ $type = '';
+ if ( ! empty( $upload['type'] ) ) {
+ $type = $upload['type'];
+ } else {
+ $mime = wp_check_filetype( $upload['file'] );
+ if ( $mime ) {
+ $type = $mime['type'];
+ }
+ }
+
+ $attachment = array(
+ 'post_title' => wp_basename( $upload['file'] ),
+ 'post_content' => '',
+ 'post_type' => 'attachment',
+ 'post_parent' => $parent_id,
+ 'post_mime_type' => $type,
+ 'guid' => $upload['url'],
+ );
+
+ // Save the data.
+ $id = wp_insert_attachment( $attachment, $upload['file'], $parent_id );
+ wp_update_attachment_metadata( $id, @wp_generate_attachment_metadata( $id, $upload['file'] ) ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
+
+ return $id;
+ }
}