Completed
Push — jetpack-fusion-mock-files ( e51750...3b1561 )
by
unknown
13:31
created

Jetpack_CLI::sitemap()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 12
nc 16
nop 2
dl 0
loc 19
rs 8.8571
c 0
b 0
f 0
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
33
		WP_CLI::line( sprintf( __( 'Checking status for %s', 'jetpack' ), esc_url( get_site_url() ) ) );
34
35
		if ( ! Jetpack::is_active() ) {
36
			WP_CLI::error( __( 'Jetpack is not currently connected to WordPress.com', 'jetpack' ) );
37
		}
38
39 View Code Duplication
		if ( isset( $args[0] ) && 'full' !== $args[0] ) {
40
			/* translators: %s is a command like "prompt" */
41
			WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $args[0] ) );
42
		}
43
44
		$master_user_email = Jetpack::get_master_user_email();
45
46
		/*
47
		 * Are they asking for all data?
48
		 *
49
		 * Loop through heartbeat data and organize by priority.
50
		 */
51
		$all_data = ( isset( $args[0] ) && 'full' == $args[0] ) ? 'full' : false;
52
		if ( $all_data ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $all_data of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
53
			WP_CLI::success( __( 'Jetpack is currently connected to WordPress.com', 'jetpack' ) );
54
			WP_CLI::line( sprintf( __( "The Jetpack Version is %s", 'jetpack' ), JETPACK__VERSION ) );
55
			WP_CLI::line( sprintf( __( "The WordPress.com blog_id is %d", 'jetpack' ), Jetpack_Options::get_option( 'id' ) ) );
56
			WP_CLI::line( sprintf( __( 'The WordPress.com account for the primary connection is %s', 'jetpack' ), $master_user_email ) );
57
58
			// Heartbeat data
59
			WP_CLI::line( "\n" . __( 'Additional data: ', 'jetpack' ) );
60
61
			// Get the filtered heartbeat data.
62
			// Filtered so we can color/list by severity
63
			$stats = Jetpack::jetpack_check_heartbeat_data();
64
65
			// Display red flags first
66
			foreach ( $stats['bad'] as $stat => $value ) {
67
				printf( "$this->red_open%-'.16s %s $this->color_close\n", $stat, $value );
68
			}
69
70
			// Display caution warnings next
71
			foreach ( $stats['caution'] as $stat => $value ) {
72
				printf( "$this->yellow_open%-'.16s %s $this->color_close\n", $stat, $value );
73
			}
74
75
			// The rest of the results are good!
76
			foreach ( $stats['good'] as $stat => $value ) {
77
78
				// Modules should get special spacing for aestetics
79
				if ( strpos( $stat, 'odule-' ) ) {
80
					printf( "%-'.30s %s\n", $stat, $value );
81
					usleep( 4000 ); // For dramatic effect lolz
82
					continue;
83
				}
84
				printf( "%-'.16s %s\n", $stat, $value );
85
				usleep( 4000 ); // For dramatic effect lolz
86
			}
87
		} else {
88
			// Just the basics
89
			WP_CLI::success( __( 'Jetpack is currently connected to WordPress.com', 'jetpack' ) );
90
			WP_CLI::line( sprintf( __( 'The Jetpack Version is %s', 'jetpack' ), JETPACK__VERSION ) );
91
			WP_CLI::line( sprintf( __( 'The WordPress.com blog_id is %d', 'jetpack' ), Jetpack_Options::get_option( 'id' ) ) );
92
			WP_CLI::line( sprintf( __( 'The WordPress.com account for the primary connection is %s', 'jetpack' ), $master_user_email ) );
93
			WP_CLI::line( "\n" . _x( "View full status with 'wp jetpack status full'", '"wp jetpack status full" is a command - do not translate', 'jetpack' ) );
94
		}
95
	}
96
97
	/**
98
	 * Tests the active connection
99
	 *
100
	 * Does a two-way test to verify that the local site can communicate with remote Jetpack/WP.com servers and that Jetpack/WP.com servers can talk to the local site.
101
	 *
102
	 * ## EXAMPLES
103
	 *
104
	 * wp jetpack test-connection
105
	 *
106
	 * @subcommand test-connection
107
	 */
108
	public function test_connection( $args, $assoc_args ) {
109
110
		WP_CLI::line( sprintf( __( 'Testing connection for %s', 'jetpack' ), esc_url( get_site_url() ) ) );
111
112
		if ( ! Jetpack::is_active() ) {
113
			WP_CLI::error( __( 'Jetpack is not currently connected to WordPress.com', 'jetpack' ) );
114
		}
115
116
		$response = Jetpack_Client::wpcom_json_api_request_as_blog(
117
			sprintf( '/jetpack-blogs/%d/test-connection', Jetpack_Options::get_option( 'id' ) ),
118
			Jetpack_Client::WPCOM_JSON_API_VERSION
119
		);
120
121
		if ( is_wp_error( $response ) ) {
122
			/* translators: %1$s is the error code, %2$s is the error message */
123
			WP_CLI::error( sprintf( __( 'Failed to test connection (#%1$s: %2$s)', 'jetpack' ), $response->get_error_code(), $response->get_error_message() ) );
124
		}
125
126
		$body = wp_remote_retrieve_body( $response );
127
		if ( ! $body ) {
128
			WP_CLI::error( __( 'Failed to test connection (empty response body)', 'jetpack' ) );
129
		}
130
131
		$result = json_decode( $body );
132
		$is_connected = (bool) $result->connected;
133
		$message = $result->message;
134
135
		if ( $is_connected ) {
136
			WP_CLI::success( $message );
137
		} else {
138
			WP_CLI::error( $message );
139
		}
140
	}
141
142
	/**
143
	 * Disconnect Jetpack Blogs or Users
144
	 *
145
	 * ## OPTIONS
146
	 *
147
	 * blog: Disconnect the entire blog.
148
	 *
149
	 * user <user_identifier>: Disconnect a specific user from WordPress.com.
150
	 *
151
	 * Please note, the primary account that the blog is connected
152
	 * to WordPress.com with cannot be disconnected without
153
	 * disconnecting the entire blog.
154
	 *
155
	 * ## EXAMPLES
156
	 *
157
	 * wp jetpack disconnect blog
158
	 * wp jetpack disconnect user 13
159
	 * wp jetpack disconnect user username
160
	 * wp jetpack disconnect user [email protected]
161
	 *
162
	 * @synopsis <blog|user> [<user_identifier>]
163
	 */
