| @@ -7,9 +7,8 @@ | ||
| 7 | 7 | |
| 8 | 8 | namespace Activitypub\Collection; |
| 9 | 9 | |
| 10 | 10 | use Activitypub\Comment; |
| 11 | -use Activitypub\Emoji; | |
| 12 | 11 | use Activitypub\Webfinger; |
| 13 | 12 | use WP_Comment_Query; |
| 14 | 13 | |
| 15 | 14 | use function Activitypub\get_remote_metadata_by_actor; |
| @@ -28,18 +27,14 @@ | ||
| 28 | 27 | |
| 29 | 28 | /** |
| 30 | 29 | * Add a comment to a post. |
| 31 | 30 | * |
| 32 | - * When $user_id is provided, comment author data is built from the | |
| 33 | - * local WordPress user instead of fetching remote actor metadata. | |
| 31 | + * @param array $activity The activity-object. | |
| 34 | 32 | * |
| 35 | - * @param array $activity The activity-object. | |
| 36 | - * @param int|null $user_id Optional. Local user ID for outbox replies. | |
| 37 | - * | |
| 38 | 33 | * @return int|false|\WP_Error The comment ID or false or WP_Error on failure. |
| 39 | 34 | */ |
| 40 | - public static function add_comment( $activity, $user_id = null ) { | |
| 41 | - $comment_data = self::activity_to_comment( $activity, $user_id ); | |
| 35 | + public static function add_comment( $activity ) { | |
| 36 | + $comment_data = self::activity_to_comment( $activity ); | |
| 42 | 37 | |
| 43 | 38 | if ( ! $comment_data ) { |
| 44 | 39 | return false; |
| 45 | 40 | } |
| @@ -74,9 +69,9 @@ | ||
| 74 | 69 | $comment_post_id = \url_to_postid( $target_url ); |
| 75 | 70 | |
| 76 | 71 | if ( ! $comment_post_id ) { |
| 77 | 72 | // Check for `ap_post`. |
| 78 | - $comment_post = Remote_Posts::get_by_guid( $target_url ); | |
| 73 | + $comment_post = Posts::get_by_guid( $target_url ); | |
| 79 | 74 | if ( $comment_post instanceof \WP_Post ) { |
| 80 | 75 | $comment_post_id = $comment_post->ID; |
| 81 | 76 | } |
| 82 | 77 | } |
| @@ -107,12 +102,8 @@ | ||
| 107 | 102 | */ |
| 108 | 103 | public static function update_comment( $activity ) { |
| 109 | 104 | $meta = get_remote_metadata_by_actor( $activity['actor'] ); |
| 110 | 105 | |
| 111 | - if ( \is_wp_error( $meta ) || ! \is_array( $meta ) ) { | |
| 112 | - return $meta; | |
| 113 | - } | |
| 114 | - | |
| 115 | 106 | // Determine comment_ID. |
| 116 | 107 | $comment = object_id_to_comment( \esc_url_raw( $activity['object']['id'] ) ); |
| 117 | 108 | $comment_data = \get_comment( $comment, ARRAY_A ); |
| 118 | 109 | |
| @@ -120,17 +111,11 @@ | ||
| 120 | 111 | return false; |
| 121 | 112 | } |
| 122 | 113 | |
| 123 | 114 | // Found a local comment id. |
| 124 | - $comment_data['comment_author'] = \sanitize_text_field( empty( $meta['name'] ) ? $meta['preferredUsername'] : $meta['name'] ); | |
| 115 | + $comment_data['comment_author'] = \esc_attr( empty( $meta['name'] ) ? $meta['preferredUsername'] : $meta['name'] ); | |
| 116 | + $comment_data['comment_content'] = \addslashes( $activity['object']['content'] ); | |
| 125 | 117 | |
| 126 | - /* | |
| 127 | - * Wrap emoji in content with blocks for runtime replacement. | |
| 128 | - * Note: Remote images in comments are stripped for security (only emoji allowed). | |
| 129 | - */ | |
| 130 | - $content = Emoji::wrap_in_content( $activity['object']['content'], $activity['object'] ); | |
| 131 | - $comment_data['comment_content'] = \addslashes( $content ); | |
| 132 | - | |
| 133 | 118 | return self::persist( $comment_data, self::UPDATE ); |
| 134 | 119 | } |
| 135 | 120 | |
| 136 | 121 | /** |
| @@ -146,9 +131,9 @@ | ||
| 146 | 131 | $parent_comment_id = url_to_commentid( $url ); |
| 147 | 132 | |
| 148 | 133 | if ( ! $comment_post_id ) { |
| 149 | 134 | // Check for `ap_post`. |
| 150 | - $comment_post = Remote_Posts::get_by_guid( $url ); | |
| 135 | + $comment_post = Posts::get_by_guid( $url ); | |
| 151 | 136 | if ( $comment_post instanceof \WP_Post ) { |
| 152 | 137 | $comment_post_id = $comment_post->ID; |
| 153 | 138 | } |
| 154 | 139 | } |
| @@ -330,81 +315,51 @@ | ||
| 330 | 315 | if ( ! array_key_exists( 'p', $allowed_tags ) ) { |
| 331 | 316 | $allowed_tags['p'] = array(); |
| 332 | 317 | } |
| 333 | 318 | |
| 334 | - // Add `img` for custom emoji support with strict validation. | |
| 335 | - $emoji_html = Emoji::get_kses_allowed_html(); | |
| 336 | - if ( ! array_key_exists( 'img', $allowed_tags ) ) { | |
| 337 | - $allowed_tags['img'] = $emoji_html['img']; | |
| 338 | - } | |
| 339 | - | |
| 340 | 319 | return $allowed_tags; |
| 341 | 320 | } |
| 342 | 321 | |
| 343 | 322 | /** |
| 344 | - * Convert an Activity to a WP_Comment. | |
| 323 | + * Convert an Activity to a WP_Comment | |
| 345 | 324 | * |
| 346 | - * When $user_id is provided, comment author data is built from the | |
| 347 | - * local WordPress user instead of fetching remote actor metadata. | |
| 325 | + * @param array $activity The Activity array. | |
| 348 | 326 | * |
| 349 | - * @param array $activity The Activity array. | |
| 350 | - * @param int|null $user_id Optional. Local user ID for outbox comments. | |
| 351 | - * | |
| 352 | 327 | * @return array|false The comment data or false on failure. |
| 353 | 328 | */ |
| 354 | - public static function activity_to_comment( $activity, $user_id = null ) { | |
| 329 | + public static function activity_to_comment( $activity ) { | |
| 355 | 330 | $comment_content = null; |
| 331 | + $actor = object_to_uri( $activity['actor'] ?? null ); | |
| 332 | + $actor = get_remote_metadata_by_actor( $actor ); | |
| 356 | 333 | |
| 357 | - if ( $user_id ) { | |
| 358 | - // Outbox: resolve author from the local WordPress user. | |
| 359 | - $user = \get_userdata( $user_id ); | |
| 334 | + // Check Actor-Meta. | |
| 335 | + if ( ! $actor || is_wp_error( $actor ) ) { | |
| 336 | + return false; | |
| 337 | + } | |
| 360 | 338 | |
| 361 | - if ( ! $user ) { | |
| 362 | - return false; | |
| 363 | - } | |
| 339 | + // Check Actor-Name. | |
| 340 | + $comment_author = null; | |
| 341 | + if ( ! empty( $actor['name'] ) ) { | |
| 342 | + $comment_author = $actor['name']; | |
| 343 | + } elseif ( ! empty( $actor['preferredUsername'] ) ) { | |
| 344 | + $comment_author = $actor['preferredUsername']; | |
| 345 | + } | |
| 364 | 346 | |
| 365 | - $comment_author = $user->display_name; | |
| 366 | - $comment_author_url = $user->user_url; | |
| 367 | - $comment_author_email = $user->user_email; | |
| 368 | - $comment_content = \wp_kses_post( $activity['object']['content'] ?? '' ); | |
| 369 | - } else { | |
| 370 | - // S2S: resolve author from remote actor metadata. | |
| 371 | - $actor = object_to_uri( $activity['actor'] ?? null ); | |
| 372 | - $actor = get_remote_metadata_by_actor( $actor ); | |
| 347 | + if ( empty( $comment_author ) && \get_option( 'require_name_email' ) ) { | |
| 348 | + return false; | |
| 349 | + } | |
| 373 | 350 | |
| 374 | - if ( ! $actor || is_wp_error( $actor ) ) { | |
| 375 | - return false; | |
| 376 | - } | |
| 351 | + $url = object_to_uri( $actor['url'] ?? $actor['id'] ); | |
| 377 | 352 | |
| 378 | - $comment_author = null; | |
| 379 | - if ( ! empty( $actor['name'] ) ) { | |
| 380 | - $comment_author = $actor['name']; | |
| 381 | - } elseif ( ! empty( $actor['preferredUsername'] ) ) { | |
| 382 | - $comment_author = $actor['preferredUsername']; | |
| 383 | - } | |
| 353 | + if ( isset( $activity['object']['content'] ) ) { | |
| 354 | + $comment_content = \addslashes( $activity['object']['content'] ); | |
| 355 | + } | |
| 384 | 356 | |
| 385 | - if ( empty( $comment_author ) && \get_option( 'require_name_email' ) ) { | |
| 386 | - return false; | |
| 387 | - } | |
| 388 | - | |
| 389 | - $comment_author = $comment_author ?? __( 'Anonymous', 'activitypub' ); | |
| 390 | - $comment_author_url = \esc_url_raw( object_to_uri( $actor['url'] ?? $actor['id'] ) ); | |
| 391 | - | |
| 392 | - $webfinger = Webfinger::uri_to_acct( $comment_author_url ); | |
| 393 | - if ( is_wp_error( $webfinger ) ) { | |
| 394 | - $comment_author_email = ''; | |
| 395 | - } else { | |
| 396 | - $comment_author_email = str_replace( 'acct:', '', $webfinger ); | |
| 397 | - } | |
| 398 | - | |
| 399 | - if ( isset( $activity['object']['content'] ) ) { | |
| 400 | - /* | |
| 401 | - * Wrap emoji in content with blocks for runtime replacement. | |
| 402 | - * Note: Remote images in comments are stripped for security (only emoji allowed). | |
| 403 | - */ | |
| 404 | - $content = Emoji::wrap_in_content( $activity['object']['content'], $activity['object'] ); | |
| 405 | - $comment_content = \addslashes( $content ); | |
| 406 | - } | |
| 357 | + $webfinger = Webfinger::uri_to_acct( $url ); | |
| 358 | + if ( is_wp_error( $webfinger ) ) { | |
| 359 | + $webfinger = ''; | |
| 360 | + } else { | |
| 361 | + $webfinger = str_replace( 'acct:', '', $webfinger ); | |
| 407 | 362 | } |
| 408 | 363 | |
| 409 | 364 | $published = $activity['object']['published'] ?? $activity['published'] ?? 'now'; |
| 410 | 365 | $gm_date = \gmdate( 'Y-m-d H:i:s', \strtotime( $published ) ); |
| @@ -409,36 +364,32 @@ | ||
| 409 | 364 | $published = $activity['object']['published'] ?? $activity['published'] ?? 'now'; |
| 410 | 365 | $gm_date = \gmdate( 'Y-m-d H:i:s', \strtotime( $published ) ); |
| 411 | 366 | |
| 412 | 367 | $comment_data = array( |
| 413 | - 'comment_author' => $comment_author, | |
| 414 | - 'comment_author_url' => $comment_author_url, | |
| 368 | + 'comment_author' => $comment_author ?? __( 'Anonymous', 'activitypub' ), | |
| 369 | + 'comment_author_url' => \esc_url_raw( $url ), | |
| 415 | 370 | 'comment_content' => $comment_content, |
| 416 | 371 | 'comment_type' => 'comment', |
| 417 | - 'comment_author_email' => $comment_author_email, | |
| 372 | + 'comment_author_email' => $webfinger, | |
| 418 | 373 | 'comment_date' => \get_date_from_gmt( $gm_date ), |
| 419 | 374 | 'comment_date_gmt' => $gm_date, |
| 420 | - 'comment_meta' => array(), | |
| 375 | + 'comment_meta' => array( | |
| 376 | + 'source_id' => \esc_url_raw( object_to_uri( $activity['object'] ) ), | |
| 377 | + 'protocol' => 'activitypub', | |
| 378 | + ), | |
| 421 | 379 | ); |
| 422 | 380 | |
| 423 | - if ( $user_id ) { | |
| 424 | - $comment_data['user_id'] = $user_id; | |
| 425 | - } else { | |
| 426 | - $comment_data['comment_meta']['protocol'] = 'activitypub'; | |
| 427 | - $comment_data['comment_meta']['source_id'] = \esc_url_raw( object_to_uri( $activity['object'] ) ); | |
| 428 | - | |
| 429 | - // Store reference to remote actor post. | |
| 430 | - $actor_uri = object_to_uri( $activity['actor'] ?? null ); | |
| 431 | - if ( $actor_uri ) { | |
| 432 | - $remote_actor = Remote_Actors::get_by_uri( $actor_uri ); | |
| 433 | - if ( ! \is_wp_error( $remote_actor ) ) { | |
| 434 | - $comment_data['comment_meta']['_activitypub_remote_actor_id'] = $remote_actor->ID; | |
| 435 | - } | |
| 381 | + // Store reference to remote actor post. | |
| 382 | + $actor_uri = object_to_uri( $activity['actor'] ?? null ); | |
| 383 | + if ( $actor_uri ) { | |
| 384 | + $remote_actor = Remote_Actors::get_by_uri( $actor_uri ); | |
| 385 | + if ( ! \is_wp_error( $remote_actor ) ) { | |
| 386 | + $comment_data['comment_meta']['_activitypub_remote_actor_id'] = $remote_actor->ID; | |
| 436 | 387 | } |
| 388 | + } | |
| 437 | 389 | |
| 438 | - if ( isset( $activity['object']['url'] ) ) { | |
| 439 | - $comment_data['comment_meta']['source_url'] = \esc_url_raw( object_to_uri( $activity['object']['url'] ) ); | |
| 440 | - } | |
| 390 | + if ( isset( $activity['object']['url'] ) ) { | |
| 391 | + $comment_data['comment_meta']['source_url'] = \esc_url_raw( object_to_uri( $activity['object']['url'] ) ); | |
| 441 | 392 | } |
| 442 | 393 | |
| 443 | 394 | return $comment_data; |
| 444 | 395 | } |