PluginProbe
ActivityPub / 7.7.0
ActivityPub v7.7.0
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/class-scheduler.php +103 -265 9.2.07.7.0 View file →
@@ -12,14 +12,12 @@
12 12 use Activitypub\Collection\Actors;
13 13 use Activitypub\Collection\Inbox;
14 14 use Activitypub\Collection\Outbox;
15 15 use Activitypub\Collection\Remote_Actors;
16 -use Activitypub\Collection\Remote_Posts;
17 16 use Activitypub\Scheduler\Actor;
18 17 use Activitypub\Scheduler\Collection_Sync;
19 18 use Activitypub\Scheduler\Comment;
20 19 use Activitypub\Scheduler\Post;
21 -use Activitypub\Scheduler\Statistics;
22 20
23 21 /**
24 22 * Scheduler class.
25 23 *
@@ -27,24 +25,8 @@
27 25 */
28 26 class Scheduler {
29 27
30 28 /**
31 - * Scheduled events with their recurrence.
32 - *
33 - * @var array
34 - */
35 - const SCHEDULES = array(
36 - 'activitypub_update_remote_actors' => 'hourly',
37 - 'activitypub_cleanup_remote_actors' => 'daily',
38 - 'activitypub_reprocess_outbox' => 'hourly',
39 - 'activitypub_outbox_purge' => 'daily',
40 - 'activitypub_inbox_purge' => 'daily',
41 - 'activitypub_ap_post_purge' => 'daily',
42 - 'activitypub_tombstone_purge' => 'daily',
43 - 'activitypub_sync_blocklist_subscriptions' => 'weekly',
44 - );
45 -
46 - /**
47 29 * Allowed batch callbacks.
48 30 *
49 31 * @var array
50 32 */
@@ -52,24 +34,17 @@
52 34
53 35 /**
54 36 * Get the pause between async batches (in seconds).
55 37 *
56 - * @param string|false|null $hook Optional. The async batch hook being scheduled. Default current action.
57 - *
58 38 * @return int The pause in seconds.
59 39 */
60 - public static function get_retry_delay( $hook = null ) {
61 - if ( null === $hook ) {
62 - $hook = \current_action();
63 - }
64 -
40 + public static function get_retry_delay() {
65 41 /**
66 42 * Filters the pause between async batches (in seconds).
67 43 *
68 - * @param int $async_batch_pause The pause in seconds. Default 30.
69 - * @param string|false|null $hook The async batch hook being scheduled.
44 + * @param int $async_batch_pause The pause in seconds. Default 30.
70 45 */
71 - return \apply_filters( 'activitypub_scheduler_async_batch_pause', 30, $hook );
46 + return apply_filters( 'activitypub_scheduler_async_batch_pause', 30 );
72 47 }
73 48
74 49 /**
75 50 * Initialize the class, registering WordPress hooks.
@@ -76,11 +51,8 @@
76 51 */
77 52 public static function init() {
78 53 self::register_schedulers();
79 54
80 - // Custom cron schedules.
81 - \add_filter( 'cron_schedules', array( self::class, 'add_cron_schedules' ) );
82 -
83 55 // Follower Cleanups.
84 56 \add_action( 'activitypub_update_remote_actors', array( self::class, 'update_remote_actors' ) );
85 57 \add_action( 'activitypub_cleanup_remote_actors', array( self::class, 'cleanup_remote_actors' ) );
86 58
@@ -88,19 +60,15 @@
88 60 \add_action( 'activitypub_async_batch', array( self::class, 'async_batch' ), 10, 99 );
89 61 \add_action( 'activitypub_reprocess_outbox', array( self::class, 'reprocess_outbox' ) );
90 62 \add_action( 'activitypub_outbox_purge', array( self::class, 'purge_outbox' ) );
91 63 \add_action( 'activitypub_inbox_purge', array( self::class, 'purge_inbox' ) );
92 - \add_action( 'activitypub_ap_post_purge', array( self::class, 'purge_ap_posts' ) );
93 - \add_action( 'activitypub_tombstone_purge', array( self::class, 'purge_tombstones' ) );
94 64 \add_action( 'activitypub_inbox_create_item', array( self::class, 'process_inbox_activity' ) );
95 - \add_action( 'activitypub_sync_blocklist_subscriptions', array( Blocklist_Subscriptions::class, 'sync_all' ) );
96 65
97 66 \add_action( 'post_activitypub_add_to_outbox', array( self::class, 'schedule_outbox_activity_for_federation' ) );
98 67 \add_action( 'post_activitypub_add_to_outbox', array( self::class, 'schedule_announce_activity' ), 10, 4 );
99 68
100 - \add_action( 'update_option_activitypub_outbox_purge_days', array( self::class, 'update_outbox_purge_schedule' ), 10, 2 );
101 - \add_action( 'update_option_activitypub_inbox_purge_days', array( self::class, 'update_inbox_purge_schedule' ), 10, 2 );
102 - \add_action( 'update_option_activitypub_ap_post_purge_days', array( self::class, 'update_ap_post_purge_schedule' ), 10, 2 );
69 + \add_action( 'update_option_activitypub_outbox_purge_days', array( self::class, 'handle_outbox_purge_days_update' ), 10, 2 );
70 + \add_action( 'update_option_activitypub_inbox_purge_days', array( self::class, 'handle_inbox_purge_days_update' ), 10, 2 );
103 71 }
104 72
105 73 /**
106 74 * Register handlers.
@@ -109,9 +77,8 @@
109 77 Post::init();
110 78 Actor::init();
111 79 Collection_Sync::init();
112 80 Comment::init();
113 - Statistics::init();
114 81
115 82 /**
116 83 * Register additional schedulers.
117 84 *
@@ -120,29 +87,8 @@
120 87 \do_action( 'activitypub_register_schedulers' );
121 88 }
122 89
123 90 /**
124 - * Add custom cron schedules.
125 - *
126 - * @param array $schedules Existing cron schedules.
127 - *
128 - * @return array Modified cron schedules.
129 - */
130 - public static function add_cron_schedules( $schedules ) {
131 - $schedules['monthly'] = array(
132 - 'interval' => MONTH_IN_SECONDS,
133 - 'display' => \__( 'Once Monthly', 'activitypub' ),
134 - );
135 -
136 - $schedules['yearly'] = array(
137 - 'interval' => YEAR_IN_SECONDS,
138 - 'display' => \__( 'Once Yearly', 'activitypub' ),
139 - );
140 -
141 - return $schedules;
142 - }
143 -
144 - /**
145 91 * Register a batch callback for async processing.
146 92 *
147 93 * @param string $hook The cron event hook name.
148 94 * @param callable $callback The callback to execute.
@@ -166,26 +112,27 @@
166 112 /**
167 113 * Schedule all ActivityPub schedules.
168 114 */
169 115 public static function register_schedules() {
170 - foreach ( self::SCHEDULES as $hook => $recurrence ) {
171 - if ( ! \wp_next_scheduled( $hook ) ) {
172 - \wp_schedule_event( \time(), $recurrence, $hook );
173 - }
116 + if ( ! \wp_next_scheduled( 'activitypub_update_remote_actors' ) ) {
117 + \wp_schedule_event( time(), 'hourly', 'activitypub_update_remote_actors' );
174 118 }
175 119
176 - // Schedule monthly stats collection for the 1st of each month.
177 - if ( ! \wp_next_scheduled( 'activitypub_collect_monthly_stats' ) ) {
178 - // Calculate next 1st of month at 2:00 AM.
179 - $next_first = self::get_next_first_of_month();
180 - \wp_schedule_event( $next_first, 'monthly', 'activitypub_collect_monthly_stats' );
120 + if ( ! \wp_next_scheduled( 'activitypub_cleanup_remote_actors' ) ) {
121 + \wp_schedule_event( time(), 'daily', 'activitypub_cleanup_remote_actors' );
181 122 }
182 123
183 - // Schedule annual stats compilation for December 1st (wrapped notification).
184 - if ( ! \wp_next_scheduled( 'activitypub_compile_annual_stats' ) ) {
185 - $next_december = self::get_next_december_first();
186 - \wp_schedule_event( $next_december, 'yearly', 'activitypub_compile_annual_stats' );
124 + if ( ! \wp_next_scheduled( 'activitypub_reprocess_outbox' ) ) {
125 + \wp_schedule_event( time(), 'hourly', 'activitypub_reprocess_outbox' );
187 126 }
127 +
128 + if ( ! \wp_next_scheduled( 'activitypub_outbox_purge' ) ) {
129 + \wp_schedule_event( time(), 'daily', 'activitypub_outbox_purge' );
130 + }
131 +
132 + if ( ! \wp_next_scheduled( 'activitypub_inbox_purge' ) ) {
133 + \wp_schedule_event( time(), 'daily', 'activitypub_inbox_purge' );
134 + }
188 135 }
189 136
190 137 /**
191 138 * Un-schedule all ActivityPub schedules.
@@ -192,64 +139,37 @@
192 139 *
193 140 * @return void
194 141 */
195 142 public static function deregister_schedules() {
196 - foreach ( \array_keys( self::SCHEDULES ) as $hook ) {
197 - \wp_unschedule_hook( $hook );
198 - }
199 -
200 - // Statistics schedules.
201 - \wp_unschedule_hook( 'activitypub_collect_monthly_stats' );
202 - \wp_unschedule_hook( 'activitypub_compile_annual_stats' );
143 + \wp_unschedule_hook( 'activitypub_update_remote_actors' );
144 + \wp_unschedule_hook( 'activitypub_cleanup_remote_actors' );
145 + \wp_unschedule_hook( 'activitypub_reprocess_outbox' );
146 + \wp_unschedule_hook( 'activitypub_outbox_purge' );
147 + \wp_unschedule_hook( 'activitypub_inbox_purge' );
203 148 }
204 149
205 150 /**
206 - * Get the next 1st of month timestamp.
207 - *
208 - * @return int Unix timestamp of next 1st of month at 2:00 AM.
209 - */
210 - private static function get_next_first_of_month() {
211 - $now = \current_time( 'timestamp' ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
212 - $next_month = \strtotime( 'first day of next month 02:00:00', $now );
213 -
214 - return $next_month;
215 - }
216 -
217 - /**
218 - * Get the next December 1st timestamp for wrapped notification.
219 - *
220 - * @return int Unix timestamp of next December 1st at 3:00 AM.
221 - */
222 - private static function get_next_december_first() {
223 - $now = \current_time( 'timestamp' ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
224 - $year = (int) \gmdate( 'Y', $now );
225 -
226 - // Get December 1st 3:00 AM for this year.
227 - $this_year_dec_first = \strtotime( \sprintf( '%d-12-01 03:00:00', $year ) );
228 -
229 - // If we're already past this year's December 1st, schedule for next year.
230 - if ( $now >= $this_year_dec_first ) {
231 - return \strtotime( \sprintf( '%d-12-01 03:00:00', $year + 1 ) );
232 - }
233 -
234 - return $this_year_dec_first;
235 - }
236 -
237 - /**
238 151 * Unschedule events for an outbox item.
239 152 *
240 153 * @param int $outbox_item_id The outbox item ID.
241 154 */
242 155 public static function unschedule_events_for_item( $outbox_item_id ) {
156 + $event_args = array(
157 + $outbox_item_id,
158 + Dispatcher::get_batch_size(),
159 + \get_post_meta( $outbox_item_id, '_activitypub_outbox_offset', true ) ?: 0, // phpcs:ignore
160 + );
161 +
243 162 \delete_post_meta( $outbox_item_id, '_activitypub_outbox_offset' );
244 163
245 164 $timestamp = \wp_next_scheduled( 'activitypub_process_outbox', array( $outbox_item_id ) );
246 165 \wp_unschedule_event( $timestamp, 'activitypub_process_outbox', array( $outbox_item_id ) );
247 166
248 - self::unschedule_outbox_delivery_batches( $outbox_item_id );
167 + $timestamp = \wp_next_scheduled( 'activitypub_send_activity', $event_args );
168 + \wp_unschedule_event( $timestamp, 'activitypub_send_activity', $event_args );
249 169
250 170 // Invalidate any retries for this outbox item.
251 - foreach ( \_get_cron_array() as $timestamp => $cron ) {
171 + foreach ( _get_cron_array() as $timestamp => $cron ) {
252 172 if ( ! isset( $cron['activitypub_retry_activity'] ) ) {
253 173 continue;
254 174 }
255 175
@@ -266,9 +186,9 @@
266 186 */
267 187 public static function update_remote_actors() {
268 188 $number = 5;
269 189
270 - if ( \defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) {
190 + if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) {
271 191 $number = 50;
272 192 }
273 193
274 194 /**
@@ -275,56 +195,18 @@
275 195 * Filter the number of remote Actors to update.
276 196 *
277 197 * @param int $number The number of remote Actors to update.
278 198 */
279 - $number = \apply_filters( 'activitypub_update_remote_actors_number', $number );
199 + $number = apply_filters( 'activitypub_update_remote_actors_number', $number );
280 200 $actors = Remote_Actors::get_outdated( $number );
281 201
282 202 foreach ( $actors as $actor ) {
283 - /*
284 - * Use Http::get_remote_object() directly here.
285 - * get_remote_metadata_by_actor() short-circuits to the locally
286 - * cached ap_actor CPT via Remote_Actors::fetch_by_uri() and never
287 - * makes an HTTP request when the actor is already cached, so the
288 - * upsert would just rewrite the same stale data and this refresh
289 - * would be a no-op. The Update handler documents the same trap.
290 - */
291 - $meta = Http::get_remote_object( $actor->guid, false );
203 + $meta = get_remote_metadata_by_actor( $actor->guid, false );
292 204
293 - if ( empty( $meta ) || ! \is_array( $meta ) || \is_wp_error( $meta ) ) {
205 + if ( empty( $meta ) || ! is_array( $meta ) || is_wp_error( $meta ) ) {
294 206 Remote_Actors::add_error( $actor->ID, 'Failed to fetch or parse metadata' );
295 207 } else {
296 - /*
297 - * Only refresh when the remote still reports the same identity. A
298 - * different (or missing) id means a Move or a malformed response;
299 - * applying it would rewrite the cached guid in place and could
300 - * collide with another cached actor, so leave the record alone.
301 - * Updating by the known post ID otherwise refreshes it without the
302 - * redundant get_by_uri() lookup upsert() would do.
303 - */
304 - $fetched_id = isset( $meta['id'] ) && \is_string( $meta['id'] ) ? \esc_url_raw( $meta['id'] ) : '';
305 - if ( $fetched_id !== $actor->guid ) {
306 - /*
307 - * Bump only the modified date, directly, so the skipped actor
308 - * drops out of the outdated queue and is not re-fetched every
309 - * run. A direct write avoids the save_post hooks wp_update_post()
310 - * fires (which would needlessly clear the cached avatar); the
311 - * record is intentionally left unchanged otherwise.
312 - */
313 - global $wpdb;
314 - $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
315 - $wpdb->posts,
316 - array(
317 - 'post_modified' => \current_time( 'mysql' ),
318 - 'post_modified_gmt' => \current_time( 'mysql', true ),
319 - ),
320 - array( 'ID' => $actor->ID )
321 - );
322 - \clean_post_cache( $actor->ID );
323 - continue;
324 - }
325 -
326 - $id = Remote_Actors::update( $actor->ID, $meta );
208 + $id = Remote_Actors::upsert( $meta );
327 209 if ( \is_wp_error( $id ) ) {
328 210 continue;
329 211 }
330 212 Remote_Actors::clear_errors( $id );
@@ -337,9 +219,9 @@
337 219 */
338 220 public static function cleanup_remote_actors() {
339 221 $number = 5;
340 222
341 - if ( \defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) {
223 + if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) {
342 224 $number = 50;
343 225 }
344 226
345 227 /**
@@ -346,9 +228,9 @@
346 228 * Filter the number of remote Actors to clean up.
347 229 *
348 230 * @param int $number The number of remote Actors to clean up.
349 231 */
350 - $number = \apply_filters( 'activitypub_cleanup_remote_actors_number', $number );
232 + $number = apply_filters( 'activitypub_cleanup_remote_actors_number', $number );
351 233 $actors = Remote_Actors::get_faulty( $number );
352 234
353 235 foreach ( $actors as $actor ) {
354 236 $meta = get_remote_metadata_by_actor( $actor->guid, false );
@@ -354,9 +236,9 @@
354 236 $meta = get_remote_metadata_by_actor( $actor->guid, false );
355 237
356 238 if ( Tombstone::exists( $meta ) ) {
357 239 \wp_delete_post( $actor->ID );
358 - } elseif ( empty( $meta ) || ! \is_array( $meta ) || \is_wp_error( $meta ) ) {
240 + } elseif ( empty( $meta ) || ! is_array( $meta ) || \is_wp_error( $meta ) ) {
359 241 if ( Remote_Actors::count_errors( $actor->ID ) >= 5 ) {
360 242 \wp_schedule_single_event( \time(), 'activitypub_delete_remote_actor_interactions', array( $actor->guid ) );
361 243 \wp_schedule_single_event( \time(), 'activitypub_delete_remote_actor_posts', array( $actor->guid ) );
362 244 \wp_delete_post( $actor->ID );
@@ -377,15 +259,15 @@
377 259 /**
378 260 * Schedule the outbox item for federation.
379 261 *
380 262 * @param int $id The ID of the outbox item.
381 - * @param int $offset The offset to add to the scheduled time. Default 3 seconds.
263 + * @param int $offset The offset to add to the scheduled time.
382 264 */
383 - public static function schedule_outbox_activity_for_federation( $id, $offset = 3 ) {
265 + public static function schedule_outbox_activity_for_federation( $id, $offset = 0 ) {
384 266 $hook = 'activitypub_process_outbox';
385 267 $args = array( $id );
386 268
387 - if ( false === \wp_next_scheduled( $hook, $args ) ) {
269 + if ( false === wp_next_scheduled( $hook, $args ) ) {
388 270 \wp_schedule_single_event(
389 271 \time() + $offset,
390 272 $hook,
391 273 $args
@@ -408,9 +290,9 @@
408 290
409 291 foreach ( $ids as $id ) {
410 292 // Bail if there is a pending batch.
411 293 $offset = \get_post_meta( $id, '_activitypub_outbox_offset', true ) ?: 0; // phpcs:ignore
412 - if ( self::has_scheduled_outbox_delivery_batch( $id, $offset ) ) {
294 + if ( \wp_next_scheduled( 'activitypub_send_activity', array( $id, Dispatcher::get_batch_size(), $offset ) ) ) {
413 295 return;
414 296 }
415 297
416 298 // Bail if there is a batch in progress.
@@ -426,9 +308,39 @@
426 308 /**
427 309 * Purge outbox items based on a schedule.
428 310 */
429 311 public static function purge_outbox() {
430 - Outbox::purge( \get_option( 'activitypub_outbox_purge_days', ACTIVITYPUB_OUTBOX_PURGE_DAYS ) );
312 + $total_posts = (int) wp_count_posts( Outbox::POST_TYPE )->publish;
313 + if ( $total_posts <= 20 ) {
314 + return;
315 + }
316 +
317 + $days = (int) get_option( 'activitypub_outbox_purge_days', 180 );
318 + $post_ids = \get_posts(
319 + array(
320 + 'post_type' => Outbox::POST_TYPE,
321 + 'post_status' => 'any',
322 + 'fields' => 'ids',
323 + 'numberposts' => -1,
324 + 'date_query' => array(
325 + array(
326 + 'before' => gmdate( 'Y-m-d', time() - ( $days * DAY_IN_SECONDS ) ),
327 + ),
328 + ),
329 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
330 + 'meta_query' => array(
331 + array(
332 + 'key' => '_activitypub_activity_type',
333 + 'value' => 'Follow',
334 + 'compare' => '!=',
335 + ),
336 + ),
337 + )
338 + );
339 +
340 + foreach ( $post_ids as $post_id ) {
341 + \wp_delete_post( $post_id, true );
342 + }
431 343 }
432 344
433 345 /**
434 346 * Purge inbox items based on a schedule.
@@ -433,28 +345,31 @@
433 345 /**
434 346 * Purge inbox items based on a schedule.
435 347 */
436 348 public static function purge_inbox() {
437 - Inbox::purge( \get_option( 'activitypub_inbox_purge_days', ACTIVITYPUB_INBOX_PURGE_DAYS ) );
438 - }
349 + $total_posts = (int) wp_count_posts( Inbox::POST_TYPE )->publish;
350 + if ( $total_posts <= 200 ) {
351 + return;
352 + }
439 353
440 - /**
441 - * Purge remote posts based on a schedule.
442 - */
443 - public static function purge_ap_posts() {
444 - Remote_Posts::purge( \get_option( 'activitypub_ap_post_purge_days', ACTIVITYPUB_AP_POST_PURGE_DAYS ) );
445 - }
354 + $days = (int) get_option( 'activitypub_inbox_purge_days', 180 );
355 + $post_ids = \get_posts(
356 + array(
357 + 'post_type' => Inbox::POST_TYPE,
358 + 'post_status' => 'any',
359 + 'fields' => 'ids',
360 + 'numberposts' => -1,
361 + 'date_query' => array(
362 + array(
363 + 'before' => gmdate( 'Y-m-d', time() - ( $days * DAY_IN_SECONDS ) ),
364 + ),
365 + ),
366 + )
367 + );
446 368
447 - /**
448 - * Daily cron handler that purges expired tombstones.
449 - *
450 - * Retention is non-urgent: large backlogs (e.g. after retention is first enforced)
451 - * drain across multiple daily runs.
452 - *
453 - * @since 8.3.0
454 - */
455 - public static function purge_tombstones() {
456 - Tombstone::purge();
369 + foreach ( $post_ids as $post_id ) {
370 + \wp_delete_post( $post_id, true );
371 + }
457 372 }
458 373
459 374 /**
460 375 * Process cached inbox activity.
@@ -472,9 +387,9 @@
472 387
473 388 $data = \json_decode( $inbox_item->post_content, true );
474 389 // Reconstruct activity from inbox post.
475 390 $activity = Activity::init_from_array( $data );
476 - $type = camel_to_snake_case( $activity->get_type() );
391 + $type = \Activitypub\camel_to_snake_case( $activity->get_type() );
477 392 $context = Inbox::CONTEXT_INBOX;
478 393 $user_ids = Inbox::get_recipients( $inbox_item->ID );
479 394
480 395 /**
@@ -508,9 +423,9 @@
508 423 *
509 424 * @param int $old_value The old value.
510 425 * @param int $value The new value.
511 426 */
512 - public static function update_outbox_purge_schedule( $old_value, $value ) {
427 + public static function handle_outbox_purge_days_update( $old_value, $value ) {
513 428 if ( 0 === (int) $value ) {
514 429 \wp_clear_scheduled_hook( 'activitypub_outbox_purge' );
515 430 } elseif ( ! \wp_next_scheduled( 'activitypub_outbox_purge' ) ) {
516 431 \wp_schedule_event( \time(), 'daily', 'activitypub_outbox_purge' );
@@ -522,9 +437,9 @@
522 437 *
523 438 * @param int $old_value The old value.
524 439 * @param int $value The new value.
525 440 */
526 - public static function update_inbox_purge_schedule( $old_value, $value ) {
441 + public static function handle_inbox_purge_days_update( $old_value, $value ) {
527 442 if ( 0 === (int) $value ) {
528 443 \wp_clear_scheduled_hook( 'activitypub_inbox_purge' );
529 444 } elseif ( ! \wp_next_scheduled( 'activitypub_inbox_purge' ) ) {
530 445 \wp_schedule_event( \time(), 'daily', 'activitypub_inbox_purge' );
@@ -531,22 +446,8 @@
531 446 }
532 447 }
533 448
534 449 /**
535 - * Update schedules when remote posts purge days settings change.
536 - *
537 - * @param int $old_value The old value.
538 - * @param int $value The new value.
539 - */
540 - public static function update_ap_post_purge_schedule( $old_value, $value ) {
541 - if ( 0 === (int) $value ) {
542 - \wp_clear_scheduled_hook( 'activitypub_ap_post_purge' );
543 - } elseif ( ! \wp_next_scheduled( 'activitypub_ap_post_purge' ) ) {
544 - \wp_schedule_event( \time(), 'daily', 'activitypub_ap_post_purge' );
545 - }
546 - }
547 -
548 - /**
549 450 * Asynchronously runs batch processing routines.
550 451 *
551 452 * The batching part is optional and only comes into play if the callback returns anything.
552 453 * Beyond that it's a helper to run a callback asynchronously with locking to prevent simultaneous processing.
@@ -579,76 +480,13 @@
579 480 self::unlock( $key );
580 481
581 482 if ( ! empty( $next ) ) {
582 483 // Schedule the next run, adding the result to the arguments.
583 - \wp_schedule_single_event( \time() + self::get_retry_delay( \current_action() ), \current_action(), \array_values( $next ) );
484 + \wp_schedule_single_event( \time() + self::get_retry_delay(), \current_action(), \array_values( $next ) );
584 485 }
585 486 }
586 487
587 488 /**
588 - * Whether an outbox item already has a scheduled delivery batch at an offset.
589 - *
590 - * @param int $outbox_item_id The outbox item ID.
591 - * @param int $offset The delivery offset.
592 - *
593 - * @return bool True when a matching delivery batch is scheduled.
594 - */
595 - private static function has_scheduled_outbox_delivery_batch( $outbox_item_id, $offset ) {
596 - return ! empty( self::get_scheduled_outbox_delivery_batches( $outbox_item_id, $offset ) );
597 - }
598 -
599 - /**
600 - * Unschedule all pending delivery batches for an outbox item.
601 - *
602 - * @param int $outbox_item_id The outbox item ID.
603 - */
604 - private static function unschedule_outbox_delivery_batches( $outbox_item_id ) {
605 - foreach ( self::get_scheduled_outbox_delivery_batches( $outbox_item_id ) as $event ) {
606 - \wp_unschedule_event( $event['timestamp'], 'activitypub_send_activity', $event['args'] );
607 - }
608 - }
609 -
610 - /**
611 - * Get scheduled delivery batches for an outbox item.
612 - *
613 - * The batch size is deliberately ignored because scheduled events may
614 - * retain an older value after the admin changes the distribution mode.
615 - *
616 - * @param int $outbox_item_id The outbox item ID.
617 - * @param int|null $offset Optional. Restrict results to this delivery offset.
618 - *
619 - * @return array Scheduled events with timestamp and args.
620 - */
621 - private static function get_scheduled_outbox_delivery_batches( $outbox_item_id, $offset = null ) {
622 - $events = array();
623 -
624 - foreach ( \_get_cron_array() as $timestamp => $cron ) {
625 - if ( empty( $cron['activitypub_send_activity'] ) ) {
626 - continue;
627 - }
628 -
629 - foreach ( $cron['activitypub_send_activity'] as $event ) {
630 - $args = $event['args'] ?? array();
631 -
632 - if ( ! isset( $args[0] ) || (int) $outbox_item_id !== (int) $args[0] ) {
633 - continue;
634 - }
635 -
636 - if ( null !== $offset && (int) ( $args[2] ?? 0 ) !== (int) $offset ) {
637 - continue;
638 - }
639 -
640 - $events[] = array(
641 - 'timestamp' => $timestamp,
642 - 'args' => $args,
643 - );
644 - }
645 - }
646 -
647 - return $events;
648 - }
649 -
650 - /**
651 489 * Locks the async batch process for individual callbacks to prevent simultaneous processing.
652 490 *
653 491 * @param string $key Serialized callback name.
654 492 * @return bool|int True if the lock was successful, timestamp of existing lock otherwise.
@@ -726,14 +564,14 @@
726 564 if ( 'Create' !== $activity->get_type() ) {
727 565 return;
728 566 }
729 567
730 - if ( ! \is_object( $activity->get_object() ) ) {
568 + if ( ! is_object( $activity->get_object() ) ) {
731 569 return;
732 570 }
733 571
734 572 // Check if the object is an article, image, audio, video, event, or document and ignore profile updates and other activities.
735 - if ( ! \in_array( $activity->get_object()->get_type(), Base_Object::TYPES, true ) ) {
573 + if ( ! in_array( $activity->get_object()->get_type(), Base_Object::TYPES, true ) ) {
736 574 return;
737 575 }
738 576
739 577 $announce = new Activity();