164
	public function disconnect( $args, $assoc_args ) {
165
		if ( ! Jetpack::is_active() ) {
166
			WP_CLI::error( __( 'You cannot disconnect, without having first connected.', 'jetpack' ) );
167
		}
168
169
		$action = isset( $args[0] ) ? $args[0] : 'prompt';
170
		if ( ! in_array( $action, array( 'blog', 'user', 'prompt' ) ) ) {
171
			/* translators: %s is a command like "prompt" */
172
			WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
173
		}
174
175
		if ( in_array( $action, array( 'user' ) ) ) {
176
			if ( isset( $args[1] ) ) {
177
				$user_id = $args[1];
178
				if ( ctype_digit( $user_id ) ) {
179
					$field = 'id';
180
					$user_id = (int) $user_id;
181
				} elseif ( is_email( $user_id ) ) {
182
					$field = 'email';
183
					$user_id = sanitize_user( $user_id, true );
184
				} else {
185
					$field = 'login';
186
					$user_id = sanitize_user( $user_id, true );
187
				}
188
				if ( ! $user = get_user_by( $field, $user_id ) ) {
189
					WP_CLI::error( __( 'Please specify a valid user.', 'jetpack' ) );
190
				}
191
			} else {
192
				WP_CLI::error( __( 'Please specify a user by either ID, username, or email.', 'jetpack' ) );
193
			}
194
		}
195
196
		switch ( $action ) {
197
			case 'blog':
198
				Jetpack::log( 'disconnect' );
199
				Jetpack::disconnect();
200
				WP_CLI::success( sprintf(
201
					__( 'Jetpack has been successfully disconnected for %s.', 'jetpack' ),
202
					esc_url( get_site_url() )
203
				) );
204
				break;
205
			case 'user':
206
				if ( Jetpack::unlink_user( $user->ID ) ) {
207
					Jetpack::log( 'unlink', $user->ID );
0 ignored issues
show
Bug introduced by
The variable $user does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
208
					WP_CLI::success( __( 'User has been successfully disconnected.', 'jetpack' ) );
209
				} else {
210
					/* translators: %s is a username */
211
					WP_CLI::error( sprintf( __( "User %s could not be disconnected. Are you sure they're connected currently?", 'jetpack' ), "{$user->login} <{$user->email}>" ) );
212
				}
213
				break;
214
			case 'prompt':
215
				WP_CLI::error( __( 'Please specify if you would like to disconnect a blog or user.', 'jetpack' ) );
216
				break;
217
		}
218
	}
219
220
	/**
221
	 * Reset Jetpack options and settings to default
222
	 *
223
	 * ## OPTIONS
224
	 *
225
	 * modules: Resets modules to default state ( get_default_modules() )
226
	 *
227
	 * options: Resets all Jetpack options except:
228
	 *  - All private options (Blog token, user token, etc...)
229
	 *  - id (The Client ID/WP.com Blog ID of this site)
230
	 *  - master_user
231
	 *  - version
232
	 *  - activated
233
	 *
234
	 * ## EXAMPLES
235
	 *
236
	 * wp jetpack reset options
237
	 * wp jetpack reset modules
238
	 *
239
	 * @synopsis <modules|options>
240
	 */
241
	public function reset( $args, $assoc_args ) {
242
		$action = isset( $args[0] ) ? $args[0] : 'prompt';
243 View Code Duplication
		if ( ! in_array( $action, array( 'options', 'modules' ) ) ) {
244
			/* translators: %s is a command like "prompt" */
245
			WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
246
		}
247
248
		// Are you sure?
249
		jetpack_cli_are_you_sure();
250
251
		switch ( $action ) {
252
			case 'options':
253
				$options_to_reset = Jetpack_Options::get_options_for_reset();
254
255
				// Reset the Jetpack options
256
				WP_CLI::line( sprintf(
257
					__( "Resetting Jetpack Options for %s...\n", "jetpack" ),
258
					esc_url( get_site_url() )
259
				) );
260
				sleep(1); // Take a breath
261
				foreach ( $options_to_reset['jp_options'] as $option_to_reset ) {
262
					Jetpack_Options::delete_option( $option_to_reset );
263
					usleep( 100000 );
264
					/* translators: This is the result of an action. The option named %s was reset */
265
					WP_CLI::success( sprintf( __( '%s option reset', 'jetpack' ), $option_to_reset ) );
266
				}
267
268
				// Reset the WP options
269
				WP_CLI::line( __( "Resetting the jetpack options stored in wp_options...\n", "jetpack" ) );
270
				usleep( 500000 ); // Take a breath
271
				foreach ( $options_to_reset['wp_options'] as $option_to_reset ) {
272
					delete_option( $option_to_reset );
273
					usleep( 100000 );
274
					/* translators: This is the result of an action. The option named %s was reset */
275
					WP_CLI::success( sprintf( __( '%s option reset', 'jetpack' ), $option_to_reset ) );
276
				}
277
278
				// Reset to default modules
279
				WP_CLI::line( __( "Resetting default modules...\n", "jetpack" ) );
280
				usleep( 500000 ); // Take a breath
281
				$default_modules = Jetpack::get_default_modules();
282
				Jetpack::update_active_modules( $default_modules );
283
				WP_CLI::success( __( 'Modules reset to default.', 'jetpack' ) );
284
285
				// Jumpstart option is special
286
				Jetpack_Options::update_option( 'jumpstart', 'new_connection' );
287
				WP_CLI::success( __( 'jumpstart option reset', 'jetpack' ) );
288
				break;
289 View Code Duplication
			case 'modules':
290
				$default_modules = Jetpack::get_default_modules();
291
				Jetpack::update_active_modules( $default_modules );
292
				WP_CLI::success( __( 'Modules reset to default.', 'jetpack' ) );
293
				break;
294
			case 'prompt':
295
				WP_CLI::error( __( 'Please specify if you would like to reset your options, or modules', 'jetpack' ) );
296
				break;
297
		}
298
	}
299
300
	/**
301
	 * Manage Jetpack Modules
302
	 *
303
	 * ## OPTIONS
304
	 *
305
	 * list          : View all available modules, and their status.
306
	 * activate all  : Activate all modules
307
	 * deactivate all: Deactivate all modules
308
	 *
309
	 * activate   <module_slug> : Activate a module.
310
	 * deactivate <module_slug> : Deactivate a module.
311
	 * toggle     <module_slug> : Toggle a module on or off.
312
	 *
313
	 * ## EXAMPLES
314
	 *
315
	 * wp jetpack module list
316
	 * wp jetpack module activate stats
317
	 * wp jetpack module deactivate stats
318
	 * wp jetpack module toggle stats
319
	 *
320
	 * wp jetpack module activate all
321
	 * wp jetpack module deactivate all
322
	 *
323
	 * @synopsis <list|activate|deactivate|toggle> [<module_name>]
324
	 */
