PluginProbe
ActivityPub / 3.2.0
ActivityPub v3.2.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
activitypub / includes / class-admin.php

class-admin.php in ActivityPub 3.2.0, at includes/class-admin.php

760 lines 21.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Activitypub;
3
4 use WP_User_Query;
5 use Activitypub\Model\Blog;
6 use Activitypub\Activitypub;
7 use Activitypub\Collection\Users;
8 use Activitypub\Collection\Extra_Fields;
9
10 use function Activitypub\count_followers;
11 use function Activitypub\is_user_disabled;
12 use function Activitypub\was_comment_received;
13 use function Activitypub\is_comment_federatable;
14
15 /**
16 * ActivityPub Admin Class
17 *
18 * @author Matthias Pfefferle
19 */
20 class Admin {
21 /**
22 * Initialize the class, registering WordPress hooks
23 */
24 public static function init() {
25 \add_action( 'admin_menu', array( self::class, 'admin_menu' ) );
26 \add_action( 'admin_init', array( self::class, 'register_settings' ) );
27 \add_action( 'load-comment.php', array( self::class, 'edit_comment' ) );
28 \add_action( 'load-post.php', array( self::class, 'edit_post' ) );
29 \add_action( 'load-edit.php', array( self::class, 'list_posts' ) );
30 \add_action( 'personal_options_update', array( self::class, 'save_user_settings' ) );
31 \add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_scripts' ) );
32 \add_action( 'admin_notices', array( self::class, 'admin_notices' ) );
33
34 \add_filter( 'comment_row_actions', array( self::class, 'comment_row_actions' ), 10, 2 );
35 \add_filter( 'manage_edit-comments_columns', array( static::class, 'manage_comment_columns' ) );
36 \add_action( 'manage_comments_custom_column', array( static::class, 'manage_comments_custom_column' ), 9, 2 );
37
38 \add_filter( 'manage_posts_columns', array( static::class, 'manage_post_columns' ), 10, 2 );
39 \add_action( 'manage_posts_custom_column', array( self::class, 'manage_posts_custom_column' ), 10, 2 );
40
41 \add_filter( 'manage_users_columns', array( self::class, 'manage_users_columns' ), 10, 1 );
42 \add_action( 'manage_users_custom_column', array( self::class, 'manage_users_custom_column' ), 10, 3 );
43 \add_filter( 'bulk_actions-users', array( self::class, 'user_bulk_options' ) );
44 \add_filter( 'handle_bulk_actions-users', array( self::class, 'handle_bulk_request' ), 10, 3 );
45
46 if ( ! is_user_disabled( get_current_user_id() ) ) {
47 \add_action( 'show_user_profile', array( self::class, 'add_profile' ) );
48 }
49
50 \add_filter( 'dashboard_glance_items', array( self::class, 'dashboard_glance_items' ) );
51 }
52
53 /**
54 * Add admin menu entry
55 */
56 public static function admin_menu() {
57 $settings_page = \add_options_page(
58 'Welcome',
59 'ActivityPub',
60 'manage_options',
61 'activitypub',
62 array( self::class, 'settings_page' )
63 );
64
65 \add_action(
66 'load-' . $settings_page,
67 array( self::class, 'add_settings_help_tab' )
68 );
69
70 // user has to be able to publish posts
71 if ( ! is_user_disabled( get_current_user_id() ) ) {
72 $followers_list_page = \add_users_page(
73 \__( '⁂ Followers', 'activitypub' ),
74 \__( '⁂ Followers', 'activitypub' ),
75 'read',
76 'activitypub-followers-list',
77 array(
78 self::class,
79 'followers_list_page',
80 )
81 );
82
83 \add_action(
84 'load-' . $followers_list_page,
85 array( self::class, 'add_followers_list_help_tab' )
86 );
87
88 \add_users_page(
89 \__( '⁂ Extra Fields', 'activitypub' ),
90 \__( '⁂ Extra Fields', 'activitypub' ),
91 'read',
92 \esc_url( \admin_url( '/edit.php?post_type=ap_extrafield' ) )
93 );
94 }
95 }
96
97 /**
98 * Display admin menu notices about configuration problems or conflicts.
99 *
100 * @return void
101 */
102 public static function admin_notices() {
103 $permalink_structure = \get_option( 'permalink_structure' );
104 if ( empty( $permalink_structure ) ) {
105 $admin_notice = \__( 'You are using the ActivityPub plugin with a permalink structure of "plain". This will prevent ActivityPub from working. Please go to "Settings" / "Permalinks" and choose a permalink structure other than "plain".', 'activitypub' );
106 self::show_admin_notice( $admin_notice, 'error' );
107 }
108
109 $current_screen = get_current_screen();
110 if ( ! $current_screen ) {
111 return;
112 }
113 if ( 'edit' === $current_screen->base && Extra_Fields::is_extra_fields_post_type( $current_screen->post_type ) ) {
114 ?>
115 <div class="notice" style="margin: 0; background: none; border: none; box-shadow: none; padding: 15px 0 0 0; font-size: 14px;">
116 <?php 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' ); ?>
117 </div>
118 <?php
119 }
120 }
121
122 /**
123 * Display one admin menu notice about configuration problems or conflicts.
124 *
125 * @param string $admin_notice The notice to display.
126 * @param string $level The level of the notice (error, warning, success, info).
127 *
128 * @return void
129 */
130 private static function show_admin_notice( $admin_notice, $level ) {
131 ?>
132
133 <div class="notice notice-<?php echo esc_attr( $level ); ?>">
134 <p><?php echo wp_kses( $admin_notice, 'data' ); ?></p>
135 </div>
136
137 <?php
138 }
139
140 /**
141 * Load settings page
142 */
143 public static function settings_page() {
144 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
145 if ( empty( $_GET['tab'] ) ) {
146 $tab = 'welcome';
147 } else {
148 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
149 $tab = sanitize_key( $_GET['tab'] );
150 }
151
152 switch ( $tab ) {
153 case 'settings':
154 \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/settings.php' );
155 break;
156 case 'blog-profile':
157 wp_enqueue_media();
158 wp_enqueue_script( 'activitypub-header-image' );
159
160 \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/blog-settings.php' );
161 break;
162 case 'followers':
163 \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/blog-followers-list.php' );
164 break;
165 case 'welcome':
166 default:
167 wp_enqueue_script( 'plugin-install' );
168 add_thickbox();
169 wp_enqueue_script( 'updates' );
170
171 \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/welcome.php' );
172 break;
173 }
174 }
175
176 /**
177 * Load user settings page
178 */
179 public static function followers_list_page() {
180 // user has to be able to publish posts
181 if ( ! is_user_disabled( get_current_user_id() ) ) {
182 \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/user-followers-list.php' );
183 }
184 }
185
186 /**
187 * Register ActivityPub settings
188 */
189 public static function register_settings() {
190 \register_setting(
191 'activitypub',
192 'activitypub_post_content_type',
193 array(
194 'type' => 'string',
195 'description' => \__( 'Use title and link, summary, full or custom content', 'activitypub' ),
196 'show_in_rest' => array(
197 'schema' => array(
198 'enum' => array(
199 'title',
200 'excerpt',
201 'content',
202 ),
203 ),
204 ),
205 'default' => 'content',
206 )
207 );
208 \register_setting(
209 'activitypub',
210 'activitypub_custom_post_content',
211 array(
212 'type' => 'string',
213 'description' => \__( 'Define your own custom post template', 'activitypub' ),
214 'show_in_rest' => true,
215 'default' => ACTIVITYPUB_CUSTOM_POST_CONTENT,
216 )
217 );
218 \register_setting(
219 'activitypub',
220 'activitypub_max_image_attachments',
221 array(
222 'type' => 'integer',
223 'description' => \__( 'Number of images to attach to posts.', 'activitypub' ),
224 'default' => ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS,
225 )
226 );
227 \register_setting(
228 'activitypub',
229 'activitypub_object_type',
230 array(
231 'type' => 'string',
232 'description' => \__( 'The Activity-Object-Type', 'activitypub' ),
233 'show_in_rest' => array(
234 'schema' => array(
235 'enum' => array(
236 'note',
237 'wordpress-post-format',
238 ),
239 ),
240 ),
241 'default' => 'note',
242 )
243 );
244 \register_setting(
245 'activitypub',
246 'activitypub_use_hashtags',
247 array(
248 'type' => 'boolean',
249 'description' => \__( 'Add hashtags in the content as native tags and replace the #tag with the tag-link', 'activitypub' ),
250 'default' => '0',
251 )
252 );
253 \register_setting(
254 'activitypub',
255 'activitypub_use_opengraph',
256 array(
257 'type' => 'boolean',
258 'description' => \__( 'Automatically add "fediverse:creator" OpenGraph tags for Authors and the Blog-User.', 'activitypub' ),
259 'default' => '1',
260 )
261 );
262 \register_setting(
263 'activitypub',
264 'activitypub_support_post_types',
265 array(
266 'type' => 'string',
267 'description' => \esc_html__( 'Enable ActivityPub support for post types', 'activitypub' ),
268 'show_in_rest' => true,
269 'default' => array( 'post' ),
270 )
271 );
272 \register_setting(
273 'activitypub',
274 'activitypub_enable_users',
275 array(
276 'type' => 'boolean',
277 'description' => \__( 'Every Author on this Blog (with the publish_posts capability) gets his own ActivityPub enabled Profile.', 'activitypub' ),
278 'default' => '1',
279 )
280 );
281 \register_setting(
282 'activitypub',
283 'activitypub_enable_blog_user',
284 array(
285 'type' => 'boolean',
286 'description' => \__( 'Your Blog becomes an ActivityPub compatible Profile.', 'activitypub' ),
287 'default' => '0',
288 )
289 );
290
291 // Blog-User Settings
292 \register_setting(
293 'activitypub_blog',
294 'activitypub_blog_description',
295 array(
296 'type' => 'string',
297 'description' => \esc_html__( 'The Description of the Blog-User', 'activitypub' ),
298 'show_in_rest' => true,
299 'default' => '',
300 )
301 );
302 \register_setting(
303 'activitypub_blog',
304 'activitypub_blog_identifier',
305 array(
306 'type' => 'string',
307 'description' => \esc_html__( 'The Identifier of the Blog-User', 'activitypub' ),
308 'show_in_rest' => true,
309 'default' => Blog::get_default_username(),
310 'sanitize_callback' => function ( $value ) {
311 // hack to allow dots in the username
312 $parts = explode( '.', $value );
313 $sanitized = array();
314
315 foreach ( $parts as $part ) {
316 $sanitized[] = \sanitize_title( $part );
317 }
318
319 $sanitized = implode( '.', $sanitized );
320
321 // check for login or nicename.
322 $user = new WP_User_Query(
323 array(
324 'search' => $sanitized,
325 'search_columns' => array( 'user_login', 'user_nicename' ),
326 'number' => 1,
327 'hide_empty' => true,
328 'fields' => 'ID',
329 )
330 );
331
332 if ( $user->results ) {
333 add_settings_error(
334 'activitypub_blog_identifier',
335 'activitypub_blog_identifier',
336 \esc_html__( 'You cannot use an existing author\'s name for the blog profile ID.', 'activitypub' ),
337 'error'
338 );
339
340 return Blog::get_default_username();
341 }
342
343 return $sanitized;
344 },
345 )
346 );
347 \register_setting(
348 'activitypub_blog',
349 'activitypub_header_image',
350 array(
351 'type' => 'integer',
352 'description' => \__( 'The Attachment-ID of the Sites Header-Image', 'activitypub' ),
353 'default' => null,
354 )
355 );
356 }
357
358 public static function add_settings_help_tab() {
359 require_once ACTIVITYPUB_PLUGIN_DIR . 'includes/help.php';
360 }
361
362 public static function add_followers_list_help_tab() {
363 // todo
364 }
365
366 public static function add_profile( $user ) {
367 $description = \get_user_option( 'activitypub_description', $user->ID );
368
369 wp_enqueue_media();
370 wp_enqueue_script( 'activitypub-header-image' );
371
372 \load_template(
373 ACTIVITYPUB_PLUGIN_DIR . 'templates/user-settings.php',
374 true,
375 array(
376 'description' => $description,
377 )
378 );
379 }
380
381 /**
382 * Save the user settings
383 *
384 * Habdles the saving of the ActivityPub settings.
385 *
386 * @param int $user_id The user ID.
387 *
388 * @return void
389 */
390 public static function save_user_settings( $user_id ) {
391 if ( ! isset( $_REQUEST['_apnonce'] ) ) {
392 return false;
393 }
394 $nonce = sanitize_text_field( wp_unslash( $_REQUEST['_apnonce'] ) );
395 if (
396 ! wp_verify_nonce( $nonce, 'activitypub-user-settings' ) ||
397 ! current_user_can( 'edit_user', $user_id )
398 ) {
399 return false;
400 }
401 $description = ! empty( $_POST['activitypub_description'] ) ? sanitize_textarea_field( wp_unslash( $_POST['activitypub_description'] ) ) : false;
402 if ( $description ) {
403 \update_user_option( $user_id, 'activitypub_description', $description );
404 } else {
405 \delete_user_option( $user_id, 'activitypub_description' );
406 }
407
408 $header_image = ! empty( $_POST['activitypub_header_image'] ) ? sanitize_text_field( wp_unslash( $_POST['activitypub_header_image'] ) ) : false;
409 if ( $header_image && \wp_attachment_is_image( $header_image ) ) {
410 \update_user_option( $user_id, 'activitypub_header_image', $header_image );
411 } else {
412 \delete_user_option( $user_id, 'activitypub_header_image' );
413 }
414 }
415
416 public static function enqueue_scripts( $hook_suffix ) {
417 wp_register_script(
418 'activitypub-header-image',
419 plugins_url(
420 'assets/js/activitypub-header-image.js',
421 ACTIVITYPUB_PLUGIN_FILE
422 ),
423 array( 'jquery' ),
424 get_plugin_version(),
425 false
426 );
427
428 if ( false !== strpos( $hook_suffix, 'activitypub' ) ) {
429 wp_enqueue_style(
430 'activitypub-admin-styles',
431 plugins_url(
432 'assets/css/activitypub-admin.css',
433 ACTIVITYPUB_PLUGIN_FILE
434 ),
435 array(),
436 get_plugin_version()
437 );
438 wp_enqueue_script(
439 'activitypub-admin-script',
440 plugins_url(
441 'assets/js/activitypub-admin.js',
442 ACTIVITYPUB_PLUGIN_FILE
443 ),
444 array( 'jquery' ),
445 get_plugin_version(),
446 false
447 );
448 }
449
450 if ( 'index.php' === $hook_suffix ) {
451 wp_enqueue_style(
452 'activitypub-admin-styles',
453 plugins_url(
454 'assets/css/activitypub-admin.css',
455 ACTIVITYPUB_PLUGIN_FILE
456 ),
457 array(),
458 get_plugin_version()
459 );
460 }
461 }
462
463 /**
464 * Hook into the edit_comment functionality
465 *
466 * * Disable the edit_comment capability for federated comments.
467 *
468 * @return void
469 */
470 public static function edit_comment() {
471 // Disable the edit_comment capability for federated comments.
472 \add_filter(
473 'user_has_cap',
474 function ( $allcaps, $caps, $arg ) {
475 if ( 'edit_comment' !== $arg[0] ) {
476 return $allcaps;
477 }
478
479 if ( was_comment_received( $arg[2] ) ) {
480 return false;
481 }
482
483 return $allcaps;
484 },
485 1,
486 3
487 );
488 }
489
490 public static function edit_post() {
491 // Disable the edit_post capability for federated posts.
492 \add_filter(
493 'user_has_cap',
494 function ( $allcaps, $caps, $arg ) {
495 if ( 'edit_post' !== $arg[0] ) {
496 return $allcaps;
497 }
498
499 $post = get_post( $arg[2] );
500
501 if ( Extra_Fields::is_extra_fields_post_type( $post->post_type ) ) {
502 return $allcaps;
503 }
504
505 if ( (int) get_current_user_id() !== (int) $post->post_author ) {
506 return false;
507 }
508
509 return $allcaps;
510 },
511 1,
512 3
513 );
514 }
515
516 /**
517 * Add ActivityPub specific actions/filters to the post list view
518 *
519 * @return void
520 */
521 public static function list_posts() {
522 // Show only the user's extra fields.
523 \add_action(
524 'pre_get_posts',
525 function ( $query ) {
526 if ( $query->get( 'post_type' ) === 'ap_extrafield' ) {
527 $query->set( 'author', get_current_user_id() );
528 }
529 }
530 );
531
532 // Remove all views for the extra fields.
533 $screen_id = get_current_screen()->id;
534
535 add_filter(
536 "views_{$screen_id}",
537 function ( $views ) {
538 if ( Extra_Fields::is_extra_fields_post_type( get_current_screen()->post_type ) ) {
539 return array();
540 }
541
542 return $views;
543 }
544 );
545 }
546
547 public static function comment_row_actions( $actions, $comment ) {
548 if ( was_comment_received( $comment ) ) {
549 unset( $actions['edit'] );
550 unset( $actions['quickedit'] );
551 }
552
553 return $actions;
554 }
555
556 /**
557 * Add a column "activitypub"
558 *
559 * This column shows if the user has the capability to use ActivityPub.
560 *
561 * @param array $columns The columns.
562 *
563 * @return array The columns extended by the activitypub.
564 */
565 public static function manage_users_columns( $columns ) {
566 $columns['activitypub'] = __( 'ActivityPub', 'activitypub' );
567 return $columns;
568 }
569
570 /**
571 * Add "comment-type" and "protocol" as column in WP-Admin
572 *
573 * @param array $columns the list of column names
574 */
575 public static function manage_comment_columns( $columns ) {
576 $columns['comment_type'] = esc_attr__( 'Comment-Type', 'activitypub' );
577 $columns['comment_protocol'] = esc_attr__( 'Protocol', 'activitypub' );
578
579 return $columns;
580 }
581
582 /**
583 * Add "post_content" as column for Extra-Fields in WP-Admin
584 *
585 * @param array $columns Tthe list of column names.
586 * @param string $post_type The post type.
587 */
588 public static function manage_post_columns( $columns, $post_type ) {
589 if ( Extra_Fields::is_extra_fields_post_type( $post_type ) ) {
590 $after_key = 'title';
591 $index = array_search( $after_key, array_keys( $columns ), true );
592 $columns = array_slice( $columns, 0, $index + 1 ) + array( 'extra_field_content' => esc_attr__( 'Content', 'activitypub' ) ) + $columns;
593 }
594
595 return $columns;
596 }
597
598 /**
599 * Add "comment-type" and "protocol" as column in WP-Admin
600 *
601 * @param array $column The column to implement
602 * @param int $comment_id The comment id
603 */
604 public static function manage_comments_custom_column( $column, $comment_id ) {
605 if ( 'comment_type' === $column && ! defined( 'WEBMENTION_PLUGIN_DIR' ) ) {
606 echo esc_attr( ucfirst( get_comment_type( $comment_id ) ) );
607 } elseif ( 'comment_protocol' === $column ) {
608 $protocol = get_comment_meta( $comment_id, 'protocol', true );
609
610 if ( $protocol ) {
611 echo esc_attr( ucfirst( str_replace( 'activitypub', 'ActivityPub', $protocol ) ) );
612 } else {
613 esc_attr_e( 'Local', 'activitypub' );
614 }
615 }
616 }
617
618 /**
619 * Return the results for the activitypub column.
620 *
621 * @param string $output Custom column output. Default empty.
622 * @param string $column_name Column name.
623 * @param int $user_id ID of the currently-listed user.
624 *
625 * @return string The column contents.
626 */
627 public static function manage_users_custom_column( $output, $column_name, $user_id ) {
628 if ( 'activitypub' !== $column_name ) {
629 return $output;
630 }
631
632 if ( \user_can( $user_id, 'activitypub' ) ) {
633 return '<span aria-hidden="true">&#x2713;</span><span class="screen-reader-text">' . esc_html__( 'ActivityPub enabled for this author', 'activitypub' ) . '</span>';
634 } else {
635 return '<span aria-hidden="true">&#x2717;</span><span class="screen-reader-text">' . esc_html__( 'ActivityPub disabled for this author', 'activitypub' ) . '</span>';
636 }
637 }
638
639 /**
640 * Add a column "extra_field_content" to the post list view
641 *
642 * @param string $column_name The column name.
643 * @param int $post_id The post ID.
644 *
645 * @return void
646 */
647 public static function manage_posts_custom_column( $column_name, $post_id ) {
648 $post = get_post( $post_id );
649
650 if ( 'extra_field_content' === $column_name ) {
651 $post = get_post( $post_id );
652 if ( Extra_Fields::is_extra_fields_post_type( $post->post_type ) ) {
653 echo esc_attr( wp_strip_all_tags( $post->post_content ) );
654 }
655 }
656 }
657
658 /**
659 * Add options to the Bulk dropdown on the users page
660 *
661 * @param array $actions The existing bulk options.
662 *
663 * @return array The extended bulk options.
664 */
665 public static function user_bulk_options( $actions ) {
666 $actions['add_activitypub_cap'] = __( 'Enable for ActivityPub', 'activitypub' );
667 $actions['remove_activitypub_cap'] = __( 'Disable for ActivityPub', 'activitypub' );
668
669 return $actions;
670 }
671
672 /**
673 * Handle bulk activitypub requests
674 *
675 * * `add_activitypub_cap` - Add the activitypub capability to the selected users.
676 * * `remove_activitypub_cap` - Remove the activitypub capability from the selected users.
677 *
678 * @param string $sendback The URL to send the user back to.
679 * @param string $action The requested action.
680 * @param array $users The selected users.
681 *
682 * @return string The URL to send the user back to.
683 */
684 public static function handle_bulk_request( $sendback, $action, $users ) {
685 if (
686 'remove_activitypub_cap' !== $action &&
687 'add_activitypub_cap' !== $action
688 ) {
689 return $sendback;
690 }
691
692 foreach ( $users as $user_id ) {
693 $user = new \WP_User( $user_id );
694 if (
695 'add_activitypub_cap' === $action &&
696 user_can( $user_id, 'publish_posts' )
697 ) {
698 $user->add_cap( 'activitypub' );
699 } elseif ( 'remove_activitypub_cap' === $action ) {
700 $user->remove_cap( 'activitypub' );
701 }
702 }
703
704 return $sendback;
705 }
706
707 /**
708 * Add ActivityPub infos to the dashboard glance items
709 *
710 * @param array $items The existing glance items.
711 *
712 * @return array The extended glance items.
713 */
714 public static function dashboard_glance_items( $items ) {
715 \add_filter( 'number_format_i18n', '\Activitypub\custom_large_numbers', 10, 3 );
716
717 if ( ! is_user_disabled( get_current_user_id() ) ) {
718 $follower_count = sprintf(
719 // translators: %s: number of followers
720 _n(
721 '%s Follower',
722 '%s Followers',
723 count_followers( \get_current_user_id() ),
724 'activitypub'
725 ),
726 \number_format_i18n( count_followers( \get_current_user_id() ) )
727 );
728 $items['activitypub-followers-user'] = sprintf(
729 '<a class="activitypub-followers" href="%1$s" title="%2$s">%3$s</a>',
730 \esc_url( \admin_url( 'users.php?page=activitypub-followers-list' ) ),
731 \esc_attr__( 'Your followers', 'activitypub' ),
732 \esc_html( $follower_count )
733 );
734 }
735
736 if ( ! is_user_type_disabled( 'blog' ) && current_user_can( 'manage_options' ) ) {
737 $follower_count = sprintf(
738 // translators: %s: number of followers
739 _n(
740 '%s Follower (Blog)',
741 '%s Followers (Blog)',
742 count_followers( Users::BLOG_USER_ID ),
743 'activitypub'
744 ),
745 \number_format_i18n( count_followers( Users::BLOG_USER_ID ) )
746 );
747 $items['activitypub-followers-blog'] = sprintf(
748 '<a class="activitypub-followers" href="%1$s" title="%2$s">%3$s</a>',
749 \esc_url( \admin_url( 'options-general.php?page=activitypub&tab=followers' ) ),
750 \esc_attr__( 'The Blog\'s followers', 'activitypub' ),
751 \esc_html( $follower_count )
752 );
753 }
754
755 \remove_filter( 'number_format_i18n', '\Activitypub\custom_large_numbers', 10, 3 );
756
757 return $items;
758 }
759 }
760