PluginProbe
ActivityPub / 3.2.4
ActivityPub v3.2.4
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
← All changes | includes/collection/class-interactions.php +117 -386 9.2.23.2.4 View file →
@@ -1,27 +1,18 @@
1 1 <?php
2 -/**
3 - * Interactions collection file.
4 - *
5 - * @package Activitypub
6 - */
7 -
8 2 namespace Activitypub\Collection;
9 3
4 +use WP_Error;
5 +use WP_Comment_Query;
10 6 use Activitypub\Comment;
11 -use Activitypub\Emoji;
12 -use Activitypub\Webfinger;
13 7
14 -use function Activitypub\get_remote_metadata_by_actor;
15 -use function Activitypub\is_ap_post;
16 -use function Activitypub\is_post_disabled;
17 -use function Activitypub\is_same_host;
18 -use function Activitypub\object_id_to_comment;
19 8 use function Activitypub\object_to_uri;
20 9 use function Activitypub\url_to_commentid;
10 +use function Activitypub\object_id_to_comment;
11 +use function Activitypub\get_remote_metadata_by_actor;
21 12
22 13 /**
23 - * ActivityPub Interactions Collection.
14 + * ActivityPub Interactions Collection
24 15 */
25 16 class Interactions {
26 17 const INSERT = 'insert';
27 18 const UPDATE = 'update';
@@ -26,179 +17,87 @@
26 17 const INSERT = 'insert';
27 18 const UPDATE = 'update';
28 19
29 20 /**
30 - * Add a comment to a post.
21 + * Add a comment to a post
31 22 *
32 - * When $user_id is provided, comment author data is built from the
33 - * local WordPress user instead of fetching remote actor metadata.
23 + * @param array $activity The activity-object
34 24 *
35 - * @param array $activity The activity-object.
36 - * @param int|null $user_id Optional. Local user ID for outbox replies.
37 - *
38 - * @return int|false|\WP_Error The comment ID or false or WP_Error on failure.
25 + * @return array|false The commentdata or false on failure
39 26 */
40 - public static function add_comment( $activity, $user_id = null ) {
41 - /*
42 - * A remote comment is stored under its object id (source_id); that id must be on
43 - * the signature-verified actor's host. Otherwise a remote server could file a
44 - * comment whose recorded id points at a different host, mis-recording its
45 - * provenance and taking over that id (the update owner-check would then reject the
46 - * genuine author). Local outbox replies ($user_id set) are trusted.
47 - */
48 - if ( null === $user_id && ! is_same_host( $activity['actor'] ?? '', $activity['object'] ?? '' ) ) {
49 - return false;
50 - }
27 + public static function add_comment( $activity ) {
28 + $commentdata = self::activity_to_comment( $activity );
51 29
52 - $comment_data = self::activity_to_comment( $activity, $user_id );
53 -
54 - if ( ! $comment_data ) {
30 + if ( ! $commentdata || ! isset( $activity['object']['inReplyTo'] ) ) {
55 31 return false;
56 32 }
57 33
58 - // Determine target URL from reply or quote.
59 - $parent_comment_id = 0;
34 + $in_reply_to = \esc_url_raw( $activity['object']['inReplyTo'] );
35 + $comment_post_id = \url_to_postid( $in_reply_to );
36 + $parent_comment_id = url_to_commentid( $in_reply_to );
60 37
61 - if ( ! empty( $activity['object']['inReplyTo'] ) ) {
62 - // Regular reply.
63 - $target_url = object_to_uri( $activity['object']['inReplyTo'] );
64 - $parent_comment_id = url_to_commentid( $target_url );
65 - } else {
66 - // Check for quote.
67 - $target_url = self::get_quote_url( $activity );
68 -
69 - if ( ! $target_url ) {
70 - return false;
71 - }
72 -
73 - // Mark as quote and clean content.
74 - $comment_data['comment_type'] = 'quote';
75 -
76 - if ( ! empty( $activity['object']['content'] ) ) {
77 - $pattern = '/<p[^>]*class=["\']quote-inline["\'][^>]*>.*?<\/p>/is';
78 - $cleaned_content = \preg_replace( $pattern, '', $activity['object']['content'], 1 );
79 - $comment_data['comment_content'] = \wp_kses_post( $cleaned_content );
80 - }
81 - }
82 -
83 - // Get post ID from target URL.
84 - $target_url = \esc_url_raw( $target_url );
85 - $comment_post_id = \url_to_postid( $target_url );
86 -
87 - if ( ! $comment_post_id ) {
88 - // Check for `ap_post`.
89 - $comment_post = Remote_Posts::get_by_guid( $target_url );
90 - if ( $comment_post instanceof \WP_Post ) {
91 - $comment_post_id = $comment_post->ID;
92 - }
93 - }
94 -
95 - // Handle nested replies (replies to comments).
38 + // save only replys and reactions
96 39 if ( ! $comment_post_id && $parent_comment_id ) {
97 - $parent_comment = \get_comment( $parent_comment_id );
40 + $parent_comment = get_comment( $parent_comment_id );
98 41 $comment_post_id = $parent_comment->comment_post_ID;
99 42 }
100 43
44 + // not a reply to a post or comment
101 45 if ( ! $comment_post_id ) {
102 - // Not a reply to a post or comment.
103 46 return false;
104 47 }
105 48
106 - $comment_data['comment_post_ID'] = $comment_post_id;
107 - $comment_data['comment_parent'] = $parent_comment_id ? $parent_comment_id : 0;
49 + $commentdata['comment_post_ID'] = $comment_post_id;
50 + $commentdata['comment_parent'] = $parent_comment_id ? $parent_comment_id : 0;
108 51
109 - return self::persist( $comment_data );
52 + return self::persist( $commentdata, self::INSERT );
110 53 }
111 54
112 55 /**
113 - * Update a comment.
56 + * Update a comment
114 57 *
115 - * @param array $activity The activity object.
58 + * @param array $activity The activity-object
116 59 *
117 - * @return array|string|int|\WP_Error|false The comment data or false on failure.
60 + * @return array|string|int|\WP_Error|false The commentdata or false on failure
118 61 */
119 62 public static function update_comment( $activity ) {
120 63 $meta = get_remote_metadata_by_actor( $activity['actor'] );
121 64
122 - if ( \is_wp_error( $meta ) || ! \is_array( $meta ) ) {
123 - return $meta;
124 - }
65 + //Determine comment_ID
66 + $comment = object_id_to_comment( \esc_url_raw( $activity['object']['id'] ) );
67 + $commentdata = \get_comment( $comment, ARRAY_A );
125 68
126 - // Determine comment_ID.
127 - $comment = object_id_to_comment( \esc_url_raw( $activity['object']['id'] ) );
128 - $comment_data = \get_comment( $comment, ARRAY_A );
129 -
130 - if ( ! $comment_data ) {
69 + if ( ! $commentdata ) {
131 70 return false;
132 71 }
133 72
134 - /*
135 - * Only the comment's author may update it. The comment maps to the remote actor that
136 - * created it via _activitypub_remote_actor_id; that actor post's guid is the
137 - * (signature-bound) actor URI. The Update's actor must match it, otherwise a remote
138 - * server could rewrite another actor's comment by sending an Update whose object.id
139 - * points at it.
140 - *
141 - * Comments created before this mapping existed have no owner recorded; those are let
142 - * through for backward compatibility (matching the Undo path) rather than becoming
143 - * permanently un-editable. On mismatch, return a WP_Error rather than false: false would
144 - * make the Update handler fall back to Create (which re-dispatches to Update for an
145 - * existing comment and recurses), while the unchanged comment array would be read as a
146 - * successful update and relayed onward. A WP_Error is handled but unsuccessful: no Create
147 - * fallback, and the handled-update success flag stays false.
148 - */
149 - $owner = \get_post( (int) \get_comment_meta( $comment_data['comment_ID'], '_activitypub_remote_actor_id', true ) );
150 - if ( $owner instanceof \WP_Post && object_to_uri( $activity['actor'] ) !== $owner->guid ) {
151 - return new \WP_Error(
152 - 'activitypub_update_forbidden',
153 - \__( 'The Update actor does not own the target comment.', 'activitypub' )
154 - );
155 - }
73 + //found a local comment id
74 + $commentdata['comment_author'] = \esc_attr( $meta['name'] ? $meta['name'] : $meta['preferredUsername'] );
75 + $commentdata['comment_content'] = \addslashes( $activity['object']['content'] );
156 76
157 - // Found a local comment id.
158 - $comment_data['comment_author'] = \sanitize_text_field( empty( $meta['name'] ) ? $meta['preferredUsername'] : $meta['name'] );
159 -
160 - /*
161 - * Wrap emoji in content with blocks for runtime replacement.
162 - * Note: Remote images in comments are stripped for security (only emoji allowed).
163 - */
164 - $content = Emoji::wrap_in_content( $activity['object']['content'], $activity['object'] );
165 - $comment_data['comment_content'] = \addslashes( $content );
166 -
167 - return self::persist( $comment_data, self::UPDATE );
77 + return self::persist( $commentdata, self::UPDATE );
168 78 }
169 79
170 80 /**
171 81 * Adds an incoming Like, Announce, ... as a comment to a post.
172 82 *
173 - * @param array $activity Activity array.
83 + * @param array $activity Activity array.
174 84 *
175 - * @return array|string|int|\WP_Error|false Comment data or `false` on failure.
85 + * @return array|false Comment data or `false` on failure.
176 86 */
177 87 public static function add_reaction( $activity ) {
178 - /*
179 - * The reaction is stored under its own id (source_id); that id must be on the
180 - * signature-verified actor's host, so a remote server cannot file a reaction
181 - * whose recorded id points at a different host and take over that id.
182 - */
183 - if ( ! is_same_host( $activity['actor'] ?? '', $activity['id'] ?? '' ) ) {
88 + $commentdata = self::activity_to_comment( $activity );
89 +
90 + if ( ! $commentdata ) {
184 91 return false;
185 92 }
186 93
187 94 $url = object_to_uri( $activity['object'] );
188 - $comment_post_id = \url_to_postid( $url );
95 + $comment_post_id = url_to_postid( $url );
189 96 $parent_comment_id = url_to_commentid( $url );
190 97
191 - if ( ! $comment_post_id ) {
192 - // Check for `ap_post`.
193 - $comment_post = Remote_Posts::get_by_guid( $url );
194 - if ( $comment_post instanceof \WP_Post ) {
195 - $comment_post_id = $comment_post->ID;
196 - }
197 - }
198 -
199 98 if ( ! $comment_post_id && $parent_comment_id ) {
200 - $parent_comment = \get_comment( $parent_comment_id );
99 + $parent_comment = get_comment( $parent_comment_id );
201 100 $comment_post_id = $parent_comment->comment_post_ID;
202 101 }
203 102
204 103 if ( ! $comment_post_id ) {
@@ -205,36 +104,34 @@
205 104 // Not a reply to a post or comment.
206 105 return false;
207 106 }
208 107
209 - $comment_type = Comment::get_comment_type_by_activity_type( $activity['type'] );
210 - if ( ! $comment_type ) {
108 + $type = $activity['type'];
109 +
110 + if ( ! Comment::is_registered_comment_type( $type ) ) {
211 111 // Not a valid comment type.
212 112 return false;
213 113 }
214 114
215 - $comment_data = self::activity_to_comment( $activity );
216 - if ( ! $comment_data ) {
217 - return false;
218 - }
115 + $comment_type = Comment::get_comment_type( $type );
116 + $comment_content = $comment_type['excerpt'];
219 117
220 - $comment_data['comment_post_ID'] = $comment_post_id;
221 - $comment_data['comment_parent'] = $parent_comment_id ? $parent_comment_id : 0;
222 - $comment_data['comment_content'] = \esc_html( $comment_type['excerpt'] );
223 - $comment_data['comment_type'] = \esc_attr( $comment_type['type'] );
224 - $comment_data['comment_meta']['source_id'] = \esc_url_raw( $activity['id'] );
118 + $commentdata['comment_post_ID'] = $comment_post_id;
119 + $commentdata['comment_content'] = \esc_html( $comment_content );
120 + $commentdata['comment_type'] = \esc_attr( $comment_type['type'] );
121 + $commentdata['comment_meta']['source_id'] = \esc_url_raw( $activity['id'] );
225 122
226 - return self::persist( $comment_data );
123 + return self::persist( $commentdata, self::INSERT );
227 124 }
228 125
229 126 /**
230 - * Get interaction(s) by ID.
127 + * Get interaction(s) for a given URL/ID.
231 128 *
232 - * @param string $url The URL/ID to get interactions for.
129 + * @param strin $url The URL/ID to get interactions for.
233 130 *
234 131 * @return array The interactions as WP_Comment objects.
235 132 */
236 - public static function get_by_id( $url ) {
133 + public static function get_interaction_by_id( $url ) {
237 134 $args = array(
238 135 'nopaging' => true,
239 136 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
240 137 'meta_query' => array(
@@ -256,39 +153,24 @@
256 153 ),
257 154 ),
258 155 );
259 156
260 - $query = new \WP_Comment_Query( $args );
157 + $query = new WP_Comment_Query( $args );
261 158 return $query->comments;
262 159 }
263 160
264 161 /**
265 - * Get interaction(s) for a given URL/ID.
162 + * Get interaction(s) for a given actor.
266 163 *
267 - * @deprecated 7.6.0 Use {@see Interactions::get_by_id()}.
268 - *
269 - * @param string $url The URL/ID to get interactions for.
270 - *
271 - * @return array The interactions as WP_Comment objects.
272 - */
273 - public static function get_interaction_by_id( $url ) {
274 - \_deprecated_function( __METHOD__, '7.6.0', 'Activitypub\Collection\Interactions::get_by_id' );
275 -
276 - return self::get_by_id( $url );
277 - }
278 -
279 - /**
280 - * Get interaction(s) by actor.
281 - *
282 164 * @param string $actor The Actor-URL.
283 165 *
284 166 * @return array The interactions as WP_Comment objects.
285 167 */
286 - public static function get_by_actor( $actor ) {
168 + public static function get_interactions_by_actor( $actor ) {
287 169 $meta = get_remote_metadata_by_actor( $actor );
288 170
289 - // Get URL, because $actor seems to be the ID.
290 - if ( $meta && ! \is_wp_error( $meta ) && isset( $meta['url'] ) ) {
171 + // get URL, because $actor seems to be the ID
172 + if ( $meta && ! is_wp_error( $meta ) && isset( $meta['url'] ) ) {
291 173 $actor = object_to_uri( $meta['url'] );
292 174 }
293 175
294 176 $args = array(
@@ -298,65 +180,21 @@
298 180 'meta_query' => array(
299 181 array(
300 182 'key' => 'protocol',
301 183 'value' => 'activitypub',
184 + 'compare' => '=',
302 185 ),
303 186 ),
304 187 );
305 -
306 - return \get_comments( $args );
188 + $comment_query = new WP_Comment_Query( $args );
189 + return $comment_query->comments;
307 190 }
308 191
309 192 /**
310 - * Get interaction(s) by remote actor ID.
311 - *
312 - * This is an optimized query that uses the remote actor post ID directly
313 - * instead of querying by author_url.
314 - *
315 - * @param int $remote_actor_id The remote actor post ID.
316 - *
317 - * @return array The interactions as WP_Comment objects.
318 - */
319 - public static function get_by_remote_actor_id( $remote_actor_id ) {
320 - $args = array(
321 - 'nopaging' => true,
322 - // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
323 - 'meta_query' => array(
324 - 'relation' => 'AND',
325 - array(
326 - 'key' => 'protocol',
327 - 'value' => 'activitypub',
328 - ),
329 - array(
330 - 'key' => '_activitypub_remote_actor_id',
331 - 'value' => $remote_actor_id,
332 - ),
333 - ),
334 - );
335 -
336 - return \get_comments( $args );
337 - }
338 -
339 - /**
340 - * Get interaction(s) for a given actor.
341 - *
342 - * @deprecated 7.6.0 Use {@see Interactions::get_by_actor()}.
343 - *
344 - * @param string $actor The Actor-URL.
345 - *
346 - * @return array The interactions as WP_Comment objects.
347 - */
348 - public static function get_interactions_by_actor( $actor ) {
349 - \_deprecated_function( __METHOD__, '7.6.0', 'Activitypub\Collection\Interactions::get_by_actor' );
350 -
351 - return self::get_by_actor( $actor );
352 - }
353 -
354 - /**
355 193 * Adds line breaks to the list of allowed comment tags.
356 194 *
357 195 * @param array $allowed_tags Allowed HTML tags.
358 - * @param string $context Optional. Context. Default empty.
196 + * @param string $context Context.
359 197 *
360 198 * @return array Filtered tag list.
361 199 */
362 200 public static function allowed_comment_html( $allowed_tags, $context = '' ) {
@@ -365,152 +203,95 @@
365 203 return $allowed_tags;
366 204 }
367 205
368 206 // Add `p` and `br` to the list of allowed tags.
369 - if ( ! \array_key_exists( 'br', $allowed_tags ) ) {
207 + if ( ! array_key_exists( 'br', $allowed_tags ) ) {
370 208 $allowed_tags['br'] = array();
371 209 }
372 210
373 - if ( ! \array_key_exists( 'p', $allowed_tags ) ) {
211 + if ( ! array_key_exists( 'p', $allowed_tags ) ) {
374 212 $allowed_tags['p'] = array();
375 213 }
376 214
377 - // Add `img` for custom emoji support with strict validation.
378 - $emoji_html = Emoji::get_kses_allowed_html();
379 - if ( ! \array_key_exists( 'img', $allowed_tags ) ) {
380 - $allowed_tags['img'] = $emoji_html['img'];
381 - }
382 -
383 215 return $allowed_tags;
384 216 }
385 217
386 218 /**
387 - * Convert an Activity to a WP_Comment.
219 + * Convert an Activity to a WP_Comment
388 220 *
389 - * When $user_id is provided, comment author data is built from the
390 - * local WordPress user instead of fetching remote actor metadata.
221 + * @param array $activity The Activity array
391 222 *
392 - * @param array $activity The Activity array.
393 - * @param int|null $user_id Optional. Local user ID for outbox comments.
394 - *
395 - * @return array|false The comment data or false on failure.
223 + * @return array|false The commentdata or false on failure
396 224 */
397 - public static function activity_to_comment( $activity, $user_id = null ) {
225 + public static function activity_to_comment( $activity ) {
398 226 $comment_content = null;
227 + $actor = object_to_uri( $activity['actor'] );
228 + $actor = get_remote_metadata_by_actor( $actor );
399 229
400 - if ( $user_id ) {
401 - // Outbox: resolve author from the local WordPress user.
402 - $user = \get_userdata( $user_id );
230 + // check Actor-Meta
231 + if ( ! $actor || is_wp_error( $actor ) ) {
232 + return false;
233 + }
403 234
404 - if ( ! $user ) {
405 - return false;
406 - }
407 -
408 - $comment_author = $user->display_name;
409 - $comment_author_url = $user->user_url;
410 - $comment_author_email = $user->user_email;
411 - $comment_content = \wp_kses_post( $activity['object']['content'] ?? '' );
235 + // check Actor-Name
236 + if ( isset( $actor['name'] ) ) {
237 + $comment_author = $actor['name'];
238 + } elseif ( isset( $actor['preferredUsername'] ) ) {
239 + $comment_author = $actor['preferredUsername'];
412 240 } else {
413 - // S2S: resolve author from remote actor metadata.
414 - $actor = object_to_uri( $activity['actor'] ?? null );
415 - $actor = get_remote_metadata_by_actor( $actor );
241 + return false;
242 + }
416 243
417 - if ( ! $actor || \is_wp_error( $actor ) ) {
418 - return false;
419 - }
244 + $url = object_to_uri( $actor['url'] );
420 245
421 - $comment_author = null;
422 - if ( ! empty( $actor['name'] ) ) {
423 - $comment_author = $actor['name'];
424 - } elseif ( ! empty( $actor['preferredUsername'] ) ) {
425 - $comment_author = $actor['preferredUsername'];
426 - }
246 + if ( ! $url ) {
247 + object_to_uri( $actor['id'] );
248 + }
427 249
428 - if ( empty( $comment_author ) && \get_option( 'require_name_email' ) ) {
429 - return false;
430 - }
431 -
432 - $comment_author = $comment_author ?? \__( 'Anonymous', 'activitypub' );
433 - $comment_author_url = \esc_url_raw( object_to_uri( $actor['url'] ?? $actor['id'] ) );
434 -
435 - $webfinger = Webfinger::uri_to_acct( $comment_author_url );
436 - if ( \is_wp_error( $webfinger ) ) {
437 - $comment_author_email = '';
438 - } else {
439 - $comment_author_email = \str_replace( 'acct:', '', $webfinger );
440 - }
441 -
442 - if ( isset( $activity['object']['content'] ) ) {
443 - /*
444 - * Wrap emoji in content with blocks for runtime replacement.
445 - * Note: Remote images in comments are stripped for security (only emoji allowed).
446 - */
447 - $content = Emoji::wrap_in_content( $activity['object']['content'], $activity['object'] );
448 - $comment_content = \addslashes( $content );
449 - }
250 + if ( isset( $activity['object']['content'] ) ) {
251 + $comment_content = \addslashes( $activity['object']['content'] );
450 252 }
451 253
452 - $published = $activity['object']['published'] ?? $activity['published'] ?? 'now';
453 - $gm_date = \gmdate( 'Y-m-d H:i:s', \strtotime( $published ) );
454 -
455 - $comment_data = array(
456 - 'comment_author' => $comment_author,
457 - 'comment_author_url' => $comment_author_url,
458 - 'comment_content' => $comment_content,
459 - 'comment_type' => 'comment',
460 - 'comment_author_email' => $comment_author_email,
461 - 'comment_date' => \get_date_from_gmt( $gm_date ),
462 - 'comment_date_gmt' => $gm_date,
463 - 'comment_meta' => array(),
254 + $commentdata = array(
255 + 'comment_author' => \esc_attr( $comment_author ),
256 + 'comment_author_url' => \esc_url_raw( $url ),
257 + 'comment_content' => $comment_content,
258 + 'comment_type' => 'comment',
259 + 'comment_author_email' => '',
260 + 'comment_meta' => array(
261 + 'source_id' => \esc_url_raw( object_to_uri( $activity['object'] ) ),
262 + 'protocol' => 'activitypub',
263 + ),
464 264 );
465 265
466 - if ( $user_id ) {
467 - $comment_data['user_id'] = $user_id;
468 - } else {
469 - $comment_data['comment_meta']['protocol'] = 'activitypub';
470 - $comment_data['comment_meta']['source_id'] = \esc_url_raw( object_to_uri( $activity['object'] ) );
266 + if ( isset( $actor['icon']['url'] ) ) {
267 + $commentdata['comment_meta']['avatar_url'] = \esc_url_raw( $actor['icon']['url'] );
268 + }
471 269
472 - // Store reference to remote actor post.
473 - $actor_uri = object_to_uri( $activity['actor'] ?? null );
474 - if ( $actor_uri ) {
475 - $remote_actor = Remote_Actors::get_by_uri( $actor_uri );
476 - if ( ! \is_wp_error( $remote_actor ) ) {
477 - $comment_data['comment_meta']['_activitypub_remote_actor_id'] = $remote_actor->ID;
478 - }
479 - }
480 -
481 - if ( isset( $activity['object']['url'] ) ) {
482 - $comment_data['comment_meta']['source_url'] = \esc_url_raw( object_to_uri( $activity['object']['url'] ) );
483 - }
270 + if ( isset( $activity['object']['url'] ) ) {
271 + $commentdata['comment_meta']['source_url'] = \esc_url_raw( object_to_uri( $activity['object']['url'] ) );
484 272 }
485 273
486 - return $comment_data;
274 + return $commentdata;
487 275 }
488 276
489 277 /**
490 - * Persist a comment.
278 + * Persist a comment
491 279 *
492 - * @param array $comment_data The comment data array.
493 - * @param string $action Optional. Either 'insert' or 'update'. Default 'insert'.
280 + * @param array $commentdata The commentdata array
281 + * @param string $action Either 'insert' or 'update'
494 282 *
495 - * @return array|string|int|\WP_Error|false The comment data or false on failure
283 + * @return array|string|int|\WP_Error|false The commentdata or false on failure
496 284 */
497 - public static function persist( $comment_data, $action = self::INSERT ) {
498 - if (
499 - is_post_disabled( $comment_data['comment_post_ID'] ) &&
500 - ! is_ap_post( $comment_data['comment_post_ID'] )
501 - ) {
502 - return false;
503 - }
504 -
505 - // Disable flood control.
506 - \remove_action( 'check_comment_flood', 'check_comment_flood_db' );
507 - // Do not require email for AP entries.
285 + public static function persist( $commentdata, $action = self::INSERT ) {
286 + // disable flood control
287 + \remove_action( 'check_comment_flood', 'check_comment_flood_db', 10 );
288 + // do not require email for AP entries
508 289 \add_filter( 'pre_option_require_name_email', '__return_false' );
509 - // No nonce possible for this submission route.
290 + // No nonce possible for this submission route
510 291 \add_filter(
511 292 'akismet_comment_nonce',
512 - static function () {
293 + function () {
513 294 return 'inactive';
514 295 }
515 296 );
516 297 \add_filter( 'wp_kses_allowed_html', array( self::class, 'allowed_comment_html' ), 10, 2 );
@@ -515,71 +296,21 @@
515 296 );
516 297 \add_filter( 'wp_kses_allowed_html', array( self::class, 'allowed_comment_html' ), 10, 2 );
517 298
518 299 if ( self::INSERT === $action ) {
519 - $state = \wp_new_comment( $comment_data, true );
300 + $state = \wp_new_comment( $commentdata, true );
520 301 } else {
521 - $state = \wp_update_comment( $comment_data, true );
302 + $state = \wp_update_comment( $commentdata, true );
522 303 }
523 304
524 - \remove_filter( 'wp_kses_allowed_html', array( self::class, 'allowed_comment_html' ) );
305 + \remove_filter( 'wp_kses_allowed_html', array( self::class, 'allowed_comment_html' ), 10 );
525 306 \remove_filter( 'pre_option_require_name_email', '__return_false' );
526 - // Restore flood control.
307 + // re-add flood control
527 308 \add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
528 309
529 310 if ( 1 === $state ) {
530 - return $comment_data;
311 + return $commentdata;
531 312 } else {
532 - return $state; // Either WP_Comment, false, a WP_Error, 0, or 1!
313 + return $state; // Either `WP_Comment`, `false` or a `WP_Error` instance or `0` or `1`!
533 314 }
534 - }
535 -
536 - /**
537 - * Get the total number of interactions by type for a given ID.
538 - *
539 - * @param int $post_id The post ID.
540 - * @param string $type The type of interaction to count.
541 - *
542 - * @return int The total number of interactions.
543 - */
544 - public static function count_by_type( $post_id, $type ) {
545 - return \get_comments(
546 - array(
547 - 'post_id' => $post_id,
548 - 'status' => 'approve',
549 - 'type' => $type,
550 - 'count' => true,
551 - 'paging' => false,
552 - 'fields' => 'ids',
553 - )
554 - );
555 - }
556 -
557 - /**
558 - * Get the quote URL from an activity.
559 - *
560 - * Checks for quote properties in priority order: quote -> quoteUrl -> quoteUri -> _misskey_quote.
561 - *
562 - * @param array $activity The activity array.
563 - *
564 - * @return string|false The quote URL or false if not found.
565 - */
566 - public static function get_quote_url( $activity ) {
567 - if ( ! empty( $activity['object']['quote'] ) ) {
568 - return object_to_uri( $activity['object']['quote'] );
569 - }
570 -
571 - if ( ! empty( $activity['object']['quoteUrl'] ) ) {
572 - return object_to_uri( $activity['object']['quoteUrl'] );
573 - }
574 -
575 - if ( ! empty( $activity['object']['quoteUri'] ) ) {
576 - return object_to_uri( $activity['object']['quoteUri'] );
577 - }
578 -
579 - if ( ! empty( $activity['object']['_misskey_quote'] ) ) {
580 - return object_to_uri( $activity['object']['_misskey_quote'] );
581 - }
582 -
583 - return false;
584 315 }
585 316 }