325
	public function module( $args, $assoc_args ) {
326
		$action = isset( $args[0] ) ? $args[0] : 'list';
327
		if ( ! in_array( $action, array( 'list', 'activate', 'deactivate', 'toggle' ) ) ) {
328
			/* translators: %s is a command like "prompt" */
329
			WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
330
		}
331
		if ( in_array( $action, array( 'activate', 'deactivate', 'toggle' ) ) ) {
332
			if ( isset( $args[1] ) ) {
333
				$module_slug = $args[1];
334
				if ( 'all' !== $module_slug && ! Jetpack::is_module( $module_slug ) ) {
335
					WP_CLI::error( sprintf( __( '%s is not a valid module.', 'jetpack' ), $module_slug ) );
336
				}
337
				if ( 'toggle' == $action ) {
338
					$action = Jetpack::is_module_active( $module_slug ) ? 'deactivate' : 'activate';
339
				}
340
				// Bulk actions
341
				if ( 'all' == $args[1] ) {
342
					$action = ( 'deactivate' == $action ) ? 'deactivate_all' : 'activate_all';
343
				}
344
				// VaultPress needs to be handled elsewhere.
345
				if ( in_array( $action, array( 'activate', 'deactivate', 'toggle' ) ) && 'vaultpress' == $args[1] ) {
346
					WP_CLI::error( sprintf( _x( 'Please visit %s to configure your VaultPress subscription.', '%s is a website', 'jetpack' ), esc_url( 'https://vaultpress.com/jetpack/' ) ) );
347
				}
348
			} else {
349
				WP_CLI::line( __( 'Please specify a valid module.', 'jetpack' ) );
350
				$action = 'list';
351
			}
352
		}
353
		switch ( $action ) {
354
			case 'list':
355
				WP_CLI::line( __( 'Available Modules:', 'jetpack' ) );
356
				$modules = Jetpack::get_available_modules();
357
				sort( $modules );
358
				foreach( $modules as $module_slug ) {
359
					if ( 'vaultpress' == $module_slug ) {
360
						continue;
361
					}
362
					$active = Jetpack::is_module_active( $module_slug ) ? __( 'Active', 'jetpack' ) : __( 'Inactive', 'jetpack' );
363
					WP_CLI::line( "\t" . str_pad( $module_slug, 24 ) . $active );
364
				}
365
				break;
366 View Code Duplication
			case 'activate':
367
				$module = Jetpack::get_module( $module_slug );
0 ignored issues
show
Bug introduced by
The variable $module_slug does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
368
				Jetpack::log( 'activate', $module_slug );
369
				Jetpack::activate_module( $module_slug, false, false );
370
				WP_CLI::success( sprintf( __( '%s has been activated.', 'jetpack' ), $module['name'] ) );
371
				break;
372 View Code Duplication
			case 'activate_all':
373
				$modules = Jetpack::get_available_modules();
374
				Jetpack::update_active_modules( $modules );
375
				WP_CLI::success( __( 'All modules activated!', 'jetpack' ) );
376
				break;
377 View Code Duplication
			case 'deactivate':
378
				$module = Jetpack::get_module( $module_slug );
379
				Jetpack::log( 'deactivate', $module_slug );
380
				Jetpack::deactivate_module( $module_slug );
381
				WP_CLI::success( sprintf( __( '%s has been deactivated.', 'jetpack' ), $module['name'] ) );
382
				break;
383
			case 'deactivate_all':
384
				Jetpack::delete_active_modules();
385
				WP_CLI::success( __( 'All modules deactivated!', 'jetpack' ) );
386
				break;
387
			case 'toggle':
388
				// Will never happen, should have been handled above and changed to activate or deactivate.
389
				break;
390
		}
391
	}
392
393
	/**
394
	 * Manage Protect Settings
395
	 *
396
	 * ## OPTIONS
397
	 *
398
	 * whitelist: Whitelist an IP address.  You can also read or clear the whitelist.
399
	 *
400
	 *
401
	 * ## EXAMPLES
402
	 *
403
	 * wp jetpack protect whitelist <ip address>
404
	 * wp jetpack protect whitelist list
405
	 * wp jetpack protect whitelist clear
406
	 *
407
	 * @synopsis <whitelist> [<ip|ip_low-ip_high|list|clear>]
408
	 */
409
	public function protect( $args, $assoc_args ) {
410
		$action = isset( $args[0] ) ? $args[0] : 'prompt';
411
		if ( ! in_array( $action, array( 'whitelist' ) ) ) {
412
			/* translators: %s is a command like "prompt" */
413
			WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
414
		}
415
		// Check if module is active
416
		if ( ! Jetpack::is_module_active( __FUNCTION__ ) ) {
417
			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__ ) );
418
		}
419
		if ( in_array( $action, array( 'whitelist' ) ) ) {
420
			if ( isset( $args[1] ) ) {
421
				$action = 'whitelist';
422
			} else {
423
				$action = 'prompt';
424
			}
425
		}
