PluginProbe
ActivityPub / 2.5.0
ActivityPub v2.5.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 2.5.0, at includes/class-admin.php

534 lines 15.9 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\Collection\Users;
7
8 use function Activitypub\count_followers;
9 use function Activitypub\is_user_disabled;
10 use function Activitypub\was_comment_received;
11 use function Activitypub\is_comment_federatable;
12
13 /**
14 * ActivityPub Admin Class
15 *
16 * @author Matthias Pfefferle
17 */
18 class Admin {
19 /**
20 * Initialize the class, registering WordPress hooks
21 */
22 public static function init() {
23 \add_action( 'admin_menu', array( self::class, 'admin_menu' ) );
24 \add_action( 'admin_init', array( self::class, 'register_settings' ) );
25 \add_action( 'load-comment.php', array( self::class, 'edit_comment' ) );
26 \add_action( 'personal_options_update', array( self::class, 'save_user_description' ) );
27 \add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_scripts' ) );
28 \add_action( 'admin_notices', array( self::class, 'admin_notices' ) );
29
30 \add_filter( 'comment_row_actions', array( self::class, 'comment_row_actions' ), 10, 2 );
31 \add_filter( 'manage_edit-comments_columns', array( static::class, 'manage_comment_columns' ) );
32 \add_filter( 'manage_comments_custom_column', array( static::class, 'manage_comments_custom_column' ), 9, 2 );
33
34 \add_filter( 'manage_users_columns', array( self::class, 'manage_users_columns' ), 10, 1 );
35 \add_filter( 'manage_users_custom_column', array( self::class, 'manage_users_custom_column' ), 10, 3 );
36 \add_filter( 'bulk_actions-users', array( self::class, 'user_bulk_options' ) );
37 \add_filter( 'handle_bulk_actions-users', array( self::class, 'handle_bulk_request' ), 10, 3 );
38
39 if ( ! is_user_disabled( get_current_user_id() ) ) {
40 \add_action( 'show_user_profile', array( self::class, 'add_profile' ) );
41 }
42
43 \add_filter( 'dashboard_glance_items', array( self::class, 'dashboard_glance_items' ) );
44 }
45
46 /**
47 * Add admin menu entry
48 */
49 public static function admin_menu() {
50 $settings_page = \add_options_page(
51 'Welcome',
52 'ActivityPub',
53 'manage_options',
54 'activitypub',
55 array( self::class, 'settings_page' )
56 );
57
58 \add_action( 'load-' . $settings_page, array( self::class, 'add_settings_help_tab' ) );
59
60 // user has to be able to publish posts
61 if ( ! is_user_disabled( get_current_user_id() ) ) {
62 $followers_list_page = \add_users_page( \__( 'Followers', 'activitypub' ), \__( 'Followers', 'activitypub' ), 'read', 'activitypub-followers-list', array( self::class, 'followers_list_page' ) );
63
64 \add_action( 'load-' . $followers_list_page, array( self::class, 'add_followers_list_help_tab' ) );
65 }
66 }
67
68 /**
69 * Display admin menu notices about configuration problems or conflicts.
70 *
71 * @return void
72 */
73 public static function admin_notices() {
74 $permalink_structure = \get_option( 'permalink_structure' );
75 if ( empty( $permalink_structure ) ) {
76 $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' );
77 self::show_admin_notice( $admin_notice, 'error' );
78 }
79 }
80
81 /**
82 * Display one admin menu notice about configuration problems or conflicts.
83 *
84 * @param string $admin_notice The notice to display.
85 * @param string $level The level of the notice (error, warning, success, info).
86 *
87 * @return void
88 */
89 private static function show_admin_notice( $admin_notice, $level ) {
90 ?>
91
92 <div class="notice notice-<?php echo esc_attr( $level ); ?>">
93 <p><?php echo wp_kses( $admin_notice, 'data' ); ?></p>
94 </div>
95
96 <?php
97 }
98
99 /**
100 * Load settings page
101 */
102 public static function settings_page() {
103 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
104 if ( empty( $_GET['tab'] ) ) {
105 $tab = 'welcome';
106 } else {
107 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
108 $tab = sanitize_key( $_GET['tab'] );
109 }
110
111 switch ( $tab ) {
112 case 'settings':
113 \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/settings.php' );
114 break;
115 case 'followers':
116 \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/blog-user-followers-list.php' );
117 break;
118 case 'welcome':
119 default:
120 wp_enqueue_script( 'plugin-install' );
121 add_thickbox();
122 wp_enqueue_script( 'updates' );
123
124 \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/welcome.php' );
125 break;
126 }
127 }
128
129 /**
130 * Load user settings page
131 */
132 public static function followers_list_page() {
133 // user has to be able to publish posts
134 if ( ! is_user_disabled( get_current_user_id() ) ) {
135 \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/user-followers-list.php' );
136 }
137 }
138
139 /**
140 * Register ActivityPub settings
141 */
142 public static function register_settings() {
143 \register_setting(
144 'activitypub',
145 'activitypub_post_content_type',
146 array(
147 'type' => 'string',
148 'description' => \__( 'Use title and link, summary, full or custom content', 'activitypub' ),
149 'show_in_rest' => array(
150 'schema' => array(
151 'enum' => array(
152 'title',
153 'excerpt',
154 'content',
155 ),
156 ),
157 ),
158 'default' => 'content',
159 )
160 );
161 \register_setting(
162 'activitypub',
163 'activitypub_custom_post_content',
164 array(
165 'type' => 'string',
166 'description' => \__( 'Define your own custom post template', 'activitypub' ),
167 'show_in_rest' => true,
168 'default' => ACTIVITYPUB_CUSTOM_POST_CONTENT,
169 )
170 );
171 \register_setting(
172 'activitypub',
173 'activitypub_max_image_attachments',
174 array(
175 'type' => 'integer',
176 'description' => \__( 'Number of images to attach to posts.', 'activitypub' ),
177 'default' => ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS,
178 )
179 );
180 \register_setting(
181 'activitypub',
182 'activitypub_object_type',
183 array(
184 'type' => 'string',
185 'description' => \__( 'The Activity-Object-Type', 'activitypub' ),
186 'show_in_rest' => array(
187 'schema' => array(
188 'enum' => array(
189 'note',
190 'wordpress-post-format',
191 ),
192 ),
193 ),
194 'default' => 'note',
195 )
196 );
197 \register_setting(
198 'activitypub',
199 'activitypub_use_hashtags',
200 array(
201 'type' => 'boolean',
202 'description' => \__( 'Add hashtags in the content as native tags and replace the #tag with the tag-link', 'activitypub' ),
203 'default' => '0',
204 )
205 );
206 \register_setting(
207 'activitypub',
208 'activitypub_support_post_types',
209 array(
210 'type' => 'string',
211 'description' => \esc_html__( 'Enable ActivityPub support for post types', 'activitypub' ),
212 'show_in_rest' => true,
213 'default' => array( 'post' ),
214 )
215 );
216 \register_setting(
217 'activitypub',
218 'activitypub_blog_user_identifier',
219 array(
220 'type' => 'string',
221 'description' => \esc_html__( 'The Identifier of the Blog-User', 'activitypub' ),
222 'show_in_rest' => true,
223 'default' => Blog::get_default_username(),
224 'sanitize_callback' => function ( $value ) {
225 // hack to allow dots in the username
226 $parts = explode( '.', $value );
227 $sanitized = array();
228
229 foreach ( $parts as $part ) {
230 $sanitized[] = \sanitize_title( $part );
231 }
232
233 $sanitized = implode( '.', $sanitized );
234
235 // check for login or nicename.
236 $user = new WP_User_Query(
237 array(
238 'search' => $sanitized,
239 'search_columns' => array( 'user_login', 'user_nicename' ),
240 'number' => 1,
241 'hide_empty' => true,
242 'fields' => 'ID',
243 )
244 );
245
246 if ( $user->results ) {
247 add_settings_error(
248 'activitypub_blog_user_identifier',
249 'activitypub_blog_user_identifier',
250 \esc_html__( 'You cannot use an existing author\'s name for the blog profile ID.', 'activitypub' ),
251 'error'
252 );
253
254 return Blog::get_default_username();
255 }
256
257 return $sanitized;
258 },
259 )
260 );
261 \register_setting(
262 'activitypub',
263 'activitypub_enable_users',
264 array(
265 'type' => 'boolean',
266 'description' => \__( 'Every Author on this Blog (with the publish_posts capability) gets his own ActivityPub enabled Profile.', 'activitypub' ),
267 'default' => '1',
268 )
269 );
270 \register_setting(
271 'activitypub',
272 'activitypub_enable_blog_user',
273 array(
274 'type' => 'boolean',
275 'description' => \__( 'Your Blog becomes an ActivityPub compatible Profile.', 'activitypub' ),
276 'default' => '0',
277 )
278 );
279 }
280
281 public static function add_settings_help_tab() {
282 require_once ACTIVITYPUB_PLUGIN_DIR . 'includes/help.php';
283 }
284
285 public static function add_followers_list_help_tab() {
286 // todo
287 }
288
289 public static function add_profile( $user ) {
290 $description = get_user_meta( $user->ID, 'activitypub_user_description', true );
291
292 \load_template(
293 ACTIVITYPUB_PLUGIN_DIR . 'templates/user-settings.php',
294 true,
295 array(
296 'description' => $description,
297 )
298 );
299 }
300
301 public static function save_user_description( $user_id ) {
302 if ( ! isset( $_REQUEST['_apnonce'] ) ) {
303 return false;
304 }
305 $nonce = sanitize_text_field( wp_unslash( $_REQUEST['_apnonce'] ) );
306 if (
307 ! wp_verify_nonce( $nonce, 'activitypub-user-description' ) ||
308 ! current_user_can( 'edit_user', $user_id )
309 ) {
310 return false;
311 }
312 $description = ! empty( $_POST['activitypub-user-description'] ) ? sanitize_text_field( wp_unslash( $_POST['activitypub-user-description'] ) ) : false;
313 if ( $description ) {
314 update_user_meta( $user_id, 'activitypub_user_description', $description );
315 }
316 }
317
318 public static function enqueue_scripts( $hook_suffix ) {
319 if ( false !== strpos( $hook_suffix, 'activitypub' ) ) {
320 wp_enqueue_style( 'activitypub-admin-styles', plugins_url( 'assets/css/activitypub-admin.css', ACTIVITYPUB_PLUGIN_FILE ), array(), get_plugin_version() );
321 wp_enqueue_script( 'activitypub-admin-script', plugins_url( 'assets/js/activitypub-admin.js', ACTIVITYPUB_PLUGIN_FILE ), array( 'jquery' ), get_plugin_version(), false );
322 }
323
324 if ( 'index.php' === $hook_suffix ) {
325 wp_enqueue_style( 'activitypub-admin-styles', plugins_url( 'assets/css/activitypub-admin.css', ACTIVITYPUB_PLUGIN_FILE ), array(), get_plugin_version() );
326 }
327 }
328
329 /**
330 * Hook into the edit_comment functionality
331 *
332 * * Disable the edit_comment capability for federated comments.
333 *
334 * @return void
335 */
336 public static function edit_comment() {
337 // Disable the edit_comment capability for federated comments.
338 \add_filter(
339 'user_has_cap',
340 function ( $allcaps, $caps, $arg ) {
341 if ( 'edit_comment' !== $arg[0] ) {
342 return $allcaps;
343 }
344
345 if ( was_comment_received( $arg[2] ) ) {
346 return false;
347 }
348
349 return $allcaps;
350 },
351 1,
352 3
353 );
354 }
355
356 public static function comment_row_actions( $actions, $comment ) {
357 if ( was_comment_received( $comment ) ) {
358 unset( $actions['edit'] );
359 unset( $actions['quickedit'] );
360 }
361
362 return $actions;
363 }
364
365 /**
366 * Add a column "activitypub"
367 *
368 * This column shows if the user has the capability to use ActivityPub.
369 *
370 * @param array $columns The columns.
371 *
372 * @return array The columns extended by the activitypub.
373 */
374 public static function manage_users_columns( $columns ) {
375 $columns['activitypub'] = __( 'ActivityPub', 'activitypub' );
376 return $columns;
377 }
378
379 /**
380 * Add "comment-type" and "protocol" as column in WP-Admin
381 *
382 * @param array $columns the list of column names
383 */
384 public static function manage_comment_columns( $columns ) {
385 $columns['comment_type'] = esc_attr__( 'Comment-Type', 'activitypub' );
386 $columns['comment_protocol'] = esc_attr__( 'Protocol', 'activitypub' );
387
388 return $columns;
389 }
390
391 /**
392 * Add "comment-type" and "protocol" as column in WP-Admin
393 *
394 * @param array $column The column to implement
395 * @param int $comment_id The comment id
396 */
397 public static function manage_comments_custom_column( $column, $comment_id ) {
398 if ( 'comment_type' === $column && ! defined( 'WEBMENTION_PLUGIN_DIR' ) ) {
399 echo esc_attr( ucfirst( get_comment_type( $comment_id ) ) );
400 } elseif ( 'comment_protocol' === $column ) {
401 $protocol = get_comment_meta( $comment_id, 'protocol', true );
402
403 if ( $protocol ) {
404 echo esc_attr( ucfirst( str_replace( 'activitypub', 'ActivityPub', $protocol ) ) );
405 } else {
406 esc_attr_e( 'Local', 'activitypub' );
407 }
408 }
409 }
410
411 /**
412 * Return the results for the activitypub column.
413 *
414 * @param string $output Custom column output. Default empty.
415 * @param string $column_name Column name.
416 * @param int $user_id ID of the currently-listed user.
417 *
418 * @return string The column contents.
419 */
420 public static function manage_users_custom_column( $output, $column_name, $user_id ) {
421 if ( 'activitypub' !== $column_name ) {
422 return $output;
423 }
424
425 if ( \user_can( $user_id, 'activitypub' ) ) {
426 return '<span aria-hidden="true">&#x2713;</span><span class="screen-reader-text">' . esc_html__( 'ActivityPub enabled for this author', 'activitypub' ) . '</span>';
427 } else {
428 return '<span aria-hidden="true">&#x2717;</span><span class="screen-reader-text">' . esc_html__( 'ActivityPub disabled for this author', 'activitypub' ) . '</span>';
429 }
430 }
431
432 /**
433 * Add options to the Bulk dropdown on the users page
434 *
435 * @param array $actions The existing bulk options.
436 *
437 * @return array The extended bulk options.
438 */
439 public static function user_bulk_options( $actions ) {
440 $actions['add_activitypub_cap'] = __( 'Enable for ActivityPub', 'activitypub' );
441 $actions['remove_activitypub_cap'] = __( 'Disable for ActivityPub', 'activitypub' );
442
443 return $actions;
444 }
445
446 /**
447 * Handle bulk activitypub requests
448 *
449 * * `add_activitypub_cap` - Add the activitypub capability to the selected users.
450 * * `remove_activitypub_cap` - Remove the activitypub capability from the selected users.
451 *
452 * @param string $sendback The URL to send the user back to.
453 * @param string $action The requested action.
454 * @param array $users The selected users.
455 *
456 * @return string The URL to send the user back to.
457 */
458 public static function handle_bulk_request( $sendback, $action, $users ) {
459 if (
460 'remove_activitypub_cap' !== $action &&
461 'add_activitypub_cap' !== $action
462 ) {
463 return $sendback;
464 }
465
466 foreach ( $users as $user_id ) {
467 $user = new \WP_User( $user_id );
468 if (
469 'add_activitypub_cap' === $action &&
470 user_can( $user_id, 'publish_posts' )
471 ) {
472 $user->add_cap( 'activitypub' );
473 } elseif ( 'remove_activitypub_cap' === $action ) {
474 $user->remove_cap( 'activitypub' );
475 }
476 }
477
478 return $sendback;
479 }
480
481 /**
482 * Add ActivityPub infos to the dashboard glance items
483 *
484 * @param array $items The existing glance items.
485 *
486 * @return array The extended glance items.
487 */
488 public static function dashboard_glance_items( $items ) {
489 \add_filter( 'number_format_i18n', '\Activitypub\custom_large_numbers', 10, 3 );
490
491 if ( ! is_user_disabled( get_current_user_id() ) ) {
492 $follower_count = sprintf(
493 // translators: %s: number of followers
494 _n(
495 '%s Follower',
496 '%s Followers',
497 count_followers( \get_current_user_id() ),
498 'activitypub'
499 ),
500 \number_format_i18n( count_followers( \get_current_user_id() ) )
501 );
502 $items['activitypub-followers-user'] = sprintf(
503 '<a class="activitypub-followers" href="%1$s" title="%2$s">%3$s</a>',
504 \esc_url( \admin_url( 'users.php?page=activitypub-followers-list' ) ),
505 \esc_attr__( 'Your followers', 'activitypub' ),
506 \esc_html( $follower_count )
507 );
508 }
509
510 if ( ! is_user_type_disabled( 'blog' ) && current_user_can( 'manage_options' ) ) {
511 $follower_count = sprintf(
512 // translators: %s: number of followers
513 _n(
514 '%s Follower (Blog)',
515 '%s Followers (Blog)',
516 count_followers( Users::BLOG_USER_ID ),
517 'activitypub'
518 ),
519 \number_format_i18n( count_followers( Users::BLOG_USER_ID ) )
520 );
521 $items['activitypub-followers-blog'] = sprintf(
522 '<a class="activitypub-followers" href="%1$s" title="%2$s">%3$s</a>',
523 \esc_url( \admin_url( 'options-general.php?page=activitypub&tab=followers' ) ),
524 \esc_attr__( 'The Blog\'s followers', 'activitypub' ),
525 \esc_html( $follower_count )
526 );
527 }
528
529 \remove_filter( 'number_format_i18n', '\Activitypub\custom_large_numbers', 10, 3 );
530
531 return $items;
532 }
533 }
534