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/wp-admin/class-admin.php +149 -358 9.2.07.7.0 View file →
@@ -6,17 +6,14 @@
6 6 */
7 7
8 8 namespace Activitypub\WP_Admin;
9 9
10 -use Activitypub\Blocklist_Subscriptions;
11 10 use Activitypub\Collection\Actors;
12 11 use Activitypub\Collection\Extra_Fields;
13 12 use Activitypub\Comment;
13 +use Activitypub\Model\Blog;
14 14 use Activitypub\Moderation;
15 -use Activitypub\OAuth\Client;
16 -use Activitypub\OAuth\Token;
17 15 use Activitypub\Scheduler\Actor;
18 -use Activitypub\Tombstone;
19 16
20 17 use function Activitypub\count_followers;
21 18 use function Activitypub\get_content_visibility;
22 19 use function Activitypub\is_user_type_disabled;
@@ -60,11 +57,8 @@
60 57 \add_action( 'admin_action_activitypub_confirm_removal', array( self::class, 'handle_bulk_actor_delete_page' ) );
61 58
62 59 if ( user_can_activitypub( \get_current_user_id() ) ) {
63 60 \add_action( 'show_user_profile', array( self::class, 'add_profile' ) );
64 - if ( \get_option( 'activitypub_api', false ) ) {
65 - \add_action( 'show_user_profile', array( User_Settings_Fields::class, 'connected_apps_section' ) );
66 - }
67 61 }
68 62
69 63 \add_filter( 'dashboard_glance_items', array( self::class, 'dashboard_glance_items' ) );
70 64 \add_filter( 'plugin_action_links_' . ACTIVITYPUB_PLUGIN_BASENAME, array( self::class, 'add_plugin_settings_link' ) );
@@ -74,19 +68,14 @@
74 68 \add_action( 'tool_box', array( self::class, 'tool_box' ) );
75 69 }
76 70
77 71 \add_action( 'admin_print_scripts-profile.php', array( self::class, 'enqueue_moderation_scripts' ) );
78 - \add_action( 'admin_print_scripts-profile.php', array( self::class, 'enqueue_connected_apps_scripts' ) );
79 72 \add_action( 'admin_print_scripts-settings_page_activitypub', array( self::class, 'enqueue_moderation_scripts' ) );
80 73 \add_action( 'admin_print_footer_scripts-settings_page_activitypub', array( self::class, 'open_help_tab' ) );
81 74
75 + \add_action( 'wp_dashboard_setup', array( self::class, 'add_dashboard_widgets' ) );
76 +
82 77 \add_action( 'wp_ajax_activitypub_moderation_settings', array( self::class, 'ajax_moderation_settings' ) );
83 - \add_action( 'wp_ajax_activitypub_blocklist_subscription', array( self::class, 'ajax_blocklist_subscription' ) );
84 - \add_action( 'wp_ajax_activitypub_register_oauth_client', array( self::class, 'ajax_register_oauth_client' ) );
85 - \add_action( 'wp_ajax_activitypub_delete_oauth_client', array( self::class, 'ajax_delete_oauth_client' ) );
86 - \add_action( 'wp_ajax_activitypub_delete_all_oauth_clients', array( self::class, 'ajax_delete_all_oauth_clients' ) );
87 - \add_action( 'wp_ajax_activitypub_revoke_oauth_token', array( self::class, 'ajax_revoke_oauth_token' ) );
88 - \add_action( 'wp_ajax_activitypub_revoke_all_oauth_tokens', array( self::class, 'ajax_revoke_all_oauth_tokens' ) );
89 78 }
90 79
91 80 /**
92 81 * Display admin menu notices about configuration problems or conflicts.
@@ -91,9 +80,9 @@
91 80 /**
92 81 * Display admin menu notices about configuration problems or conflicts.
93 82 */
94 83 public static function admin_notices() {
95 - $current_screen = \get_current_screen();
84 + $current_screen = get_current_screen();
96 85
97 86 if ( ! $current_screen ) {
98 87 return;
99 88 }
@@ -105,12 +94,12 @@
105 94 \delete_option( 'activitypub_self_destruct_complete' );
106 95 ?>
107 96 <div class="notice notice-success is-dismissible">
108 97 <p>
109 - <strong><?php \esc_html_e( 'ActivityPub Self-Destruct Complete!', 'activitypub' ); ?></strong>
98 + <strong><?php esc_html_e( 'ActivityPub Self-Destruct Complete!', 'activitypub' ); ?></strong>
110 99 </p>
111 100 <p>
112 - <?php \esc_html_e( 'All Delete activities have been successfully sent to the Fediverse. Your blog is no longer discoverable via ActivityPub and all followers have been notified of the deletion.', 'activitypub' ); ?>
101 + <?php esc_html_e( 'All Delete activities have been successfully sent to the Fediverse. Your blog is no longer discoverable via ActivityPub and all followers have been notified of the deletion.', 'activitypub' ); ?>
113 102 </p>
114 103 </div>
115 104 <?php
116 105 }
@@ -118,9 +107,9 @@
118 107 if ( 'edit' === $current_screen->base && Extra_Fields::is_extra_fields_post_type( $current_screen->post_type ) ) {
119 108 ?>
120 109 <div class="notice" style="margin: 0; background: none; border: none; box-shadow: none; padding: 15px 0 0 0; font-size: 14px;">
121 110 <?php
122 - \esc_html_e( 'These are extra fields that are used for your ActivityPub profile. You can use your homepage, social profiles, pronouns, age, anything you want.', 'activitypub' );
111 + esc_html_e( 'These are extra fields that are used for your ActivityPub profile. You can use your homepage, social profiles, pronouns, age, anything you want.', 'activitypub' );
123 112 ?>
124 113 </div>
125 114 <?php
126 115 }
@@ -199,13 +188,13 @@
199 188 /**
200 189 * Render user settings.
201 190 */
202 191 public static function add_profile() {
203 - \wp_enqueue_media();
204 - \wp_enqueue_script( 'activitypub-header-image' );
192 + wp_enqueue_media();
193 + wp_enqueue_script( 'activitypub-header-image' );
205 194
206 - \wp_nonce_field( 'activitypub-user-settings', '_apnonce' );
207 - \do_settings_sections( 'activitypub_user_settings' );
195 + wp_nonce_field( 'activitypub-user-settings', '_apnonce' );
196 + do_settings_sections( 'activitypub_user_settings' );
208 197 }
209 198
210 199 /**
211 200 * Save the user settings.
@@ -218,12 +207,12 @@
218 207 if ( ! isset( $_REQUEST['_apnonce'] ) ) {
219 208 return;
220 209 }
221 210
222 - $nonce = \sanitize_text_field( \wp_unslash( $_REQUEST['_apnonce'] ) );
211 + $nonce = sanitize_text_field( wp_unslash( $_REQUEST['_apnonce'] ) );
223 212 if (
224 - ! \wp_verify_nonce( $nonce, 'activitypub-user-settings' ) ||
225 - ! \current_user_can( 'edit_user', $user_id )
213 + ! wp_verify_nonce( $nonce, 'activitypub-user-settings' ) ||
214 + ! current_user_can( 'edit_user', $user_id )
226 215 ) {
227 216 return;
228 217 }
229 218
@@ -234,9 +223,9 @@
234 223 );
235 224
236 225 foreach ( $textarea_field_user_options as $option ) {
237 226 if ( ! empty( $_POST[ $option ] ) ) {
238 - \update_user_option( $user_id, $option, \sanitize_textarea_field( \wp_unslash( $_POST[ $option ] ) ) );
227 + \update_user_option( $user_id, $option, sanitize_textarea_field( wp_unslash( $_POST[ $option ] ) ) );
239 228 } else {
240 229 \delete_user_option( $user_id, $option );
241 230 }
242 231 }
@@ -247,9 +236,9 @@
247 236 );
248 237
249 238 foreach ( $text_field_user_options as $option ) {
250 239 if ( ! empty( $_POST[ $option ] ) ) {
251 - \update_user_option( $user_id, $option, \sanitize_text_field( \wp_unslash( $_POST[ $option ] ) ) );
240 + \update_user_option( $user_id, $option, sanitize_text_field( wp_unslash( $_POST[ $option ] ) ) );
252 241 } else {
253 242 \delete_user_option( $user_id, $option );
254 243 }
255 244 }
@@ -259,14 +248,12 @@
259 248 'activitypub_hide_social_graph',
260 249 'activitypub_mailer_new_dm',
261 250 'activitypub_mailer_new_follower',
262 251 'activitypub_mailer_new_mention',
263 - 'activitypub_mailer_annual_report',
264 - 'activitypub_mailer_monthly_report',
265 252 );
266 253
267 254 foreach ( $required_user_options as $option ) {
268 - \update_user_option( $user_id, $option, \sanitize_text_field( \wp_unslash( $_POST[ $option ] ?? 0 ) ) );
255 + \update_user_option( $user_id, $option, sanitize_text_field( wp_unslash( $_POST[ $option ] ?? 0 ) ) );
269 256 }
270 257 }
271 258
272 259 /**
@@ -274,11 +261,11 @@
274 261 *
275 262 * @param string $hook_suffix The current page.
276 263 */
277 264 public static function enqueue_scripts( $hook_suffix ) {
278 - \wp_register_script(
265 + wp_register_script(
279 266 'activitypub-header-image',
280 - \plugins_url(
267 + plugins_url(
281 268 'assets/js/activitypub-header-image.js',
282 269 ACTIVITYPUB_PLUGIN_FILE
283 270 ),
284 271 array( 'jquery' ),
@@ -288,17 +275,17 @@
288 275
289 276 // Register and enqueue command palette integration.
290 277 if ( user_can_activitypub( \get_current_user_id() ) || \current_user_can( 'manage_options' ) ) {
291 278 $asset_data = include ACTIVITYPUB_PLUGIN_DIR . 'build/command-palette/plugin.asset.php';
292 - \wp_enqueue_script(
279 + wp_enqueue_script(
293 280 'activitypub-command-palette',
294 - \plugins_url( 'build/command-palette/plugin.js', ACTIVITYPUB_PLUGIN_FILE ),
281 + plugins_url( 'build/command-palette/plugin.js', ACTIVITYPUB_PLUGIN_FILE ),
295 282 $asset_data['dependencies'],
296 283 $asset_data['version'],
297 284 true
298 285 );
299 286
300 - \wp_localize_script(
287 + wp_localize_script(
301 288 'activitypub-command-palette',
302 289 'activitypubCommandPalette',
303 290 array(
304 291 'followingEnabled' => '1' === \get_option( 'activitypub_following_ui', '0' ),
@@ -307,12 +294,12 @@
307 294 )
308 295 );
309 296 }
310 297
311 - if ( false !== \strpos( $hook_suffix, 'activitypub' ) && 'dashboard_page_activitypub-social-web' !== $hook_suffix ) {
312 - \wp_enqueue_style(
298 + if ( false !== strpos( $hook_suffix, 'activitypub' ) ) {
299 + wp_enqueue_style(
313 300 'activitypub-admin-styles',
314 - \plugins_url(
301 + plugins_url(
315 302 'assets/css/activitypub-admin.css',
316 303 ACTIVITYPUB_PLUGIN_FILE
317 304 ),
318 305 array(),
@@ -317,11 +304,11 @@
317 304 ),
318 305 array(),
319 306 ACTIVITYPUB_PLUGIN_VERSION
320 307 );
321 - \wp_enqueue_script(
308 + wp_enqueue_script(
322 309 'activitypub-admin-script',
323 - \plugins_url(
310 + plugins_url(
324 311 'assets/js/activitypub-admin.js',
325 312 ACTIVITYPUB_PLUGIN_FILE
326 313 ),
327 314 array( 'jquery', 'wp-util' ),
@@ -335,11 +322,11 @@
335 322 \wp_enqueue_script( 'updates' );
336 323 }
337 324
338 325 if ( 'index.php' === $hook_suffix ) {
339 - \wp_enqueue_style(
326 + wp_enqueue_style(
340 327 'activitypub-admin-styles',
341 - \plugins_url(
328 + plugins_url(
342 329 'assets/css/activitypub-admin.css',
343 330 ACTIVITYPUB_PLUGIN_FILE
344 331 ),
345 332 array(),
@@ -345,15 +332,8 @@
345 332 array(),
346 333 ACTIVITYPUB_PLUGIN_VERSION
347 334 );
348 335 }
349 -
350 - if ( 'edit-comments.php' === $hook_suffix ) {
351 - \wp_add_inline_style(
352 - 'wp-emoji-styles',
353 - '.column-author img.emoji { float: none; }'
354 - );
355 - }
356 336 }
357 337
358 338 /**
359 339 * Enqueue moderation admin scripts.
@@ -361,70 +341,29 @@
361 341 public static function enqueue_moderation_scripts() {
362 342 \wp_enqueue_script(
363 343 'activitypub-moderation-admin',
364 344 ACTIVITYPUB_PLUGIN_URL . 'assets/js/activitypub-moderation-admin.js',
365 - array( 'jquery', 'wp-util', 'wp-a11y', 'wp-i18n' ),
345 + array( 'jquery', 'wp-util', 'wp-a11y' ),
366 346 ACTIVITYPUB_PLUGIN_VERSION,
367 347 true
368 348 );
369 349
370 - \wp_set_script_translations(
371 - 'activitypub-moderation-admin',
372 - 'activitypub',
373 - ACTIVITYPUB_PLUGIN_DIR . 'languages'
374 - );
375 -
376 350 // Localize script with translations and nonces.
377 351 \wp_localize_script(
378 352 'activitypub-moderation-admin',
379 353 'activitypubModerationL10n',
380 354 array(
381 - 'nonce' => \wp_create_nonce( 'activitypub_moderation_settings' ),
355 + 'enterValue' => \__( 'Please enter a value to block.', 'activitypub' ),
356 + 'addBlockFailed' => \__( 'Failed to add block.', 'activitypub' ),
357 + 'removeBlockFailed' => \__( 'Failed to remove block.', 'activitypub' ),
358 + 'alreadyBlocked' => \__( 'This term is already blocked.', 'activitypub' ),
359 + 'invalidDomain' => \__( 'Please enter a valid domain (e.g., example.com).', 'activitypub' ),
360 + 'nonce' => \wp_create_nonce( 'activitypub_moderation_settings' ),
382 361 )
383 362 );
384 363 }
385 364
386 365 /**
387 - * Enqueue connected apps admin scripts on the profile page.
388 - *
389 - * @since 8.1.0
390 - */
391 - public static function enqueue_connected_apps_scripts() {
392 - \wp_enqueue_script(
393 - 'activitypub-connected-apps',
394 - ACTIVITYPUB_PLUGIN_URL . 'assets/js/activitypub-connected-apps.js',
395 - array( 'jquery' ),
396 - ACTIVITYPUB_PLUGIN_VERSION,
397 - true
398 - );
399 -
400 - \wp_localize_script(
401 - 'activitypub-connected-apps',
402 - 'activitypubConnectedApps',
403 - array(
404 - 'ajaxUrl' => \admin_url( 'admin-ajax.php' ),
405 - 'nonce' => \wp_create_nonce( 'activitypub_connected_apps' ),
406 - 'confirm' => \__( 'Are you sure you want to revoke this application token? This action cannot be undone.', 'activitypub' ),
407 - 'confirmAll' => \__( 'Are you sure you want to revoke all connected applications? This action cannot be undone.', 'activitypub' ),
408 - 'confirmDelete' => \__( 'Are you sure you want to delete this application? This action cannot be undone.', 'activitypub' ),
409 - 'confirmDeleteAll' => \__( 'Are you sure you want to delete all registered applications? This action cannot be undone.', 'activitypub' ),
410 - 'registerError' => \__( 'Failed to register application.', 'activitypub' ),
411 - 'deleteLabel' => \__( 'Delete', 'activitypub' ),
412 - 'dismiss' => \__( 'Dismiss this notice.', 'activitypub' ),
413 - 'clientIdLabel' => \__( 'Your new Client ID:', 'activitypub' ),
414 - 'clientSecretLabel' => \__( 'Your new Client Secret:', 'activitypub' ),
415 - 'copy' => \__( 'Copy', 'activitypub' ),
416 - 'copied' => \__( 'Copied!', 'activitypub' ),
417 - 'saveWarning' => \__( 'Be sure to save this in a safe location. You will not be able to retrieve it.', 'activitypub' ),
418 - 'appRevoked' => \__( 'Application token revoked.', 'activitypub' ),
419 - 'allAppsRevoked' => \__( 'All application tokens revoked.', 'activitypub' ),
420 - 'appDeleted' => \__( 'Application deleted.', 'activitypub' ),
421 - 'allAppsDeleted' => \__( 'All registered applications deleted.', 'activitypub' ),
422 - )
423 - );
424 - }
425 -
426 - /**
427 366 * Hook into the edit_comment functionality.
428 367 *
429 368 * Disables the edit_comment capability for federated comments.
430 369 */
@@ -462,20 +401,20 @@
462 401 public static function edit_post() {
463 402 // Disable the edit_post capability for federated posts.
464 403 \add_filter(
465 404 'user_has_cap',
466 - static function ( $all_caps, $caps, $arg ) {
405 + function ( $all_caps, $caps, $arg ) {
467 406 if ( 'edit_post' !== $arg[0] ) {
468 407 return $all_caps;
469 408 }
470 409
471 - $post = \get_post( $arg[2] );
410 + $post = get_post( $arg[2] );
472 411
473 412 if ( ! Extra_Fields::is_extra_field_post_type( $post->post_type ) ) {
474 413 return $all_caps;
475 414 }
476 415
477 - if ( \get_current_user_id() !== (int) $post->post_author ) {
416 + if ( get_current_user_id() !== (int) $post->post_author ) {
478 417 return false;
479 418 }
480 419
481 420 return $all_caps;
@@ -489,14 +428,14 @@
489 428 * Add ActivityPub specific actions/filters to the post list view.
490 429 */
491 430 public static function list_posts() {
492 431 // Remove all views for the extra fields.
493 - $screen_id = \get_current_screen()->id;
432 + $screen_id = get_current_screen()->id;
494 433
495 - \add_filter(
434 + add_filter(
496 435 "views_{$screen_id}",
497 - static function ( $views ) {
498 - if ( Extra_Fields::is_extra_fields_post_type( \get_current_screen()->post_type ) ) {
436 + function ( $views ) {
437 + if ( Extra_Fields::is_extra_fields_post_type( get_current_screen()->post_type ) ) {
499 438 return array();
500 439 }
501 440
502 441 return $views;
@@ -516,9 +455,9 @@
516 455 if ( was_comment_received( $comment ) ) {
517 456 unset( $actions['edit'], $actions['quickedit'] );
518 457 }
519 458
520 - if ( \in_array( \get_comment_type( $comment ), Comment::get_comment_type_slugs(), true ) ) {
459 + if ( in_array( get_comment_type( $comment ), Comment::get_comment_type_slugs(), true ) ) {
521 460 unset( $actions['reply'] );
522 461 }
523 462
524 463 return $actions;
@@ -533,9 +472,9 @@
533 472 *
534 473 * @return array The columns extended by the activitypub.
535 474 */
536 475 public static function manage_users_columns( $columns ) {
537 - $columns['activitypub'] = \__( 'ActivityPub', 'activitypub' );
476 + $columns['activitypub'] = __( 'ActivityPub', 'activitypub' );
538 477 return $columns;
539 478 }
540 479
541 480 /**
@@ -545,10 +484,10 @@
545 484 *
546 485 * @return array The extended list of column names.
547 486 */
548 487 public static function manage_comment_columns( $columns ) {
549 - $columns['comment_type'] = \esc_attr__( 'Comment-Type', 'activitypub' );
550 - $columns['comment_protocol'] = \esc_attr__( 'Protocol', 'activitypub' );
488 + $columns['comment_type'] = esc_attr__( 'Comment-Type', 'activitypub' );
489 + $columns['comment_protocol'] = esc_attr__( 'Protocol', 'activitypub' );
551 490
552 491 return $columns;
553 492 }
554 493
@@ -562,10 +501,10 @@
562 501 */
563 502 public static function manage_post_columns( $columns, $post_type ) {
564 503 if ( Extra_Fields::is_extra_fields_post_type( $post_type ) ) {
565 504 $after_key = 'title';
566 - $index = \array_search( $after_key, \array_keys( $columns ), true );
567 - $columns = \array_slice( $columns, 0, $index + 1 ) + array( 'extra_field_content' => \esc_attr__( 'Content', 'activitypub' ) ) + $columns;
505 + $index = array_search( $after_key, array_keys( $columns ), true );
506 + $columns = array_slice( $columns, 0, $index + 1 ) + array( 'extra_field_content' => esc_attr__( 'Content', 'activitypub' ) ) + $columns;
568 507 }
569 508
570 509 return $columns;
571 510 }
@@ -576,17 +515,17 @@
576 515 * @param array $column The column to implement.
577 516 * @param int $comment_id The comment id.
578 517 */
579 518 public static function manage_comments_custom_column( $column, $comment_id ) {
580 - if ( 'comment_type' === $column && ! \defined( 'WEBMENTION_PLUGIN_DIR' ) ) {
581 - echo \esc_attr( \ucfirst( \get_comment_type( $comment_id ) ) );
519 + if ( 'comment_type' === $column && ! defined( 'WEBMENTION_PLUGIN_DIR' ) ) {
520 + echo esc_attr( ucfirst( get_comment_type( $comment_id ) ) );
582 521 } elseif ( 'comment_protocol' === $column ) {
583 - $protocol = \get_comment_meta( $comment_id, 'protocol', true );
522 + $protocol = get_comment_meta( $comment_id, 'protocol', true );
584 523
585 524 if ( $protocol ) {
586 - echo \esc_attr( \ucfirst( \str_replace( 'activitypub', 'ActivityPub', $protocol ) ) );
525 + echo esc_attr( ucfirst( str_replace( 'activitypub', 'ActivityPub', $protocol ) ) );
587 526 } else {
588 - \esc_attr_e( 'Local', 'activitypub' );
527 + esc_attr_e( 'Local', 'activitypub' );
589 528 }
590 529 }
591 530 }
592 531
@@ -598,9 +537,9 @@
598 537 * @return array The extended comment types.
599 538 */
600 539 public static function comment_types_dropdown( $types ) {
601 540 foreach ( Comment::get_comment_types() as $comment_type ) {
602 - $types[ $comment_type['type'] ] = \esc_html( $comment_type['label'] );
541 + $types[ $comment_type['type'] ] = esc_html( $comment_type['label'] );
603 542 }
604 543
605 544 return $types;
606 545 }
@@ -619,11 +558,11 @@
619 558 return $output;
620 559 }
621 560
622 561 if ( \user_can( $user_id, 'activitypub' ) ) {
623 - return '<span aria-hidden="true">&#x2713;</span><span class="screen-reader-text">' . \esc_html__( 'ActivityPub enabled for this author', 'activitypub' ) . '</span>';
562 + return '<span aria-hidden="true">&#x2713;</span><span class="screen-reader-text">' . esc_html__( 'ActivityPub enabled for this author', 'activitypub' ) . '</span>';
624 563 } else {
625 - return '<span aria-hidden="true">&#x2717;</span><span class="screen-reader-text">' . \esc_html__( 'ActivityPub disabled for this author', 'activitypub' ) . '</span>';
564 + return '<span aria-hidden="true">&#x2717;</span><span class="screen-reader-text">' . esc_html__( 'ActivityPub disabled for this author', 'activitypub' ) . '</span>';
626 565 }
627 566 }
628 567
629 568 /**
@@ -635,11 +574,11 @@
635 574 * @return void
636 575 */
637 576 public static function manage_posts_custom_column( $column_name, $post_id ) {
638 577 if ( 'extra_field_content' === $column_name ) {
639 - $post = \get_post( $post_id );
578 + $post = get_post( $post_id );
640 579 if ( Extra_Fields::is_extra_fields_post_type( $post->post_type ) ) {
641 - echo \esc_attr( \wp_strip_all_tags( $post->post_content ) );
580 + echo esc_attr( wp_strip_all_tags( $post->post_content ) );
642 581 }
643 582 }
644 583 }
645 584
@@ -650,10 +589,10 @@
650 589 *
651 590 * @return array The extended bulk options.
652 591 */
653 592 public static function user_bulk_options( $actions ) {
654 - $actions['add_activitypub_cap'] = \__( 'Enable for ActivityPub', 'activitypub' );
655 - $actions['remove_activitypub_cap'] = \__( 'Disable for ActivityPub', 'activitypub' );
593 + $actions['add_activitypub_cap'] = __( 'Enable for ActivityPub', 'activitypub' );
594 + $actions['remove_activitypub_cap'] = __( 'Disable for ActivityPub', 'activitypub' );
656 595
657 596 return $actions;
658 597 }
659 598
@@ -675,14 +614,8 @@
675 614 case 'add_activitypub_cap':
676 615 foreach ( $users as $user_id ) {
677 616 $user = new \WP_User( $user_id );
678 617 $user->add_cap( 'activitypub' );
679 -
680 - // Remove user from tombstone registry if they were previously buried.
681 - $actor = Actors::get_by_id( $user_id );
682 - if ( ! \is_wp_error( $actor ) ) {
683 - Tombstone::remove( $actor->get_id(), $actor->get_url() );
684 - }
685 618 }
686 619 return $send_back;
687 620 case 'remove_activitypub_cap':
688 621 $removed_count = 0;
@@ -714,9 +647,9 @@
714 647 );
715 648
716 649 // Add user IDs as separate parameters.
717 650 foreach ( $users as $index => $user_id ) {
718 - $query_args[ \sprintf( 'users[%d]', $index ) ] = \absint( $user_id );
651 + $query_args[ sprintf( 'users[%d]', $index ) ] = absint( $user_id );
719 652 }
720 653
721 654 $confirmation_url = \add_query_arg( $query_args, \admin_url( 'users.php' ) );
722 655
@@ -818,9 +751,9 @@
818 751 * @return string The URL to redirect to.
819 752 */
820 753 public static function process_capability_removal( $users, $remove_from_fediverse, $send_back ) {
821 754 // Normalize fediverse removal parameter.
822 - if ( \is_string( $remove_from_fediverse ) ) {
755 + if ( is_string( $remove_from_fediverse ) ) {
823 756 // Legacy format: 'delete' or 'keep' for all users.
824 757 $delete_all = ( 'delete' === $remove_from_fediverse );
825 758 $users_to_delete = $delete_all ? $users : array();
826 759 } else {
@@ -858,11 +791,11 @@
858 791 public static function dashboard_glance_items( $items ) {
859 792 \add_filter( 'number_format_i18n', '\Activitypub\custom_large_numbers', 10, 2 );
860 793
861 794 if ( user_can_activitypub( \get_current_user_id() ) ) {
862 - $follower_count = \sprintf(
795 + $follower_count = sprintf(
863 796 // translators: %s: number of followers.
864 - \_n(
797 + _n(
865 798 '%s Follower',
866 799 '%s Followers',
867 800 count_followers( \get_current_user_id() ),
868 801 'activitypub'
@@ -868,9 +801,9 @@
868 801 'activitypub'
869 802 ),
870 803 \number_format_i18n( count_followers( \get_current_user_id() ) )
871 804 );
872 - $items['activitypub-followers-user'] = \sprintf(
805 + $items['activitypub-followers-user'] = sprintf(
873 806 '<a class="activitypub-followers" href="%1$s" title="%2$s">%3$s</a>',
874 807 \esc_url( \admin_url( 'users.php?page=activitypub-followers-list' ) ),
875 808 \esc_attr__( 'Your followers', 'activitypub' ),
876 809 \esc_html( $follower_count )
@@ -876,12 +809,12 @@
876 809 \esc_html( $follower_count )
877 810 );
878 811 }
879 812
880 - if ( ! is_user_type_disabled( 'blog' ) && \current_user_can( 'manage_options' ) ) {
881 - $follower_count = \sprintf(
813 + if ( ! is_user_type_disabled( 'blog' ) && current_user_can( 'manage_options' ) ) {
814 + $follower_count = sprintf(
882 815 // translators: %s: number of followers.
883 - \_n(
816 + _n(
884 817 '%s Follower (Blog)',
885 818 '%s Followers (Blog)',
886 819 count_followers( Actors::BLOG_USER_ID ),
887 820 'activitypub'
@@ -887,9 +820,9 @@
887 820 'activitypub'
888 821 ),
889 822 \number_format_i18n( count_followers( Actors::BLOG_USER_ID ) )
890 823 );
891 - $items['activitypub-followers-blog'] = \sprintf(
824 + $items['activitypub-followers-blog'] = sprintf(
892 825 '<a class="activitypub-followers" href="%1$s" title="%2$s">%3$s</a>',
893 826 \esc_url( \admin_url( 'options-general.php?page=activitypub&tab=followers' ) ),
894 827 \esc_attr__( 'The Blog\'s followers', 'activitypub' ),
895 828 \esc_html( $follower_count )
@@ -912,9 +845,9 @@
912 845 public static function row_actions( $actions, $post ) {
913 846 // check if the post is enabled for ActivityPub.
914 847 if (
915 848 ! \post_type_supports( \get_post_type( $post ), 'activitypub' ) ||
916 - ! \in_array( $post->post_status, array( 'pending', 'draft', 'future', 'publish' ), true ) ||
849 + ! in_array( $post->post_status, array( 'pending', 'draft', 'future', 'publish' ), true ) ||
917 850 ! \current_user_can( 'edit_post', $post->ID ) ||
918 851 ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL === get_content_visibility( $post->ID ) ||
919 852 ( site_supports_blocks() && \use_block_editor_for_post_type( $post->post_type ) )
920 853 ) {
@@ -920,11 +853,11 @@
920 853 ) {
921 854 return $actions;
922 855 }
923 856
924 - $preview_url = \add_query_arg( 'activitypub', 'true', \get_preview_post_link( $post ) );
857 + $preview_url = add_query_arg( 'activitypub', 'true', \get_preview_post_link( $post ) );
925 858
926 - $actions['activitypub'] = \sprintf(
859 + $actions['activitypub'] = sprintf(
927 860 '<a href="%s" target="_blank">%s</a>',
928 861 \esc_url( $preview_url ),
929 862 \esc_html__( 'Fediverse Preview ⁂', 'activitypub' )
930 863 );
@@ -957,9 +890,9 @@
957 890 if ( ! isset( $update->upgrade_notice ) ) {
958 891 return;
959 892 }
960 893
961 - echo '<br>' . \wp_strip_all_tags( $update->upgrade_notice ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
894 + echo '<br>' . wp_strip_all_tags( $update->upgrade_notice ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
962 895 }
963 896
964 897 /**
965 898 * Adds meta box on wp-admin/tools.php.
@@ -978,9 +911,9 @@
978 911 // get all tabs registered for the ActivityPub settings page.
979 912 $tabs = \get_current_screen()->get_help_tabs();
980 913 $ids = \array_values( \wp_list_pluck( $tabs, 'id' ) );
981 914 $ids = \array_map(
982 - static function ( $id ) {
915 + function ( $id ) {
983 916 return '#tab-link-' . $id;
984 917 },
985 918 $ids
986 919 );
@@ -1004,8 +937,80 @@
1004 937 <?php
1005 938 }
1006 939
1007 940 /**
941 + * Add Dashboard widgets.
942 + */
943 + public static function add_dashboard_widgets() {
944 + \wp_add_dashboard_widget( 'activitypub_blog', \__( 'ActivityPub Plugin News', 'activitypub' ), array( self::class, 'blog_dashboard_widget' ) );
945 + if ( user_can_activitypub( \get_current_user_id() ) && ! is_user_type_disabled( 'user' ) ) {
946 + \wp_add_dashboard_widget( 'activitypub_profile', \__( 'ActivityPub Author profile', 'activitypub' ), array( self::class, 'profile_dashboard_widget' ) );
947 + }
948 + if ( ! is_user_type_disabled( 'blog' ) ) {
949 + \wp_add_dashboard_widget( 'activitypub_blog_profile', \__( 'ActivityPub Blog profile', 'activitypub' ), array( self::class, 'blogprofile_dashboard_widget' ) );
950 + }
951 + }
952 +
953 + /**
954 + * Add the `ActivityPub.blog` feed as a Dashboard widget.
955 + */
956 + public static function blog_dashboard_widget() {
957 + echo '<div class="rss-widget">';
958 + \wp_widget_rss_output(
959 + array(
960 + 'url' => 'https://activitypub.blog/feed/',
961 + 'items' => 3,
962 + 'show_summary' => 1,
963 + 'show_author' => 0,
964 + 'show_date' => 1,
965 + )
966 + );
967 + echo '</div>';
968 + }
969 +
970 + /**
971 + * Add the ActivityPub Author profile as a Dashboard widget.
972 + */
973 + public static function profile_dashboard_widget() {
974 + $user = Actors::get_by_id( \get_current_user_id() );
975 + ?>
976 + <p>
977 + <?php \esc_html_e( 'People can follow you by using your author name:', 'activitypub' ); ?>
978 + </p>
979 + <p><label for="activitypub-user-identifier"><?php \esc_html_e( 'Username', 'activitypub' ); ?></label><input type="text" class="large-text code" id="activitypub-user-identifier" value="<?php echo \esc_attr( $user->get_webfinger() ); ?>" readonly /></p>
980 + <p><label for="activitypub-user-url"><?php \esc_html_e( 'Profile URL', 'activitypub' ); ?></label><input type="text" class="large-text code" id="activitypub-user-url" value="<?php echo \esc_attr( $user->get_url() ); ?>" readonly /></p>
981 + <p>
982 + <?php \esc_html_e( 'Authors who can not access this settings page will find their username on the "Edit Profile" page.', 'activitypub' ); ?>
983 + <a href="<?php echo \esc_url( \admin_url( '/profile.php#activitypub' ) ); ?>">
984 + <?php \esc_html_e( 'Customize username on "Edit Profile" page.', 'activitypub' ); ?>
985 + </a>
986 + </p>
987 + <?php
988 + }
989 +
990 + /**
991 + * Add the ActivityPub Blog profile as a Dashboard widget.
992 + */
993 + public static function blogprofile_dashboard_widget() {
994 + $user = new Blog();
995 + ?>
996 + <p>
997 + <?php \esc_html_e( 'People can follow your blog by using:', 'activitypub' ); ?>
998 + </p>
999 + <p><label for="activitypub-user-identifier"><?php \esc_html_e( 'Username', 'activitypub' ); ?></label><input type="text" class="large-text code" id="activitypub-user-identifier" value="<?php echo \esc_attr( $user->get_webfinger() ); ?>" readonly /></p>
1000 + <p><label for="activitypub-user-url"><?php \esc_html_e( 'Profile URL', 'activitypub' ); ?></label><input type="text" class="large-text code" id="activitypub-user-url" value="<?php echo \esc_attr( $user->get_url() ); ?>" readonly /></p>
1001 + <p>
1002 + <?php \esc_html_e( 'This blog profile will federate all posts written on your blog, regardless of the author who posted it.', 'activitypub' ); ?>
1003 + <?php if ( current_user_can( 'manage_options' ) ) : ?>
1004 + <a href="<?php echo \esc_url( \admin_url( '/options-general.php?page=activitypub&tab=blog-profile' ) ); ?>">
1005 + <?php \esc_html_e( 'Customize the blog profile.', 'activitypub' ); ?>
1006 + </a>
1007 + <?php endif; ?>
1008 + </p>
1009 + <?php
1010 + }
1011 +
1012 + /**
1008 1013 * AJAX handler for moderation settings (add/remove blocks).
1009 1014 */
1010 1015 public static function ajax_moderation_settings() {
1011 1016 $context = \sanitize_text_field( \wp_unslash( $_POST['context'] ?? '' ) );
@@ -1013,13 +1018,13 @@
1013 1018 $type = \sanitize_text_field( \wp_unslash( $_POST['type'] ?? '' ) );
1014 1019 $value = \sanitize_text_field( \wp_unslash( $_POST['value'] ?? '' ) );
1015 1020
1016 1021 // Validate required parameters.
1017 - if ( ! \in_array( $context, array( 'user', 'site' ), true ) || ! \in_array( $operation, array( 'add', 'remove' ), true ) ) {
1022 + if ( ! in_array( $context, array( 'user', 'site' ), true ) || ! in_array( $operation, array( 'add', 'remove' ), true ) ) {
1018 1023 \wp_send_json_error( array( 'message' => \__( 'Invalid context or action.', 'activitypub' ) ) );
1019 1024 }
1020 1025
1021 - if ( empty( $type ) || empty( $value ) || ! \in_array( $type, array( 'domain', 'keyword' ), true ) ) {
1026 + if ( empty( $type ) || empty( $value ) || ! in_array( $type, array( 'domain', 'keyword' ), true ) ) {
1022 1027 \wp_send_json_error( array( 'message' => \__( 'Invalid parameters.', 'activitypub' ) ) );
1023 1028 }
1024 1029
1025 1030 // Verify nonce for all operations.
@@ -1062,220 +1067,6 @@
1062 1067 \wp_send_json_success();
1063 1068 } else {
1064 1069 \wp_send_json_error( array( 'message' => $error_message ) );
1065 1070 }
1066 - }
1067 -
1068 - /**
1069 - * AJAX handler for blocklist subscriptions (add/remove).
1070 - */
1071 - public static function ajax_blocklist_subscription() {
1072 - $operation = \sanitize_text_field( \wp_unslash( $_POST['operation'] ?? '' ) );
1073 - $url = \sanitize_url( \wp_unslash( $_POST['url'] ?? '' ) );
1074 -
1075 - // Validate required parameters.
1076 - if ( ! \in_array( $operation, array( 'add', 'remove' ), true ) ) {
1077 - \wp_send_json_error( array( 'message' => \__( 'Invalid operation.', 'activitypub' ) ) );
1078 - }
1079 -
1080 - if ( empty( $url ) ) {
1081 - \wp_send_json_error( array( 'message' => \__( 'Invalid URL.', 'activitypub' ) ) );
1082 - }
1083 -
1084 - // Verify nonce.
1085 - if ( ! \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST['_wpnonce'] ?? '' ) ), 'activitypub_moderation_settings' ) ) {
1086 - \wp_send_json_error( array( 'message' => \__( 'Invalid nonce.', 'activitypub' ) ) );
1087 - }
1088 -
1089 - if ( ! \current_user_can( 'manage_options' ) ) {
1090 - \wp_send_json_error( array( 'message' => \__( 'You do not have permission to perform this action.', 'activitypub' ) ) );
1091 - }
1092 -
1093 - if ( 'add' === $operation ) {
1094 - // First add the subscription (validates URL format).
1095 - if ( ! Blocklist_Subscriptions::add( $url ) ) {
1096 - \wp_send_json_error( array( 'message' => \__( 'Invalid URL.', 'activitypub' ) ) );
1097 - }
1098 -
1099 - // Then sync to validate it works and import domains.
1100 - $result = Blocklist_Subscriptions::sync( $url );
1101 - if ( false === $result ) {
1102 - // Remove the subscription since sync failed.
1103 - Blocklist_Subscriptions::remove( $url );
1104 - \wp_send_json_error( array( 'message' => \__( 'Failed to fetch blocklist. The URL may be unreachable or not contain valid domains.', 'activitypub' ) ) );
1105 - }
1106 -
1107 - \wp_send_json_success();
1108 - } elseif ( Blocklist_Subscriptions::remove( $url ) ) {
1109 - \wp_send_json_success();
1110 - } else {
1111 - \wp_send_json_error( array( 'message' => \__( 'Failed to remove subscription.', 'activitypub' ) ) );
1112 - }
1113 - }
1114 -
1115 - /**
1116 - * AJAX handler for registering a new OAuth client from the user profile.
1117 - *
1118 - * @since 8.1.0
1119 - */
1120 - public static function ajax_register_oauth_client() {
1121 - // Verify nonce.
1122 - if ( ! \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST['_wpnonce'] ?? '' ) ), 'activitypub_connected_apps' ) ) {
1123 - \wp_send_json_error( array( 'message' => \__( 'Invalid nonce.', 'activitypub' ) ) );
1124 - }
1125 -
1126 - if ( ! \current_user_can( 'manage_options' ) ) {
1127 - \wp_send_json_error( array( 'message' => \__( 'You do not have permission to perform this action.', 'activitypub' ) ) );
1128 - }
1129 -
1130 - $name = \sanitize_text_field( \wp_unslash( $_POST['name'] ?? '' ) );
1131 - $redirect_uri = \sanitize_url( \wp_unslash( $_POST['redirect_uri'] ?? '' ) );
1132 -
1133 - if ( empty( $name ) ) {
1134 - \wp_send_json_error( array( 'message' => \__( 'Application name is required.', 'activitypub' ) ) );
1135 - }
1136 -
1137 - if ( empty( $redirect_uri ) ) {
1138 - \wp_send_json_error( array( 'message' => \__( 'Redirect URI is required.', 'activitypub' ) ) );
1139 - }
1140 -
1141 - $result = Client::register(
1142 - array(
1143 - 'name' => $name,
1144 - 'redirect_uris' => array( $redirect_uri ),
1145 - 'is_public' => false,
1146 - )
1147 - );
1148 -
1149 - if ( \is_wp_error( $result ) ) {
1150 - \wp_send_json_error( array( 'message' => $result->get_error_message() ) );
1151 - }
1152 -
1153 - $data = array(
1154 - 'client_id' => $result['client_id'],
1155 - 'created' => \date_i18n( \get_option( 'date_format' ) ),
1156 - );
1157 -
1158 - if ( ! empty( $result['client_secret'] ) ) {
1159 - $data['client_secret'] = $result['client_secret'];
1160 - }
1161 -
1162 - \wp_send_json_success( $data );
1163 - }
1164 -
1165 - /**
1166 - * AJAX handler for deleting a registered OAuth client.
1167 - *
1168 - * @since 8.1.0
1169 - */
1170 - public static function ajax_delete_oauth_client() {
1171 - // Verify nonce.
1172 - if ( ! \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST['_wpnonce'] ?? '' ) ), 'activitypub_connected_apps' ) ) {
1173 - \wp_send_json_error( array( 'message' => \__( 'Invalid nonce.', 'activitypub' ) ) );
1174 - }
1175 -
1176 - if ( ! \current_user_can( 'manage_options' ) ) {
1177 - \wp_send_json_error( array( 'message' => \__( 'You do not have permission to perform this action.', 'activitypub' ) ) );
1178 - }
1179 -
1180 - $client_id = \sanitize_text_field( \wp_unslash( $_POST['client_id'] ?? '' ) );
1181 -
1182 - if ( empty( $client_id ) ) {
1183 - \wp_send_json_error( array( 'message' => \__( 'Invalid client ID.', 'activitypub' ) ) );
1184 - }
1185 -
1186 - $deleted = Client::delete( $client_id );
1187 -
1188 - if ( ! $deleted ) {
1189 - \wp_send_json_error( array( 'message' => \__( 'Failed to delete application.', 'activitypub' ) ) );
1190 - }
1191 -
1192 - \wp_send_json_success( array( 'deleted' => true ) );
1193 - }
1194 -
1195 - /**
1196 - * AJAX handler for deleting all manually registered OAuth clients.
1197 - *
1198 - * @since 8.1.0
1199 - */
1200 - public static function ajax_delete_all_oauth_clients() {
1201 - // Verify nonce.
1202 - if ( ! \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST['_wpnonce'] ?? '' ) ), 'activitypub_connected_apps' ) ) {
1203 - \wp_send_json_error( array( 'message' => \__( 'Invalid nonce.', 'activitypub' ) ) );
1204 - }
1205 -
1206 - if ( ! \current_user_can( 'manage_options' ) ) {
1207 - \wp_send_json_error( array( 'message' => \__( 'You do not have permission to perform this action.', 'activitypub' ) ) );
1208 - }
1209 -
1210 - $clients = Client::get_manually_registered();
1211 -
1212 - foreach ( $clients as $client ) {
1213 - Client::delete( $client->get_client_id() );
1214 - }
1215 -
1216 - \wp_send_json_success( array( 'deleted' => ! empty( $clients ) ) );
1217 - }
1218 -
1219 - /**
1220 - * AJAX handler for revoking an OAuth token from the user profile.
1221 - *
1222 - * Follows the WordPress core Application Passwords pattern.
1223 - *
1224 - * @since 8.1.0
1225 - */
1226 - public static function ajax_revoke_oauth_token() {
1227 - // Verify nonce.
1228 - if ( ! \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST['_wpnonce'] ?? '' ) ), 'activitypub_connected_apps' ) ) {
1229 - \wp_send_json_error( array( 'message' => \__( 'Invalid nonce.', 'activitypub' ) ) );
1230 - }
1231 -
1232 - if ( ! \current_user_can( 'read' ) ) {
1233 - \wp_send_json_error( array( 'message' => \__( 'You do not have permission to perform this action.', 'activitypub' ) ) );
1234 - }
1235 -
1236 - $meta_key = \sanitize_text_field( \wp_unslash( $_POST['meta_key'] ?? '' ) ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Not a DB query parameter.
1237 -
1238 - // Verify the meta key belongs to our token prefix.
1239 - if ( 0 !== \strpos( $meta_key, Token::META_PREFIX ) ) {
1240 - \wp_send_json_error( array( 'message' => \__( 'Invalid token.', 'activitypub' ) ) );
1241 - }
1242 -
1243 - $user_id = \get_current_user_id();
1244 - $token_data = \get_user_meta( $user_id, $meta_key, true );
1245 -
1246 - // Verify the token belongs to the current user.
1247 - if ( empty( $token_data ) || ! \is_array( $token_data ) ) {
1248 - \wp_send_json_error( array( 'message' => \__( 'Token not found.', 'activitypub' ) ) );
1249 - }
1250 -
1251 - // Delete the token.
1252 - \delete_user_meta( $user_id, $meta_key );
1253 -
1254 - // Delete the associated refresh token index.
1255 - if ( ! empty( $token_data['refresh_token_hash'] ) ) {
1256 - \delete_user_meta( $user_id, Token::REFRESH_INDEX_PREFIX . $token_data['refresh_token_hash'] );
1257 - }
1258 -
1259 - \wp_send_json_success( array( 'deleted' => true ) );
1260 - }
1261 -
1262 - /**
1263 - * AJAX handler for revoking all OAuth tokens for the current user.
1264 - *
1265 - * @since 8.1.0
1266 - */
1267 - public static function ajax_revoke_all_oauth_tokens() {
1268 - // Verify nonce.
1269 - if ( ! \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST['_wpnonce'] ?? '' ) ), 'activitypub_connected_apps' ) ) {
1270 - \wp_send_json_error( array( 'message' => \__( 'Invalid nonce.', 'activitypub' ) ) );
1271 - }
1272 -
1273 - if ( ! \current_user_can( 'read' ) ) {
1274 - \wp_send_json_error( array( 'message' => \__( 'You do not have permission to perform this action.', 'activitypub' ) ) );
1275 - }
1276 -
1277 - $count = Token::revoke_all_for_user( \get_current_user_id() );
1278 -
1279 - \wp_send_json_success( array( 'deleted' => $count > 0 ) );
1280 1071 }
1281 1072 }