426
		switch ( $action ) {
427
			case 'whitelist':
428
				$whitelist         = array();
429
				$new_ip            = $args[1];
430
				$current_whitelist = get_site_option( 'jetpack_protect_whitelist', array() );
431
432
				// Build array of IPs that are already whitelisted.
433
				// Re-build manually instead of using jetpack_protect_format_whitelist() so we can easily get
434
				// low & high range params for jetpack_protect_ip_address_is_in_range();
435
				foreach( $current_whitelist as $whitelisted ) {
436
437
					// IP ranges
438
					if ( $whitelisted->range ) {
439
440
						// Is it already whitelisted?
441
						if ( jetpack_protect_ip_address_is_in_range( $new_ip, $whitelisted->range_low, $whitelisted->range_high ) ) {
442
							/* translators: %s is an IP address */
443
							WP_CLI::error( sprintf( __( '%s has already been whitelisted', 'jetpack' ), $new_ip ) );
444
							break;
445
						}
446
						$whitelist[] = $whitelisted->range_low . " - " . $whitelisted->range_high;
447
448
					} else { // Individual IPs
449
450
						// Check if the IP is already whitelisted (single IP only)
451
						if ( $new_ip == $whitelisted->ip_address ) {
452
							/* translators: %s is an IP address */
453
							WP_CLI::error( sprintf( __( '%s has already been whitelisted', 'jetpack' ), $new_ip ) );
454
							break;
455
						}
456
						$whitelist[] = $whitelisted->ip_address;
457
458
					}
459
				}
460
461
				/*
462
				 * List the whitelist
463
				 * Done here because it's easier to read the $whitelist array after it's been rebuilt
464
				 */
465
				if ( isset( $args[1] ) && 'list' == $args[1] ) {
466
					if ( ! empty( $whitelist ) ) {
467
						WP_CLI::success( __( 'Here are your whitelisted IPs:', 'jetpack' ) );
468
						foreach ( $whitelist as $ip ) {
469
							WP_CLI::line( "\t" . str_pad( $ip, 24 ) ) ;
470
						}
471
					} else {
472
						WP_CLI::line( __( 'Whitelist is empty.', "jetpack" ) ) ;
473
					}
474
					break;
475
				}
476
477
				/*
478
				 * Clear the whitelist
479
				 */
480
				if ( isset( $args[1] ) && 'clear' == $args[1] ) {
481 View Code Duplication
					if ( ! empty( $whitelist ) ) {
482
						$whitelist = array();
483
						jetpack_protect_save_whitelist( $whitelist );
484
						WP_CLI::success( __( 'Cleared all whitelisted IPs', 'jetpack' ) );
485
					} else {
486
						WP_CLI::line( __( 'Whitelist is empty.', "jetpack" ) ) ;
487
					}
488
					break;
489
				}
490
491
				// Append new IP to whitelist array
492
				array_push( $whitelist, $new_ip );
493
494
				// Save whitelist if there are no errors
495
				$result = jetpack_protect_save_whitelist( $whitelist );
496
				if ( is_wp_error( $result ) ) {
497
					WP_CLI::error( __( $result, 'jetpack' ) );
498
				}
499
500
				/* translators: %s is an IP address */
501
				WP_CLI::success( sprintf( __( '%s has been whitelisted.', 'jetpack' ), $new_ip ) );
502
				break;
503
			case 'prompt':
504
				WP_CLI::error(
505
					__( 'No command found.', 'jetpack' ) . "\n" .
506
					__( 'Please enter the IP address you want to whitelist.', 'jetpack' ) . "\n" .
507
					_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" .
508
					_x( "You can also 'list' or 'clear' the whitelist.", "'list' and 'clear' are commands and should not be translated", 'jetpack' ) . "\n"
509
				);
510
				break;
511
		}
512
	}
513
514
	/**
515
	 * Manage Jetpack Options
516
	 *
517
	 * ## OPTIONS
518
	 *
519
	 * list   : List all jetpack options and their values
520
	 * delete : Delete an option
521
	 *          - can only delete options that are white listed.
522
	 * update : update an option
523
	 *          - can only update option strings
524
	 * get    : get the value of an option
525
	 *
526
	 * ## EXAMPLES
527
	 *
528
	 * wp jetpack options list
529
	 * wp jetpack options get    <option_name>
530
	 * wp jetpack options delete <option_name>
531
	 * wp jetpack options update <option_name> [<option_value>]
532
	 *
533
	 * @synopsis <list|get|delete|update> [<option_name>] [<option_value>]
534
	 */
535
	public function options( $args, $assoc_args ) {
536
		$action = isset( $args[0] ) ? $args[0] : 'list';
537
		$safe_to_modify = Jetpack_Options::get_options_for_reset();
538
539
		// Jumpstart is special
540
		array_push( $safe_to_modify, 'jumpstart' );
541
542
		// Is the option flagged as unsafe?
543
		$flagged = ! in_array( $args[1], $safe_to_modify );
544
545 View Code Duplication
		if ( ! in_array( $action, array( 'list', 'get', 'delete', 'update' ) ) ) {
546
			/* translators: %s is a command like "prompt" */
547
			WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
548
		}
549
550
		if ( isset( $args[0] ) ) {
551
			if ( 'get' == $args[0] && isset( $args[1] ) ) {
552
				$action = 'get';
553
			} else if ( 'delete' == $args[0] && isset( $args[1] ) ) {
554
				$action = 'delete';
555 View Code Duplication
			} else if ( 'update' == $args[0] && isset( $args[1] ) ) {
556
				$action = 'update';
557
			} else {
558
				$action = 'list';
559
			}
560
		}
561
562
		// Bail if the option isn't found
563
		$option = isset( $args[1] ) ? Jetpack_Options::get_option( $args[1] ) : false;
564 View Code Duplication
		if ( isset( $args[1] ) && ! $option && 'update' !== $args[0] ) {
565
			WP_CLI::error( __( 'Option not found or is empty.  Use "list" to list option names', 'jetpack' ) );
566
		}
567
568
		// Let's print_r the option if it's an array
569
		// Used in the 'get' and 'list' actions
570
		$option = is_array( $option ) ? print_r( $option ) : $option;
571
572
		switch ( $action ) {
573
			case 'get':
574
				WP_CLI::success( "\t" . $option );
575
				break;
576
			case 'delete':
577
				jetpack_cli_are_you_sure( $flagged );
578
579
				Jetpack_Options::delete_option( $args[1] );
580
				WP_CLI::success( sprintf( __( 'Deleted option: %s', 'jetpack' ), $args[1] ) );
581
				break;
582
			case 'update':
583
				jetpack_cli_are_you_sure( $flagged );
584
585
				// Updating arrays would get pretty tricky...
586
				$value = Jetpack_Options::get_option( $args[1] );
587
				if ( $value && is_array( $value ) ) {
588
					WP_CLI::error( __( 'Sorry, no updating arrays at this time', 'jetpack' ) );
589
				}
590
591
				Jetpack_Options::update_option( $args[1], $args[2] );
592
				WP_CLI::success( sprintf( _x( 'Updated option: %s to "%s"', 'Updating an option from "this" to "that".', 'jetpack' ), $args[1], $args[2] ) );
593
				break;
594
			case 'list':
595
				$options_compact     = Jetpack_Options::get_option_names();
596
				$options_non_compact = Jetpack_Options::get_option_names( 'non_compact' );
597
				$options_private     = Jetpack_Options::get_option_names( 'private' );
598
				$options             = array_merge( $options_compact, $options_non_compact, $options_private );
599
600
				// Table headers
601
				WP_CLI::line( "\t" . str_pad( __( 'Option', 'jetpack' ), 30 ) . __( 'Value', 'jetpack' ) );
602
603
				// List out the options and their values
604
				// Tell them if the value is empty or not
605
				// Tell them if it's an array
606
				foreach ( $options as $option ) {
607
					$value = Jetpack_Options::get_option( $option );
608
					if ( ! $value ) {
609
						WP_CLI::line( "\t" . str_pad( $option, 30 ) . 'Empty' );
610
						continue;
611
					}
612
613
					if ( ! is_array( $value ) ) {
614
						WP_CLI::line( "\t" . str_pad( $option, 30 ) . $value );
615
					} else if ( is_array( $value ) ) {
616
						WP_CLI::line( "\t" . str_pad( $option, 30 ) . 'Array - Use "get <option>" to read option array.' );
617
					}
618
				}
619
				$option_text = '{' . _x( 'option', 'a variable command that a user can write, provided in the printed instructions', 'jetpack' ) . '}';
620
				$value_text  = '{' . _x( 'value', 'the value that they want to update the option to', 'jetpack' ) . '}';
621
622
				WP_CLI::success(
623
					_x( "Above are your options. You may 'get', 'delete', and 'update' them.", "'get', 'delete', and 'update' are commands - do not translate.", 'jetpack' ) . "\n" .
624
					str_pad( 'wp jetpack options get', 26 )    . $option_text . "\n" .
625
					str_pad( 'wp jetpack options delete', 26 ) . $option_text . "\n" .
626
					str_pad( 'wp jetpack options update', 26 ) . "$option_text $value_text" . "\n" .
627
					_x( "Type 'wp jetpack options' for more info.", "'wp jetpack options' is a command - do not translate.", 'jetpack' ) . "\n"
628
				);
629
				break;
630
		}
631
	}
