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