PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 4.5.3
Jetpack – WP Security, Backup, Speed, & Growth v4.5.3
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / class.jetpack-cli.php

class.jetpack-cli.php in Jetpack – WP Security, Backup, Speed, & Growth 4.5.3, at class.jetpack-cli.php

782 lines 26.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 WP_CLI::add_command( 'jetpack', 'Jetpack_CLI' );
4
5 /**
6 * Control your local Jetpack installation.
7 */
8 class Jetpack_CLI extends WP_CLI_Command {
9
10 // Aesthetics
11 public $green_open = "\033[32m";
12 public $red_open = "\033[31m";
13 public $yellow_open = "\033[33m";
14 public $color_close = "\033[0m";
15
16 /**
17 * Get Jetpack Details
18 *
19 * ## OPTIONS
20 *
21 * empty: Leave it empty for basic stats
22 *
23 * full: View full stats. It's the data from the heartbeat
24 *
25 * ## EXAMPLES
26 *
27 * wp jetpack status
28 * wp jetpack status full
29 *
30 */
31 public function status( $args, $assoc_args ) {
32 if ( ! Jetpack::is_active() ) {
33 WP_CLI::error( __( 'Jetpack is not currently connected to WordPress.com', 'jetpack' ) );
34 }
35
36 if ( isset( $args[0] ) && 'full' !== $args[0] ) {
37 WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $args[0] ) );
38 }
39
40 /*
41 * Are they asking for all data?
42 *
43 * Loop through heartbeat data and organize by priority.
44 */
45 $all_data = ( isset( $args[0] ) && 'full' == $args[0] ) ? 'full' : false;
46 if ( $all_data ) {
47 WP_CLI::success( __( 'Jetpack is currently connected to WordPress.com', 'jetpack' ) );
48 WP_CLI::line( sprintf( __( "The Jetpack Version is %s", 'jetpack' ), JETPACK__VERSION ) );
49 WP_CLI::line( sprintf( __( "The WordPress.com blog_id is %d", 'jetpack' ), Jetpack_Options::get_option( 'id' ) ) );
50
51 // Heartbeat data
52 WP_CLI::line( "\n" . __( 'Additional data: ', 'jetpack' ) );
53
54 // Get the filtered heartbeat data.
55 // Filtered so we can color/list by severity
56 $stats = Jetpack::jetpack_check_heartbeat_data();
57
58 // Display red flags first
59 foreach ( $stats['bad'] as $stat => $value ) {
60 printf( "$this->red_open%-'.16s %s $this->color_close\n", $stat, $value );
61 }
62
63 // Display caution warnings next
64 foreach ( $stats['caution'] as $stat => $value ) {
65 printf( "$this->yellow_open%-'.16s %s $this->color_close\n", $stat, $value );
66 }
67
68 // The rest of the results are good!
69 foreach ( $stats['good'] as $stat => $value ) {
70
71 // Modules should get special spacing for aestetics
72 if ( strpos( $stat, 'odule-' ) ) {
73 printf( "%-'.30s %s\n", $stat, $value );
74 usleep( 4000 ); // For dramatic effect lolz
75 continue;
76 }
77 printf( "%-'.16s %s\n", $stat, $value );
78 usleep( 4000 ); // For dramatic effect lolz
79 }
80 } else {
81 // Just the basics
82 WP_CLI::success( __( 'Jetpack is currently connected to WordPress.com', 'jetpack' ) );
83 WP_CLI::line( sprintf( __( 'The Jetpack Version is %s', 'jetpack' ), JETPACK__VERSION ) );
84 WP_CLI::line( sprintf( __( 'The WordPress.com blog_id is %d', 'jetpack' ), Jetpack_Options::get_option( 'id' ) ) );
85 WP_CLI::line( "\n" . _x( "View full status with 'wp jetpack status full'", '"wp jetpack status full" is a command - do not translate', 'jetpack' ) );
86 }
87 }
88
89 /**
90 * Disconnect Jetpack Blogs or Users
91 *
92 * ## OPTIONS
93 *
94 * blog: Disconnect the entire blog.
95 *
96 * user <user_identifier>: Disconnect a specific user from WordPress.com.
97 *
98 * Please note, the primary account that the blog is connected
99 * to WordPress.com with cannot be disconnected without
100 * disconnecting the entire blog.
101 *
102 * ## EXAMPLES
103 *
104 * wp jetpack disconnect blog
105 * wp jetpack disconnect user 13
106 * wp jetpack disconnect user username
107 * wp jetpack disconnect user email@domain.com
108 *
109 * @synopsis <blog|user> [<user_identifier>]
110 */
111 public function disconnect( $args, $assoc_args ) {
112 if ( ! Jetpack::is_active() ) {
113 WP_CLI::error( __( 'You cannot disconnect, without having first connected.', 'jetpack' ) );
114 }
115
116 $action = isset( $args[0] ) ? $args[0] : 'prompt';
117 if ( ! in_array( $action, array( 'blog', 'user', 'prompt' ) ) ) {
118 WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
119 }
120
121 if ( in_array( $action, array( 'user' ) ) ) {
122 if ( isset( $args[1] ) ) {
123 $user_id = $args[1];
124 if ( ctype_digit( $user_id ) ) {
125 $field = 'id';
126 $user_id = (int) $user_id;
127 } elseif ( is_email( $user_id ) ) {
128 $field = 'email';
129 $user_id = sanitize_user( $user_id, true );
130 } else {
131 $field = 'login';
132 $user_id = sanitize_user( $user_id, true );
133 }
134 if ( ! $user = get_user_by( $field, $user_id ) ) {
135 WP_CLI::error( __( 'Please specify a valid user.', 'jetpack' ) );
136 }
137 } else {
138 WP_CLI::error( __( 'Please specify a user by either ID, username, or email.', 'jetpack' ) );
139 }
140 }
141
142 switch ( $action ) {
143 case 'blog':
144 Jetpack::log( 'disconnect' );
145 Jetpack::disconnect();
146 WP_CLI::success( __( 'Jetpack has been successfully disconnected.', 'jetpack' ) );
147 break;
148 case 'user':
149 if ( Jetpack::unlink_user( $user->ID ) ) {
150 Jetpack::log( 'unlink', $user->ID );
151 WP_CLI::success( sprintf( __( '%s has been successfully disconnected.', 'jetpack' ), $action ) );
152 } else {
153 WP_CLI::error( sprintf( __( '%s could not be disconnected. Are you sure they\'re connected currently?', 'jetpack' ), "{$user->login} <{$user->email}>" ) );
154 }
155 break;
156 case 'prompt':
157 WP_CLI::error( __( 'Please specify if you would like to disconnect a blog or user.', 'jetpack' ) );
158 break;
159 }
160 }
161
162 /**
163 * Reset Jetpack options and settings to default
164 *
165 * ## OPTIONS
166 *
167 * modules: Resets modules to default state ( get_default_modules() )
168 *
169 * options: Resets all Jetpack options except:
170 * - All private options (Blog token, user token, etc...)
171 * - id (The Client ID/WP.com Blog ID of this site)
172 * - master_user
173 * - version
174 * - activated
175 *
176 * ## EXAMPLES
177 *
178 * wp jetpack reset options
179 * wp jetpack reset modules
180 *
181 * @synopsis <modules|options>
182 */
183 public function reset( $args, $assoc_args ) {
184 $action = isset( $args[0] ) ? $args[0] : 'prompt';
185 if ( ! in_array( $action, array( 'options', 'modules' ) ) ) {
186 WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
187 }
188
189 // Are you sure?
190 jetpack_cli_are_you_sure();
191
192 switch ( $action ) {
193 case 'options':
194 $options_to_reset = Jetpack::get_jetpack_options_for_reset();
195
196 // Reset the Jetpack options
197 _e( "Resetting Jetpack Options...\n", "jetpack" );
198 sleep(1); // Take a breath
199 foreach ( $options_to_reset['jp_options'] as $option_to_reset ) {
200 Jetpack_Options::delete_option( $option_to_reset );
201 usleep( 100000 );
202 WP_CLI::success( sprintf( __( '%s option reset', 'jetpack' ), $option_to_reset ) );
203 }
204
205 // Reset the WP options
206 _e( "Resetting the jetpack options stored in wp_options...\n", "jetpack" );
207 usleep( 500000 ); // Take a breath
208 foreach ( $options_to_reset['wp_options'] as $option_to_reset ) {
209 delete_option( $option_to_reset );
210 usleep( 100000 );
211 WP_CLI::success( sprintf( __( '%s option reset', 'jetpack' ), $option_to_reset ) );
212 }
213
214 // Reset to default modules
215 _e( "Resetting default modules...\n", "jetpack" );
216 usleep( 500000 ); // Take a breath
217 $default_modules = Jetpack::get_default_modules();
218 Jetpack::update_active_modules( $default_modules );
219 WP_CLI::success( __( 'Modules reset to default.', 'jetpack' ) );
220
221 // Jumpstart option is special
222 Jetpack_Options::update_option( 'jumpstart', 'new_connection' );
223 WP_CLI::success( __( 'jumpstart option reset', 'jetpack' ) );
224 break;
225 case 'modules':
226 $default_modules = Jetpack::get_default_modules();
227 Jetpack::update_active_modules( $default_modules );
228 WP_CLI::success( __( 'Modules reset to default.', 'jetpack' ) );
229 break;
230 case 'prompt':
231 WP_CLI::error( __( 'Please specify if you would like to reset your options, or modules', 'jetpack' ) );
232 break;
233 }
234 }
235
236 /**
237 * Manage Jetpack Modules
238 *
239 * ## OPTIONS
240 *
241 * list : View all available modules, and their status.
242 * activate all : Activate all modules
243 * deactivate all: Deactivate all modules
244 *
245 * activate <module_slug> : Activate a module.
246 * deactivate <module_slug> : Deactivate a module.
247 * toggle <module_slug> : Toggle a module on or off.
248 *
249 * ## EXAMPLES
250 *
251 * wp jetpack module list
252 * wp jetpack module activate stats
253 * wp jetpack module deactivate stats
254 * wp jetpack module toggle stats
255 *
256 * wp jetpack module activate all
257 * wp jetpack module deactivate all
258 *
259 * @synopsis <list|activate|deactivate|toggle> [<module_name>]
260 */
261 public function module( $args, $assoc_args ) {
262 $action = isset( $args[0] ) ? $args[0] : 'list';
263 if ( ! in_array( $action, array( 'list', 'activate', 'deactivate', 'toggle' ) ) ) {
264 WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
265 }
266 if ( in_array( $action, array( 'activate', 'deactivate', 'toggle' ) ) ) {
267 if ( isset( $args[1] ) ) {
268 $module_slug = $args[1];
269 if ( 'all' !== $module_slug && ! Jetpack::is_module( $module_slug ) ) {
270 WP_CLI::error( sprintf( __( '%s is not a valid module.', 'jetpack' ), $module_slug ) );
271 }
272 if ( 'toggle' == $action ) {
273 $action = Jetpack::is_module_active( $module_slug ) ? 'deactivate' : 'activate';
274 }
275 // Bulk actions
276 if ( 'all' == $args[1] ) {
277 $action = ( 'deactivate' == $action ) ? 'deactivate_all' : 'activate_all';
278 }
279 // VaultPress needs to be handled elsewhere.
280 if ( in_array( $action, array( 'activate', 'deactivate', 'toggle' ) ) && 'vaultpress' == $args[1] ) {
281 WP_CLI::error( sprintf( _x( 'Please visit %s to configure your VaultPress subscription.', '%s is a website', 'jetpack' ), esc_url( 'https://vaultpress.com/jetpack/' ) ) );
282 }
283 } else {
284 WP_CLI::line( __( 'Please specify a valid module.', 'jetpack' ) );
285 $action = 'list';
286 }
287 }
288 switch ( $action ) {
289 case 'list':
290 WP_CLI::line( __( 'Available Modules:', 'jetpack' ) );
291 $modules = Jetpack::get_available_modules();
292 sort( $modules );
293 foreach( $modules as $module_slug ) {
294 if ( 'vaultpress' == $module_slug ) {
295 continue;
296 }
297 $active = Jetpack::is_module_active( $module_slug ) ? __( 'Active', 'jetpack' ) : __( 'Inactive', 'jetpack' );
298 WP_CLI::line( "\t" . str_pad( $module_slug, 24 ) . $active );
299 }
300 break;
301 case 'activate':
302 $module = Jetpack::get_module( $module_slug );
303 Jetpack::log( 'activate', $module_slug );
304 Jetpack::activate_module( $module_slug, false, false );
305 WP_CLI::success( sprintf( __( '%s has been activated.', 'jetpack' ), $module['name'] ) );
306 break;
307 case 'activate_all':
308 $modules = Jetpack::get_available_modules();
309 Jetpack::update_active_modules( $modules );
310 WP_CLI::success( __( 'All modules activated!', 'jetpack' ) );
311 break;
312 case 'deactivate':
313 $module = Jetpack::get_module( $module_slug );
314 Jetpack::log( 'deactivate', $module_slug );
315 Jetpack::deactivate_module( $module_slug );
316 WP_CLI::success( sprintf( __( '%s has been deactivated.', 'jetpack' ), $module['name'] ) );
317 break;
318 case 'deactivate_all':
319 Jetpack::delete_active_modules();
320 WP_CLI::success( __( 'All modules deactivated!', 'jetpack' ) );
321 break;
322 case 'toggle':
323 // Will never happen, should have been handled above and changed to activate or deactivate.
324 break;
325 }
326 }
327
328 /**
329 * Manage Protect Settings
330 *
331 * ## OPTIONS
332 *
333 * whitelist: Whitelist an IP address. You can also read or clear the whitelist.
334 *
335 *
336 * ## EXAMPLES
337 *
338 * wp jetpack protect whitelist <ip address>
339 * wp jetpack protect whitelist list
340 * wp jetpack protect whitelist clear
341 *
342 * @synopsis <whitelist> [<ip|ip_low-ip_high|list|clear>]
343 */
344 public function protect( $args, $assoc_args ) {
345 $action = isset( $args[0] ) ? $args[0] : 'prompt';
346 if ( ! in_array( $action, array( 'whitelist' ) ) ) {
347 WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
348 }
349 // Check if module is active
350 if ( ! Jetpack::is_module_active( __FUNCTION__ ) ) {
351 WP_CLI::error( sprintf( _x( '%s is not active. You can activate it with "wp jetpack module activate %s"', '"wp jetpack module activate" is a command - do not translate', 'jetpack' ), __FUNCTION__, __FUNCTION__ ) );
352 }
353 if ( in_array( $action, array( 'whitelist' ) ) ) {
354 if ( isset( $args[1] ) ) {
355 $action = 'whitelist';
356 } else {
357 $action = 'prompt';
358 }
359 }
360 switch ( $action ) {
361 case 'whitelist':
362 $whitelist = array();
363 $new_ip = $args[1];
364 $current_whitelist = get_site_option( 'jetpack_protect_whitelist' );
365
366 // Build array of IPs that are already whitelisted.
367 // Re-build manually instead of using jetpack_protect_format_whitelist() so we can easily get
368 // low & high range params for jetpack_protect_ip_address_is_in_range();
369 foreach( $current_whitelist as $whitelisted ) {
370
371 // IP ranges
372 if ( $whitelisted->range ) {
373
374 // Is it already whitelisted?
375 if ( jetpack_protect_ip_address_is_in_range( $new_ip, $whitelisted->range_low, $whitelisted->range_high ) ) {
376 WP_CLI::error( sprintf( __( "%s has already been whitelisted", 'jetpack' ), $new_ip ) );
377 break;
378 }
379 $whitelist[] = $whitelisted->range_low . " - " . $whitelisted->range_high;
380
381 } else { // Individual IPs
382
383 // Check if the IP is already whitelisted (single IP only)
384 if ( $new_ip == $whitelisted->ip_address ) {
385 WP_CLI::error( sprintf( __( "%s has already been whitelisted", 'jetpack' ), $new_ip ) );
386 break;
387 }
388 $whitelist[] = $whitelisted->ip_address;
389
390 }
391 }
392
393 /*
394 * List the whitelist
395 * Done here because it's easier to read the $whitelist array after it's been rebuilt
396 */
397 if ( isset( $args[1] ) && 'list' == $args[1] ) {
398 if ( ! empty( $whitelist ) ) {
399 WP_CLI::success( __( 'Here are your whitelisted IPs:', 'jetpack' ) );
400 foreach ( $whitelist as $ip ) {
401 WP_CLI::line( "\t" . str_pad( $ip, 24 ) ) ;
402 }
403 } else {
404 WP_CLI::line( __( 'Whitelist is empty.', "jetpack" ) ) ;
405 }
406 break;
407 }
408
409 /*
410 * Clear the whitelist
411 */
412 if ( isset( $args[1] ) && 'clear' == $args[1] ) {
413 if ( ! empty( $whitelist ) ) {
414 $whitelist = array();
415 jetpack_protect_save_whitelist( $whitelist );
416 WP_CLI::success( __( 'Cleared all whitelisted IPs', 'jetpack' ) );
417 } else {
418 WP_CLI::line( __( 'Whitelist is empty.', "jetpack" ) ) ;
419 }
420 break;
421 }
422
423 // Append new IP to whitelist array
424 array_push( $whitelist, $new_ip );
425
426 // Save whitelist if there are no errors
427 $result = jetpack_protect_save_whitelist( $whitelist );
428 if ( is_wp_error( $result ) ) {
429 WP_CLI::error( __( $result, 'jetpack' ) );
430 }
431
432 WP_CLI::success( sprintf( __( '%s has been whitelisted.', 'jetpack' ), $new_ip ) );
433 break;
434 case 'prompt':
435 WP_CLI::error(
436 __( 'No command found.', 'jetpack' ) . "\n" .
437 __( 'Please enter the IP address you want to whitelist.', 'jetpack' ) . "\n" .
438 _x( 'You can save a range of IPs {low_range}-{high_range}. No spaces allowed. (example: 1.1.1.1-2.2.2.2)', 'Instructions on how to whitelist IP ranges - low_range/high_range should be translated.', 'jetpack' ) . "\n" .
439 _x( "You can also 'list' or 'clear' the whitelist.", "'list' and 'clear' are commands and should not be translated", 'jetpack' ) . "\n"
440 );
441 break;
442 }
443 }
444
445 /**
446 * Manage Jetpack Options
447 *
448 * ## OPTIONS
449 *
450 * list : List all jetpack options and their values
451 * delete : Delete an option
452 * - can only delete options that are white listed.
453 * update : update an option
454 * - can only update option strings
455 * get : get the value of an option
456 *
457 * ## EXAMPLES
458 *
459 * wp jetpack options list
460 * wp jetpack options get <option_name>
461 * wp jetpack options delete <option_name>
462 * wp jetpack options update <option_name> [<option_value>]
463 *
464 * @synopsis <list|get|delete|update> [<option_name>] [<option_value>]
465 */
466 public function options( $args, $assoc_args ) {
467 $action = isset( $args[0] ) ? $args[0] : 'list';
468 $safe_to_modify = Jetpack::get_jetpack_options_for_reset();
469
470 // Jumpstart is special
471 array_push( $safe_to_modify, 'jumpstart' );
472
473 // Is the option flagged as unsafe?
474 $flagged = ! in_array( $args[1], $safe_to_modify );
475
476 if ( ! in_array( $action, array( 'list', 'get', 'delete', 'update' ) ) ) {
477 WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
478 }
479
480 if ( isset( $args[0] ) ) {
481 if ( 'get' == $args[0] && isset( $args[1] ) ) {
482 $action = 'get';
483 } else if ( 'delete' == $args[0] && isset( $args[1] ) ) {
484 $action = 'delete';
485 } else if ( 'update' == $args[0] && isset( $args[1] ) ) {
486 $action = 'update';
487 } else {
488 $action = 'list';
489 }
490 }
491
492 // Bail if the option isn't found
493 $option = isset( $args[1] ) ? Jetpack_Options::get_option( $args[1] ) : false;
494 if ( isset( $args[1] ) && ! $option && 'update' !== $args[0] ) {
495 WP_CLI::error( __( 'Option not found or is empty. Use "list" to list option names', 'jetpack' ) );
496 }
497
498 // Let's print_r the option if it's an array
499 // Used in the 'get' and 'list' actions
500 $option = is_array( $option ) ? print_r( $option ) : $option;
501
502 switch ( $action ) {
503 case 'get':
504 WP_CLI::success( "\t" . $option );
505 break;
506 case 'delete':
507 jetpack_cli_are_you_sure( $flagged );
508
509 Jetpack_Options::delete_option( $args[1] );
510 WP_CLI::success( sprintf( __( 'Deleted option: %s', 'jetpack' ), $args[1] ) );
511 break;
512 case 'update':
513 jetpack_cli_are_you_sure( $flagged );
514
515 // Updating arrays would get pretty tricky...
516 $value = Jetpack_Options::get_option( $args[1] );
517 if ( $value && is_array( $value ) ) {
518 WP_CLI::error( __( 'Sorry, no updating arrays at this time', 'jetpack' ) );
519 }
520
521 Jetpack_Options::update_option( $args[1], $args[2] );
522 WP_CLI::success( sprintf( _x( 'Updated option: %s to "%s"', 'Updating an option from "this" to "that".', 'jetpack' ), $args[1], $args[2] ) );
523 break;
524 case 'list':
525 $options_compact = Jetpack_Options::get_option_names();
526 $options_non_compact = Jetpack_Options::get_option_names( 'non_compact' );
527 $options_private = Jetpack_Options::get_option_names( 'private' );
528 $options = array_merge( $options_compact, $options_non_compact, $options_private );
529
530 // Table headers
531 WP_CLI::line( "\t" . str_pad( __( 'Option', 'jetpack' ), 30 ) . __( 'Value', 'jetpack' ) );
532
533 // List out the options and their values
534 // Tell them if the value is empty or not
535 // Tell them if it's an array
536 foreach ( $options as $option ) {
537 $value = Jetpack_Options::get_option( $option );
538 if ( ! $value ) {
539 WP_CLI::line( "\t" . str_pad( $option, 30 ) . 'Empty' );
540 continue;
541 }
542
543 if ( ! is_array( $value ) ) {
544 WP_CLI::line( "\t" . str_pad( $option, 30 ) . $value );
545 } else if ( is_array( $value ) ) {
546 WP_CLI::line( "\t" . str_pad( $option, 30 ) . 'Array - Use "get <option>" to read option array.' );
547 }
548 }
549 $option_text = '{' . _x( 'option', 'a variable command that a user can write, provided in the printed instructions', 'jetpack' ) . '}';
550 $value_text = '{' . _x( 'value', 'the value that they want to update the option to', 'jetpack' ) . '}';
551
552 WP_CLI::success(
553 _x( "Above are your options. You may 'get', 'delete', and 'update' them.", "'get', 'delete', and 'update' are commands - do not translate.", 'jetpack' ) . "\n" .
554 str_pad( 'wp jetpack options get', 26 ) . $option_text . "\n" .
555 str_pad( 'wp jetpack options delete', 26 ) . $option_text . "\n" .
556 str_pad( 'wp jetpack options update', 26 ) . "$option_text $value_text" . "\n" .
557 _x( "Type 'wp jetpack options' for more info.", "'wp jetpack options' is a command - do not translate.", 'jetpack' ) . "\n"
558 );
559 break;
560 }
561 }
562
563 /**
564 * Get the status of or start a new Jetpack sync.
565 *
566 * ## OPTIONS
567 *
568 * status : Print the current sync status
569 * start : Start a full sync from this site to WordPress.com
570 *
571 * ## EXAMPLES
572 *
573 * wp jetpack sync status
574 * wp jetpack sync start --modules=functions --sync_wait_time=5
575 *
576 * @synopsis <status|start> [--<field>=<value>]
577 */
578 public function sync( $args, $assoc_args ) {
579 if ( ! Jetpack_Sync_Actions::sync_allowed() ) {
580 WP_CLI::error( __( 'Jetpack sync is not currently allowed for this site.', 'jetpack' ) );
581 }
582
583 $action = isset( $args[0] ) ? $args[0] : 'status';
584
585 switch ( $action ) {
586 case 'status':
587 $status = Jetpack_Sync_Actions::get_sync_status();
588 $collection = array();
589 foreach ( $status as $key => $item ) {
590 $collection[] = array(
591 'option' => $key,
592 'value' => is_scalar( $item ) ? $item : json_encode( $item )
593 );
594 }
595
596 WP_CLI\Utils\format_items( 'table', $collection, array( 'option', 'value' ) );
597 break;
598 case 'start':
599 // Get the original settings so that we can restore them later
600 $original_settings = Jetpack_Sync_Settings::get_settings();
601
602 // Initialize sync settigns so we can sync as quickly as possible
603 $sync_settings = wp_parse_args(
604 array_intersect_key( $assoc_args, Jetpack_Sync_Settings::$valid_settings ),
605 array(
606 'sync_wait_time' => 0,
607 'enqueue_wait_time' => 0,
608 'queue_max_writes_sec' => 10000,
609 'max_queue_size_full_sync' => 100000
610 )
611 );
612 Jetpack_Sync_Settings::update_settings( $sync_settings );
613
614 // Convert comma-delimited string of modules to an array
615 if ( ! empty( $assoc_args['modules'] ) ) {
616 $modules = array_map( 'trim', explode( ',', $assoc_args['modules'] ) );
617
618 // Convert the array so that the keys are the module name and the value is true to indicate
619 // that we want to sync the module
620 $modules = array_map( '__return_true', array_flip( $modules ) );
621 }
622
623 foreach ( array( 'posts', 'comments', 'users' ) as $module_name ) {
624 if (
625 'users' === $module_name &&
626 isset( $assoc_args[ $module_name ] ) &&
627 'initial' === $assoc_args[ $module_name ]
628 ) {
629 $modules[ 'users' ] = 'initial';
630 } elseif ( isset( $assoc_args[ $module_name ] ) ) {
631 $ids = explode( ',', $assoc_args[ $module_name ] );
632 if ( count( $ids ) > 0 ) {
633 $modules[ $module_name ] = $ids;
634 }
635 }
636 }
637
638 if ( empty( $modules ) ) {
639 $modules = null;
640 }
641
642 // Kick off a full sync
643 if ( Jetpack_Sync_Actions::do_full_sync( $modules ) ) {
644 if ( $modules ) {
645 WP_CLI::log( sprintf( __( 'Initialized a new full sync with modules: ', 'jetpack' ), join( ', ', $modules ) ) );
646 } else {
647 WP_CLI::log( __( 'Initialized a new full sync', 'jetpack' ) );
648 }
649 } else {
650
651 // Reset sync settings to original.
652 Jetpack_Sync_Settings::update_settings( $original_settings );
653
654 if ( $modules ) {
655 WP_CLI::error( sprintf( __( 'Could not start a new full sync with modules: %s', 'jetpack' ), join( ', ', $modules ) ) );
656 } else {
657 WP_CLI::error( __( 'Could not start a new full sync', 'jetpack' ) );
658 }
659 }
660
661 // Keep sending to WPCOM until there's nothing to send
662 $i = 1;
663 do {
664 $result = Jetpack_Sync_Actions::$sender->do_full_sync();
665 if ( $result ) {
666 if ( 1 == $i++ ) {
667 WP_CLI::log( __( 'Sent data to WordPress.com', 'jetpack' ) );
668 } else {
669 WP_CLI::log( __( 'Sent more data to WordPress.com', 'jetpack' ) );
670 }
671 }
672 } while ( $result );
673
674 // Reset sync settings to original.
675 Jetpack_Sync_Settings::update_settings( $original_settings );
676
677 WP_CLI::success( __( 'Finished syncing to WordPress.com', 'jetpack' ) );
678 break;
679 }
680 }
681
682 /**
683 * List the contents of a specific Jetpack sync queue.
684 *
685 * ## OPTIONS
686 *
687 * peek : List the 100 front-most items on the queue.
688 *
689 * ## EXAMPLES
690 *
691 * wp jetpack sync_queue full_sync peek
692 *
693 * @synopsis <incremental|full_sync> <peek>
694 */
695 public function sync_queue( $args, $assoc_args ) {
696 if ( ! Jetpack_Sync_Actions::sync_allowed() ) {
697 WP_CLI::error( __( 'Jetpack sync is not currently allowed for this site.', 'jetpack' ) );
698 }
699
700 $queue_name = isset( $args[0] ) ? $args[0] : 'sync';
701 $action = isset( $args[1] ) ? $args[1] : 'peek';
702
703 // We map the queue name that way we can support more friendly queue names in the commands, but still use
704 // the queue name that the code expects.
705 $queue_name_map = $allowed_queues = array(
706 'incremental' => 'sync',
707 'full' => 'full_sync',
708 );
709 $mapped_queue_name = isset( $queue_name_map[ $queue_name ] ) ? $queue_name_map[ $queue_name ] : $queue_name;
710
711 switch( $action ) {
712 case 'peek':
713 require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-queue.php';
714 $queue = new Jetpack_Sync_Queue( $mapped_queue_name );
715 $items = $queue->peek( 100 );
716
717 if ( empty( $items ) ) {
718 WP_CLI::log( sprintf( __( 'Nothing is in the %s queue', 'jetpack' ), $queue_name ) );
719 } else {
720 $collection = array();
721 foreach ( $items as $item ) {
722 $collection[] = array(
723 'action' => $item[0],
724 'args' => json_encode( $item[1] ),
725 'current_user_id' => $item[2],
726 'microtime' => $item[3],
727 'importing' => (string) $item[4],
728 );
729 }
730 WP_CLI\Utils\format_items(
731 'table',
732 $collection,
733 array(
734 'action',
735 'args',
736 'current_user_id',
737 'microtime',
738 'importing',
739 )
740 );
741 }
742 break;
743 }
744 }
745 }
746
747 /*
748 * Standard "ask for permission to continue" function.
749 * If action cancelled, ask if they need help.
750 *
751 * Written outside of the class so it's not listed as an executable command w/ 'wp jetpack'
752 *
753 * @param $flagged bool false = normal option | true = flagged by get_jetpack_options_for_reset()
754 * @param $error_msg string (optional)
755 */
756 function jetpack_cli_are_you_sure( $flagged = false, $error_msg = false ) {
757 $cli = new Jetpack_CLI();
758
759 // Default cancellation message
760 if ( ! $error_msg ) {
761 $error_msg =
762 __( 'Action cancelled. Have a question?', 'jetpack' )
763 . ' '
764 . $cli->green_open
765 . 'jetpack.com/support'
766 . $cli->color_close;
767 }
768
769 if ( ! $flagged ) {
770 $prompt_message = __( 'Are you sure? This cannot be undone. Type "yes" to continue:', '"yes" is a command. Do not translate that.', 'jetpack' );
771 } else {
772 /* translators: Don't translate the word yes here. */
773 $prompt_message = __( 'Are you sure? Modifying this option may disrupt your Jetpack connection. Type "yes" to continue.', 'jetpack' );
774 }
775
776 WP_CLI::line( $prompt_message );
777 $handle = fopen( "php://stdin", "r" );
778 $line = fgets( $handle );
779 if ( 'yes' != trim( $line ) ){
780 WP_CLI::error( $error_msg );
781 }
782 }