632
633
	/**
634
	 * Get the status of or start a new Jetpack sync.
635
	 *
636
	 * ## OPTIONS
637
	 *
638
	 * status : Print the current sync status
639
	 * start  : Start a full sync from this site to WordPress.com
640
	 *
641
	 * ## EXAMPLES
642
	 *
643
	 * wp jetpack sync status
644
	 * wp jetpack sync start --modules=functions --sync_wait_time=5
645
	 *
646
	 * @synopsis <status|start> [--<field>=<value>]
647
	 */
648
	public function sync( $args, $assoc_args ) {
649
		if ( ! Jetpack_Sync_Actions::sync_allowed() ) {
650
			WP_CLI::error( __( 'Jetpack sync is not currently allowed for this site.', 'jetpack' ) );
651
		}
652
653
		$action = isset( $args[0] ) ? $args[0] : 'status';
654
655
		switch ( $action ) {
656
			case 'status':
657
				$status = Jetpack_Sync_Actions::get_sync_status();
658
				$collection = array();
659
				foreach ( $status as $key => $item ) {
660
					$collection[]  = array(
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 2 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
661
						'option' => $key,
662
						'value' => is_scalar( $item ) ? $item : json_encode( $item )
663
					);
664
				}
665
666
				WP_CLI\Utils\format_items( 'table', $collection, array( 'option', 'value' ) );
667
				break;
668
			case 'start':
669
				// Get the original settings so that we can restore them later
670
				$original_settings = Jetpack_Sync_Settings::get_settings();
671
672
				// Initialize sync settigns so we can sync as quickly as possible
673
				$sync_settings = wp_parse_args(
674
					array_intersect_key( $assoc_args, Jetpack_Sync_Settings::$valid_settings ),
0 ignored issues
show
Bug introduced by
The property valid_settings cannot be accessed from this context as it is declared private in class Jetpack_Sync_Settings.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
675
					array(
676
						'sync_wait_time' => 0,
677
						'enqueue_wait_time' => 0,
678
						'queue_max_writes_sec' => 10000,
679
						'max_queue_size_full_sync' => 100000
680
					)
681
				);
682
				Jetpack_Sync_Settings::update_settings( $sync_settings );
683
684
				// Convert comma-delimited string of modules to an array
685 View Code Duplication
				if ( ! empty( $assoc_args['modules'] ) ) {
686
					$modules = array_map( 'trim', explode( ',', $assoc_args['modules'] ) );
687
688
					// Convert the array so that the keys are the module name and the value is true to indicate
689
					// that we want to sync the module
690
					$modules = array_map( '__return_true', array_flip( $modules ) );
691
				}
692
693 View Code Duplication
				foreach ( array( 'posts', 'comments', 'users' ) as $module_name ) {
694
					if (
695
						'users' === $module_name &&
696
						isset( $assoc_args[ $module_name ] ) &&
697
						'initial' === $assoc_args[ $module_name ]
698
					) {
699
						$modules[ 'users' ] = 'initial';
0 ignored issues
show
Bug introduced by
The variable $modules does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
700
					} elseif ( isset( $assoc_args[ $module_name ] ) ) {
701
						$ids = explode( ',', $assoc_args[ $module_name ] );
702
						if ( count( $ids ) > 0 ) {
703
							$modules[ $module_name ] = $ids;
704
						}
705
					}
706
				}
707
708
				if ( empty( $modules ) ) {
709
					$modules = null;
710
				}
711
712
				// Kick off a full sync
713
				if ( Jetpack_Sync_Actions::do_full_sync( $modules ) ) {
714 View Code Duplication
					if ( $modules ) {
715
						WP_CLI::log( sprintf( __( 'Initialized a new full sync with modules: %s', 'jetpack' ), join( ', ', array_keys( $modules ) ) ) );
716
					} else {
717
						WP_CLI::log( __( 'Initialized a new full sync', 'jetpack' ) );
718
					}
719 View Code Duplication
				} else {
720
721
					// Reset sync settings to original.
722
					Jetpack_Sync_Settings::update_settings( $original_settings );
723
724
					if ( $modules ) {
725
						WP_CLI::error( sprintf( __( 'Could not start a new full sync with modules: %s', 'jetpack' ), join( ', ', $modules ) ) );
726
					} else {
727
						WP_CLI::error( __( 'Could not start a new full sync', 'jetpack' ) );
728
					}
729
				}
730
731
				// Keep sending to WPCOM until there's nothing to send
732
				$i = 1;
733
				do {
734
					$result = Jetpack_Sync_Actions::$sender->do_full_sync();
0 ignored issues
show
Bug introduced by
The property sender cannot be accessed from this context as it is declared private in class Jetpack_Sync_Actions.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
735
					if ( is_wp_error( $result ) ) {
736
						$queue_empty_error = ( 'empty_queue_full_sync' == $result->get_error_code() );
737
						if ( ! $queue_empty_error || ( $queue_empty_error && ( 1 == $i ) ) ) {
738
							WP_CLI::error( sprintf( __( 'Sync errored with code: %s', 'jetpack' ), $result->get_error_code() ) );
739
						}
740
					} else {
741
						if ( 1 == $i ) {
742
							WP_CLI::log( __( 'Sent data to WordPress.com', 'jetpack' ) );
743
						} else {
744
							WP_CLI::log( __( 'Sent more data to WordPress.com', 'jetpack' ) );
745
						}
746
					}
747
					$i++;
748
				} while ( $result && ! is_wp_error( $result ) );
749
750
				// Reset sync settings to original.
751
				Jetpack_Sync_Settings::update_settings( $original_settings );
752
753
				WP_CLI::success( __( 'Finished syncing to WordPress.com', 'jetpack' ) );
754
				break;
755
		}
756
	}
