PluginProbe
ActivityPub / 5.3.1
ActivityPub v5.3.1
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.3.1, at includes/wp-admin/class-admin.php

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