PluginProbe
ActivityPub / 5.7.0
ActivityPub v5.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
activitypub / includes / wp-admin / class-admin.php

class-admin.php in ActivityPub 5.7.0, at includes/wp-admin/class-admin.php

613 lines 18.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Admin Class.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\WP_Admin;
9
10 use Activitypub\Comment;
11 use Activitypub\Collection\Actors;
12 use Activitypub\Collection\Extra_Fields;
13 use function Activitypub\count_followers;
14 use function Activitypub\get_content_visibility;
15 use function Activitypub\is_user_type_disabled;
16 use function Activitypub\site_supports_blocks;
17 use function Activitypub\user_can_activitypub;
18 use function Activitypub\was_comment_received;
19
20 /**
21 * ActivityPub Admin Class.
22 *
23 * @author Matthias Pfefferle
24 */
25 class Admin {
26 /**
27 * Initialize the class, registering WordPress hooks,
28 */
29 public static function init() {
30 \add_action( 'load-comment.php', array( self::class, 'edit_comment' ) );
31 \add_action( 'load-post.php', array( self::class, 'edit_post' ) );
32 \add_action( 'load-edit.php', array( self::class, 'list_posts' ) );
33 \add_filter( 'page_row_actions', array( self::class, 'row_actions' ), 10, 2 );
34 \add_filter( 'post_row_actions', array( self::class, 'row_actions' ), 10, 2 );
35 \add_action( 'personal_options_update', array( self::class, 'save_user_settings' ) );
36 \add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_scripts' ) );
37 \add_action( 'admin_notices', array( self::class, 'admin_notices' ) );
38
39 \add_filter( 'comment_row_actions', array( self::class, 'comment_row_actions' ), 10, 2 );
40 \add_filter( 'manage_edit-comments_columns', array( static::class, 'manage_comment_columns' ) );
41 \add_action( 'manage_comments_custom_column', array( static::class, 'manage_comments_custom_column' ), 9, 2 );
42 \add_filter( 'admin_comment_types_dropdown', array( static::class, 'comment_types_dropdown' ) );
43
44 \add_filter( 'manage_posts_columns', array( static::class, 'manage_post_columns' ), 10, 2 );
45 \add_action( 'manage_posts_custom_column', array( self::class, 'manage_posts_custom_column' ), 10, 2 );
46
47 \add_filter( 'manage_users_columns', array( self::class, 'manage_users_columns' ) );
48 \add_filter( 'manage_users_custom_column', array( self::class, 'manage_users_custom_column' ), 10, 3 );
49 \add_filter( 'bulk_actions-users', array( self::class, 'user_bulk_options' ) );
50 \add_filter( 'handle_bulk_actions-users', array( self::class, 'handle_bulk_request' ), 10, 3 );
51
52 if ( user_can_activitypub( \get_current_user_id() ) ) {
53 \add_action( 'show_user_profile', array( self::class, 'add_profile' ) );
54 }
55
56 \add_filter( 'dashboard_glance_items', array( self::class, 'dashboard_glance_items' ) );
57 \add_filter( 'plugin_action_links_' . ACTIVITYPUB_PLUGIN_BASENAME, array( self::class, 'add_plugin_settings_link' ) );
58 \add_action( 'in_plugin_update_message-' . ACTIVITYPUB_PLUGIN_BASENAME, array( self::class, 'plugin_update_message' ), 10, 2 );
59
60 if ( site_supports_blocks() ) {
61 \add_action( 'tool_box', array( self::class, 'tool_box' ) );
62 }
63 }
64
65 /**
66 * Display admin menu notices about configuration problems or conflicts.
67 */
68 public static function admin_notices() {
69 $current_screen = get_current_screen();
70 if ( ! $current_screen ) {
71 return;
72 }
73 if ( 'edit' === $current_screen->base && Extra_Fields::is_extra_fields_post_type( $current_screen->post_type ) ) {
74 ?>
75 <div class="notice" style="margin: 0; background: none; border: none; box-shadow: none; padding: 15px 0 0 0; font-size: 14px;">
76 <?php
77 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' );
78 ?>
79 </div>
80 <?php
81 }
82 }
83
84 /**
85 * Display one admin menu notice about configuration problems or conflicts.
86 *
87 * @param string $admin_notice The notice to display.
88 * @param string $level The level of the notice (error, warning, success, info).
89 */
90 private static function show_admin_notice( $admin_notice, $level ) {
91 ?>
92
93 <div class="notice notice-<?php echo esc_attr( $level ); ?>">
94 <p><?php echo wp_kses( $admin_notice, 'data' ); ?></p>
95 </div>
96
97 <?php
98 }
99
100 /**
101 * Load user settings page
102 */
103 public static function followers_list_page() {
104 // User has to be able to publish posts.
105 if ( user_can_activitypub( \get_current_user_id() ) ) {
106 \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/user-followers-list.php' );
107 }
108 }
109
110 /**
111 * Adds the follower list to the Help tab.
112 */
113 public static function add_followers_list_help_tab() {
114 // todo.
115 }
116
117 /**
118 * Render user settings.
119 */
120 public static function add_profile() {
121 wp_enqueue_media();
122 wp_enqueue_script( 'activitypub-header-image' );
123
124 wp_nonce_field( 'activitypub-user-settings', '_apnonce' );
125 do_settings_sections( 'activitypub_user_settings' );
126 }
127
128 /**
129 * Save the user settings.
130 *
131 * Handles the saving of the ActivityPub settings.
132 *
133 * @param int $user_id The user ID.
134 */
135 public static function save_user_settings( $user_id ) {
136 if ( ! isset( $_REQUEST['_apnonce'] ) ) {
137 return;
138 }
139
140 $nonce = sanitize_text_field( wp_unslash( $_REQUEST['_apnonce'] ) );
141 if (
142 ! wp_verify_nonce( $nonce, 'activitypub-user-settings' ) ||
143 ! current_user_can( 'edit_user', $user_id )
144 ) {
145 return;
146 }
147
148 $description = ! empty( $_POST['activitypub_description'] ) ? sanitize_textarea_field( wp_unslash( $_POST['activitypub_description'] ) ) : false;
149 if ( $description ) {
150 \update_user_option( $user_id, 'activitypub_description', $description );
151 } else {
152 \delete_user_option( $user_id, 'activitypub_description' );
153 }
154
155 $header_image = ! empty( $_POST['activitypub_header_image'] ) ? sanitize_text_field( wp_unslash( $_POST['activitypub_header_image'] ) ) : false;
156 if ( $header_image && \wp_attachment_is_image( $header_image ) ) {
157 \update_user_option( $user_id, 'activitypub_header_image', $header_image );
158 } else {
159 \delete_user_option( $user_id, 'activitypub_header_image' );
160 }
161
162 $also_known_as = ! empty( $_POST['activitypub_blog_user_also_known_as'] ) ? \sanitize_textarea_field( wp_unslash( $_POST['activitypub_blog_user_also_known_as'] ) ) : false;
163 if ( $also_known_as ) {
164 \update_user_option( $user_id, 'activitypub_also_known_as', $also_known_as );
165 } else {
166 \delete_user_option( $user_id, 'activitypub_also_known_as' );
167 }
168 }
169
170 /**
171 * Enqueue the admin scripts and styles.
172 *
173 * @param string $hook_suffix The current page.
174 */
175 public static function enqueue_scripts( $hook_suffix ) {
176 wp_register_script(
177 'activitypub-header-image',
178 plugins_url(
179 'assets/js/activitypub-header-image.js',
180 ACTIVITYPUB_PLUGIN_FILE
181 ),
182 array( 'jquery' ),
183 ACTIVITYPUB_PLUGIN_VERSION,
184 false
185 );
186
187 if ( false !== strpos( $hook_suffix, 'activitypub' ) ) {
188 wp_enqueue_style(
189 'activitypub-admin-styles',
190 plugins_url(
191 'assets/css/activitypub-admin.css',
192 ACTIVITYPUB_PLUGIN_FILE
193 ),
194 array(),
195 ACTIVITYPUB_PLUGIN_VERSION
196 );
197 wp_enqueue_script(
198 'activitypub-admin-script',
199 plugins_url(
200 'assets/js/activitypub-admin.js',
201 ACTIVITYPUB_PLUGIN_FILE
202 ),
203 array( 'jquery' ),
204 ACTIVITYPUB_PLUGIN_VERSION,
205 false
206 );
207 }
208
209 if ( 'index.php' === $hook_suffix ) {
210 wp_enqueue_style(
211 'activitypub-admin-styles',
212 plugins_url(
213 'assets/css/activitypub-admin.css',
214 ACTIVITYPUB_PLUGIN_FILE
215 ),
216 array(),
217 ACTIVITYPUB_PLUGIN_VERSION
218 );
219 }
220 }
221
222 /**
223 * Hook into the edit_comment functionality.
224 *
225 * Disables the edit_comment capability for federated comments.
226 */
227 public static function edit_comment() {
228 // Disable the edit_comment capability for federated comments.
229 \add_filter(
230 'user_has_cap',
231 function ( $allcaps, $caps, $arg ) {
232 if ( 'edit_comment' !== $arg[0] ) {
233 return $allcaps;
234 }
235
236 if ( was_comment_received( $arg[2] ) ) {
237 return false;
238 }
239
240 return $allcaps;
241 },
242 1,
243 3
244 );
245 }
246
247 /**
248 * Hook into the edit_post functionality.
249 *
250 * Disables the edit_post capability for federated posts.
251 */
252 public static function edit_post() {
253 // Disable the edit_post capability for federated posts.
254 \add_filter(
255 'user_has_cap',
256 function ( $allcaps, $caps, $arg ) {
257 if ( 'edit_post' !== $arg[0] ) {
258 return $allcaps;
259 }
260
261 $post = get_post( $arg[2] );
262
263 if ( ! Extra_Fields::is_extra_field_post_type( $post->post_type ) ) {
264 return $allcaps;
265 }
266
267 if ( (int) get_current_user_id() !== (int) $post->post_author ) {
268 return false;
269 }
270
271 return $allcaps;
272 },
273 1,
274 3
275 );
276 }
277
278 /**
279 * Add ActivityPub specific actions/filters to the post list view.
280 */
281 public static function list_posts() {
282 // Show only the user's extra fields.
283 \add_action(
284 'pre_get_posts',
285 function ( $query ) {
286 if ( $query->get( 'post_type' ) === 'ap_extrafield' ) {
287 $query->set( 'author', get_current_user_id() );
288 }
289 }
290 );
291
292 // Remove all views for the extra fields.
293 $screen_id = get_current_screen()->id;
294
295 add_filter(
296 "views_{$screen_id}",
297 function ( $views ) {
298 if ( Extra_Fields::is_extra_fields_post_type( get_current_screen()->post_type ) ) {
299 return array();
300 }
301
302 return $views;
303 }
304 );
305 }
306
307 /**
308 * Comment row actions.
309 *
310 * @param array $actions The existing actions.
311 * @param int|\WP_Comment $comment The comment object or ID.
312 *
313 * @return array The modified actions.
314 */
315 public static function comment_row_actions( $actions, $comment ) {
316 if ( was_comment_received( $comment ) ) {
317 unset( $actions['edit'] );
318 unset( $actions['quickedit'] );
319 }
320
321 if ( in_array( get_comment_type( $comment ), Comment::get_comment_type_slugs(), true ) ) {
322 unset( $actions['reply'] );
323 }
324
325 return $actions;
326 }
327
328 /**
329 * Add a column "activitypub".
330 *
331 * This column shows if the user has the capability to use ActivityPub.
332 *
333 * @param array $columns The columns.
334 *
335 * @return array The columns extended by the activitypub.
336 */
337 public static function manage_users_columns( $columns ) {
338 $columns['activitypub'] = __( 'ActivityPub', 'activitypub' );
339 return $columns;
340 }
341
342 /**
343 * Add "comment-type" and "protocol" as column in WP-Admin.
344 *
345 * @param array $columns The list of column names.
346 *
347 * @return array The extended list of column names.
348 */
349 public static function manage_comment_columns( $columns ) {
350 $columns['comment_type'] = esc_attr__( 'Comment-Type', 'activitypub' );
351 $columns['comment_protocol'] = esc_attr__( 'Protocol', 'activitypub' );
352
353 return $columns;
354 }
355
356 /**
357 * Add "post_content" as column for Extra-Fields in WP-Admin.
358 *
359 * @param array $columns The list of column names.
360 * @param string $post_type The post type.
361 *
362 * @return array The extended list of column names.
363 */
364 public static function manage_post_columns( $columns, $post_type ) {
365 if ( Extra_Fields::is_extra_fields_post_type( $post_type ) ) {
366 $after_key = 'title';
367 $index = array_search( $after_key, array_keys( $columns ), true );
368 $columns = array_slice( $columns, 0, $index + 1 ) + array( 'extra_field_content' => esc_attr__( 'Content', 'activitypub' ) ) + $columns;
369 }
370
371 return $columns;
372 }
373
374 /**
375 * Add "comment-type" and "protocol" as column in WP-Admin.
376 *
377 * @param array $column The column to implement.
378 * @param int $comment_id The comment id.
379 */
380 public static function manage_comments_custom_column( $column, $comment_id ) {
381 if ( 'comment_type' === $column && ! defined( 'WEBMENTION_PLUGIN_DIR' ) ) {
382 echo esc_attr( ucfirst( get_comment_type( $comment_id ) ) );
383 } elseif ( 'comment_protocol' === $column ) {
384 $protocol = get_comment_meta( $comment_id, 'protocol', true );
385
386 if ( $protocol ) {
387 echo esc_attr( ucfirst( str_replace( 'activitypub', 'ActivityPub', $protocol ) ) );
388 } else {
389 esc_attr_e( 'Local', 'activitypub' );
390 }
391 }
392 }
393
394 /**
395 * Add the new ActivityPub comment types to the comment types dropdown.
396 *
397 * @param array $types The existing comment types.
398 *
399 * @return array The extended comment types.
400 */
401 public static function comment_types_dropdown( $types ) {
402 foreach ( Comment::get_comment_types() as $comment_type ) {
403 $types[ $comment_type['type'] ] = esc_html( $comment_type['label'] );
404 }
405
406 return $types;
407 }
408
409 /**
410 * Return the results for the activitypub column.
411 *
412 * @param string $output Custom column output. Default empty.
413 * @param string $column_name Column name.
414 * @param int $user_id ID of the currently-listed user.
415 *
416 * @return string The column contents.
417 */
418 public static function manage_users_custom_column( $output, $column_name, $user_id ) {
419 if ( 'activitypub' !== $column_name ) {
420 return $output;
421 }
422
423 if ( \user_can( $user_id, 'activitypub' ) ) {
424 return '<span aria-hidden="true">&#x2713;</span><span class="screen-reader-text">' . esc_html__( 'ActivityPub enabled for this author', 'activitypub' ) . '</span>';
425 } else {
426 return '<span aria-hidden="true">&#x2717;</span><span class="screen-reader-text">' . esc_html__( 'ActivityPub disabled for this author', 'activitypub' ) . '</span>';
427 }
428 }
429
430 /**
431 * Add a column "extra_field_content" to the post list view.
432 *
433 * @param string $column_name The column name.
434 * @param int $post_id The post ID.
435 *
436 * @return void
437 */
438 public static function manage_posts_custom_column( $column_name, $post_id ) {
439 if ( 'extra_field_content' === $column_name ) {
440 $post = get_post( $post_id );
441 if ( Extra_Fields::is_extra_fields_post_type( $post->post_type ) ) {
442 echo esc_attr( wp_strip_all_tags( $post->post_content ) );
443 }
444 }
445 }
446
447 /**
448 * Add options to the Bulk dropdown on the users page.
449 *
450 * @param array $actions The existing bulk options.
451 *
452 * @return array The extended bulk options.
453 */
454 public static function user_bulk_options( $actions ) {
455 $actions['add_activitypub_cap'] = __( 'Enable for ActivityPub', 'activitypub' );
456 $actions['remove_activitypub_cap'] = __( 'Disable for ActivityPub', 'activitypub' );
457
458 return $actions;
459 }
460
461 /**
462 * Handle bulk activitypub requests.
463 *
464 * * `add_activitypub_cap` - Add the activitypub capability to the selected users.
465 * * `remove_activitypub_cap` - Remove the activitypub capability from the selected users.
466 *
467 * @param string $sendback The URL to send the user back to.
468 * @param string $action The requested action.
469 * @param array $users The selected users.
470 *
471 * @return string The URL to send the user back to.
472 */
473 public static function handle_bulk_request( $sendback, $action, $users ) {
474 if (
475 'remove_activitypub_cap' !== $action &&
476 'add_activitypub_cap' !== $action
477 ) {
478 return $sendback;
479 }
480
481 foreach ( $users as $user_id ) {
482 $user = new \WP_User( $user_id );
483 if ( 'add_activitypub_cap' === $action ) {
484 $user->add_cap( 'activitypub' );
485 } elseif ( 'remove_activitypub_cap' === $action ) {
486 $user->remove_cap( 'activitypub' );
487 }
488 }
489
490 return $sendback;
491 }
492
493 /**
494 * Add ActivityPub infos to the dashboard glance items.
495 *
496 * @param array $items The existing glance items.
497 *
498 * @return array The extended glance items.
499 */
500 public static function dashboard_glance_items( $items ) {
501 \add_filter( 'number_format_i18n', '\Activitypub\custom_large_numbers', 10, 3 );
502
503 if ( user_can_activitypub( \get_current_user_id() ) ) {
504 $follower_count = sprintf(
505 // translators: %s: number of followers.
506 _n(
507 '%s Follower',
508 '%s Followers',
509 count_followers( \get_current_user_id() ),
510 'activitypub'
511 ),
512 \number_format_i18n( count_followers( \get_current_user_id() ) )
513 );
514 $items['activitypub-followers-user'] = sprintf(
515 '<a class="activitypub-followers" href="%1$s" title="%2$s">%3$s</a>',
516 \esc_url( \admin_url( 'users.php?page=activitypub-followers-list' ) ),
517 \esc_attr__( 'Your followers', 'activitypub' ),
518 \esc_html( $follower_count )
519 );
520 }
521
522 if ( ! is_user_type_disabled( 'blog' ) && current_user_can( 'manage_options' ) ) {
523 $follower_count = sprintf(
524 // translators: %s: number of followers.
525 _n(
526 '%s Follower (Blog)',
527 '%s Followers (Blog)',
528 count_followers( Actors::BLOG_USER_ID ),
529 'activitypub'
530 ),
531 \number_format_i18n( count_followers( Actors::BLOG_USER_ID ) )
532 );
533 $items['activitypub-followers-blog'] = sprintf(
534 '<a class="activitypub-followers" href="%1$s" title="%2$s">%3$s</a>',
535 \esc_url( \admin_url( 'options-general.php?page=activitypub&tab=followers' ) ),
536 \esc_attr__( 'The Blog\'s followers', 'activitypub' ),
537 \esc_html( $follower_count )
538 );
539 }
540
541 \remove_filter( 'number_format_i18n', '\Activitypub\custom_large_numbers' );
542
543 return $items;
544 }
545
546 /**
547 * Add a "Fediverse Preview ⁂" link to the row actions.
548 *
549 * @param array $actions The existing actions.
550 * @param \WP_Post $post The post object.
551 *
552 * @return array The modified actions.
553 */
554 public static function row_actions( $actions, $post ) {
555 // check if the post is enabled for ActivityPub.
556 if (
557 ! \post_type_supports( \get_post_type( $post ), 'activitypub' ) ||
558 ! in_array( $post->post_status, array( 'pending', 'draft', 'future', 'publish' ), true ) ||
559 ! \current_user_can( 'edit_post', $post->ID ) ||
560 ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL === get_content_visibility( $post->ID ) ||
561 ( site_supports_blocks() && \use_block_editor_for_post_type( $post->post_type ) )
562 ) {
563 return $actions;
564 }
565
566 $preview_url = add_query_arg( 'activitypub', 'true', \get_preview_post_link( $post ) );
567
568 $actions['activitypub'] = sprintf(
569 '<a href="%s" target="_blank">%s</a>',
570 \esc_url( $preview_url ),
571 \esc_html__( 'Fediverse Preview ⁂', 'activitypub' )
572 );
573
574 return $actions;
575 }
576
577 /**
578 * Add plugin settings link.
579 *
580 * @param array $actions The current actions.
581 */
582 public static function add_plugin_settings_link( $actions ) {
583 $actions[] = \sprintf(
584 '<a href="%1s">%2s</a>',
585 \menu_page_url( 'activitypub', false ),
586 \__( 'Settings', 'activitypub' )
587 );
588
589 return $actions;
590 }
591
592 /**
593 * Display plugin upgrade notice to users.
594 *
595 * @param array $data The plugin data.
596 * @param object $update The plugin update data.
597 */
598 public static function plugin_update_message( $data, $update ) {
599 if ( ! isset( $update->upgrade_notice ) ) {
600 return;
601 }
602
603 echo '<br>' . wp_strip_all_tags( $update->upgrade_notice ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
604 }
605
606 /**
607 * Adds metabox on wp-admin/tools.php.
608 */
609 public static function tool_box() {
610 \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/toolbox.php' );
611 }
612 }
613