757
758
	/**
759
	 * List the contents of a specific Jetpack sync queue.
760
	 *
761
	 * ## OPTIONS
762
	 *
763
	 * peek : List the 100 front-most items on the queue.
764
	 *
765
	 * ## EXAMPLES
766
	 *
767
	 * wp jetpack sync_queue full_sync peek
768
	 *
769
	 * @synopsis <incremental|full_sync> <peek>
770
	 */
771
	public function sync_queue( $args, $assoc_args ) {
772
		if ( ! Jetpack_Sync_Actions::sync_allowed() ) {
773
			WP_CLI::error( __( 'Jetpack sync is not currently allowed for this site.', 'jetpack' ) );
774
		}
775
776
		$queue_name = isset( $args[0] ) ? $args[0] : 'sync';
777
		$action = isset( $args[1] ) ? $args[1] : 'peek';
778
779
		// We map the queue name that way we can support more friendly queue names in the commands, but still use
780
		// the queue name that the code expects.
781
		$queue_name_map = $allowed_queues = array(
0 ignored issues
show
Unused Code introduced by
$allowed_queues is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
782
			'incremental' => 'sync',
783
			'full'        => 'full_sync',
784
		);
785
		$mapped_queue_name = isset( $queue_name_map[ $queue_name ] ) ? $queue_name_map[ $queue_name ] : $queue_name;
786
787
		switch( $action ) {
788
			case 'peek':
789
				require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-queue.php';
790
				$queue = new Jetpack_Sync_Queue( $mapped_queue_name );
791
				$items = $queue->peek( 100 );
792
793
				if ( empty( $items ) ) {
794
					/* translators: %s is the name of the queue, either 'incremental' or 'full' */
795
					WP_CLI::log( sprintf( __( 'Nothing is in the queue: %s', 'jetpack' ), $queue_name  ) );
796
				} else {
797
					$collection = array();
798
					foreach ( $items as $item ) {
799
						$collection[] = array(
800
							'action'          => $item[0],
801
							'args'            => json_encode( $item[1] ),
802
							'current_user_id' => $item[2],
803
							'microtime'       => $item[3],
804
							'importing'       => (string) $item[4],
805
						);
806
					}
807
					WP_CLI\Utils\format_items(
808
						'table',
809
						$collection,
810
						array(
811
							'action',
812
							'args',
813
							'current_user_id',
814
							'microtime',
815
							'importing',
816
						)
817
					);
818
				}
819
				break;
820
		}
821
	}
822
823
	/**
824
	 * Cancel's the current Jetpack plan granted by this partner, if applicable
825
	 *
826
	 * Returns success or error JSON
827
	 *
828
	 * <token_json>
829
	 * : JSON blob of WPCOM API token
830
	 */
831
	public function partner_cancel( $args, $named_args ) {
832
		list( $token_json ) = $args;
833
834 View Code Duplication
		if ( ! $token_json || ! ( $token = json_decode( $token_json ) ) ) {
835
			$this->partner_provision_error( new WP_Error( 'missing_access_token',  sprintf( __( 'Invalid token JSON: %s', 'jetpack' ), $token_json ) ) );
836
		}
837
838
		if ( isset( $token->error ) ) {
839
			$this->partner_provision_error( new WP_Error( $token->error, $token->message ) );
0 ignored issues
show
Bug introduced by
The variable $token does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
840
		}
841
842
		if ( ! isset( $token->access_token ) ) {
843
			$this->partner_provision_error( new WP_Error( 'missing_access_token', __( 'Missing or invalid access token', 'jetpack' ) ) );
844
		}
845
846
		$site_identifier = Jetpack_Options::get_option( 'id' );
847
848
		if ( ! $site_identifier ) {
849
			$site_identifier = Jetpack::build_raw_urls( get_home_url() );
850
		}
851
852
		$request = array(
853
			'headers' => array(
854
				'Authorization' => "Bearer " . $token->access_token,
855
				'Host'          => defined( 'JETPACK__WPCOM_JSON_API_HOST_HEADER' ) ? JETPACK__WPCOM_JSON_API_HOST_HEADER : 'public-api.wordpress.com',
856
			),
857
			'timeout' => 60,
858
			'method'  => 'POST',
859
		);
860
861
		$url = sprintf( 'https://%s/rest/v1.3/jpphp/%s/partner-cancel', $this->get_api_host(), $site_identifier );
862
863
		$result = Jetpack_Client::_wp_remote_request( $url, $request );
864
865
		Jetpack_Options::delete_option( 'onboarding' );
866
867
		if ( is_wp_error( $result ) ) {
868
			$this->partner_provision_error( $result );
869
		}
870
871
		WP_CLI::log( wp_remote_retrieve_body( $result ) );
872
	}
873
874
	/**
875
	 * Provision a site using a Jetpack Partner license
876
	 *
877
	 * Returns JSON blob
878
	 *
879
	 * ## OPTIONS
880
	 *
881
	 * <token_json>
882
	 * : JSON blob of WPCOM API token
883
	 * --user_id=<user_id>
884
	 * : Local ID of user to connect as (if omitted, user will be required to redirect via wp-admin)
885
	 * [--plan=<plan_name>]
886
	 * : Slug of the requested plan, e.g. premium
887
	 * [--wpcom_user_id=<user_id>]
888
	 * : WordPress.com ID of user to connect as (must be whitelisted against partner key)
889
	 * [--onboarding=<onboarding>]
890
	 * : Guide the user through an onboarding wizard
891
	 * [--force_register=<register>]
892
	 * : Whether to force a site to register
893
	 * [--force_connect=<force_connect>]
894
	 * : Force JPS to not reuse existing credentials
895
	 * [--home_url=<home_url>]
896
	 * : Overrides the home option via the home_url filter, or the WP_HOME constant
897
	 * [--site_url=<site_url>]
898
	 * : Overrides the siteurl option via the site_url filter, or the WP_SITEURL constant
899
	 *
900
	 * ## EXAMPLES
901
	 *
902
	 *     $ wp jetpack partner_provision '{ some: "json" }' premium 1
903
	 *     { success: true }
904
	 *
905
	 * @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>]
906
	 */
