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-options.php +0 -860 9.3.07.7.0 View file →
@@ -6,10 +6,8 @@
6 6 */
7 7
8 8 namespace Activitypub;
9 9
10 -use Activitypub\Model\Blog;
11 -
12 10 /**
13 11 * Options class.
14 12 */
15 13 class Options {
@@ -17,21 +15,12 @@
17 15 /**
18 16 * Initialize the options.
19 17 */
20 18 public static function init() {
21 - \add_action( 'admin_init', array( self::class, 'register_settings' ) );
22 - \add_action( 'rest_api_init', array( self::class, 'register_settings' ) );
23 -
24 19 \add_filter( 'pre_option_activitypub_actor_mode', array( self::class, 'pre_option_activitypub_actor_mode' ) );
25 20 \add_filter( 'pre_option_activitypub_authorized_fetch', array( self::class, 'pre_option_activitypub_authorized_fetch' ) );
26 21 \add_filter( 'pre_option_activitypub_vary_header', array( self::class, 'pre_option_activitypub_vary_header' ) );
27 - \add_filter( 'pre_option_activitypub_following_ui', array( self::class, 'pre_option_activitypub_following_ui' ) );
28 - \add_filter( 'pre_option_activitypub_create_posts', array( self::class, 'pre_option_activitypub_create_posts' ) );
29 22
30 - \add_filter( 'pre_option_activitypub_distribution_mode', array( self::class, 'pre_option_activitypub_distribution_mode' ) );
31 - \add_filter( 'activitypub_dispatcher_batch_size', array( self::class, 'filter_dispatcher_batch_size' ) );
32 - \add_filter( 'activitypub_scheduler_async_batch_pause', array( self::class, 'filter_scheduler_batch_pause' ), 10, 2 );
33 -
34 23 \add_filter( 'pre_option_activitypub_allow_likes', array( self::class, 'maybe_disable_interactions' ) );
35 24 \add_filter( 'pre_option_activitypub_allow_replies', array( self::class, 'maybe_disable_interactions' ) );
36 25
37 26 \add_filter( 'default_option_activitypub_negotiate_content', array( self::class, 'default_option_activitypub_negotiate_content' ) );
@@ -37,513 +26,11 @@
37 26 \add_filter( 'default_option_activitypub_negotiate_content', array( self::class, 'default_option_activitypub_negotiate_content' ) );
38 27 \add_filter( 'option_activitypub_max_image_attachments', array( self::class, 'default_max_image_attachments' ) );
39 28 \add_filter( 'option_activitypub_support_post_types', array( self::class, 'support_post_types_ensure_array' ) );
40 29 \add_filter( 'option_activitypub_object_type', array( self::class, 'default_object_type' ) );
41 -
42 - \add_filter( 'option_activitypub_outbox_purge_days', array( self::class, 'sanitize_purge_days' ) );
43 - \add_filter( 'option_activitypub_inbox_purge_days', array( self::class, 'sanitize_purge_days' ) );
44 - \add_filter( 'option_activitypub_ap_post_purge_days', array( self::class, 'sanitize_purge_days' ) );
45 -
46 - \add_action( 'update_option_activitypub_relay_mode', array( self::class, 'relay_mode_changed' ), 10, 2 );
47 30 }
48 31
49 32 /**
50 - * Register ActivityPub settings.
51 - */
52 - public static function register_settings() {
53 - /*
54 - * Options Group: activitypub
55 - */
56 - \register_setting(
57 - 'activitypub',
58 - 'activitypub_post_content_type',
59 - array(
60 - 'type' => 'string',
61 - 'description' => 'Use title and link, summary, full or custom content',
62 - 'show_in_rest' => array(
63 - 'schema' => array(
64 - 'enum' => array( 'title', 'excerpt', 'content' ),
65 - ),
66 - ),
67 - 'default' => 'content',
68 - )
69 - );
70 -
71 - \register_setting(
72 - 'activitypub',
73 - 'activitypub_custom_post_content',
74 - array(
75 - 'type' => 'string',
76 - 'description' => 'Define your own custom post template',
77 - 'show_in_rest' => true,
78 - 'default' => ACTIVITYPUB_CUSTOM_POST_CONTENT,
79 - )
80 - );
81 -
82 - \register_setting(
83 - 'activitypub',
84 - 'activitypub_max_image_attachments',
85 - array(
86 - 'type' => 'integer',
87 - 'description' => 'Number of images to attach to posts.',
88 - 'default' => ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS,
89 - 'sanitize_callback' => static function ( $value ) {
90 - return \is_numeric( $value ) ? \absint( $value ) : ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS;
91 - },
92 - )
93 - );
94 -
95 - \register_setting(
96 - 'activitypub',
97 - 'activitypub_use_hashtags',
98 - array(
99 - 'type' => 'boolean',
100 - 'description' => 'Add hashtags in the content as native tags and replace the #tag with the tag-link',
101 - 'default' => '0',
102 - )
103 - );
104 -
105 - \register_setting(
106 - 'activitypub',
107 - 'activitypub_use_opengraph',
108 - array(
109 - 'type' => 'boolean',
110 - 'description' => 'Automatically add "fediverse:creator" OpenGraph tags for Authors and the Blog-User.',
111 - 'default' => '1',
112 - )
113 - );
114 -
115 - \register_setting(
116 - 'activitypub',
117 - 'activitypub_support_post_types',
118 - array(
119 - 'type' => 'string',
120 - 'description' => 'Enable ActivityPub support for post types',
121 - 'show_in_rest' => true,
122 - 'default' => array( 'post' ),
123 - )
124 - );
125 -
126 - \register_setting(
127 - 'activitypub',
128 - 'activitypub_actor_mode',
129 - array(
130 - 'type' => 'string',
131 - 'description' => 'Choose your preferred Actor-Mode.',
132 - 'default' => ACTIVITYPUB_ACTOR_MODE,
133 - 'show_in_rest' => array(
134 - 'schema' => array(
135 - 'type' => 'string',
136 - 'enum' => array(
137 - ACTIVITYPUB_ACTOR_MODE,
138 - ACTIVITYPUB_BLOG_MODE,
139 - ACTIVITYPUB_ACTOR_AND_BLOG_MODE,
140 - ),
141 - ),
142 - ),
143 - )
144 - );
145 -
146 - \register_setting(
147 - 'activitypub',
148 - 'activitypub_attribution_domains',
149 - array(
150 - 'type' => 'string',
151 - 'description' => 'Websites allowed to credit you.',
152 - 'default' => home_host(),
153 - 'sanitize_callback' => array( Sanitize::class, 'host_list' ),
154 - )
155 - );
156 -
157 - \register_setting(
158 - 'activitypub',
159 - 'activitypub_allow_likes',
160 - array(
161 - 'type' => 'integer',
162 - 'description' => 'Allow likes.',
163 - 'default' => '1',
164 - 'sanitize_callback' => 'absint',
165 - )
166 - );
167 -
168 - \register_setting(
169 - 'activitypub',
170 - 'activitypub_allow_reposts',
171 - array(
172 - 'type' => 'integer',
173 - 'description' => 'Allow reposts.',
174 - 'default' => '1',
175 - 'sanitize_callback' => 'absint',
176 - )
177 - );
178 -
179 - \register_setting(
180 - 'activitypub',
181 - 'activitypub_auto_approve_reactions',
182 - array(
183 - 'type' => 'integer',
184 - 'description' => 'Auto-approve Reactions.',
185 - 'default' => '0',
186 - 'sanitize_callback' => 'absint',
187 - )
188 - );
189 -
190 - \register_setting(
191 - 'activitypub',
192 - 'activitypub_default_quote_policy',
193 - array(
194 - 'type' => 'string',
195 - 'description' => 'Default quote policy for new posts.',
196 - 'default' => ACTIVITYPUB_INTERACTION_POLICY_ANYONE,
197 - 'sanitize_callback' => static function ( $value ) {
198 - $allowed = array(
199 - ACTIVITYPUB_INTERACTION_POLICY_ANYONE,
200 - ACTIVITYPUB_INTERACTION_POLICY_FOLLOWERS,
201 - ACTIVITYPUB_INTERACTION_POLICY_ME,
202 - );
203 - return \in_array( $value, $allowed, true ) ? $value : ACTIVITYPUB_INTERACTION_POLICY_ANYONE;
204 - },
205 - )
206 - );
207 -
208 - \register_setting(
209 - 'activitypub',
210 - 'activitypub_default_feature_policy',
211 - array(
212 - 'type' => 'string',
213 - 'description' => 'Default policy for who can include this site\'s actors in featured collections (FEP-7aa9).',
214 - 'default' => ACTIVITYPUB_INTERACTION_POLICY_ME,
215 - 'sanitize_callback' => static function ( $value ) {
216 - $allowed = array(
217 - ACTIVITYPUB_INTERACTION_POLICY_ANYONE,
218 - ACTIVITYPUB_INTERACTION_POLICY_FOLLOWERS,
219 - ACTIVITYPUB_INTERACTION_POLICY_ME,
220 - );
221 - return \in_array( $value, $allowed, true ) ? $value : ACTIVITYPUB_INTERACTION_POLICY_ME;
222 - },
223 - )
224 - );
225 -
226 - \register_setting(
227 - 'activitypub',
228 - 'activitypub_relays',
229 - array(
230 - 'type' => 'array',
231 - 'description' => 'Relays',
232 - 'default' => array(),
233 - 'sanitize_callback' => array( Sanitize::class, 'url_list' ),
234 - )
235 - );
236 -
237 - \register_setting(
238 - 'activitypub',
239 - 'activitypub_site_blocked_actors',
240 - array(
241 - 'type' => 'array',
242 - 'description' => 'Site-wide blocked ActivityPub actors.',
243 - 'default' => array(),
244 - 'sanitize_callback' => array( Sanitize::class, 'identifier_list' ),
245 - )
246 - );
247 -
248 - /*
249 - * Options Group: activitypub_advanced
250 - */
251 - \register_setting(
252 - 'activitypub_advanced',
253 - 'activitypub_outbox_purge_days',
254 - array(
255 - 'type' => 'integer',
256 - 'description' => 'Number of days to keep items in the Outbox.',
257 - 'default' => ACTIVITYPUB_OUTBOX_PURGE_DAYS,
258 - 'sanitize_callback' => static function ( $value ) {
259 - return \max( 1, \absint( $value ) );
260 - },
261 - )
262 - );
263 -
264 - \register_setting(
265 - 'activitypub_advanced',
266 - 'activitypub_inbox_purge_days',
267 - array(
268 - 'type' => 'integer',
269 - 'description' => 'Number of days to keep items in the Inbox.',
270 - 'default' => ACTIVITYPUB_INBOX_PURGE_DAYS,
271 - 'sanitize_callback' => static function ( $value ) {
272 - return \max( 1, \absint( $value ) );
273 - },
274 - )
275 - );
276 -
277 - \register_setting(
278 - 'activitypub_advanced',
279 - 'activitypub_ap_post_purge_days',
280 - array(
281 - 'type' => 'integer',
282 - 'description' => 'Number of days to keep remote posts.',
283 - 'default' => ACTIVITYPUB_AP_POST_PURGE_DAYS,
284 - 'sanitize_callback' => static function ( $value ) {
285 - return \max( 1, \absint( $value ) );
286 - },
287 - )
288 - );
289 -
290 - \register_setting(
291 - 'activitypub_advanced',
292 - 'activitypub_vary_header',
293 - array(
294 - 'type' => 'boolean',
295 - 'description' => 'Add the Vary header to the ActivityPub response.',
296 - 'default' => true,
297 - )
298 - );
299 -
300 - \register_setting(
301 - 'activitypub_advanced',
302 - 'activitypub_content_negotiation',
303 - array(
304 - 'type' => 'boolean',
305 - 'description' => 'Enable content negotiation.',
306 - 'default' => true,
307 - )
308 - );
309 -
310 - \register_setting(
311 - 'activitypub_advanced',
312 - 'activitypub_authorized_fetch',
313 - array(
314 - 'type' => 'boolean',
315 - 'description' => 'Require HTTP signature authentication.',
316 - 'default' => false,
317 - )
318 - );
319 -
320 - \register_setting(
321 - 'activitypub_advanced',
322 - 'activitypub_rfc9421_signature',
323 - array(
324 - 'type' => 'boolean',
325 - 'description' => 'Use RFC-9421 signature.',
326 - 'default' => true,
327 - )
328 - );
329 -
330 - \register_setting(
331 - 'activitypub_advanced',
332 - 'activitypub_following_ui',
333 - array(
334 - 'type' => 'boolean',
335 - 'description' => 'Show Following UI in admin menus and settings.',
336 - 'default' => false,
337 - )
338 - );
339 -
340 - \register_setting(
341 - 'activitypub_advanced',
342 - 'activitypub_reader_ui',
343 - array(
344 - 'type' => 'boolean',
345 - 'description' => 'Enable the Reader to view posts from accounts you follow.',
346 - 'default' => false,
347 - )
348 - );
349 -
350 - \register_setting(
351 - 'activitypub_advanced',
352 - 'activitypub_create_posts',
353 - array(
354 - 'type' => 'boolean',
355 - 'description' => 'Allow creating posts via ActivityPub.',
356 - 'default' => false,
357 - )
358 - );
359 -
360 - \register_setting(
361 - 'activitypub_advanced',
362 - 'activitypub_api',
363 - array(
364 - 'type' => 'boolean',
365 - 'description' => 'Enable the ActivityPub API to allow third-party clients.',
366 - 'default' => false,
367 - )
368 - );
369 -
370 - \register_setting(
371 - 'activitypub_advanced',
372 - 'activitypub_object_type',
373 - array(
374 - 'type' => 'string',
375 - 'description' => 'The Activity-Object-Type',
376 - 'show_in_rest' => array(
377 - 'schema' => array(
378 - 'enum' => array( 'note', 'wordpress-post-format' ),
379 - ),
380 - ),
381 - 'default' => ACTIVITYPUB_DEFAULT_OBJECT_TYPE,
382 - )
383 - );
384 -
385 - \register_setting(
386 - 'activitypub_advanced',
387 - 'activitypub_relay_mode',
388 - array(
389 - 'type' => 'integer',
390 - 'description' => 'Enable relay mode to forward public activities to all followers.',
391 - 'default' => 0,
392 - 'sanitize_callback' => 'absint',
393 - )
394 - );
395 -
396 - $default_distribution = self::get_distribution_preset_values()['default'];
397 -
398 - \register_setting(
399 - 'activitypub_advanced',
400 - 'activitypub_distribution_mode',
401 - array(
402 - 'type' => 'string',
403 - 'description' => \__( 'Distribution mode for federation delivery.', 'activitypub' ),
404 - 'default' => 'default',
405 - 'sanitize_callback' => array( self::class, 'sanitize_distribution_mode' ),
406 - )
407 - );
408 -
409 - \register_setting(
410 - 'activitypub_advanced',
411 - 'activitypub_custom_batch_size',
412 - array(
413 - 'type' => 'integer',
414 - 'description' => \__( 'Custom batch size for federation delivery.', 'activitypub' ),
415 - 'default' => $default_distribution['batch_size'],
416 - 'sanitize_callback' => static function ( $value ) {
417 - return \min( 500, \max( 1, \absint( $value ) ) );
418 - },
419 - )
420 - );
421 -
422 - \register_setting(
423 - 'activitypub_advanced',
424 - 'activitypub_custom_batch_pause',
425 - array(
426 - 'type' => 'integer',
427 - 'description' => \__( 'Custom pause in seconds between batches.', 'activitypub' ),
428 - 'default' => $default_distribution['pause'],
429 - 'sanitize_callback' => static function ( $value ) {
430 - return \min( 3600, \absint( $value ) );
431 - },
432 - )
433 - );
434 -
435 - /*
436 - * Options Group: activitypub_blog
437 - */
438 - \register_setting(
439 - 'activitypub_blog',
440 - 'activitypub_blog_description',
441 - array(
442 - 'type' => 'string',
443 - 'description' => 'The Description of the Blog-User',
444 - 'show_in_rest' => true,
445 - 'default' => '',
446 - )
447 - );
448 -
449 - \register_setting(
450 - 'activitypub_blog',
451 - 'activitypub_blog_identifier',
452 - array(
453 - 'type' => 'string',
454 - 'description' => 'The Identifier of the Blog-User',
455 - 'show_in_rest' => true,
456 - 'default' => Blog::get_default_username(),
457 - 'sanitize_callback' => array( Sanitize::class, 'blog_identifier' ),
458 - )
459 - );
460 -
461 - \register_setting(
462 - 'activitypub_blog',
463 - 'activitypub_header_image',
464 - array(
465 - 'type' => 'integer',
466 - 'description' => 'The Attachment-ID of the Sites Header-Image',
467 - 'default' => null,
468 - )
469 - );
470 -
471 - \register_setting(
472 - 'activitypub_blog',
473 - 'activitypub_blog_user_mailer_new_dm',
474 - array(
475 - 'type' => 'integer',
476 - 'description' => 'Send a notification when someone sends a user of the blog a direct message.',
477 - 'default' => 1,
478 - )
479 - );
480 -
481 - \register_setting(
482 - 'activitypub_blog',
483 - 'activitypub_blog_user_mailer_new_follower',
484 - array(
485 - 'type' => 'integer',
486 - 'description' => 'Send a notification when someone starts to follow a user of the blog.',
487 - 'default' => 1,
488 - )
489 - );
490 -
491 - \register_setting(
492 - 'activitypub_blog',
493 - 'activitypub_blog_user_mailer_new_mention',
494 - array(
495 - 'type' => 'integer',
496 - 'description' => 'Send a notification when someone mentions a user of the blog.',
497 - 'default' => 1,
498 - )
499 - );
500 -
501 - \register_setting(
502 - 'activitypub_blog',
503 - 'activitypub_mailer_annual_report',
504 - array(
505 - 'type' => 'integer',
506 - 'description' => 'Send the annual Fediverse Year in Review email.',
507 - 'default' => 1,
508 - )
509 - );
510 -
511 - \register_setting(
512 - 'activitypub_blog',
513 - 'activitypub_mailer_monthly_report',
514 - array(
515 - 'type' => 'integer',
516 - 'description' => 'Send a monthly Fediverse stats report email.',
517 - 'default' => 0,
518 - )
519 - );
520 -
521 - \register_setting(
522 - 'activitypub_blog',
523 - 'activitypub_blog_user_also_known_as',
524 - array(
525 - 'type' => 'array',
526 - 'description' => 'An array of URLs that the blog user is known by.',
527 - 'default' => array(),
528 - 'sanitize_callback' => array( Sanitize::class, 'identifier_list' ),
529 - )
530 - );
531 -
532 - \register_setting(
533 - 'activitypub_blog',
534 - 'activitypub_hide_social_graph',
535 - array(
536 - 'type' => 'integer',
537 - 'description' => 'Hide Followers and Followings on Profile.',
538 - 'default' => 0,
539 - 'sanitize_callback' => 'absint',
540 - 'show_in_rest' => true,
541 - )
542 - );
543 - }
544 -
545 - /**
546 33 * Delete all options.
547 34 */
548 35 public static function delete() {
549 36 global $wpdb;
@@ -613,46 +100,8 @@
613 100 return '0';
614 101 }
615 102
616 103 /**
617 - * Pre-get option filter for the Following UI.
618 - *
619 - * Forces the Following UI to be enabled when the Reader is enabled.
620 - *
621 - * @param string $pre The pre-get option value.
622 - *
623 - * @return string If the Reader is enabled, return '1', otherwise return the pre-get option value.
624 - */
625 - public static function pre_option_activitypub_following_ui( $pre ) {
626 - /*
627 - * Bypass the filter to get the actual stored value for activitypub_reader_ui.
628 - * This avoids infinite loops if activitypub_reader_ui also had a pre_option filter.
629 - */
630 - if ( \get_option( 'activitypub_reader_ui', '0' ) ) {
631 - return '1';
632 - }
633 -
634 - return $pre;
635 - }
636 -
637 - /**
638 - * Pre-get option filter for the Create Posts setting.
639 - *
640 - * Forces the Create Posts setting to be enabled when the Reader is enabled.
641 - *
642 - * @param string $pre The pre-get option value.
643 - *
644 - * @return string If the Reader is enabled, return '1', otherwise return the pre-get option value.
645 - */
646 - public static function pre_option_activitypub_create_posts( $pre ) {
647 - if ( \get_option( 'activitypub_reader_ui', '0' ) ) {
648 - return '1';
649 - }
650 -
651 - return $pre;
652 - }
653 -
654 - /**
655 104 * Disallow interactions if the constant is set.
656 105 *
657 106 * @param bool $pre The value of the option.
658 107 *
@@ -731,315 +180,6 @@
731 180 $value = ACTIVITYPUB_DEFAULT_OBJECT_TYPE;
732 181 }
733 182
734 183 return $value;
735 - }
736 -
737 - /**
738 - * Pre-get option filter for the Distribution Mode.
739 - *
740 - * @since 9.0.0
741 - *
742 - * @param string|false $pre The pre-get option value.
743 - *
744 - * @return string|false The distribution mode or false if it should not be filtered.
745 - */
746 - public static function pre_option_activitypub_distribution_mode( $pre ) {
747 - return self::resolve_distribution_mode( $pre, ACTIVITYPUB_DISTRIBUTION_MODE );
748 - }
749 -
750 - /**
751 - * Whether the distribution mode is locked to a valid preset by the
752 - * `ACTIVITYPUB_DISTRIBUTION_MODE` constant.
753 - *
754 - * Returns true only when the constant is set to a key recognized by
755 - * `get_distribution_preset_values()`. Invalid constant values fall back
756 - * to `'default'` at runtime (see `resolve_distribution_mode()`) but the
757 - * UI stays visible so admins can spot the misconfiguration.
758 - *
759 - * @since 9.0.0
760 - *
761 - * @return bool True when the constant pins the mode to a valid preset.
762 - */
763 - public static function is_distribution_mode_locked() {
764 - if ( false === ACTIVITYPUB_DISTRIBUTION_MODE ) {
765 - return false;
766 - }
767 -
768 - return \in_array( ACTIVITYPUB_DISTRIBUTION_MODE, \array_keys( self::get_distribution_preset_values() ), true );
769 - }
770 -
771 - /**
772 - * Resolve the distribution mode against the wp-config constant.
773 - *
774 - * Extracted from `pre_option_activitypub_distribution_mode()` so the
775 - * constant-lock path can be exercised from tests without redefining
776 - * the real constant.
777 - *
778 - * Only preset modes are honored via the constant. The 'custom' mode
779 - * is excluded because its batch size and pause values are still read
780 - * from the database, which would defeat the purpose of locking the
781 - * mode via wp-config.php.
782 - *
783 - * @since 9.0.0
784 - *
785 - * @param string|false $pre The pre-get option value.
786 - * @param mixed $constant_value The value of `ACTIVITYPUB_DISTRIBUTION_MODE`.
787 - *
788 - * @return string|false Mode if locked, `$pre` otherwise.
789 - */
790 - public static function resolve_distribution_mode( $pre, $constant_value ) {
791 - if ( false === $constant_value ) {
792 - return $pre;
793 - }
794 -
795 - $allowed = \array_keys( self::get_distribution_preset_values() );
796 -
797 - if ( \in_array( $constant_value, $allowed, true ) ) {
798 - return $constant_value;
799 - }
800 -
801 - \_doing_it_wrong(
802 - __METHOD__,
803 - \sprintf(
804 - /* translators: %s: invalid constant value */
805 - \esc_html__( 'ACTIVITYPUB_DISTRIBUTION_MODE value %s is not a valid preset; falling back to default.', 'activitypub' ),
806 - \esc_html( (string) $constant_value )
807 - ),
808 - '9.0.0'
809 - );
810 -
811 - return 'default';
812 - }
813 -
814 - /**
815 - * Get the raw batch_size/pause values for each distribution preset.
816 - *
817 - * Single source of truth for the preset values, used in the hot path
818 - * (get_distribution_params, sanitize_distribution_mode, resolve_distribution_mode)
819 - * to avoid running translation calls just to check keys or numbers.
820 - *
821 - * @since 9.0.0
822 - *
823 - * @return array Associative array of mode => { batch_size, pause }.
824 - */
825 - private static function get_distribution_preset_values() {
826 - return array(
827 - 'default' => array(
828 - 'batch_size' => 100,
829 - 'pause' => 15,
830 - ),
831 - 'balanced' => array(
832 - 'batch_size' => 50,
833 - 'pause' => 30,
834 - ),
835 - 'eco' => array(
836 - 'batch_size' => 20,
837 - 'pause' => 30,
838 - ),
839 - );
840 - }
841 -
842 - /**
843 - * Get the available distribution mode presets with UI labels.
844 - *
845 - * Decorates `get_distribution_preset_values()` with translated labels
846 - * and descriptions for use in the admin settings page.
847 - *
848 - * @since 9.0.0
849 - *
850 - * @return array Associative array of mode => { batch_size, pause, label, description }.
851 - */
852 - public static function get_distribution_modes() {
853 - $modes = self::get_distribution_preset_values();
854 -
855 - $modes['default']['label'] = \__( 'Default', 'activitypub' );
856 - $modes['default']['description'] = \sprintf(
857 - /* translators: 1: batch size, 2: pause in seconds */
858 - \__( 'Deliver activities as fast as possible (<code>%1$d</code> per batch, <code>%2$ds</code> pause).', 'activitypub' ),
859 - $modes['default']['batch_size'],
860 - $modes['default']['pause']
861 - );
862 - $modes['balanced']['label'] = \__( 'Balanced', 'activitypub' );
863 - $modes['balanced']['description'] = \sprintf(
864 - /* translators: 1: batch size, 2: pause in seconds */
865 - \__( 'Moderate pace with reasonable pauses between batches (<code>%1$d</code> per batch, <code>%2$ds</code> pause).', 'activitypub' ),
866 - $modes['balanced']['batch_size'],
867 - $modes['balanced']['pause']
868 - );
869 - $modes['eco']['label'] = \__( 'Eco Mode', 'activitypub' );
870 - $modes['eco']['description'] = \sprintf(
871 - /* translators: 1: batch size, 2: pause in seconds */
872 - \__( 'Gentle on server resources, ideal for shared hosting (<code>%1$d</code> per batch, <code>%2$ds</code> pause).', 'activitypub' ),
873 - $modes['eco']['batch_size'],
874 - $modes['eco']['pause']
875 - );
876 -
877 - return $modes;
878 - }
879 -
880 - /**
881 - * Sanitize the distribution mode option.
882 - *
883 - * Restricts the stored value to a known preset (from
884 - * `get_distribution_modes()`) or `'custom'`. Anything else
885 - * falls back to `'default'`.
886 - *
887 - * @since 9.0.0
888 - *
889 - * @param string $value The submitted option value.
890 - *
891 - * @return string A valid distribution mode key.
892 - */
893 - public static function sanitize_distribution_mode( $value ) {
894 - $allowed = \array_merge( \array_keys( self::get_distribution_preset_values() ), array( 'custom' ) );
895 -
896 - return \in_array( $value, $allowed, true ) ? $value : 'default';
897 - }
898 -
899 - /**
900 - * Get distribution parameters for the current mode.
901 - *
902 - * @since 9.0.0
903 - *
904 - * @return array { mode: string, batch_size: int, pause: int }
905 - */
906 - public static function get_distribution_params() {
907 - $mode = \get_option( 'activitypub_distribution_mode', 'default' );
908 - $modes = self::get_distribution_preset_values();
909 -
910 - if ( isset( $modes[ $mode ] ) ) {
911 - return array(
912 - 'mode' => $mode,
913 - 'batch_size' => $modes[ $mode ]['batch_size'],
914 - 'pause' => $modes[ $mode ]['pause'],
915 - );
916 - }
917 -
918 - // Custom mode reads its values from dedicated options; any other
919 - // unrecognized mode falls back to the default preset so callers
920 - // always receive a valid configuration.
921 - if ( 'custom' !== $mode ) {
922 - return array(
923 - 'mode' => 'default',
924 - 'batch_size' => $modes['default']['batch_size'],
925 - 'pause' => $modes['default']['pause'],
926 - );
927 - }
928 -
929 - $default_params = $modes['default'];
930 -
931 - return array(
932 - 'mode' => 'custom',
933 - 'batch_size' => \max( 1, \absint( \get_option( 'activitypub_custom_batch_size', $default_params['batch_size'] ) ) ),
934 - 'pause' => \absint( \get_option( 'activitypub_custom_batch_pause', $default_params['pause'] ) ),
935 - );
936 - }
937 -
938 - /**
939 - * Filter the dispatcher batch size based on distribution mode.
940 - *
941 - * In `'default'` mode the upstream value is passed through so the
942 - * `ACTIVITYPUB_OUTBOX_PROCESSING_BATCH_SIZE` constant and other filters
943 - * still win; any explicit mode imposes its own batch size.
944 - *
945 - * @since 9.0.0
946 - *
947 - * @param int $batch_size The default batch size.
948 - *
949 - * @return int The batch size for the current distribution mode.
950 - */
951 - public static function filter_dispatcher_batch_size( $batch_size ) {
952 - $params = self::get_distribution_params();
953 -
954 - return 'default' === $params['mode'] ? $batch_size : $params['batch_size'];
955 - }
956 -
957 - /**
958 - * Filter the scheduler batch pause based on distribution mode.
959 - *
960 - * Only delivery batches (`activitypub_send_activity`) are affected. Every
961 - * mode imposes its own delivery pause: `'default'` is the fast preset, which
962 - * is intentionally shorter than the generic async-batch baseline, so it does
963 - * not pass the upstream value through.
964 - *
965 - * @since 9.0.0
966 - *
967 - * @param int $pause The default pause in seconds.
968 - * @param string|false|null $hook The async batch hook being scheduled.
969 - *
970 - * @return int The pause for the current distribution mode.
971 - */
972 - public static function filter_scheduler_batch_pause( $pause, $hook = null ) {
973 - if ( 'activitypub_send_activity' !== $hook ) {
974 - return $pause;
975 - }
976 -
977 - return self::get_distribution_params()['pause'];
978 - }
979 -
980 - /**
981 - * Sanitize purge day values.
982 - *
983 - * Ensures the value is a non-negative integer. Returns the
984 - * registered default when the stored value is empty or false
985 - * (option not properly set), but allows 0 to disable purging.
986 - *
987 - * @since 8.1.0
988 - *
989 - * @param mixed $value The stored option value.
990 - *
991 - * @return int The sanitized value.
992 - */
993 - public static function sanitize_purge_days( $value ) {
994 - if ( '' === $value || false === $value ) {
995 - $filter = \current_filter();
996 - $defaults = array(
997 - 'option_activitypub_outbox_purge_days' => ACTIVITYPUB_OUTBOX_PURGE_DAYS,
998 - 'option_activitypub_inbox_purge_days' => ACTIVITYPUB_INBOX_PURGE_DAYS,
999 - 'option_activitypub_ap_post_purge_days' => ACTIVITYPUB_AP_POST_PURGE_DAYS,
1000 - );
1001 -
1002 - return $defaults[ $filter ] ?? ACTIVITYPUB_OUTBOX_PURGE_DAYS;
1003 - }
1004 -
1005 - return \max( 1, \absint( $value ) );
1006 - }
1007 -
1008 - /**
1009 - * Handle relay mode option changes.
1010 - *
1011 - * When relay mode is enabled, switch to blog-only mode and set username to "relay".
1012 - * When disabled, restore previous settings.
1013 - *
1014 - * @param mixed $old_value The old option value.
1015 - * @param mixed $new_value The new option value.
1016 - */
1017 - public static function relay_mode_changed( $old_value, $new_value ) {
1018 - if ( $new_value && ! $old_value ) {
1019 - // Enabling relay mode.
1020 - // Store previous username and actor mode for restoration.
1021 - \update_option( 'activitypub_relay_previous_blog_identifier', \get_option( 'activitypub_blog_identifier' ) );
1022 - \update_option( 'activitypub_relay_previous_actor_mode', \get_option( 'activitypub_actor_mode' ) );
1023 -
1024 - // Set blog username to "relay".
1025 - \update_option( 'activitypub_blog_identifier', 'relay' );
1026 -
1027 - // Switch to blog-only mode.
1028 - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE );
1029 - } elseif ( ! $new_value && $old_value ) {
1030 - // Disabling relay mode - restore previous settings.
1031 - $previous_identifier = \get_option( 'activitypub_relay_previous_blog_identifier' );
1032 - $previous_actor_mode = \get_option( 'activitypub_relay_previous_actor_mode' );
1033 -
1034 - if ( $previous_identifier ) {
1035 - \update_option( 'activitypub_blog_identifier', $previous_identifier );
1036 - \delete_option( 'activitypub_relay_previous_blog_identifier' );
1037 - }
1038 -
1039 - if ( $previous_actor_mode ) {
1040 - \update_option( 'activitypub_actor_mode', $previous_actor_mode );
1041 - \delete_option( 'activitypub_relay_previous_actor_mode' );
1042 - }
1043 - }
1044 184 }
1045 185 }