PluginProbe
ActivityPub / 2.3.0
ActivityPub v2.3.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.3.0, at includes/class-admin.php

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