907
	public function partner_provision( $args, $named_args ) {
908
		list( $token_json ) = $args;
909
910 View Code Duplication
		if ( ! $token_json || ! ( $token = json_decode( $token_json ) ) ) {
911
			$this->partner_provision_error( new WP_Error( 'missing_access_token',  sprintf( __( 'Invalid token JSON: %s', 'jetpack' ), $token_json ) ) );
912
		}
913
914
		if ( isset( $token->error ) ) {
915
			$message = isset( $token->message )
0 ignored issues
show
Bug introduced by
The variable $token does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
916
				? $token->message
917
				: '';
918
			$this->partner_provision_error( new WP_Error( $token->error, $message ) );
919
		}
920
921
		if ( ! isset( $token->access_token ) ) {
922
			$this->partner_provision_error( new WP_Error( 'missing_access_token', __( 'Missing or invalid access token', 'jetpack' ) ) );
923
		}
924
925
		$url_args = array(
926
			'home_url' => 'WP_HOME',
927
			'site_url' => 'WP_SITEURL',
928
		);
929
930
		foreach ( $url_args as $url_arg => $constant_name ) {
931
			// Anonymous functions were introduced in 5.3.0. So, if we're running on
932
			// >= 5.3.0, use an anonymous function to set the home/siteurl values.
933
			//
934
			// Otherwise, fallback to setting the home/siteurl value via the WP_HOME and
935
			// WP_SITEURL constants if the constant hasn't already been defined.
936
			if ( isset( $named_args[ $url_arg ] ) ) {
937
				if ( version_compare( phpversion(), '5.3.0', '>=') ) {
938
					add_filter( $url_arg, function( $url ) use ( $url_arg, $named_args ) {
939
						return $named_args[ $url_arg ];
940
					}, 11 );
941
				} else if ( ! defined( $constant_name ) ) {
942
					define( $constant_name, $named_args[ $url_arg ] );
943
				}
944
			}
945
		}
946
947
		$blog_id    = Jetpack_Options::get_option( 'id' );
948
		$blog_token = Jetpack_Options::get_option( 'blog_token' );
949
950
		if ( ! $blog_id || ! $blog_token || ( isset( $named_args['force_register'] ) && intval( $named_args['force_register'] ) ) ) {
951
			// this code mostly copied from Jetpack::admin_page_load
952
			Jetpack::maybe_set_version_option();
953
			$registered = Jetpack::try_registration();
954
			if ( is_wp_error( $registered ) ) {
955
				$this->partner_provision_error( $registered );
956
			} elseif ( ! $registered ) {
957
				$this->partner_provision_error( new WP_Error( 'registration_error', __( 'There was an unspecified error registering the site', 'jetpack' ) ) );
958
			}
959
960
			$blog_id    = Jetpack_Options::get_option( 'id' );
961
			$blog_token = Jetpack_Options::get_option( 'blog_token' );
0 ignored issues
show
Unused Code introduced by
$blog_token is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
962
		}
963
964
		// if the user isn't specified, but we have a current master user, then set that to current user
965
		if ( ! get_current_user_id() && $master_user_id = Jetpack_Options::get_option( 'master_user' ) ) {
966
			wp_set_current_user( $master_user_id );
967
		}
968
969
		$site_icon = ( function_exists( 'has_site_icon') && has_site_icon() )
970
			? get_site_icon_url()
971
			: false;
972
973
		$auto_enable_sso = ( ! Jetpack::is_active() || Jetpack::is_module_active( 'sso' ) );
974
975
		/** This filter is documented in class.jetpack-cli.php */
976
		if ( apply_filters( 'jetpack_start_enable_sso', $auto_enable_sso ) ) {
977
			$redirect_uri = add_query_arg(
978
				array( 'action' => 'jetpack-sso', 'redirect_to' => urlencode( admin_url() ) ),
979
				wp_login_url() // TODO: come back to Jetpack dashboard?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
980
			);
981
		} else {
982
			$redirect_uri = admin_url();
983
		}
984
985
		$request_body = array(
986
			'jp_version'    => JETPACK__VERSION,
987
			'redirect_uri'  => $redirect_uri
988
		);
989
990
		if ( $site_icon ) {
991
			$request_body['site_icon'] = $site_icon;
992
		}
993
994
		if ( get_current_user_id() ) {
995
			$user = wp_get_current_user();
996
997
			// role
998
			$role = Jetpack::translate_current_user_to_role();
999
			$signed_role = Jetpack::sign_role( $role );
1000
1001
			$secrets = Jetpack::init()->generate_secrets( 'authorize' );
1002
1003
			// Jetpack auth stuff
1004
			$request_body['scope']  = $signed_role;
1005
			$request_body['secret'] = $secrets['secret_1'];
1006
1007
			// User stuff
1008
			$request_body['user_id']    = $user->ID;
1009
			$request_body['user_email'] = $user->user_email;
1010
			$request_body['user_login'] = $user->user_login;
1011
		}
1012
1013
		// optional additional params
1014 View Code Duplication
		if ( isset( $named_args['wpcom_user_id'] ) && ! empty( $named_args['wpcom_user_id'] ) ) {
1015
			$request_body['wpcom_user_id'] = $named_args['wpcom_user_id'];
1016
		}
1017
1018 View Code Duplication
		if ( isset( $named_args['plan'] ) && ! empty( $named_args['plan'] ) ) {
1019
			$request_body['plan'] = $named_args['plan'];
1020
		}
1021
1022 View Code Duplication
		if ( isset( $named_args['onboarding'] ) && ! empty( $named_args['onboarding'] ) ) {
1023
			$request_body['onboarding'] = intval( $named_args['onboarding'] );
1024
		}
1025
1026 View Code Duplication
		if ( isset( $named_args['force_connect'] ) && ! empty( $named_args['force_connect'] ) ) {
1027
			$request_body['force_connect'] = intval( $named_args['force_connect'] );
1028
		}
1029
1030
		if ( isset( $request_body['onboarding'] ) && (bool) $request_body['onboarding'] ) {
1031
			Jetpack::create_onboarding_token();
1032
		}
1033
1034
		$request = array(
1035
			'headers' => array(
1036
				'Authorization' => "Bearer " . $token->access_token,
1037
				'Host'          => defined( 'JETPACK__WPCOM_JSON_API_HOST_HEADER' ) ? JETPACK__WPCOM_JSON_API_HOST_HEADER : 'public-api.wordpress.com',
1038
			),
1039
			'timeout' => 60,
1040
			'method'  => 'POST',
1041
			'body'    => json_encode( $request_body )
1042
		);
1043
1044
		$url = sprintf( 'https://%s/rest/v1.3/jpphp/%d/partner-provision', $this->get_api_host(), $blog_id );
1045
1046
		// add calypso env if set
1047
		if ( getenv( 'CALYPSO_ENV' ) ) {
1048
			$url = add_query_arg( array( 'calypso_env' => getenv( 'CALYPSO_ENV' ) ), $url );
1049
		}
1050
1051
		$result = Jetpack_Client::_wp_remote_request( $url, $request );
1052
1053
		if ( is_wp_error( $result ) ) {
1054
			$this->partner_provision_error( $result );
1055
		}
1056
1057
		$response_code = wp_remote_retrieve_response_code( $result );
1058
		$body_json     = json_decode( wp_remote_retrieve_body( $result ) );
1059
1060
		if( 200 !== $response_code ) {
1061
			if ( isset( $body_json->error ) ) {
1062
				$this->partner_provision_error( new WP_Error( $body_json->error, $body_json->message ) );
1063
			} else {
1064
				$this->partner_provision_error( new WP_Error( 'server_error', sprintf( __( "Request failed with code %s" ), $response_code ) ) );
1065
			}
1066
		}
1067
1068
		if ( isset( $body_json->access_token ) ) {
1069
			// authorize user and enable SSO
1070
			Jetpack::update_user_token( $user->ID, sprintf( '%s.%d', $body_json->access_token, $user->ID ), true );
0 ignored issues
show
Bug introduced by
The variable $user does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1071
1072
			/**
1073
			 * Auto-enable SSO module for new Jetpack Start connections
1074
			 *
1075
			 * @since 5.0.0
1076
			 *
1077
			 * @param bool $enable_sso Whether to enable the SSO module. Default to true.
1078
			 */
1079
			$other_modules = apply_filters( 'jetpack_start_enable_sso', true )
1080
				? array( 'sso' )
1081
				: array();
1082
1083 View Code Duplication
			if ( $active_modules = Jetpack_Options::get_option( 'active_modules' ) ) {
1084
				Jetpack::delete_active_modules();
1085
				Jetpack::activate_default_modules( 999, 1, array_merge( $active_modules, $other_modules ), false );
0 ignored issues
show
Documentation introduced by
999 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1086
			} else {
1087
				Jetpack::activate_default_modules( false, false, $other_modules, false );
1088
			}
1089
		}
1090
1091
		WP_CLI::log( json_encode( $body_json ) );
1092
	}
