PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.2
Jetpack – WP Security, Backup, Speed, & Growth v16.2
16.2 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 All 502 releases
← All changes | class.jetpack-cli.php +162 -126 12.0.316.2 View file →
@@ -9,8 +9,10 @@
9 9 use Automattic\Jetpack\Connection\Manager as Connection_Manager;
10 10 use Automattic\Jetpack\Connection\Tokens;
11 11 use Automattic\Jetpack\Identity_Crisis;
12 12 use Automattic\Jetpack\IP\Utils as IP_Utils;
13 +use Automattic\Jetpack\Publicize\Connections;
14 +use Automattic\Jetpack\Publicize\Publicize;
13 15 use Automattic\Jetpack\Status;
14 16 use Automattic\Jetpack\Sync\Actions;
15 17 use Automattic\Jetpack\Sync\Listener;
16 18 use Automattic\Jetpack\Sync\Modules;
@@ -84,9 +86,9 @@
84 86 }
85 87
86 88 $master_user_email = Jetpack::get_master_user_email();
87 89
88 - $cxntests = new Jetpack_Cxn_Tests();
90 + $cxntests = new Automattic\Jetpack\Connection\Connection_Health_Tests();
89 91
90 92 if ( $cxntests->pass() ) {
91 93 $cxntests->output_results_for_cli();
92 94
@@ -223,14 +225,15 @@
223 225 * @param array $args Positional args.
224 226 * @param array $assoc_args Named args.
225 227 */
226 228 public function disconnect( $args, $assoc_args ) {
229 + $user = null;
227 230 if ( ! Jetpack::is_connection_ready() ) {
228 231 WP_CLI::success( __( 'The site is not currently connected, so nothing to do!', 'jetpack' ) );
229 232 return;
230 233 }
231 234
232 - $action = isset( $args[0] ) ? $args[0] : 'prompt';
235 + $action = $args[0] ?? 'prompt';
233 236 if ( ! in_array( $action, array( 'blog', 'user', 'prompt' ), true ) ) {
234 237 /* translators: %s is a command like "prompt" */
235 238 WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
236 239 }
@@ -322,9 +325,9 @@
322 325 * @param array $args Positional args.
323 326 * @param array $assoc_args Named args.
324 327 */
325 328 public function reset( $args, $assoc_args ) {
326 - $action = isset( $args[0] ) ? $args[0] : 'prompt';
329 + $action = $args[0] ?? 'prompt';
327 330 if ( ! in_array( $action, array( 'options', 'modules', 'sync-checksum' ), true ) ) {
328 331 /* translators: %s is a command like "prompt" */
329 332 WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
330 333 }
@@ -542,9 +545,10 @@
542 545 * @param array $args Positional args.
543 546 * @param array $assoc_args Named args.
544 547 */
545 548 public function module( $args, $assoc_args ) {
546 - $action = isset( $args[0] ) ? $args[0] : 'list';
549 + $module_slug = null;
550 + $action = $args[0] ?? 'list';
547 551
548 552 if ( isset( $args[1] ) ) {
549 553 $module_slug = $args[1];
550 554 if ( 'all' !== $module_slug && ! Jetpack::is_module( $module_slug ) ) {
@@ -635,9 +639,9 @@
635 639 *
636 640 * @param array $args Positional args.
637 641 */
638 642 public function protect( $args ) {
639 - $action = isset( $args[0] ) ? $args[0] : 'prompt';
643 + $action = $args[0] ?? 'prompt';
640 644 if ( ! in_array( $action, array( 'whitelist', 'allow' ), true ) ) { // Still allow "whitelist" for legacy support.
641 645 /* translators: %s is a command like "prompt" */
642 646 WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
643 647 }
@@ -764,9 +768,9 @@
764 768 *
765 769 * @param array $args Positional args.
766 770 */
767 771 public function options( $args ) {
768 - $action = isset( $args[0] ) ? $args[0] : 'list';
772 + $action = $args[0] ?? 'list';
769 773 $safe_to_modify = Jetpack_Options::get_options_for_reset();
770 774
771 775 // Is the option flagged as unsafe?
772 776 $flagged = ! in_array( $args[1], $safe_to_modify, true );
@@ -890,9 +894,9 @@
890 894 * @param array $assoc_args Named args.
891 895 */
892 896 public function sync( $args, $assoc_args ) {
893 897
894 - $action = isset( $args[0] ) ? $args[0] : 'status';
898 + $action = $args[0] ?? 'status';
895 899
896 900 switch ( $action ) {
897 901 case 'status':
898 902 $status = Actions::get_sync_status();
@@ -899,9 +903,9 @@
899 903 $collection = array();
900 904 foreach ( $status as $key => $item ) {
901 905 $collection[] = array(
902 906 'option' => $key,
903 - 'value' => is_scalar( $item ) ? $item : wp_json_encode( $item ),
907 + 'value' => is_scalar( $item ) ? $item : wp_json_encode( $item, JSON_UNESCAPED_SLASHES ),
904 908 );
905 909 }
906 910 WP_CLI::log( __( 'Sync Status:', 'jetpack' ) );
907 911 WP_CLI\Utils\format_items( 'table', $collection, array( 'option', 'value' ) );
@@ -911,9 +915,9 @@
911 915 $settings = array();
912 916 foreach ( Settings::get_settings() as $setting => $item ) {
913 917 $settings[] = array(
914 918 'setting' => $setting,
915 - 'value' => is_scalar( $item ) ? $item : wp_json_encode( $item ),
919 + 'value' => is_scalar( $item ) ? $item : wp_json_encode( $item, JSON_UNESCAPED_SLASHES ),
916 920 );
917 921 }
918 922 WP_CLI\Utils\format_items( 'table', $settings, array( 'setting', 'value' ) );
919 923 break;
@@ -981,10 +985,10 @@
981 985 if ( $status->is_offline_mode() ) {
982 986 WP_CLI::error( __( 'Jetpack sync is not currently allowed for this site. The site is in offline mode.', 'jetpack' ) );
983 987 return;
984 988 }
985 - if ( $status->is_staging_site() ) {
986 - WP_CLI::error( __( 'Jetpack sync is not currently allowed for this site. The site is in staging mode.', 'jetpack' ) );
989 + if ( $status->in_safe_mode() ) {
990 + WP_CLI::error( __( 'Jetpack sync is not currently allowed for this site. The site is in safe mode.', 'jetpack' ) );
987 991 return;
988 992 }
989 993 }
990 994 // Get the original settings so that we can restore them later.
@@ -1020,9 +1024,9 @@
1020 1024 ) {
1021 1025 $modules['users'] = 'initial';
1022 1026 } elseif ( isset( $assoc_args[ $module_name ] ) ) {
1023 1027 $ids = explode( ',', $assoc_args[ $module_name ] );
1024 - if ( count( $ids ) > 0 ) {
1028 + if ( $ids !== array() ) {
1025 1029 $modules[ $module_name ] = $ids;
1026 1030 }
1027 1031 }
1028 1032 }
@@ -1031,12 +1035,12 @@
1031 1035 $modules = null;
1032 1036 }
1033 1037
1034 1038 // Kick off a full sync.
1035 - if ( Actions::do_full_sync( $modules ) ) {
1039 + if ( Actions::do_full_sync( $modules, 'jetpack_cli' ) ) {
1036 1040 if ( $modules ) {
1037 - /* translators: %s is a comma separated list of Jetpack modules */
1038 - WP_CLI::log( sprintf( __( 'Initialized a new full sync with modules: %s', 'jetpack' ), join( ', ', array_keys( $modules ) ) ) );
1041 + /* translators: %s is a comma-separated list of Jetpack modules */
1042 + WP_CLI::log( sprintf( __( 'Initialized a new full sync with modules: %s', 'jetpack' ), implode( ', ', array_keys( $modules ) ) ) );
1039 1043 } else {
1040 1044 WP_CLI::log( __( 'Initialized a new full sync', 'jetpack' ) );
1041 1045 }
1042 1046 } else {
@@ -1044,10 +1048,10 @@
1044 1048 // Reset sync settings to original.
1045 1049 Settings::update_settings( $original_settings );
1046 1050
1047 1051 if ( $modules ) {
1048 - /* translators: %s is a comma separated list of Jetpack modules */
1049 - WP_CLI::error( sprintf( __( 'Could not start a new full sync with modules: %s', 'jetpack' ), join( ', ', $modules ) ) );
1052 + /* translators: %s is a comma-separated list of Jetpack modules */
1053 + WP_CLI::error( sprintf( __( 'Could not start a new full sync with modules: %s', 'jetpack' ), implode( ', ', $modules ) ) );
1050 1054 } else {
1051 1055 WP_CLI::error( __( 'Could not start a new full sync', 'jetpack' ) );
1052 1056 }
1053 1057 }
@@ -1069,9 +1073,9 @@
1069 1073 WP_CLI::log( __( 'Sent more data to WordPress.com', 'jetpack' ) );
1070 1074 }
1071 1075
1072 1076 // Immediate Full Sync does not wait for WP.com to process data so we need to enforce a wait.
1073 - if ( false !== strpos( get_class( Modules::get_module( 'full-sync' ) ), 'Full_Sync_Immediately' ) ) {
1077 + if ( Modules::get_module( 'full-sync' ) instanceof \Automattic\Jetpack\Sync\Modules\Full_Sync_Immediately ) {
1074 1078 sleep( 15 );
1075 1079 }
1076 1080 }
1077 1081 ++$i;
@@ -1104,10 +1108,10 @@
1104 1108 if ( ! Actions::sync_allowed() ) {
1105 1109 WP_CLI::error( __( 'Jetpack sync is not currently allowed for this site.', 'jetpack' ) );
1106 1110 }
1107 1111
1108 - $queue_name = isset( $args[0] ) ? $args[0] : 'sync';
1109 - $action = isset( $args[1] ) ? $args[1] : 'peek';
1112 + $queue_name = $args[0] ?? 'sync';
1113 + $action = $args[1] ?? 'peek';
1110 1114
1111 1115 // We map the queue name that way we can support more friendly queue names in the commands, but still use
1112 1116 // the queue name that the code expects.
1113 1117 $allowed_queues = array(
@@ -1114,9 +1118,9 @@
1114 1118 'incremental' => 'sync',
1115 1119 'full' => 'full_sync',
1116 1120 );
1117 1121 $queue_name_map = $allowed_queues;
1118 - $mapped_queue_name = isset( $queue_name_map[ $queue_name ] ) ? $queue_name_map[ $queue_name ] : $queue_name;
1122 + $mapped_queue_name = $queue_name_map[ $queue_name ] ?? $queue_name;
1119 1123
1120 1124 switch ( $action ) {
1121 1125 case 'peek':
1122 1126 $queue = new Queue( $mapped_queue_name );
@@ -1129,9 +1133,9 @@
1129 1133 $collection = array();
1130 1134 foreach ( $items as $item ) {
1131 1135 $collection[] = array(
1132 1136 'action' => $item[0],
1133 - 'args' => wp_json_encode( $item[1] ),
1137 + 'args' => wp_json_encode( $item[1], JSON_UNESCAPED_SLASHES ),
1134 1138 'current_user_id' => $item[2],
1135 1139 'microtime' => $item[3],
1136 1140 'importing' => (string) $item[4],
1137 1141 );
@@ -1187,9 +1191,9 @@
1187 1191 if ( Identity_Crisis::validate_sync_error_idc_option() ) {
1188 1192 $this->partner_provision_error(
1189 1193 new WP_Error(
1190 1194 'site_in_safe_mode',
1191 - esc_html__( 'Can not cancel a plan while in safe mode. See: https://jetpack.com/support/safe-mode/', 'jetpack' )
1195 + esc_html__( 'Cannot cancel a plan while in safe mode. See: https://jetpack.com/support/safe-mode/', 'jetpack' )
1192 1196 )
1193 1197 );
1194 1198 }
1195 1199
@@ -1213,12 +1217,11 @@
1213 1217 if ( ! empty( $named_args ) && ! empty( $named_args['partner_tracking_id'] ) ) {
1214 1218 $url = esc_url_raw( add_query_arg( 'partner_tracking_id', $named_args['partner_tracking_id'], $url ) );
1215 1219 }
1216 1220
1221 + // @phan-suppress-next-line PhanAccessMethodInternal -- Phan is correct, but the usage is intentional.
1217 1222 $result = Client::_wp_remote_request( $url, $request );
1218 1223
1219 - Jetpack_Options::delete_option( 'onboarding' );
1220 -
1221 1224 if ( is_wp_error( $result ) ) {
1222 1225 $this->partner_provision_error( $result );
1223 1226 }
1224 1227
@@ -1239,10 +1242,8 @@
1239 1242 * [--wpcom_user_id=<user_id>]
1240 1243 * : WordPress.com ID of user to connect as (must be whitelisted against partner key)
1241 1244 * [--wpcom_user_email=<wpcom_user_email>]
1242 1245 * : Override the email we send to WordPress.com for registration
1243 - * [--onboarding=<onboarding>]
1244 - * : Guide the user through an onboarding wizard
1245 1246 * [--force_register=<register>]
1246 1247 * : Whether to force a site to register
1247 1248 * [--force_connect=<force_connect>]
1248 1249 * : Force JPS to not reuse existing credentials
@@ -1257,9 +1258,9 @@
1257 1258 *
1258 1259 * $ wp jetpack partner_provision '{ some: "json" }' premium 1
1259 1260 * { success: true }
1260 1261 *
1261 - * @synopsis <token_json> [--wpcom_user_id=<user_id>] [--plan=<plan_name>] [--onboarding=<onboarding>] [--force_register=<register>] [--force_connect=<force_connect>] [--home_url=<home_url>] [--site_url=<site_url>] [--wpcom_user_email=<wpcom_user_email>] [--partner_tracking_id=<partner_tracking_id>]
1262 + * @synopsis <token_json> [--wpcom_user_id=<user_id>] [--plan=<plan_name>] [--force_register=<register>] [--force_connect=<force_connect>] [--home_url=<home_url>] [--site_url=<site_url>] [--wpcom_user_email=<wpcom_user_email>] [--partner_tracking_id=<partner_tracking_id>]
1262 1263 *
1263 1264 * @param array $args Positional args.
1264 1265 * @param array $named_args Named args.
1265 1266 */
@@ -1272,11 +1273,9 @@
1272 1273 $this->partner_provision_error( new WP_Error( 'missing_access_token', sprintf( __( 'Invalid token JSON: %s', 'jetpack' ), $token_json ) ) );
1273 1274 }
1274 1275
1275 1276 if ( isset( $token->error ) ) {
1276 - $message = isset( $token->message )
1277 - ? $token->message
1278 - : '';
1277 + $message = $token->message ?? '';
1279 1278 $this->partner_provision_error( new WP_Error( $token->error, $message ) );
1280 1279 }
1281 1280
1282 1281 if ( ! isset( $token->access_token ) ) {
@@ -1293,15 +1292,16 @@
1293 1292 array(
1294 1293 'success' => false,
1295 1294 'error_code' => $body_json->get_error_code(),
1296 1295 'error_message' => $body_json->get_error_message(),
1297 - )
1296 + ),
1297 + JSON_UNESCAPED_SLASHES
1298 1298 )
1299 1299 );
1300 1300 exit( 1 );
1301 1301 }
1302 1302
1303 - WP_CLI::log( wp_json_encode( $body_json ) );
1303 + WP_CLI::log( wp_json_encode( $body_json, JSON_UNESCAPED_SLASHES ) );
1304 1304 }
1305 1305
1306 1306 /**
1307 1307 * Manages your Jetpack sitemap
@@ -1309,23 +1309,23 @@
1309 1309 * ## OPTIONS
1310 1310 *
1311 1311 * rebuild : Rebuild all sitemaps
1312 1312 * --purge : if set, will remove all existing sitemap data before rebuilding
1313 + * --monitor : if set, will output elapsed time, peak memory usage, CPU time (user/system), and average CPU utilization
1314 + * --suspend-cache-addition : if set, will suspend cache additions during sitemap generation
1313 1315 *
1314 1316 * ## EXAMPLES
1315 1317 *
1316 1318 * wp jetpack sitemap rebuild
1319 + * wp jetpack sitemap rebuild --monitor
1317 1320 *
1318 1321 * @subcommand sitemap
1319 - * @synopsis <rebuild> [--purge]
1322 + * @synopsis <rebuild> [--purge] [--monitor] [--suspend-cache-addition]
1320 1323 *
1321 1324 * @param array $args Positional args.
1322 1325 * @param array $assoc_args Named args.
1323 1326 */
1324 1327 public function sitemap( $args, $assoc_args ) {
1325 - if ( ! Jetpack::is_connection_ready() ) {
1326 - WP_CLI::error( __( 'Jetpack is not currently connected to WordPress.com', 'jetpack' ) );
1327 - }
1328 1328 if ( ! Jetpack::is_module_active( 'sitemaps' ) ) {
1329 1329 WP_CLI::error( __( 'Jetpack Sitemaps module is not currently active. Activate it first if you want to work with sitemaps.', 'jetpack' ) );
1330 1330 }
1331 1331 if ( ! class_exists( 'Jetpack_Sitemap_Builder' ) ) {
@@ -1331,15 +1331,65 @@
1331 1331 if ( ! class_exists( 'Jetpack_Sitemap_Builder' ) ) {
1332 1332 WP_CLI::error( __( 'Jetpack Sitemaps module is active, but unavailable. This can happen if your site is set to discourage search engine indexing. Please enable search engine indexing to allow sitemap generation.', 'jetpack' ) );
1333 1333 }
1334 1334
1335 + if ( isset( $assoc_args['suspend-cache-addition'] ) && $assoc_args['suspend-cache-addition'] ) {
1336 + add_filter( 'jetpack_sitemap_suspend_cache_addition', '__return_true' );
1337 + WP_CLI::success( 'Suspending cache addition.' );
1338 + }
1339 +
1340 + $monitor = isset( $assoc_args['monitor'] ) && $assoc_args['monitor'];
1341 +
1342 + if ( $monitor ) {
1343 + $start_time = microtime( true );
1344 + $rusage_start = function_exists( 'getrusage' ) ? getrusage() : null;
1345 + }
1346 +
1335 1347 if ( isset( $assoc_args['purge'] ) && $assoc_args['purge'] ) {
1336 1348 $librarian = new Jetpack_Sitemap_Librarian();
1337 1349 $librarian->delete_all_stored_sitemap_data();
1350 +
1351 + // Clear sitemap-related transients
1352 + delete_transient( 'jetpack_news_sitemap_xml' );
1353 + delete_transient( 'jetpack-sitemap-state-lock' );
1354 + WP_CLI::success( __( 'Purged all sitemap data and cleared sitemap transients.', 'jetpack' ) );
1338 1355 }
1339 1356
1340 1357 $sitemap_builder = new Jetpack_Sitemap_Builder();
1341 1358 $sitemap_builder->update_sitemap();
1359 +
1360 + WP_CLI::success( __( 'Sitemap rebuilt successfully.', 'jetpack' ) );
1361 +
1362 + if ( $monitor && isset( $start_time ) ) {
1363 + $end_time = microtime( true );
1364 + $peak_memory = memory_get_peak_usage();
1365 + $elapsed_time = $end_time - $start_time;
1366 + $rusage_end = function_exists( 'getrusage' ) ? getrusage() : null;
1367 +
1368 + WP_CLI::log( '----------------------------------' );
1369 + WP_CLI::log( __( 'Performance Metrics:', 'jetpack' ) );
1370 + /* translators: %s is a float representing seconds */
1371 + WP_CLI::log( sprintf( __( 'Elapsed Time: %.4f seconds', 'jetpack' ), $elapsed_time ) );
1372 + /* translators: %s is a human-readable memory size (e.g., 128MB) */
1373 + WP_CLI::log( sprintf( __( 'Peak Memory Usage: %s', 'jetpack' ), size_format( $peak_memory ) ) );
1374 +
1375 + if ( ! empty( $rusage_start ) && ! empty( $rusage_end ) ) {
1376 + $user_cpu_time = ( $rusage_end['ru_utime.tv_sec'] * 1e6 + $rusage_end['ru_utime.tv_usec'] ) - ( $rusage_start['ru_utime.tv_sec'] * 1e6 + $rusage_start['ru_utime.tv_usec'] );
1377 + $system_cpu_time = ( $rusage_end['ru_stime.tv_sec'] * 1e6 + $rusage_end['ru_stime.tv_usec'] ) - ( $rusage_start['ru_stime.tv_sec'] * 1e6 + $rusage_start['ru_stime.tv_usec'] );
1378 +
1379 + /* translators: %d is an integer representing microseconds */
1380 + WP_CLI::log( sprintf( __( 'CPU time (user): %d microseconds', 'jetpack' ), $user_cpu_time ) );
1381 + /* translators: %d is an integer representing microseconds */
1382 + WP_CLI::log( sprintf( __( 'CPU time (system): %d microseconds', 'jetpack' ), $system_cpu_time ) );
1383 +
1384 + // Average CPU utilization over the elapsed wall time.
1385 + $total_cpu_sec = ( $user_cpu_time + $system_cpu_time ) / 1e6;
1386 + $avg_cpu_pct = $elapsed_time > 0 ? ( $total_cpu_sec / $elapsed_time ) * 100 : 0.0;
1387 + /* translators: %s is a percentage like 83.4 */
1388 + WP_CLI::log( sprintf( __( 'Average CPU Utilization: %.1f%%', 'jetpack' ), $avg_cpu_pct ) );
1389 + }
1390 + WP_CLI::log( '----------------------------------' );
1391 + }
1342 1392 }
1343 1393
1344 1394 /**
1345 1395 * Allows authorizing a user via the command line and will activate
@@ -1366,9 +1416,9 @@
1366 1416 $current_user_id = get_current_user_id();
1367 1417
1368 1418 ( new Tokens() )->update_user_token( $current_user_id, sprintf( '%s.%d', $named_args['token'], $current_user_id ), $is_connection_owner );
1369 1419
1370 - WP_CLI::log( wp_json_encode( $named_args ) );
1420 + WP_CLI::log( wp_json_encode( $named_args, JSON_UNESCAPED_SLASHES ) );
1371 1421
1372 1422 if ( $is_connection_owner ) {
1373 1423 /**
1374 1424 * Auto-enable SSO module for new Jetpack Start connections
@@ -1442,9 +1492,9 @@
1442 1492 $decoded_body = ! empty( $named_args['body'] )
1443 1493 ? json_decode( $named_args['body'], true )
1444 1494 : false;
1445 1495
1446 - $resource_url = ( false === strpos( $named_args['resource'], '%d' ) )
1496 + $resource_url = ( ! str_contains( $named_args['resource'], '%d' ) )
1447 1497 ? $named_args['resource']
1448 1498 : sprintf( $named_args['resource'], Jetpack_Options::get_option( 'id' ) );
1449 1499
1450 1500 $response = Client::wpcom_json_api_request_as_blog(
@@ -1481,9 +1531,9 @@
1481 1531 $output = wp_remote_retrieve_body( $response );
1482 1532 if ( isset( $named_args['pretty'] ) ) {
1483 1533 $decoded_output = json_decode( $output );
1484 1534 if ( $decoded_output ) {
1485 - $output = wp_json_encode( $decoded_output, JSON_PRETTY_PRINT );
1535 + $output = wp_json_encode( $decoded_output, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT );
1486 1536 }
1487 1537 }
1488 1538
1489 1539 if ( isset( $named_args['strip-success'] ) ) {
@@ -1569,9 +1619,9 @@
1569 1619 array(
1570 1620 'resource' => '/activity-log/%d/update-credentials',
1571 1621 'method' => 'POST',
1572 1622 'api_version' => '1.1',
1573 - 'body' => wp_json_encode( $values ),
1623 + 'body' => wp_json_encode( $values, JSON_UNESCAPED_SLASHES ),
1574 1624 'timeout' => 30,
1575 1625 ),
1576 1626 $named_args
1577 1627 );
@@ -1668,8 +1718,11 @@
1668 1718 *
1669 1719 * [<identifier>]
1670 1720 * : The connection ID or service to perform an action on.
1671 1721 *
1722 + * [--ignore-cache]
1723 + * : Whether to ignore connections cache.
1724 + *
1672 1725 * [--format=<format>]
1673 1726 * : Allows overriding the output of the command when listing connections.
1674 1727 * ---
1675 1728 * default: table
@@ -1686,16 +1739,19 @@
1686 1739 *
1687 1740 * # List all publicize connections.
1688 1741 * $ wp jetpack publicize list
1689 1742 *
1743 + * # List all publicize connections, ignoring the cache.
1744 + * $ wp jetpack publicize list --ignore-cache
1745 + *
1690 1746 * # List publicize connections for a given service.
1691 - * $ wp jetpack publicize list twitter
1747 + * $ wp jetpack publicize list linkedin
1692 1748 *
1693 1749 * # List all publicize connections for a given user.
1694 1750 * $ wp --user=1 jetpack publicize list
1695 1751 *
1696 1752 * # List all publicize connections for a given user and service.
1697 - * $ wp --user=1 jetpack publicize list twitter
1753 + * $ wp --user=1 jetpack publicize list linkedin
1698 1754 *
1699 1755 * # Display details for a given connection.
1700 1756 * $ wp jetpack publicize list 123456
1701 1757 *
@@ -1705,9 +1761,9 @@
1705 1761 * # Disconnect all connections.
1706 1762 * $ wp jetpack publicize disconnect all
1707 1763 *
1708 1764 * # Disconnect all connections for a given service.
1709 - * $ wp jetpack publicize disconnect twitter
1765 + * $ wp jetpack publicize disconnect linkedin
1710 1766 *
1711 1767 * @param array $args Positional args.
1712 1768 * @param array $named_args Named args.
1713 1769 */
@@ -1722,11 +1778,10 @@
1722 1778
1723 1779 if ( ( new Status() )->is_offline_mode() ) {
1724 1780 if (
1725 1781 ! defined( 'JETPACK_DEV_DEBUG' ) &&
1726 - ! has_filter( 'jetpack_development_mode' ) &&
1727 1782 ! has_filter( 'jetpack_offline_mode' ) &&
1728 - false === strpos( site_url(), '.' )
1783 + ! str_contains( site_url(), '.' )
1729 1784 ) {
1730 1785 WP_CLI::error( __( "Jetpack is current in offline mode because the site url does not contain a '.', which often occurs when dynamically setting the WP_SITEURL constant. While in offline mode, the Jetpack Social module will not load.", 'jetpack' ) );
1731 1786 }
1732 1787
@@ -1732,9 +1787,9 @@
1732 1787
1733 1788 WP_CLI::error( __( 'Jetpack is currently in offline mode, so the Jetpack Social module will not load.', 'jetpack' ) );
1734 1789 }
1735 1790
1736 - if ( ! class_exists( 'Publicize' ) ) {
1791 + if ( ! class_exists( Publicize::class ) ) {
1737 1792 WP_CLI::error( __( 'The Jetpack Social module is not loaded.', 'jetpack' ) );
1738 1793 }
1739 1794
1740 1795 $action = $args[0];
@@ -1744,30 +1799,23 @@
1744 1799 $id_is_service = in_array( $identifier, $services, true );
1745 1800
1746 1801 switch ( $action ) {
1747 1802 case 'list':
1748 - $connections_to_return = array();
1749 -
1803 + $_args = array(
1804 + 'ignore_cache' => $named_args['ignore-cache'] ?? false,
1805 + );
1750 1806 // For the CLI command, let's return all connections when a user isn't specified. This
1751 1807 // differs from the logic in the Publicize class.
1752 - $option_connections = is_user_logged_in()
1753 - ? (array) $publicize->get_all_connections_for_user()
1754 - : (array) $publicize->get_all_connections();
1808 + $connections_to_return = is_user_logged_in()
1809 + ? Connections::get_all_for_user( $_args )
1810 + : Connections::get_all( $_args );
1755 1811
1756 - foreach ( $option_connections as $service_name => $connections ) {
1757 - foreach ( (array) $connections as $id => $connection ) {
1758 - $connection['id'] = $id;
1759 - $connection['service'] = $service_name;
1760 - $connections_to_return[] = $connection;
1761 - }
1762 - }
1763 -
1764 1812 if ( $id_is_service && ! empty( $identifier ) && ! empty( $connections_to_return ) ) {
1765 1813 $temp_connections = $connections_to_return;
1766 1814 $connections_to_return = array();
1767 1815
1768 1816 foreach ( $temp_connections as $connection ) {
1769 - if ( $identifier === $connection['service'] ) {
1817 + if ( $identifier === $connection['service_name'] ) {
1770 1818 $connections_to_return[] = $connection;
1771 1819 }
1772 1820 }
1773 1821 }
@@ -1772,27 +1820,22 @@
1772 1820 }
1773 1821 }
1774 1822
1775 1823 if ( $identifier && ! $id_is_service && ! empty( $connections_to_return ) ) {
1776 - $connections_to_return = wp_list_filter( $connections_to_return, array( 'id' => $identifier ) );
1824 + $connections_to_return = wp_list_filter( $connections_to_return, array( 'connection_id' => $identifier ) );
1777 1825 }
1778 1826
1779 1827 $expected_keys = array(
1780 - 'id',
1781 - 'service',
1782 - 'user_id',
1783 - 'provider',
1784 - 'issued',
1785 - 'expires',
1828 + 'connection_id',
1829 + 'service_name',
1830 + 'display_name',
1786 1831 'external_id',
1787 - 'external_name',
1788 - 'external_display',
1789 - 'type',
1790 - 'connection_data',
1832 + 'wpcom_user_id',
1833 + 'shared',
1791 1834 );
1792 1835
1793 1836 // Somehow, a test site ended up in a state where $connections_to_return looked like:
1794 - // array( array( array( 'id' => 0, 'service' => 0 ) ) ) // phpcs:ignore Squiz.PHP.CommentedOutCode.Found
1837 + // array( array( array( 'id' => 0, 'service' => 0 ) ) )
1795 1838 // This caused the CLI command to error when running WP_CLI\Utils\format_items() below. So
1796 1839 // to minimize future issues, this nested loop will remove any connections that don't contain
1797 1840 // any keys that we expect.
1798 1841 foreach ( (array) $connections_to_return as $connection_key => $connection ) {
@@ -1826,27 +1869,19 @@
1826 1869 }
1827 1870
1828 1871 jetpack_cli_are_you_sure();
1829 1872
1830 - $connections = array();
1831 1873 $service = $identifier;
1874 + $connections = is_user_logged_in()
1875 + ? Connections::get_all_for_user()
1876 + : Connections::get_all();
1832 1877
1833 - $option_connections = is_user_logged_in()
1834 - ? (array) $publicize->get_all_connections_for_user()
1835 - : (array) $publicize->get_all_connections();
1836 -
1837 - if ( 'all' === $service ) {
1838 - foreach ( (array) $option_connections as $service_name => $service_connections ) {
1839 - foreach ( $service_connections as $id => $connection ) {
1840 - $connections[ $id ] = $connection;
1841 - }
1842 - }
1843 - } elseif ( ! empty( $option_connections[ $service ] ) ) {
1844 - $connections = $option_connections[ $service ];
1878 + if ( 'all' !== $service ) {
1879 + $connections = wp_list_filter( $connections, array( 'service_name' => $service ) );
1845 1880 }
1846 1881
1847 1882 if ( ! empty( $connections ) ) {
1848 - $count = count( $connections );
1883 + $count = is_countable( $connections ) ? count( $connections ) : 0;
1849 1884 $progress = \WP_CLI\Utils\make_progress_bar(
1850 1885 /* translators: %s is a lowercase string for a social network. */
1851 1886 sprintf( __( 'Disconnecting all connections to %s.', 'jetpack' ), $service ),
1852 1887 $count
@@ -1851,9 +1886,10 @@
1851 1886 sprintf( __( 'Disconnecting all connections to %s.', 'jetpack' ), $service ),
1852 1887 $count
1853 1888 );
1854 1889
1855 - foreach ( $connections as $id => $connection ) {
1890 + foreach ( $connections as $connection ) {
1891 + $id = $connection['connection_id'];
1856 1892 if ( false === $publicize->disconnect( false, $id ) ) {
1857 1893 WP_CLI::error(
1858 1894 sprintf(
1859 1895 /* translators: %1$d is a numeric ID and %2$s is a lowercase string for a social network. */
@@ -1862,11 +1898,13 @@
1862 1898 )
1863 1899 );
1864 1900 }
1865 1901
1902 + // @phan-suppress-next-line PhanUndeclaredClassMethod - Class is missing from php-stubs/wp-cli-stubs 🤷
1866 1903 $progress->tick();
1867 1904 }
1868 1905
1906 + // @phan-suppress-next-line PhanUndeclaredClassMethod - Class is missing from php-stubs/wp-cli-stubs 🤷
1869 1907 $progress->finish();
1870 1908
1871 1909 if ( 'all' === $service ) {
1872 1910 WP_CLI::success( __( 'All Jetpack Social connections were successfully disconnected.', 'jetpack' ) );
@@ -1871,9 +1909,9 @@
1871 1909 if ( 'all' === $service ) {
1872 1910 WP_CLI::success( __( 'All Jetpack Social connections were successfully disconnected.', 'jetpack' ) );
1873 1911 } else {
1874 1912 /* translators: %s is a lowercase string for a social network. */
1875 - WP_CLI::success( __( 'All Jetpack Social connections to %s were successfully disconnected.', 'jetpack' ), $service );
1913 + WP_CLI::success( sprintf( __( 'All Jetpack Social connections to %s were successfully disconnected.', 'jetpack' ), $service ) );
1876 1914 }
1877 1915 }
1878 1916 } elseif ( false !== $publicize->disconnect( false, $identifier ) ) {
1879 1917 /* translators: %d is a numeric ID. Example: 1234. */
@@ -1899,8 +1937,9 @@
1899 1937 /**
1900 1938 * Log and exit on a partner provision error.
1901 1939 *
1902 1940 * @param WP_Error $error Error.
1941 + * @return never
1903 1942 */
1904 1943 private function partner_provision_error( $error ) {
1905 1944 WP_CLI::log(
1906 1945 wp_json_encode(
@@ -1907,9 +1946,10 @@
1907 1946 array(
1908 1947 'success' => false,
1909 1948 'error_code' => $error->get_error_code(),
1910 1949 'error_message' => $error->get_error_message(),
1911 - )
1950 + ),
1951 + JSON_UNESCAPED_SLASHES
1912 1952 )
1913 1953 );
1914 1954 exit( 1 );
1915 1955 }
@@ -1962,19 +2002,19 @@
1962 2002 * @param array $args Positional parameters. Only one is used, that corresponds to the block title.
1963 2003 * @param array $assoc_args Associative parameters defined in the scaffold() method.
1964 2004 */
1965 2005 public function block( $args, $assoc_args ) {
1966 - if ( isset( $args[1] ) ) {
1967 - $title = ucwords( $args[1] );
1968 - } else {
2006 + if ( ! isset( $args[1] ) ) {
1969 2007 WP_CLI::error( esc_html__( 'The title parameter is required.', 'jetpack' ) . ' 👻' );
1970 2008 exit( 1 );
1971 2009 }
1972 2010
1973 - $slug = isset( $assoc_args['slug'] )
1974 - ? $assoc_args['slug']
1975 - : sanitize_title( $title );
2011 + $title = ucwords( $args[1] );
1976 2012
2013 + $slug = $assoc_args['slug'] ?? sanitize_title( $title );
2014 +
2015 + $next_version = "\x24\x24next-version$$"; // Escapes to hide the string from tools/replace-next-version-tag.sh
2016 +
1977 2017 $variation_options = array( 'production', 'experimental', 'beta' );
1978 2018 $variation = ( isset( $assoc_args['variation'] ) && in_array( $assoc_args['variation'], $variation_options, true ) )
1979 2019 ? $assoc_args['variation']
1980 2020 : 'beta';
@@ -2001,42 +2041,40 @@
2001 2041 }
2002 2042
2003 2043 $wp_filesystem->mkdir( $path );
2004 2044
2005 - $has_keywords = isset( $assoc_args['keywords'] );
2045 + $keywords = isset( $assoc_args['keywords'] )
2046 + ? array_map(
2047 + function ( $keyword ) {
2048 + return trim( $keyword );
2049 + },
2050 + array_slice( explode( ',', $assoc_args['keywords'] ), 0, 3 )
2051 + )
2052 + : array();
2006 2053
2007 2054 $files = array(
2008 - "$path/$slug.php" => $this->render_block_file(
2055 + "$path/block.json" => self::render_block_file(
2056 + 'block-block-json',
2057 + array(
2058 + 'slug' => $slug,
2059 + 'title' => wp_json_encode( $title, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ),
2060 + 'description' => isset( $assoc_args['description'] )
2061 + ? wp_json_encode( $assoc_args['description'], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE )
2062 + : wp_json_encode( $title, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ),
2063 + 'nextVersion' => $next_version,
2064 + 'keywords' => wp_json_encode( $keywords, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ),
2065 + )
2066 + ),
2067 + "$path/$slug.php" => self::render_block_file(
2009 2068 'block-register-php',
2010 2069 array(
2011 - 'slug' => $slug,
2070 + 'nextVersion' => $next_version,
2012 2071 'title' => $title,
2013 - 'underscoredSlug' => str_replace( '-', '_', $slug ),
2014 2072 'underscoredTitle' => str_replace( ' ', '_', $title ),
2015 2073 )
2016 2074 ),
2017 - "$path/index.js" => $this->render_block_file(
2018 - 'block-index-js',
2019 - array(
2020 - 'slug' => $slug,
2021 - 'title' => $title,
2022 - 'description' => isset( $assoc_args['description'] )
2023 - ? $assoc_args['description']
2024 - : $title,
2025 - 'keywords' => $has_keywords
2026 - ? array_map(
2027 - function ( $keyword ) {
2028 - // Construction necessary for Mustache lists.
2029 - return array( 'keyword' => trim( $keyword ) );
2030 - },
2031 - explode( ',', $assoc_args['keywords'], 3 )
2032 - )
2033 - : '',
2034 - 'hasKeywords' => $has_keywords,
2035 - )
2036 - ),
2037 - "$path/editor.js" => $this->render_block_file( 'block-editor-js' ),
2038 - "$path/editor.scss" => $this->render_block_file(
2075 + "$path/editor.js" => self::render_block_file( 'block-editor-js' ),
2076 + "$path/editor.scss" => self::render_block_file(
2039 2077 'block-editor-scss',
2040 2078 array(
2041 2079 'slug' => $slug,
2042 2080 'title' => $title,
@@ -2041,9 +2079,9 @@
2041 2079 'slug' => $slug,
2042 2080 'title' => $title,
2043 2081 )
2044 2082 ),
2045 - "$path/edit.js" => $this->render_block_file(
2083 + "$path/edit.js" => self::render_block_file(
2046 2084 'block-edit-js',
2047 2085 array(
2048 2086 'title' => $title,
2049 2087 'className' => str_replace( ' ', '', ucwords( str_replace( '-', ' ', $slug ) ) ),
@@ -2048,10 +2086,8 @@
2048 2086 'title' => $title,
2049 2087 'className' => str_replace( ' ', '', ucwords( str_replace( '-', ' ', $slug ) ) ),
2050 2088 )
2051 2089 ),
2052 - "$path/icon.js" => $this->render_block_file( 'block-icon-js' ),
2053 - "$path/attributes.js" => $this->render_block_file( 'block-attributes-js' ),
2054 2090 );
2055 2091
2056 2092 $files_written = array();
2057 2093
@@ -2077,9 +2113,9 @@
2077 2113 $new_block_list = json_decode( $block_list );
2078 2114 $new_block_list->{ $variation }[] = $slug;
2079 2115
2080 2116 // Format the JSON to match our coding standards.
2081 - $new_block_list_formatted = wp_json_encode( $new_block_list, JSON_PRETTY_PRINT ) . "\n";
2117 + $new_block_list_formatted = wp_json_encode( $new_block_list, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT ) . "\n";
2082 2118 $new_block_list_formatted = preg_replace_callback(
2083 2119 // Find all occurrences of multiples of 4 spaces a the start of the line.
2084 2120 '/^((?: )+)/m',
2085 2121 function ( $matches ) {