PluginProbe
ActivityPub / 7.7.0
ActivityPub v7.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
← All changes | includes/class-cli.php +535 -100 9.0.27.7.0 View file →
@@ -1,7 +1,7 @@
1 1 <?php
2 2 /**
3 - * WP-CLI commands registration.
3 + * WP-CLI file.
4 4 *
5 5 * @package Activitypub
6 6 */
7 7
@@ -6,131 +6,566 @@
6 6 */
7 7
8 8 namespace Activitypub;
9 9
10 +use Activitypub\Activity\Activity;
11 +use Activitypub\Collection\Actors;
12 +use Activitypub\Collection\Outbox;
13 +use Activitypub\Scheduler\Actor;
14 +
10 15 /**
11 - * ActivityPub CLI command registry.
16 + * WP-CLI commands.
12 17 *
13 - * Registers all ActivityPub CLI subcommands with WP-CLI.
14 - *
15 18 * @package Activitypub
16 19 */
17 -class Cli {
20 +class Cli extends \WP_CLI_Command {
18 21
19 22 /**
20 - * Register all ActivityPub CLI commands.
23 + * Remove the entire blog from the Fediverse.
21 24 *
22 - * This method registers the main 'activitypub' command namespace and all its
23 - * subcommands for managing ActivityPub functionality via WP-CLI.
25 + * This command permanently removes your blog from ActivityPub networks by sending
26 + * Delete activities to all followers. This action is IRREVERSIBLE.
24 27 *
25 - * Available commands:
26 - * - wp activitypub post <delete|update> <id>
27 - * - wp activitypub comment <delete|update> <id>
28 - * - wp activitypub actor <delete|update> <id>
29 - * - wp activitypub outbox <undo|reschedule> <id>
30 - * - wp activitypub cache <clear|status> [--type=<type>]
31 - * - wp activitypub self-destruct [--status] [--yes]
32 - * - wp activitypub move <from> <to>
33 - * - wp activitypub follow <remote_user>
34 - * - wp activitypub stats <collect|compile|send>
35 - * - wp activitypub fetch <url>
36 - * - wp activitypub blurhash backfill [--dry-run] [--limit=<n>] [--force]
28 + * ## OPTIONS
29 + *
30 + * [--status]
31 + * : Check the status of the self-destruct process instead of running it.
32 + * Use this to monitor progress after initiating the deletion process.
33 + *
34 + * [--yes]
35 + * : Skip the confirmation prompt and proceed with deletion immediately.
36 + * Use with extreme caution as this bypasses all safety checks.
37 + *
38 + * ## EXAMPLES
39 + *
40 + * # Start the self-destruct process (with confirmation prompt)
41 + * $ wp activitypub self_destruct
42 + *
43 + * # Check the status of an ongoing self-destruct process
44 + * $ wp activitypub self_destruct --status
45 + *
46 + * # Force deletion without confirmation (dangerous!)
47 + * $ wp activitypub self_destruct --yes
48 + *
49 + * ## WHAT THIS DOES
50 + *
51 + * - Finds all users with ActivityPub capabilities
52 + * - Creates Delete activities for each user
53 + * - Sends these activities to all followers
54 + * - Removes your blog from ActivityPub discovery
55 + * - Sets a flag to track completion status
56 + *
57 + * ## IMPORTANT NOTES
58 + *
59 + * - This action cannot be undone
60 + * - Keep the ActivityPub plugin active during the process
61 + * - The process may take several minutes to complete
62 + * - You will be notified when the process finishes
63 + *
64 + * @param array|null $args The positional arguments (unused).
65 + * @param array|null $assoc_args The associative arguments (--status, --yes).
66 + *
67 + * @return void
37 68 */
38 - public static function register() {
39 - // Register parent command with version subcommand.
40 - \WP_CLI::add_command(
41 - 'activitypub',
42 - '\Activitypub\Cli\Command',
69 + public function self_destruct( $args, $assoc_args = array() ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
70 + // Check if --status flag is provided.
71 + if ( isset( $assoc_args['status'] ) ) {
72 + $this->show_self_destruct_status();
73 + return;
74 + }
75 +
76 + // Check if self-destruct has already been run.
77 + if ( \get_option( 'activitypub_self_destruct' ) ) {
78 + \WP_CLI::error( 'Self-destruct has already been initiated. The process may still be running or has completed.' . PHP_EOL . \WP_CLI::colorize( 'To check the status, run: %Bwp activitypub self_destruct --status%n' ) );
79 + return;
80 + }
81 +
82 + $this->execute_self_destruct( $assoc_args );
83 + }
84 +
85 + /**
86 + * Execute the self-destruct process.
87 + *
88 + * This method handles the actual deletion process:
89 + * 1. Displays warning and confirmation prompt
90 + * 2. Retrieves all ActivityPub-capable users
91 + * 3. Creates and schedules Delete activities for each user
92 + * 4. Sets the self-destruct flag for status tracking
93 + * 5. Provides progress feedback and completion instructions
94 + *
95 + * @param array $assoc_args The associative arguments from WP-CLI.
96 + *
97 + * @return void
98 + */
99 + private function execute_self_destruct( $assoc_args ) {
100 + $this->display_self_destruct_warning();
101 + \WP_CLI::confirm( 'Are you absolutely sure you want to continue?', $assoc_args );
102 +
103 + $user_ids = $this->get_activitypub_users();
104 + if ( empty( $user_ids ) ) {
105 + \WP_CLI::warning( 'No ActivityPub users found. Nothing to delete.' );
106 + return;
107 + }
108 +
109 + $processed = $this->process_user_deletions( $user_ids );
110 + $this->display_completion_message( $processed );
111 + }
112 +
113 + /**
114 + * Display the self-destruct warning message.
115 + *
116 + * @return void
117 + */
118 + private function display_self_destruct_warning() {
119 + \WP_CLI::line( \WP_CLI::colorize( '%R⚠️ DESTRUCTIVE OPERATION ⚠️%n' ) );
120 + \WP_CLI::line( '' );
121 +
122 + $question = 'You are about to delete your blog from the Fediverse. This action is IRREVERSIBLE and will:';
123 + \WP_CLI::line( \WP_CLI::colorize( "%y{$question}%n" ) );
124 + \WP_CLI::line( \WP_CLI::colorize( '%y• Send Delete activities to all followers%n' ) );
125 + \WP_CLI::line( \WP_CLI::colorize( '%y• Remove your blog from ActivityPub networks%n' ) );
126 + \WP_CLI::line( '' );
127 + }
128 +
129 + /**
130 + * Get all users with ActivityPub capabilities.
131 + *
132 + * @return array Array of user IDs with ActivityPub capabilities.
133 + */
134 + private function get_activitypub_users() {
135 + return \get_users(
43 136 array(
44 - 'shortdesc' => 'Manage ActivityPub plugin functionality and federation.',
137 + 'fields' => 'ID',
138 + 'capability__in' => array( 'activitypub' ),
45 139 )
46 140 );
141 + }
47 142
48 - \WP_CLI::add_command(
49 - 'activitypub post',
50 - '\Activitypub\Cli\Post_Command',
143 + /**
144 + * Process user deletions and create Delete activities.
145 + *
146 + * @param array $user_ids Array of user IDs to process.
147 + *
148 + * @return int Number of users successfully processed.
149 + */
150 + private function process_user_deletions( $user_ids ) {
151 + $user_count = \count( $user_ids );
152 + \WP_CLI::line( \WP_CLI::colorize( '%GStarting Fediverse deletion process...%n' ) );
153 + \WP_CLI::line( \WP_CLI::colorize( "%BFound {$user_count} ActivityPub user(s) to process:%n" ) );
154 + \WP_CLI::line( '' );
155 +
156 + // Set the self-destruct flag.
157 + \update_option( 'activitypub_self_destruct', true );
158 +
159 + $processed = 0;
160 + foreach ( $user_ids as $user_id ) {
161 + if ( $this->create_delete_activity_for_user( $user_id, $processed, $user_count ) ) {
162 + ++$processed;
163 + }
164 + }
165 +
166 + \WP_CLI::line( '' );
167 +
168 + if ( 0 === $processed ) {
169 + \WP_CLI::error( 'Failed to schedule any deletions. Please check your configuration.' );
170 + }
171 +
172 + return $processed;
173 + }
174 +
175 + /**
176 + * Create a Delete activity for a specific user.
177 + *
178 + * @param int $user_id The user ID to process.
179 + * @param int $processed Number of users already processed.
180 + * @param int $user_count Total number of users to process.
181 + *
182 + * @return bool True if the activity was created successfully, false otherwise.
183 + */
184 + private function create_delete_activity_for_user( $user_id, $processed, $user_count ) {
185 + $actor = Actors::get_by_id( $user_id );
186 +
187 + if ( ! $actor ) {
188 + \WP_CLI::line( \WP_CLI::colorize( "%R✗ Failed to load user ID: {$user_id}%n" ) );
189 + return false;
190 + }
191 +
192 + $activity = new Activity();
193 + $activity->set_actor( $actor->get_id() );
194 + $activity->set_object( $actor->get_id() );
195 + $activity->set_type( 'Delete' );
196 +
197 + $result = add_to_outbox( $activity, null, $user_id );
198 + if ( is_wp_error( $result ) ) {
199 + \WP_CLI::line( \WP_CLI::colorize( "%R✗ Failed to schedule deletion for: %B{$actor->get_name()}%n - {$result->get_error_message()}" ) );
200 + return false;
201 + }
202 +
203 + $current = $processed + 1;
204 + \WP_CLI::line( \WP_CLI::colorize( "%G✓%n [{$current}/{$user_count}] Scheduled deletion for: %B{$actor->get_name()}%n" ) );
205 + return true;
206 + }
207 +
208 + /**
209 + * Display the completion message after processing.
210 + *
211 + * @param int $processed Number of users successfully processed.
212 + *
213 + * @return void
214 + */
215 + private function display_completion_message( $processed ) {
216 + if ( 0 === $processed ) {
217 + return; // Error already displayed in process_user_deletions.
218 + }
219 +
220 + \WP_CLI::success( "Successfully scheduled {$processed} user(s) for Fediverse deletion." );
221 + \WP_CLI::line( '' );
222 + \WP_CLI::line( \WP_CLI::colorize( '%Y📋 Next Steps:%n' ) );
223 + \WP_CLI::line( \WP_CLI::colorize( '%Y• Keep the ActivityPub plugin active%n' ) );
224 + \WP_CLI::line( \WP_CLI::colorize( '%Y• Delete activities will be sent automatically%n' ) );
225 + \WP_CLI::line( \WP_CLI::colorize( '%Y• Process may take several minutes to complete%n' ) );
226 + \WP_CLI::line( \WP_CLI::colorize( '%Y• The plugin will notify you when the process is done.%n' ) );
227 + \WP_CLI::line( '' );
228 + }
229 +
230 + /**
231 + * Show the status of the self-destruct process.
232 + *
233 + * Checks the current state of the self-destruct process by:
234 + * - Verifying if the process has been initiated
235 + * - Counting remaining pending Delete activities
236 + * - Displaying appropriate status messages and progress
237 + * - Providing guidance on next steps
238 + *
239 + * Status can be:
240 + * - NOT STARTED: Process hasn't been initiated
241 + * - IN PROGRESS: Delete activities are still being processed
242 + * - COMPLETED: All Delete activities have been sent
243 + *
244 + * @return void
245 + */
246 + private function show_self_destruct_status() {
247 + // Only proceed if self-destruct is active.
248 + if ( ! \get_option( 'activitypub_self_destruct', false ) ) {
249 + \WP_CLI::line( \WP_CLI::colorize( '%C❌ Status: NOT STARTED%n' ) );
250 + \WP_CLI::line( \WP_CLI::colorize( '%CThe self-destruct process has not been initiated.%n' ) );
251 + \WP_CLI::line( '' );
252 + \WP_CLI::line( \WP_CLI::colorize( '%CTo start the process, run:%n %Bwp activitypub self_destruct%n' ) );
253 + \WP_CLI::line( '' );
254 + return;
255 + }
256 +
257 + \WP_CLI::line( \WP_CLI::colorize( '%B🔍 Self-Destruct Status Check%n' ) );
258 + \WP_CLI::line( '' );
259 +
260 + // Check if there are any more pending Delete activities for self-destruct.
261 + $pending_deletes = \get_posts(
51 262 array(
52 - 'shortdesc' => 'Manage ActivityPub posts (delete or update).',
263 + 'post_type' => Outbox::POST_TYPE,
264 + 'post_status' => 'pending',
265 + 'posts_per_page' => -1,
266 + 'fields' => 'ids',
267 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
268 + 'meta_query' => array(
269 + array(
270 + 'key' => '_activitypub_activity_type',
271 + 'value' => 'Delete',
272 + ),
273 + ),
53 274 )
54 275 );
55 276
56 - \WP_CLI::add_command(
57 - 'activitypub comment',
58 - '\Activitypub\Cli\Comment_Command',
59 - array(
60 - 'shortdesc' => 'Manage ActivityPub comments (delete or update).',
61 - )
62 - );
277 + // Get count of pending Delete activities.
278 + $pending_count = count( $pending_deletes );
63 279
64 - \WP_CLI::add_command(
65 - 'activitypub actor',
66 - '\Activitypub\Cli\Actor_Command',
67 - array(
68 - 'shortdesc' => 'Manage ActivityPub actors (delete or update).',
69 - )
70 - );
280 + // If no more pending Delete activities, self-destruct is complete.
281 + if ( 0 === $pending_count ) {
282 + \WP_CLI::line( \WP_CLI::colorize( '%G✅ Status: COMPLETED%n' ) );
283 + \WP_CLI::line( \WP_CLI::colorize( '%GYour blog has been successfully removed from the Fediverse.%n' ) );
284 + \WP_CLI::line( '' );
285 + \WP_CLI::line( \WP_CLI::colorize( '%Y📋 What happened:%n' ) );
286 + \WP_CLI::line( \WP_CLI::colorize( '%Y• Delete activities were sent to all followers%n' ) );
287 + \WP_CLI::line( \WP_CLI::colorize( '%Y• Your blog is no longer discoverable on ActivityPub networks%n' ) );
288 + \WP_CLI::line( \WP_CLI::colorize( '%Y• The self-destruct process has finished%n' ) );
289 + } else {
290 + \WP_CLI::line( \WP_CLI::colorize( '%Y⏳ Status: IN PROGRESS%n' ) );
291 + \WP_CLI::line( \WP_CLI::colorize( '%YThe self-destruct process is currently running.%n' ) );
292 + \WP_CLI::line( '' );
71 293
72 - \WP_CLI::add_command(
73 - 'activitypub outbox',
74 - '\Activitypub\Cli\Outbox_Command',
75 - array(
76 - 'shortdesc' => 'Manage ActivityPub outbox items (undo or reschedule).',
77 - )
78 - );
294 + \WP_CLI::line( \WP_CLI::colorize( "%YProgress: {$pending_count} Delete Activities still pending%n" ) );
79 295
80 - \WP_CLI::add_command(
81 - 'activitypub self-destruct',
82 - '\Activitypub\Cli\Self_Destruct_Command',
83 - array(
84 - 'shortdesc' => 'Remove the entire blog from the Fediverse.',
85 - )
86 - );
296 + \WP_CLI::line( '' );
297 + \WP_CLI::line( \WP_CLI::colorize( '%YNote: The process may take several minutes to complete.%n' ) );
298 + }
87 299
88 - \WP_CLI::add_command(
89 - 'activitypub move',
90 - '\Activitypub\Cli\Move_Command',
91 - array(
92 - 'shortdesc' => 'Move the blog to a new URL.',
93 - )
94 - );
300 + \WP_CLI::line( '' );
301 + }
95 302
96 - \WP_CLI::add_command(
97 - 'activitypub follow',
98 - '\Activitypub\Cli\Follow_Command',
99 - array(
100 - 'shortdesc' => 'Follow a remote ActivityPub user.',
101 - )
102 - );
303 + /**
304 + * Delete or Update a Post, Page, Custom Post Type or Attachment.
305 + *
306 + * ## OPTIONS
307 + *
308 + * <action>
309 + * : The action to perform. Either `delete` or `update`.
310 + * ---
311 + * options:
312 + * - delete
313 + * - update
314 + * ---
315 + *
316 + * <id>
317 + * : The id of the Post, Page, Custom Post Type or Attachment.
318 + *
319 + * ## EXAMPLES
320 + *
321 + * $ wp activitypub post delete 1
322 + *
323 + * @synopsis <action> <id>
324 + *
325 + * @param array $args The arguments.
326 + */
327 + public function post( $args ) {
328 + $post = get_post( $args[1] );
103 329
104 - \WP_CLI::add_command(
105 - 'activitypub cache',
106 - '\Activitypub\Cli\Cache_Command',
107 - array(
108 - 'shortdesc' => 'Manage remote media cache (clear or show status).',
109 - )
110 - );
330 + if ( ! $post ) {
331 + \WP_CLI::error( 'Post not found.' );
332 + }
111 333
112 - \WP_CLI::add_command(
113 - 'activitypub fetch',
114 - '\Activitypub\Cli\Fetch_Command',
115 - array(
116 - 'shortdesc' => 'Fetch a remote URL with a signed ActivityPub request.',
117 - )
118 - );
334 + switch ( $args[0] ) {
335 + case 'delete':
336 + \WP_CLI::confirm( 'Do you really want to delete the (Custom) Post with the ID: ' . $args[1] );
337 + add_to_outbox( $post, 'Delete', $post->post_author );
338 + \WP_CLI::success( '"Delete" activity is queued.' );
339 + break;
340 + case 'update':
341 + add_to_outbox( $post, 'Update', $post->post_author );
342 + \WP_CLI::success( '"Update" activity is queued.' );
343 + break;
344 + default:
345 + \WP_CLI::error( 'Unknown action.' );
346 + }
347 + }
119 348
120 - \WP_CLI::add_command(
121 - 'activitypub stats',
122 - '\Activitypub\Cli\Stats_Command',
123 - array(
124 - 'shortdesc' => 'Manage ActivityPub statistics (collect, compile or send).',
125 - )
126 - );
349 + /**
350 + * Delete or Update a Comment.
351 + *
352 + * ## OPTIONS
353 + *
354 + * <action>
355 + * : The action to perform. Either `delete` or `update`.
356 + * ---
357 + * options:
358 + * - delete
359 + * - update
360 + * ---
361 + *
362 + * <id>
363 + * : The id of the Comment.
364 + *
365 + * ## EXAMPLES
366 + *
367 + * $ wp activitypub comment delete 1
368 + *
369 + * @synopsis <action> <id>
370 + *
371 + * @param array $args The arguments.
372 + */
373 + public function comment( $args ) {
374 + $comment = get_comment( $args[1] );
127 375
128 - \WP_CLI::add_command(
129 - 'activitypub blurhash',
130 - '\Activitypub\Cli\Blurhash_Command',
131 - array(
132 - 'shortdesc' => 'Backfill Blurhash placeholders for image attachments.',
133 - )
134 - );
376 + if ( ! $comment ) {
377 + \WP_CLI::error( 'Comment not found.' );
378 + }
379 +
380 + if ( was_comment_received( $comment ) ) {
381 + \WP_CLI::error( 'This comment was received via ActivityPub and cannot be deleted or updated.' );
382 + }
383 +
384 + switch ( $args[0] ) {
385 + case 'delete':
386 + \WP_CLI::confirm( 'Do you really want to delete the Comment with the ID: ' . $args[1] );
387 + add_to_outbox( $comment, 'Delete', $comment->user_id );
388 + \WP_CLI::success( '"Delete" activity is queued.' );
389 + break;
390 + case 'update':
391 + add_to_outbox( $comment, 'Update', $comment->user_id );
392 + \WP_CLI::success( '"Update" activity is queued.' );
393 + break;
394 + default:
395 + \WP_CLI::error( 'Unknown action.' );
396 + }
397 + }
398 +
399 + /**
400 + * Delete or Update an Actor.
401 + *
402 + * ## OPTIONS
403 + *
404 + * <action>
405 + * : The action to perform. Either `delete` or `update`.
406 + * ---
407 + * options:
408 + * - delete
409 + * - update
410 + * ---
411 + *
412 + * <id>
413 + * : The id of the Actor.
414 + *
415 + * ## EXAMPLES
416 + *
417 + * $ wp activitypub actor delete 1
418 + *
419 + * @synopsis <action> <id>
420 + *
421 + * @param array $args The arguments.
422 + */
423 + public function actor( $args ) {
424 + if ( Actors::APPLICATION_USER_ID === (int) $args[1] ) {
425 + \WP_CLI::error( 'You cannot delete the application actor.' );
426 + }
427 +
428 + switch ( $args[0] ) {
429 + case 'delete':
430 + \add_filter( 'activitypub_user_can_activitypub', '__return_true' );
431 + Actor::schedule_user_delete( $args[1] );
432 + \remove_filter( 'activitypub_user_can_activitypub', '__return_true' );
433 + \WP_CLI::success( '"Delete" activity is queued.' );
434 + break;
435 + case 'update':
436 + Actor::schedule_profile_update( $args[1] );
437 + \WP_CLI::success( '"Update" activity is queued.' );
438 + break;
439 + default:
440 + \WP_CLI::error( 'Unknown action.' );
441 + }
442 + }
443 +
444 + /**
445 + * Undo an activity that was sent to the Fediverse.
446 + *
447 + * ## OPTIONS
448 + *
449 + * <outbox_item_id>
450 + * The ID or URL of the outbox item to undo.
451 + *
452 + * ## EXAMPLES
453 + *
454 + * $ wp activitypub undo 123
455 + * $ wp activitypub undo "https://example.com/?post_type=ap_outbox&p=123"
456 + *
457 + * @synopsis <outbox_item_id>
458 + *
459 + * @param array $args The arguments.
460 + */
461 + public function undo( $args ) {
462 + $outbox_item_id = $args[0];
463 + if ( ! is_numeric( $outbox_item_id ) ) {
464 + $outbox_item_id = url_to_postid( $outbox_item_id );
465 + }
466 +
467 + $outbox_item_id = get_post( $outbox_item_id );
468 + if ( ! $outbox_item_id ) {
469 + \WP_CLI::error( 'Activity not found.' );
470 + }
471 +
472 + $undo_id = Outbox::undo( $outbox_item_id );
473 + if ( ! $undo_id ) {
474 + \WP_CLI::error( 'Failed to undo activity.' );
475 + }
476 + \WP_CLI::success( 'Undo activity scheduled.' );
477 + }
478 +
479 + /**
480 + * Re-Schedule an activity that was sent to the Fediverse before.
481 + *
482 + * ## OPTIONS
483 + *
484 + * <outbox_item_id>
485 + * The ID or URL of the outbox item to reschedule.
486 + *
487 + * ## EXAMPLES
488 + *
489 + * $ wp activitypub reschedule 123
490 + * $ wp activitypub reschedule "https://example.com/?post_type=ap_outbox&p=123"
491 + *
492 + * @synopsis <outbox_item_id>
493 + *
494 + * @param array $args The arguments.
495 + */
496 + public function reschedule( $args ) {
497 + $outbox_item_id = $args[0];
498 + if ( ! is_numeric( $outbox_item_id ) ) {
499 + $outbox_item_id = url_to_postid( $outbox_item_id );
500 + }
501 +
502 + $outbox_item_id = get_post( $outbox_item_id );
503 + if ( ! $outbox_item_id ) {
504 + \WP_CLI::error( 'Activity not found.' );
505 + }
506 +
507 + Outbox::reschedule( $outbox_item_id );
508 +
509 + \WP_CLI::success( 'Rescheduled activity.' );
510 + }
511 +
512 + /**
513 + * Move the blog to a new URL.
514 + *
515 + * ## OPTIONS
516 + *
517 + * <from>
518 + * The current URL of the blog.
519 + *
520 + * <to>
521 + * The new URL of the blog.
522 + *
523 + * ## EXAMPLES
524 + *
525 + * $ wp activitypub move https://example.com/ https://newsite.com/
526 + *
527 + * @synopsis <from> <to>
528 + *
529 + * @param array $args The arguments.
530 + */
531 + public function move( $args ) {
532 + $from = $args[0];
533 + $to = $args[1];
534 +
535 + $outbox_item_id = Move::account( $from, $to );
536 +
537 + if ( is_wp_error( $outbox_item_id ) ) {
538 + \WP_CLI::error( $outbox_item_id->get_error_message() );
539 + } else {
540 + \WP_CLI::success( 'Move Scheduled.' );
541 + }
542 + }
543 +
544 + /**
545 + * Follow a user.
546 + *
547 + * ## OPTIONS
548 + *
549 + * <remote-user>
550 + * The remote user to follow.
551 + *
552 + * ## EXAMPLES
553 + *
554 + * $ wp activitypub follow https://example.com/@user
555 + * $ wp --user=pfefferle activitypub follow https://example.com/@user
556 + *
557 + * @synopsis <remote_user>
558 + *
559 + * @param array $args The arguments.
560 + */
561 + public function follow( $args ) {
562 + $user_id = \get_current_user_id();
563 + $follow = follow( $args[0], $user_id );
564 +
565 + if ( is_wp_error( $follow ) ) {
566 + \WP_CLI::error( $follow->get_error_message() );
567 + } else {
568 + \WP_CLI::success( 'Follow Scheduled.' );
569 + }
135 570 }
136 571 }