1093
1094
	/**
1095
	 * Manages your Jetpack sitemap
1096
	 *
1097
	 * ## OPTIONS
1098
	 *
1099
	 * rebuild : Rebuild all sitemaps
1100
	 * --purge : if set, will remove all existing sitemap data before rebuilding
1101
	 *
1102
	 * ## EXAMPLES
1103
	 *
1104
	 * wp jetpack sitemap rebuild
1105
	 *
1106
	 * @subcommand sitemap
1107
	 * @synopsis <rebuild> [--purge]
1108
	 */
1109
	public function sitemap( $args, $assoc_args ) {
1110
		if ( ! Jetpack::is_active() ) {
1111
			WP_CLI::error( __( 'Jetpack is not currently connected to WordPress.com', 'jetpack' ) );
1112
		}
1113
		if ( ! Jetpack::is_module_active( 'sitemaps' ) ) {
1114
			WP_CLI::error( __( 'Jetpack Sitemaps module is not currently active. Activate it first if you want to work with sitemaps.', 'jetpack' ) );
1115
		}
1116
		if ( ! class_exists( 'Jetpack_Sitemap_Builder' ) ) {
1117
			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' ) );
1118
		}
1119
1120
		if ( isset( $assoc_args['purge'] ) && $assoc_args['purge'] ) {
1121
			$librarian = new Jetpack_Sitemap_Librarian();
1122
			$librarian->delete_all_stored_sitemap_data();
1123
		}
1124
1125
		$sitemap_builder = new Jetpack_Sitemap_Builder();
1126
		$sitemap_builder->update_sitemap();
1127
	}
1128
1129
	private function get_api_host() {
1130
		$env_api_host = getenv( 'JETPACK_START_API_HOST', true );
1131
		return $env_api_host ? $env_api_host : JETPACK__WPCOM_JSON_API_HOST;
1132
	}
1133
1134
	private function partner_provision_error( $error ) {
1135
		WP_CLI::log( json_encode( array(
1136
			'success'       => false,
1137
			'error_code'    => $error->get_error_code(),
1138
			'error_message' => $error->get_error_message()
1139
		) ) );
1140
		exit( 1 );
0 ignored issues
show
Coding Style Compatibility introduced by
The method partner_provision_error() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1141
	}
1142
}
1143
1144
/*
1145
 * Standard "ask for permission to continue" function.
1146
 * If action cancelled, ask if they need help.
1147
 *
1148
 * Written outside of the class so it's not listed as an executable command w/ 'wp jetpack'
1149
 *
1150
 * @param $flagged   bool   false = normal option | true = flagged by get_jetpack_options_for_reset()
1151
 * @param $error_msg string (optional)
1152
 */
1153
function jetpack_cli_are_you_sure( $flagged = false, $error_msg = false ) {
1154
	$cli = new Jetpack_CLI();
1155
1156
	// Default cancellation message
1157
	if ( ! $error_msg ) {
1158
		$error_msg =
1159
			__( 'Action cancelled. Have a question?', 'jetpack' )
1160
			. ' '
1161
			. $cli->green_open
1162
			. 'jetpack.com/support'
1163
			.  $cli->color_close;
1164
	}
1165
1166
	if ( ! $flagged ) {
1167
		$prompt_message = __( 'Are you sure? This cannot be undone. Type "yes" to continue:', '"yes" is a command.  Do not translate that.', 'jetpack' );
1168
	} else {
1169
		/* translators: Don't translate the word yes here. */
1170
		$prompt_message = __( 'Are you sure? Modifying this option may disrupt your Jetpack connection.  Type "yes" to continue.', 'jetpack' );
1171
	}
1172
1173
	WP_CLI::line( $prompt_message );
1174
	$handle = fopen( "php://stdin", "r" );
1175
	$line = fgets( $handle );
1176
	if ( 'yes' != trim( $line ) ){
1177
		WP_CLI::error( $error_msg );
1178
	}
1179
}
1180