Skip to content

Commit

Permalink
Improved comment-type handling (#1072)
Browse files Browse the repository at this point in the history
  • Loading branch information
pfefferle authored Dec 12, 2024
1 parent cba6228 commit 253cfff
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 44 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Email templates for Likes and Reposts
* Improve Interactions moderation
* Compatibility with Akismet
* Comment type mapping for `Like` and `Announce`

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion includes/class-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ public static function comment_row_actions( $actions, $comment ) {
unset( $actions['quickedit'] );
}

if ( in_array( get_comment_type( $comment ), Comment::get_comment_type_names(), true ) ) {
if ( in_array( get_comment_type( $comment ), Comment::get_comment_type_slugs(), true ) ) {
unset( $actions['reply'] );
}

Expand Down
108 changes: 70 additions & 38 deletions includes/class-comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,27 @@ public static function enqueue_scripts() {
}
}

/**
* Get the comment type by activity type.
*
* @param string $activity_type The activity type.
*
* @return array|null The comment type.
*/
public static function get_comment_type_by_activity_type( $activity_type ) {
$activity_type = \strtolower( $activity_type );
$activity_type = \sanitize_key( $activity_type );
$comment_types = self::get_comment_types();

foreach ( $comment_types as $comment_type ) {
if ( in_array( $activity_type, $comment_type['activity_types'], true ) ) {
return $comment_type;
}
}

return null;
}

/**
* Return the registered custom comment types.
*
Expand All @@ -520,23 +541,39 @@ public static function get_comment_types() {
/**
* Is this a registered comment type.
*
* @param string $slug The name of the type.
* @param string $slug The slug of the type.
*
* @return boolean True if registered.
*/
public static function is_registered_comment_type( $slug ) {
$slug = strtolower( $slug );
$slug = sanitize_key( $slug );
$slug = \strtolower( $slug );
$slug = \sanitize_key( $slug );

return in_array( $slug, array_keys( self::get_comment_types() ), true );
$comment_types = self::get_comment_types();

return isset( $comment_types[ $slug ] );
}

/**
* Return the registered custom comment type slugs.
*
* @return array The registered custom comment type slugs.
*/
public static function get_comment_type_slugs() {
return array_keys( self::get_comment_types() );
}

/**
* Return the registered custom comment types names.
* Return the registered custom comment type slugs.
*
* @deprecated 4.5.0 Use get_comment_type_slugs instead.
*
* @return array The registered custom comment type names.
* @return array The registered custom comment type slugs.
*/
public static function get_comment_type_names() {
return array_values( wp_list_pluck( self::get_comment_types(), 'type' ) );
_deprecated_function( __METHOD__, '4.5.0', 'get_comment_type_slugs' );

return self::get_comment_type_slugs();
}

/**
Expand All @@ -552,22 +589,15 @@ public static function get_comment_type_names() {
* @return array The comment type.
*/
public static function get_comment_type( $type ) {
$type = strtolower( $type );
$type = sanitize_key( $type );
$types = self::get_comment_types();
$type = strtolower( $type );
$type = sanitize_key( $type );

$type_array = array();
$comment_types = self::get_comment_types();
$type_array = array();

// Check array keys.
if ( in_array( $type, array_keys( $types ), true ) ) {
$type_array = $types[ $type ];
} else { // Fall back to type attribute.
foreach ( $types as $item ) {
if ( $type === $item['type'] ) {
$type_array = $item;
break;
}
}
if ( in_array( $type, array_keys( $comment_types ), true ) ) {
$type_array = $comment_types[ $type ];
}

/**
Expand Down Expand Up @@ -609,28 +639,30 @@ public static function get_comment_type_attr( $type, $attr ) {
*/
public static function register_comment_types() {
register_comment_type(
'announce',
'repost',
array(
'label' => __( 'Reposts', 'activitypub' ),
'singular' => __( 'Repost', 'activitypub' ),
'description' => __( 'A repost on the indieweb is a post that is purely a 100% re-publication of another (typically someone else\'s) post.', 'activitypub' ),
'icon' => '♻️',
'class' => 'p-repost',
'type' => 'repost',
'excerpt' => __( '… reposted this!', 'activitypub' ),
'label' => __( 'Reposts', 'activitypub' ),
'singular' => __( 'Repost', 'activitypub' ),
'description' => __( 'A repost on the indieweb is a post that is purely a 100% re-publication of another (typically someone else\'s) post.', 'activitypub' ),
'icon' => '♻️',
'class' => 'p-repost',
'type' => 'repost',
'activity_types' => array( 'announce' ),
'excerpt' => __( '… reposted this!', 'activitypub' ),
)
);

register_comment_type(
'like',
array(
'label' => __( 'Likes', 'activitypub' ),
'singular' => __( 'Like', 'activitypub' ),
'description' => __( 'A like is a popular webaction button and in some cases post type on various silos such as Facebook and Instagram.', 'activitypub' ),
'icon' => '👍',
'class' => 'p-like',
'type' => 'like',
'excerpt' => __( '… liked this!', 'activitypub' ),
'label' => __( 'Likes', 'activitypub' ),
'singular' => __( 'Like', 'activitypub' ),
'description' => __( 'A like is a popular webaction button and in some cases post type on various silos such as Facebook and Instagram.', 'activitypub' ),
'icon' => '👍',
'class' => 'p-like',
'type' => 'like',
'activity_types' => array( 'like' ),
'excerpt' => __( '… liked this!', 'activitypub' ),
)
);
}
Expand All @@ -643,7 +675,7 @@ public static function register_comment_types() {
* @return array show avatars on Activities
*/
public static function get_avatar_comment_types( $types ) {
$comment_types = self::get_comment_type_names();
$comment_types = self::get_comment_type_slugs();
$types = array_merge( $types, $comment_types );

return array_unique( $types );
Expand Down Expand Up @@ -672,7 +704,7 @@ public static function comment_query( $query ) {
}

// Exclude likes and reposts by the ActivityPub plugin.
$query->query_vars['type__not_in'] = self::get_comment_type_names();
$query->query_vars['type__not_in'] = self::get_comment_type_slugs();
}

/**
Expand Down Expand Up @@ -726,7 +758,7 @@ public static function pre_wp_update_comment_count_now( $new_count, $old_count,
if ( null === $new_count ) {
global $wpdb;

$excluded_types = self::get_comment_type_names();
$excluded_types = self::get_comment_type_slugs();

// phpcs:ignore WordPress.DB
$new_count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1' AND comment_type NOT IN ('" . implode( "','", $excluded_types ) . "')", $post_id ) );
Expand Down
9 changes: 4 additions & 5 deletions includes/collection/class-interactions.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ public static function add_reaction( $activity ) {
}

$url = object_to_uri( $activity['object'] );
$comment_post_id = url_to_postid( $url );
$comment_post_id = \url_to_postid( $url );
$parent_comment_id = url_to_commentid( $url );

if ( ! $comment_post_id && $parent_comment_id ) {
$parent_comment = get_comment( $parent_comment_id );
$parent_comment = \get_comment( $parent_comment_id );
$comment_post_id = $parent_comment->comment_post_ID;
}

Expand All @@ -111,14 +111,13 @@ public static function add_reaction( $activity ) {
return false;
}

$type = $activity['type'];
$comment_type = Comment::get_comment_type_by_activity_type( $activity['type'] );

if ( ! Comment::is_registered_comment_type( $type ) ) {
if ( ! $comment_type ) {
// Not a valid comment type.
return false;
}

$comment_type = Comment::get_comment_type( $type );
$comment_content = $comment_type['excerpt'];

$commentdata['comment_post_ID'] = $comment_post_id;
Expand Down
1 change: 1 addition & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ For reasons of data protection, it is not possible to see the followers of other
* Improved: Email templates for Likes and Reposts
* Improved: Interactions moderation
* Improved: Compatibility with Akismet
* Improved: Comment type mapping for `Like` and `Announce`
* Fixed: Empty `url` attributes in the Reply block no longer cause PHP warnings

= 4.4.0 =
Expand Down
120 changes: 120 additions & 0 deletions tests/includes/class-test-comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -455,4 +455,124 @@ public function ability_to_federate_threaded_comment() {
),
);
}

/**
* Test get_comment_type_by_activity_type method.
*
* @covers ::get_comment_type_by_activity_type
*/
public function test_get_comment_type_by_activity_type() {
// Test Like activity type.
$comment_type = Comment::get_comment_type_by_activity_type( 'Like' );
$this->assertIsArray( $comment_type );
$this->assertEquals( 'like', $comment_type['type'] );
$this->assertEquals( 'Like', $comment_type['singular'] );
$this->assertEquals( 'Likes', $comment_type['label'] );
$this->assertContains( 'like', $comment_type['activity_types'] );

// Test Announce activity type.
$comment_type = Comment::get_comment_type_by_activity_type( 'Announce' );
$this->assertIsArray( $comment_type );
$this->assertEquals( 'repost', $comment_type['type'] );
$this->assertEquals( 'Repost', $comment_type['singular'] );
$this->assertEquals( 'Reposts', $comment_type['label'] );
$this->assertContains( 'announce', $comment_type['activity_types'] );

// Test case insensitivity.
$comment_type = Comment::get_comment_type_by_activity_type( 'like' );
$this->assertIsArray( $comment_type );
$this->assertEquals( 'like', $comment_type['type'] );

$comment_type = Comment::get_comment_type_by_activity_type( 'ANNOUNCE' );
$this->assertIsArray( $comment_type );
$this->assertEquals( 'repost', $comment_type['type'] );

// Test invalid activity type.
$comment_type = Comment::get_comment_type_by_activity_type( 'InvalidType' );
$this->assertNull( $comment_type );

// Test empty activity type.
$comment_type = Comment::get_comment_type_by_activity_type( '' );
$this->assertNull( $comment_type );
}

/**
* Test is_registered_comment_type.
*
* @covers ::is_registered_comment_type
*/
public function test_is_registered_comment_type() {
// Test registered types (these are registered in Comment::register_comment_types()).
$this->assertTrue( Comment::is_registered_comment_type( 'repost' ) );
$this->assertTrue( Comment::is_registered_comment_type( 'like' ) );

// Test case insensitivity.
$this->assertTrue( Comment::is_registered_comment_type( 'REPOST' ) );
$this->assertTrue( Comment::is_registered_comment_type( 'Like' ) );

// Test with spaces and special characters (sanitize_key removes these).
$this->assertTrue( Comment::is_registered_comment_type( ' repost ' ) );
$this->assertTrue( Comment::is_registered_comment_type( 'like!' ) );

// Test unregistered types.
$this->assertFalse( Comment::is_registered_comment_type( 'nonexistent' ) );
$this->assertFalse( Comment::is_registered_comment_type( '' ) );
$this->assertFalse( Comment::is_registered_comment_type( 'comment' ) );
}

/**
* Test get_comment_type_slugs.
*
* @covers ::get_comment_type_slugs
*/
public function test_get_comment_type_slugs() {
// Get the registered slugs.
$slugs = Comment::get_comment_type_slugs();

// Test that we get an array.
$this->assertIsArray( $slugs );

// Test that the array is not empty.
$this->assertNotEmpty( $slugs );

// Test that it contains the expected default types.
$this->assertContains( 'repost', $slugs );
$this->assertContains( 'like', $slugs );

// Test that the array only contains strings.
foreach ( $slugs as $slug ) {
$this->assertIsString( $slug );
}

// Test that there are no duplicate slugs.
$this->assertEquals( count( $slugs ), count( array_unique( $slugs ) ) );
}

/**
* Test get_comment_type_names to maintain backwards compatibility.
*
* @covers ::get_comment_type_names
*/
public function test_get_comment_type_names() {
$this->setExpectedDeprecated( 'Activitypub\Comment::get_comment_type_names' );

// Get both types of results.
$names = Comment::get_comment_type_names();
$slugs = Comment::get_comment_type_slugs();

// Test that we get an array.
$this->assertIsArray( $names );

// Test that the array is not empty.
$this->assertNotEmpty( $names );

// Test that it returns exactly the same as get_comment_type_slugs().
$this->assertEquals( $slugs, $names );

// Verify it returns slugs and not singular names.
$this->assertContains( 'repost', $names );
$this->assertContains( 'like', $names );
$this->assertNotContains( 'Repost', $names );
$this->assertNotContains( 'Like', $names );
}
}

0 comments on commit 253cfff

Please sign in to comment.