From 55d1ec4a40c295e9bed0f8524886264eca13677f Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Wed, 19 Nov 2025 10:32:43 +0100 Subject: [PATCH 1/5] Handle array input in get_object_title method Updated get_object_title to return an empty string if the input is an array, improving robustness when handling different types of activity objects. --- includes/collection/class-inbox.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/collection/class-inbox.php b/includes/collection/class-inbox.php index e75c65417..c079bc5d6 100644 --- a/includes/collection/class-inbox.php +++ b/includes/collection/class-inbox.php @@ -139,12 +139,12 @@ public static function add( $activity, $recipients ) { /** * Get the title of an activity recursively. * - * @param Activity|Base_Object $activity_object The activity object. + * @param Activity|Base_Object|array $activity_object The activity object. * * @return string The title. */ private static function get_object_title( $activity_object ) { - if ( ! $activity_object ) { + if ( ! $activity_object || is_array( $activity_object ) ) { return ''; } From c2599fe22daf115633a496374f81ca40d2db4535 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Wed, 19 Nov 2025 10:37:18 +0100 Subject: [PATCH 2/5] Add tests for get_object_title array handling Add comprehensive test coverage for the get_object_title method's handling of different object types: - Array objects (the bug fix case) - Null objects - String URL objects - Objects with name property - Objects with content but no name All tests verify that inbox posts are created correctly without errors regardless of the object type. --- .../includes/collection/class-test-inbox.php | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/tests/phpunit/tests/includes/collection/class-test-inbox.php b/tests/phpunit/tests/includes/collection/class-test-inbox.php index d3733d423..572c320cf 100644 --- a/tests/phpunit/tests/includes/collection/class-test-inbox.php +++ b/tests/phpunit/tests/includes/collection/class-test-inbox.php @@ -858,6 +858,153 @@ public function test_deduplicate_only_matches_specific_guid() { $this->assertEquals( 2, $count_second, 'Should still have two posts with second-activity GUID (not deduplicated)' ); } + /** + * Test adding activity when object is an array. + * + * This test verifies that the inbox can handle activities where get_object() + * returns an array instead of an object, which can happen with certain + * ActivityPub implementations. + * + * @covers ::add + */ + public function test_add_activity_with_array_object() { + // Create an activity with an array as the object. + $activity = new Activity(); + $activity->set_id( 'https://remote.example.com/activities/array-object' ); + $activity->set_type( 'Create' ); + $activity->set_actor( 'https://remote.example.com/users/testuser' ); + + // Set object as an array (this can happen with certain implementations). + $activity->set_object( + array( + 'id' => 'https://remote.example.com/objects/array-test', + 'type' => 'Note', + 'content' => 'Test content', + ) + ); + + $user_id = 1; + + // Add activity to inbox - should not throw an error. + $inbox_id = Inbox::add( $activity, $user_id ); + + $this->assertIsInt( $inbox_id ); + $this->assertGreaterThan( 0, $inbox_id ); + + // Verify the post was created with empty title (since array doesn't have get_name()). + $post = \get_post( $inbox_id ); + $this->assertInstanceOf( 'WP_Post', $post ); + $this->assertEquals( Inbox::POST_TYPE, $post->post_type ); + + // Post title should be "[Create] " (activity type with no object title). + $this->assertStringStartsWith( '[Create]', $post->post_title ); + } + + /** + * Test adding activity when object is null. + * + * @covers ::add + */ + public function test_add_activity_with_null_object() { + $activity = new Activity(); + $activity->set_id( 'https://remote.example.com/activities/null-object' ); + $activity->set_type( 'Delete' ); + $activity->set_actor( 'https://remote.example.com/users/testuser' ); + // Don't set any object - it will be null. + + $inbox_id = Inbox::add( $activity, 1 ); + + $this->assertIsInt( $inbox_id ); + $this->assertGreaterThan( 0, $inbox_id ); + + // Post title should be "[Delete] " with no object title. + $post = \get_post( $inbox_id ); + $this->assertStringStartsWith( '[Delete]', $post->post_title ); + } + + /** + * Test adding activity when object is a string URL. + * + * @covers ::add + */ + public function test_add_activity_with_string_object() { + // Create a post to reference. + $post_id = self::factory()->post->create( + array( + 'post_title' => 'Referenced Post', + 'post_status' => 'publish', + ) + ); + $post_url = \get_permalink( $post_id ); + + $activity = new Activity(); + $activity->set_id( 'https://remote.example.com/activities/string-object' ); + $activity->set_type( 'Like' ); + $activity->set_actor( 'https://remote.example.com/users/testuser' ); + $activity->set_object( $post_url ); // String URL. + + $inbox_id = Inbox::add( $activity, 1 ); + + $this->assertIsInt( $inbox_id ); + + // Post title should include the referenced post title. + $post = \get_post( $inbox_id ); + $this->assertStringContainsString( 'Referenced Post', $post->post_title ); + } + + /** + * Test adding activity with object that has name property. + * + * @covers ::add + */ + public function test_add_activity_with_object_name() { + $activity = new Activity(); + $activity->set_id( 'https://remote.example.com/activities/object-name' ); + $activity->set_type( 'Create' ); + $activity->set_actor( 'https://remote.example.com/users/testuser' ); + + $object = new Base_Object(); + $object->set_id( 'https://remote.example.com/objects/named' ); + $object->set_type( 'Note' ); + $object->set_name( 'My Note Title' ); + $object->set_content( 'This is the content' ); + $activity->set_object( $object ); + + $inbox_id = Inbox::add( $activity, 1 ); + + $this->assertIsInt( $inbox_id ); + + // Post title should include the object name. + $post = \get_post( $inbox_id ); + $this->assertStringContainsString( 'My Note Title', $post->post_title ); + } + + /** + * Test adding activity with object that has content but no name. + * + * @covers ::add + */ + public function test_add_activity_with_object_content_no_name() { + $activity = new Activity(); + $activity->set_id( 'https://remote.example.com/activities/object-content' ); + $activity->set_type( 'Create' ); + $activity->set_actor( 'https://remote.example.com/users/testuser' ); + + $object = new Base_Object(); + $object->set_id( 'https://remote.example.com/objects/content-only' ); + $object->set_type( 'Note' ); + $object->set_content( 'This is the content without a name' ); + $activity->set_object( $object ); + + $inbox_id = Inbox::add( $activity, 1 ); + + $this->assertIsInt( $inbox_id ); + + // Post title should include part of the content (since no name). + $post = \get_post( $inbox_id ); + $this->assertStringContainsString( 'This is the content', $post->post_title ); + } + /** * Test adding Like activity with trailing slash in object URL. * From 443a3f8b75640a62f3460217a8033cdc647d81b4 Mon Sep 17 00:00:00 2001 From: Automattic Bot Date: Wed, 19 Nov 2025 11:47:12 +0200 Subject: [PATCH 3/5] Add changelog --- .github/changelog/2502-from-description | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .github/changelog/2502-from-description diff --git a/.github/changelog/2502-from-description b/.github/changelog/2502-from-description new file mode 100644 index 000000000..3cf4fdc33 --- /dev/null +++ b/.github/changelog/2502-from-description @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Improved handling of unusual activity data to avoid errors when activities contain unexpected formats. From 5e80ecb3673d358edc7597fa45a5741d3deab2a0 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Wed, 19 Nov 2025 15:05:35 +0100 Subject: [PATCH 4/5] Add test for Flag activity with array of URLs Introduces a unit test to verify that the inbox can handle Flag activities where the object is an array of URLs, reflecting real-world Mastodon moderation report scenarios. Ensures that such activities are processed without errors and the corresponding post is created correctly. --- .../includes/collection/class-test-inbox.php | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/phpunit/tests/includes/collection/class-test-inbox.php b/tests/phpunit/tests/includes/collection/class-test-inbox.php index 572c320cf..8df731975 100644 --- a/tests/phpunit/tests/includes/collection/class-test-inbox.php +++ b/tests/phpunit/tests/includes/collection/class-test-inbox.php @@ -900,6 +900,48 @@ public function test_add_activity_with_array_object() { $this->assertStringStartsWith( '[Create]', $post->post_title ); } + /** + * Test adding Flag activity with array of URLs as object. + * + * This test verifies that the inbox can handle Flag activities (used for + * reporting content) where the object is an array of URLs, which is a + * real-world scenario from Mastodon moderation reports. + * + * @covers ::add + */ + public function test_add_flag_activity_with_url_array() { + // Create a Flag activity based on real-world Mastodon moderation report. + $activity = new Activity(); + $activity->set_id( 'https://mastodon.social/c35aa724-e6b6-4266-b85f-f27d84b166f9' ); + $activity->set_type( 'Flag' ); + $activity->set_actor( 'https://mastodon.social/actor' ); + $activity->set_content( '' ); // Flag activities often have empty content. + + // Set object as an array of URLs (actor being reported + content being reported). + $activity->set_object( + array( + 'https://skydancingblog.com/@skydancingblog.com', + 'https://skydancingblog.com/?p=211771', + ) + ); + + $user_id = 1; + + // Add activity to inbox - should not throw an error despite array object. + $inbox_id = Inbox::add( $activity, $user_id ); + + $this->assertIsInt( $inbox_id ); + $this->assertGreaterThan( 0, $inbox_id ); + + // Verify the post was created. + $post = \get_post( $inbox_id ); + $this->assertInstanceOf( 'WP_Post', $post ); + $this->assertEquals( Inbox::POST_TYPE, $post->post_type ); + + // Post title should be "[Flag] " (activity type with no object title from array). + $this->assertStringStartsWith( '[Flag]', $post->post_title ); + } + /** * Test adding activity when object is null. * From d7c89f54ca13077c8ad1251b962de8099628b353 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Wed, 19 Nov 2025 15:16:44 +0100 Subject: [PATCH 5/5] Update test data in Flag activity test Replaces Mastodon-specific URLs with generic example URLs in the test_add_flag_activity_with_url_array test to improve clarity and generalize the test case. --- .../tests/includes/collection/class-test-inbox.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/phpunit/tests/includes/collection/class-test-inbox.php b/tests/phpunit/tests/includes/collection/class-test-inbox.php index 8df731975..d0f1f9c34 100644 --- a/tests/phpunit/tests/includes/collection/class-test-inbox.php +++ b/tests/phpunit/tests/includes/collection/class-test-inbox.php @@ -910,18 +910,18 @@ public function test_add_activity_with_array_object() { * @covers ::add */ public function test_add_flag_activity_with_url_array() { - // Create a Flag activity based on real-world Mastodon moderation report. + // Create a Flag activity similar to moderation reports. $activity = new Activity(); - $activity->set_id( 'https://mastodon.social/c35aa724-e6b6-4266-b85f-f27d84b166f9' ); + $activity->set_id( 'https://remote.example.com/activities/flag-report' ); $activity->set_type( 'Flag' ); - $activity->set_actor( 'https://mastodon.social/actor' ); + $activity->set_actor( 'https://remote.example.com/users/reporter' ); $activity->set_content( '' ); // Flag activities often have empty content. // Set object as an array of URLs (actor being reported + content being reported). $activity->set_object( array( - 'https://skydancingblog.com/@skydancingblog.com', - 'https://skydancingblog.com/?p=211771', + 'https://example.org/users/reported-user', + 'https://example.org/posts/12345', ) );