PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 6.0.4
Jetpack – WP Security, Backup, Speed, & Growth v6.0.4
15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / class.jetpack-cli.php
jetpack Last commit date
3rd-party 8 years ago _inc 1 year ago bin 8 years ago css 8 years ago images 1 year ago json-endpoints 3 years ago languages 8 years ago modules 1 year ago sal 8 years ago scss 8 years ago sync 8 years ago views 8 years ago .svnignore 12 years ago CODE-OF-CONDUCT.md 9 years ago changelog.txt 8 years ago class.frame-nonce-preview.php 9 years ago class.jetpack-admin.php 8 years ago class.jetpack-autoupdate.php 9 years ago class.jetpack-bbpress-json-api-compat.php 9 years ago class.jetpack-cli.php 8 years ago class.jetpack-client-server.php 8 years ago class.jetpack-client.php 8 years ago class.jetpack-connection-banner.php 8 years ago class.jetpack-constants.php 8 years ago class.jetpack-data.php 9 years ago class.jetpack-debugger.php 8 years ago class.jetpack-error.php 10 years ago class.jetpack-heartbeat.php 9 years ago class.jetpack-idc.php 8 years ago class.jetpack-ixr-client.php 10 years ago class.jetpack-jitm.php 8 years ago class.jetpack-modules-list-table.php 8 years ago class.jetpack-network-sites-list-table.php 9 years ago class.jetpack-network.php 8 years ago class.jetpack-options.php 8 years ago class.jetpack-post-images.php 8 years ago class.jetpack-signature.php 8 years ago class.jetpack-tracks.php 8 years ago class.jetpack-twitter-cards.php 8 years ago class.jetpack-user-agent.php 8 years ago class.jetpack-xmlrpc-server.php 8 years ago class.jetpack.php 8 years ago class.json-api-endpoints.php 3 years ago class.json-api.php 8 years ago class.photon.php 8 years ago composer.json 8 years ago functions.compat.php 9 years ago functions.gallery.php 8 years ago functions.global.php 8 years ago functions.opengraph.php 8 years ago functions.photon.php 9 years ago jetpack.php 1 year ago json-api-config.php 10 years ago json-endpoints.php 8 years ago locales.php 9 years ago phpcs.xml 8 years ago readme.txt 1 year ago require-lib.php 8 years ago uninstall.php 8 years ago wpml-config.xml 10 years ago
class.jetpack-cli.php
1042 lines
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 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 ) {
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@domain.com
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 );
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 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 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 } else {
345 WP_CLI::line( __( 'Please specify a valid module.', 'jetpack' ) );
346 $action = 'list';
347 }
348 }
349 switch ( $action ) {
350 case 'list':
351 WP_CLI::line( __( 'Available Modules:', 'jetpack' ) );
352 $modules = Jetpack::get_available_modules();
353 sort( $modules );
354 foreach( $modules as $module_slug ) {
355 if ( 'vaultpress' == $module_slug ) {
356 continue;
357 }
358 $active = Jetpack::is_module_active( $module_slug ) ? __( 'Active', 'jetpack' ) : __( 'Inactive', 'jetpack' );
359 WP_CLI::line( "\t" . str_pad( $module_slug, 24 ) . $active );
360 }
361 break;
362 case 'activate':
363 $module = Jetpack::get_module( $module_slug );
364 Jetpack::log( 'activate', $module_slug );
365 if ( Jetpack::activate_module( $module_slug, false, false ) ) {
366 WP_CLI::success( sprintf( __( '%s has been activated.', 'jetpack' ), $module['name'] ) );
367 } else {
368 WP_CLI::error( sprintf( __( '%s could not be activated.', 'jetpack' ), $module['name'] ) );
369 }
370 break;
371 case 'activate_all':
372 $modules = Jetpack::get_available_modules();
373 Jetpack::update_active_modules( $modules );
374 WP_CLI::success( __( 'All modules activated!', 'jetpack' ) );
375 break;
376 case 'deactivate':
377 $module = Jetpack::get_module( $module_slug );
378 Jetpack::log( 'deactivate', $module_slug );
379 Jetpack::deactivate_module( $module_slug );
380 WP_CLI::success( sprintf( __( '%s has been deactivated.', 'jetpack' ), $module['name'] ) );
381 break;
382 case 'deactivate_all':
383 Jetpack::delete_active_modules();
384 WP_CLI::success( __( 'All modules deactivated!', 'jetpack' ) );
385 break;
386 case 'toggle':
387 // Will never happen, should have been handled above and changed to activate or deactivate.
388 break;
389 }
390 }
391
392 /**
393 * Manage Protect Settings
394 *
395 * ## OPTIONS
396 *
397 * whitelist: Whitelist an IP address. You can also read or clear the whitelist.
398 *
399 *
400 * ## EXAMPLES
401 *
402 * wp jetpack protect whitelist <ip address>
403 * wp jetpack protect whitelist list
404 * wp jetpack protect whitelist clear
405 *
406 * @synopsis <whitelist> [<ip|ip_low-ip_high|list|clear>]
407 */
408 public function protect( $args, $assoc_args ) {
409 $action = isset( $args[0] ) ? $args[0] : 'prompt';
410 if ( ! in_array( $action, array( 'whitelist' ) ) ) {
411 /* translators: %s is a command like "prompt" */
412 WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
413 }
414 // Check if module is active
415 if ( ! Jetpack::is_module_active( __FUNCTION__ ) ) {
416 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__ ) );
417 }
418 if ( in_array( $action, array( 'whitelist' ) ) ) {
419 if ( isset( $args[1] ) ) {
420 $action = 'whitelist';
421 } else {
422 $action = 'prompt';
423 }
424 }
425 switch ( $action ) {
426 case 'whitelist':
427 $whitelist = array();
428 $new_ip = $args[1];
429 $current_whitelist = get_site_option( 'jetpack_protect_whitelist', array() );
430
431 // Build array of IPs that are already whitelisted.
432 // Re-build manually instead of using jetpack_protect_format_whitelist() so we can easily get
433 // low & high range params for jetpack_protect_ip_address_is_in_range();
434 foreach( $current_whitelist as $whitelisted ) {
435
436 // IP ranges
437 if ( $whitelisted->range ) {
438
439 // Is it already whitelisted?
440 if ( jetpack_protect_ip_address_is_in_range( $new_ip, $whitelisted->range_low, $whitelisted->range_high ) ) {
441 /* translators: %s is an IP address */
442 WP_CLI::error( sprintf( __( '%s has already been whitelisted', 'jetpack' ), $new_ip ) );
443 break;
444 }
445 $whitelist[] = $whitelisted->range_low . " - " . $whitelisted->range_high;
446
447 } else { // Individual IPs
448
449 // Check if the IP is already whitelisted (single IP only)
450 if ( $new_ip == $whitelisted->ip_address ) {
451 /* translators: %s is an IP address */
452 WP_CLI::error( sprintf( __( '%s has already been whitelisted', 'jetpack' ), $new_ip ) );
453 break;
454 }
455 $whitelist[] = $whitelisted->ip_address;
456
457 }
458 }
459
460 /*
461 * List the whitelist
462 * Done here because it's easier to read the $whitelist array after it's been rebuilt
463 */
464 if ( isset( $args[1] ) && 'list' == $args[1] ) {
465 if ( ! empty( $whitelist ) ) {
466 WP_CLI::success( __( 'Here are your whitelisted IPs:', 'jetpack' ) );
467 foreach ( $whitelist as $ip ) {
468 WP_CLI::line( "\t" . str_pad( $ip, 24 ) ) ;
469 }
470 } else {
471 WP_CLI::line( __( 'Whitelist is empty.', "jetpack" ) ) ;
472 }
473 break;
474 }
475
476 /*
477 * Clear the whitelist
478 */
479 if ( isset( $args[1] ) && 'clear' == $args[1] ) {
480 if ( ! empty( $whitelist ) ) {
481 $whitelist = array();
482 jetpack_protect_save_whitelist( $whitelist );
483 WP_CLI::success( __( 'Cleared all whitelisted IPs', 'jetpack' ) );
484 } else {
485 WP_CLI::line( __( 'Whitelist is empty.', "jetpack" ) ) ;
486 }
487 break;
488 }
489
490 // Append new IP to whitelist array
491 array_push( $whitelist, $new_ip );
492
493 // Save whitelist if there are no errors
494 $result = jetpack_protect_save_whitelist( $whitelist );
495 if ( is_wp_error( $result ) ) {
496 WP_CLI::error( __( $result, 'jetpack' ) );
497 }
498
499 /* translators: %s is an IP address */
500 WP_CLI::success( sprintf( __( '%s has been whitelisted.', 'jetpack' ), $new_ip ) );
501 break;
502 case 'prompt':
503 WP_CLI::error(
504 __( 'No command found.', 'jetpack' ) . "\n" .
505 __( 'Please enter the IP address you want to whitelist.', 'jetpack' ) . "\n" .
506 _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" .
507 _x( "You can also 'list' or 'clear' the whitelist.", "'list' and 'clear' are commands and should not be translated", 'jetpack' ) . "\n"
508 );
509 break;
510 }
511 }
512
513 /**
514 * Manage Jetpack Options
515 *
516 * ## OPTIONS
517 *
518 * list : List all jetpack options and their values
519 * delete : Delete an option
520 * - can only delete options that are white listed.
521 * update : update an option
522 * - can only update option strings
523 * get : get the value of an option
524 *
525 * ## EXAMPLES
526 *
527 * wp jetpack options list
528 * wp jetpack options get <option_name>
529 * wp jetpack options delete <option_name>
530 * wp jetpack options update <option_name> [<option_value>]
531 *
532 * @synopsis <list|get|delete|update> [<option_name>] [<option_value>]
533 */
534 public function options( $args, $assoc_args ) {
535 $action = isset( $args[0] ) ? $args[0] : 'list';
536 $safe_to_modify = Jetpack_Options::get_options_for_reset();
537
538 // Jumpstart is special
539 array_push( $safe_to_modify, 'jumpstart' );
540
541 // Is the option flagged as unsafe?
542 $flagged = ! in_array( $args[1], $safe_to_modify );
543
544 if ( ! in_array( $action, array( 'list', 'get', 'delete', 'update' ) ) ) {
545 /* translators: %s is a command like "prompt" */
546 WP_CLI::error( sprintf( __( '%s is not a valid command.', 'jetpack' ), $action ) );
547 }
548
549 if ( isset( $args[0] ) ) {
550 if ( 'get' == $args[0] && isset( $args[1] ) ) {
551 $action = 'get';
552 } else if ( 'delete' == $args[0] && isset( $args[1] ) ) {
553 $action = 'delete';
554 } else if ( 'update' == $args[0] && isset( $args[1] ) ) {
555 $action = 'update';
556 } else {
557 $action = 'list';
558 }
559 }
560
561 // Bail if the option isn't found
562 $option = isset( $args[1] ) ? Jetpack_Options::get_option( $args[1] ) : false;
563 if ( isset( $args[1] ) && ! $option && 'update' !== $args[0] ) {
564 WP_CLI::error( __( 'Option not found or is empty. Use "list" to list option names', 'jetpack' ) );
565 }
566
567 // Let's print_r the option if it's an array
568 // Used in the 'get' and 'list' actions
569 $option = is_array( $option ) ? print_r( $option ) : $option;
570
571 switch ( $action ) {
572 case 'get':
573 WP_CLI::success( "\t" . $option );
574 break;
575 case 'delete':
576 jetpack_cli_are_you_sure( $flagged );
577
578 Jetpack_Options::delete_option( $args[1] );
579 WP_CLI::success( sprintf( __( 'Deleted option: %s', 'jetpack' ), $args[1] ) );
580 break;
581 case 'update':
582 jetpack_cli_are_you_sure( $flagged );
583
584 // Updating arrays would get pretty tricky...
585 $value = Jetpack_Options::get_option( $args[1] );
586 if ( $value && is_array( $value ) ) {
587 WP_CLI::error( __( 'Sorry, no updating arrays at this time', 'jetpack' ) );
588 }
589
590 Jetpack_Options::update_option( $args[1], $args[2] );
591 WP_CLI::success( sprintf( _x( 'Updated option: %s to "%s"', 'Updating an option from "this" to "that".', 'jetpack' ), $args[1], $args[2] ) );
592 break;
593 case 'list':
594 $options_compact = Jetpack_Options::get_option_names();
595 $options_non_compact = Jetpack_Options::get_option_names( 'non_compact' );
596 $options_private = Jetpack_Options::get_option_names( 'private' );
597 $options = array_merge( $options_compact, $options_non_compact, $options_private );
598
599 // Table headers
600 WP_CLI::line( "\t" . str_pad( __( 'Option', 'jetpack' ), 30 ) . __( 'Value', 'jetpack' ) );
601
602 // List out the options and their values
603 // Tell them if the value is empty or not
604 // Tell them if it's an array
605 foreach ( $options as $option ) {
606 $value = Jetpack_Options::get_option( $option );
607 if ( ! $value ) {
608 WP_CLI::line( "\t" . str_pad( $option, 30 ) . 'Empty' );
609 continue;
610 }
611
612 if ( ! is_array( $value ) ) {
613 WP_CLI::line( "\t" . str_pad( $option, 30 ) . $value );
614 } else if ( is_array( $value ) ) {
615 WP_CLI::line( "\t" . str_pad( $option, 30 ) . 'Array - Use "get <option>" to read option array.' );
616 }
617 }
618 $option_text = '{' . _x( 'option', 'a variable command that a user can write, provided in the printed instructions', 'jetpack' ) . '}';
619 $value_text = '{' . _x( 'value', 'the value that they want to update the option to', 'jetpack' ) . '}';
620
621 WP_CLI::success(
622 _x( "Above are your options. You may 'get', 'delete', and 'update' them.", "'get', 'delete', and 'update' are commands - do not translate.", 'jetpack' ) . "\n" .
623 str_pad( 'wp jetpack options get', 26 ) . $option_text . "\n" .
624 str_pad( 'wp jetpack options delete', 26 ) . $option_text . "\n" .
625 str_pad( 'wp jetpack options update', 26 ) . "$option_text $value_text" . "\n" .
626 _x( "Type 'wp jetpack options' for more info.", "'wp jetpack options' is a command - do not translate.", 'jetpack' ) . "\n"
627 );
628 break;
629 }
630 }
631
632 /**
633 * Get the status of or start a new Jetpack sync.
634 *
635 * ## OPTIONS
636 *
637 * status : Print the current sync status
638 * start : Start a full sync from this site to WordPress.com
639 *
640 * ## EXAMPLES
641 *
642 * wp jetpack sync status
643 * wp jetpack sync start --modules=functions --sync_wait_time=5
644 *
645 * @synopsis <status|start> [--<field>=<value>]
646 */
647 public function sync( $args, $assoc_args ) {
648 if ( ! Jetpack_Sync_Actions::sync_allowed() ) {
649 WP_CLI::error( __( 'Jetpack sync is not currently allowed for this site.', 'jetpack' ) );
650 }
651
652 $action = isset( $args[0] ) ? $args[0] : 'status';
653
654 switch ( $action ) {
655 case 'status':
656 $status = Jetpack_Sync_Actions::get_sync_status();
657 $collection = array();
658 foreach ( $status as $key => $item ) {
659 $collection[] = array(
660 'option' => $key,
661 'value' => is_scalar( $item ) ? $item : json_encode( $item )
662 );
663 }
664
665 WP_CLI\Utils\format_items( 'table', $collection, array( 'option', 'value' ) );
666 break;
667 case 'start':
668 // Get the original settings so that we can restore them later
669 $original_settings = Jetpack_Sync_Settings::get_settings();
670
671 // Initialize sync settigns so we can sync as quickly as possible
672 $sync_settings = wp_parse_args(
673 array_intersect_key( $assoc_args, Jetpack_Sync_Settings::$valid_settings ),
674 array(
675 'sync_wait_time' => 0,
676 'enqueue_wait_time' => 0,
677 'queue_max_writes_sec' => 10000,
678 'max_queue_size_full_sync' => 100000
679 )
680 );
681 Jetpack_Sync_Settings::update_settings( $sync_settings );
682
683 // Convert comma-delimited string of modules to an array
684 if ( ! empty( $assoc_args['modules'] ) ) {
685 $modules = array_map( 'trim', explode( ',', $assoc_args['modules'] ) );
686
687 // Convert the array so that the keys are the module name and the value is true to indicate
688 // that we want to sync the module
689 $modules = array_map( '__return_true', array_flip( $modules ) );
690 }
691
692 foreach ( array( 'posts', 'comments', 'users' ) as $module_name ) {
693 if (
694 'users' === $module_name &&
695 isset( $assoc_args[ $module_name ] ) &&
696 'initial' === $assoc_args[ $module_name ]
697 ) {
698 $modules[ 'users' ] = 'initial';
699 } elseif ( isset( $assoc_args[ $module_name ] ) ) {
700 $ids = explode( ',', $assoc_args[ $module_name ] );
701 if ( count( $ids ) > 0 ) {
702 $modules[ $module_name ] = $ids;
703 }
704 }
705 }
706
707 if ( empty( $modules ) ) {
708 $modules = null;
709 }
710
711 // Kick off a full sync
712 if ( Jetpack_Sync_Actions::do_full_sync( $modules ) ) {
713 if ( $modules ) {
714 WP_CLI::log( sprintf( __( 'Initialized a new full sync with modules: %s', 'jetpack' ), join( ', ', array_keys( $modules ) ) ) );
715 } else {
716 WP_CLI::log( __( 'Initialized a new full sync', 'jetpack' ) );
717 }
718 } else {
719
720 // Reset sync settings to original.
721 Jetpack_Sync_Settings::update_settings( $original_settings );
722
723 if ( $modules ) {
724 WP_CLI::error( sprintf( __( 'Could not start a new full sync with modules: %s', 'jetpack' ), join( ', ', $modules ) ) );
725 } else {
726 WP_CLI::error( __( 'Could not start a new full sync', 'jetpack' ) );
727 }
728 }
729
730 // Keep sending to WPCOM until there's nothing to send
731 $i = 1;
732 do {
733 $result = Jetpack_Sync_Actions::$sender->do_full_sync();
734 if ( is_wp_error( $result ) ) {
735 $queue_empty_error = ( 'empty_queue_full_sync' == $result->get_error_code() );
736 if ( ! $queue_empty_error || ( $queue_empty_error && ( 1 == $i ) ) ) {
737 WP_CLI::error( sprintf( __( 'Sync errored with code: %s', 'jetpack' ), $result->get_error_code() ) );
738 }
739 } else {
740 if ( 1 == $i ) {
741 WP_CLI::log( __( 'Sent data to WordPress.com', 'jetpack' ) );
742 } else {
743 WP_CLI::log( __( 'Sent more data to WordPress.com', 'jetpack' ) );
744 }
745 }
746 $i++;
747 } while ( $result && ! is_wp_error( $result ) );
748
749 // Reset sync settings to original.
750 Jetpack_Sync_Settings::update_settings( $original_settings );
751
752 WP_CLI::success( __( 'Finished syncing to WordPress.com', 'jetpack' ) );
753 break;
754 }
755 }
756
757 /**
758 * List the contents of a specific Jetpack sync queue.
759 *
760 * ## OPTIONS
761 *
762 * peek : List the 100 front-most items on the queue.
763 *
764 * ## EXAMPLES
765 *
766 * wp jetpack sync_queue full_sync peek
767 *
768 * @synopsis <incremental|full_sync> <peek>
769 */
770 public function sync_queue( $args, $assoc_args ) {
771 if ( ! Jetpack_Sync_Actions::sync_allowed() ) {
772 WP_CLI::error( __( 'Jetpack sync is not currently allowed for this site.', 'jetpack' ) );
773 }
774
775 $queue_name = isset( $args[0] ) ? $args[0] : 'sync';
776 $action = isset( $args[1] ) ? $args[1] : 'peek';
777
778 // We map the queue name that way we can support more friendly queue names in the commands, but still use
779 // the queue name that the code expects.
780 $queue_name_map = $allowed_queues = array(
781 'incremental' => 'sync',
782 'full' => 'full_sync',
783 );
784 $mapped_queue_name = isset( $queue_name_map[ $queue_name ] ) ? $queue_name_map[ $queue_name ] : $queue_name;
785
786 switch( $action ) {
787 case 'peek':
788 require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-queue.php';
789 $queue = new Jetpack_Sync_Queue( $mapped_queue_name );
790 $items = $queue->peek( 100 );
791
792 if ( empty( $items ) ) {
793 /* translators: %s is the name of the queue, either 'incremental' or 'full' */
794 WP_CLI::log( sprintf( __( 'Nothing is in the queue: %s', 'jetpack' ), $queue_name ) );
795 } else {
796 $collection = array();
797 foreach ( $items as $item ) {
798 $collection[] = array(
799 'action' => $item[0],
800 'args' => json_encode( $item[1] ),
801 'current_user_id' => $item[2],
802 'microtime' => $item[3],
803 'importing' => (string) $item[4],
804 );
805 }
806 WP_CLI\Utils\format_items(
807 'table',
808 $collection,
809 array(
810 'action',
811 'args',
812 'current_user_id',
813 'microtime',
814 'importing',
815 )
816 );
817 }
818 break;
819 }
820 }
821
822 /**
823 * Cancel's the current Jetpack plan granted by this partner, if applicable
824 *
825 * Returns success or error JSON
826 *
827 * <token_json>
828 * : JSON blob of WPCOM API token
829 * [--partner_tracking_id=<partner_tracking_id>]
830 * : This is an optional ID that a host can pass to help identify a site in logs on WordPress.com
831 *
832 * * @synopsis <token_json> [--partner_tracking_id=<partner_tracking_id>]
833 */
834 public function partner_cancel( $args, $named_args ) {
835 list( $token_json ) = $args;
836
837 if ( ! $token_json || ! ( $token = json_decode( $token_json ) ) ) {
838 $this->partner_provision_error( new WP_Error( 'missing_access_token', sprintf( __( 'Invalid token JSON: %s', 'jetpack' ), $token_json ) ) );
839 }
840
841 if ( isset( $token->error ) ) {
842 $this->partner_provision_error( new WP_Error( $token->error, $token->message ) );
843 }
844
845 if ( ! isset( $token->access_token ) ) {
846 $this->partner_provision_error( new WP_Error( 'missing_access_token', __( 'Missing or invalid access token', 'jetpack' ) ) );
847 }
848
849 if ( Jetpack::validate_sync_error_idc_option() ) {
850 $this->partner_provision_error( new WP_Error(
851 'site_in_safe_mode',
852 esc_html__( 'Can not cancel a plan while in safe mode. See: https://jetpack.com/support/safe-mode/', 'jetpack' )
853 ) );
854 }
855
856 $site_identifier = Jetpack_Options::get_option( 'id' );
857
858 if ( ! $site_identifier ) {
859 $site_identifier = Jetpack::build_raw_urls( get_home_url() );
860 }
861
862 $request = array(
863 'headers' => array(
864 'Authorization' => "Bearer " . $token->access_token,
865 'Host' => defined( 'JETPACK__WPCOM_JSON_API_HOST_HEADER' ) ? JETPACK__WPCOM_JSON_API_HOST_HEADER : 'public-api.wordpress.com',
866 ),
867 'timeout' => 60,
868 'method' => 'POST',
869 );
870
871 $url = sprintf( 'https://%s/rest/v1.3/jpphp/%s/partner-cancel', $this->get_api_host(), $site_identifier );
872 if ( ! empty( $named_args ) && ! empty( $named_args['partner_tracking_id'] ) ) {
873 $url = esc_url_raw( add_query_arg( 'partner_tracking_id', $named_args['partner_tracking_id'], $url ) );
874 }
875
876 $result = Jetpack_Client::_wp_remote_request( $url, $request );
877
878 Jetpack_Options::delete_option( 'onboarding' );
879
880 if ( is_wp_error( $result ) ) {
881 $this->partner_provision_error( $result );
882 }
883
884 WP_CLI::log( wp_remote_retrieve_body( $result ) );
885 }
886
887 /**
888 * Provision a site using a Jetpack Partner license
889 *
890 * Returns JSON blob
891 *
892 * ## OPTIONS
893 *
894 * <token_json>
895 * : JSON blob of WPCOM API token
896 * [--plan=<plan_name>]
897 * : Slug of the requested plan, e.g. premium
898 * [--wpcom_user_id=<user_id>]
899 * : WordPress.com ID of user to connect as (must be whitelisted against partner key)
900 * [--wpcom_user_email=<wpcom_user_email>]
901 * : Override the email we send to WordPress.com for registration
902 * [--onboarding=<onboarding>]
903 * : Guide the user through an onboarding wizard
904 * [--force_register=<register>]
905 * : Whether to force a site to register
906 * [--force_connect=<force_connect>]
907 * : Force JPS to not reuse existing credentials
908 * [--home_url=<home_url>]
909 * : Overrides the home option via the home_url filter, or the WP_HOME constant
910 * [--site_url=<site_url>]
911 * : Overrides the siteurl option via the site_url filter, or the WP_SITEURL constant
912 * [--partner_tracking_id=<partner_tracking_id>]
913 * : This is an optional ID that a host can pass to help identify a site in logs on WordPress.com
914 *
915 * ## EXAMPLES
916 *
917 * $ wp jetpack partner_provision '{ some: "json" }' premium 1
918 * { success: true }
919 *
920 * @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>]
921 */
922 public function partner_provision( $args, $named_args ) {
923 list( $token_json ) = $args;
924
925 if ( ! $token_json || ! ( $token = json_decode( $token_json ) ) ) {
926 $this->partner_provision_error( new WP_Error( 'missing_access_token', sprintf( __( 'Invalid token JSON: %s', 'jetpack' ), $token_json ) ) );
927 }
928
929 if ( isset( $token->error ) ) {
930 $message = isset( $token->message )
931 ? $token->message
932 : '';
933 $this->partner_provision_error( new WP_Error( $token->error, $message ) );
934 }
935
936 if ( ! isset( $token->access_token ) ) {
937 $this->partner_provision_error( new WP_Error( 'missing_access_token', __( 'Missing or invalid access token', 'jetpack' ) ) );
938 }
939
940 require_once JETPACK__PLUGIN_DIR . '_inc/class.jetpack-provision.php';
941
942 $body_json = Jetpack_Provision::partner_provision( $token->access_token, $named_args );
943
944 if ( is_wp_error( $body_json ) ) {
945 error_log( json_encode( array(
946 'success' => false,
947 'error_code' => $body_json->get_error_code(),
948 'error_message' => $body_json->get_error_message()
949 ) ) );
950 exit( 1 );
951 }
952
953 WP_CLI::log( json_encode( $body_json ) );
954 }
955
956 /**
957 * Manages your Jetpack sitemap
958 *
959 * ## OPTIONS
960 *
961 * rebuild : Rebuild all sitemaps
962 * --purge : if set, will remove all existing sitemap data before rebuilding
963 *
964 * ## EXAMPLES
965 *
966 * wp jetpack sitemap rebuild
967 *
968 * @subcommand sitemap
969 * @synopsis <rebuild> [--purge]
970 */
971 public function sitemap( $args, $assoc_args ) {
972 if ( ! Jetpack::is_active() ) {
973 WP_CLI::error( __( 'Jetpack is not currently connected to WordPress.com', 'jetpack' ) );
974 }
975 if ( ! Jetpack::is_module_active( 'sitemaps' ) ) {
976 WP_CLI::error( __( 'Jetpack Sitemaps module is not currently active. Activate it first if you want to work with sitemaps.', 'jetpack' ) );
977 }
978 if ( ! class_exists( 'Jetpack_Sitemap_Builder' ) ) {
979 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' ) );
980 }
981
982 if ( isset( $assoc_args['purge'] ) && $assoc_args['purge'] ) {
983 $librarian = new Jetpack_Sitemap_Librarian();
984 $librarian->delete_all_stored_sitemap_data();
985 }
986
987 $sitemap_builder = new Jetpack_Sitemap_Builder();
988 $sitemap_builder->update_sitemap();
989 }
990
991 private function get_api_host() {
992 $env_api_host = getenv( 'JETPACK_START_API_HOST', true );
993 return $env_api_host ? $env_api_host : JETPACK__WPCOM_JSON_API_HOST;
994 }
995
996 private function partner_provision_error( $error ) {
997 WP_CLI::log( json_encode( array(
998 'success' => false,
999 'error_code' => $error->get_error_code(),
1000 'error_message' => $error->get_error_message()
1001 ) ) );
1002 exit( 1 );
1003 }
1004 }
1005
1006 /*
1007 * Standard "ask for permission to continue" function.
1008 * If action cancelled, ask if they need help.
1009 *
1010 * Written outside of the class so it's not listed as an executable command w/ 'wp jetpack'
1011 *
1012 * @param $flagged bool false = normal option | true = flagged by get_jetpack_options_for_reset()
1013 * @param $error_msg string (optional)
1014 */
1015 function jetpack_cli_are_you_sure( $flagged = false, $error_msg = false ) {
1016 $cli = new Jetpack_CLI();
1017
1018 // Default cancellation message
1019 if ( ! $error_msg ) {
1020 $error_msg =
1021 __( 'Action cancelled. Have a question?', 'jetpack' )
1022 . ' '
1023 . $cli->green_open
1024 . 'jetpack.com/support'
1025 . $cli->color_close;
1026 }
1027
1028 if ( ! $flagged ) {
1029 $prompt_message = __( 'Are you sure? This cannot be undone. Type "yes" to continue:', '"yes" is a command. Do not translate that.', 'jetpack' );
1030 } else {
1031 /* translators: Don't translate the word yes here. */
1032 $prompt_message = __( 'Are you sure? Modifying this option may disrupt your Jetpack connection. Type "yes" to continue.', 'jetpack' );
1033 }
1034
1035 WP_CLI::line( $prompt_message );
1036 $handle = fopen( "php://stdin", "r" );
1037 $line = fgets( $handle );
1038 if ( 'yes' != trim( $line ) ){
1039 WP_CLI::error( $error_msg );
1040 }
1041 }
1042