Completed
Push — add/options-filter ( 4787ea )
by
unknown
50:04 queued 41:20
created

Jetpack_Options::get_option_from_database()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 19

Duplication

Lines 7
Ratio 36.84 %

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 2
dl 7
loc 19
rs 9.3222
c 0
b 0
f 0
1
<?php
2
/**
3
 * Legacy Jetpack_Options class.
4
 *
5
 * @package automattic/jetpack-options
6
 */
7
8
use Automattic\Jetpack\Constants;
9
10
/**
11
 * Class Jetpack_Options
12
 */
13
class Jetpack_Options {
14
15
	/**
16
	 * An array that maps a grouped option type to an option name.
17
	 *
18
	 * @var array
19
	 */
20
	private static $grouped_options = array(
21
		'compact' => 'jetpack_options',
22
		'private' => 'jetpack_private_options',
23
	);
24
25
	/**
26
	 * Returns an array of option names for a given type.
27
	 *
28
	 * @param string $type The type of option to return. Defaults to 'compact'.
29
	 *
30
	 * @return array
31
	 */
32
	public static function get_option_names( $type = 'compact' ) {
33
		switch ( $type ) {
34
			case 'non-compact':
35
			case 'non_compact':
36
				return array(
37
					'activated',
38
					'active_modules',
39
					'allowed_xsite_search_ids', // (array) Array of WP.com blog ids that are allowed to search the content of this site
40
					'available_modules',
41
					'do_activate',
42
					'edit_links_calypso_redirect', // (bool) Whether post/page edit links on front end should point to Calypso.
43
					'log',
44
					'slideshow_background_color',
45
					'widget_twitter',
46
					'wpcc_options',
47
					'relatedposts',
48
					'file_data',
49
					'autoupdate_plugins',          // (array)  An array of plugin ids ( eg. jetpack/jetpack ) that should be autoupdated
50
					'autoupdate_plugins_translations', // (array)  An array of plugin ids ( eg. jetpack/jetpack ) that should be autoupdated translation files.
51
					'autoupdate_themes',           // (array)  An array of theme ids ( eg. twentyfourteen ) that should be autoupdated
52
					'autoupdate_themes_translations', // (array)  An array of theme ids ( eg. twentyfourteen ) that should autoupdated translation files.
53
					'autoupdate_core',             // (bool)   Whether or not to autoupdate core
54
					'autoupdate_translations',     // (bool)   Whether or not to autoupdate all translations
55
					'json_api_full_management',    // (bool)   Allow full management (eg. Activate, Upgrade plugins) of the site via the JSON API.
56
					'sync_non_public_post_stati',  // (bool)   Allow synchronisation of posts and pages with non-public status.
57
					'site_icon_url',               // (string) url to the full site icon
58
					'site_icon_id',                // (int)    Attachment id of the site icon file
59
					'dismissed_manage_banner',     // (bool) Dismiss Jetpack manage banner allows the user to dismiss the banner permanently
60
					'unique_connection',           // (array)  A flag to determine a unique connection to wordpress.com two values "connected" and "disconnected" with values for how many times each has occured
61
					'protect_whitelist',           // (array) IP Address for the Protect module to ignore
62
					'sync_error_idc',              // (bool|array) false or array containing the site's home and siteurl at time of IDC error
63
					'sync_health_status',          // (bool|array) An array of data relating to Jetpack's sync health.
64
					'safe_mode_confirmed',         // (bool) True if someone confirms that this site was correctly put into safe mode automatically after an identity crisis is discovered.
65
					'migrate_for_idc',             // (bool) True if someone confirms that this site should migrate stats and subscribers from its previous URL
66
					'dismissed_connection_banner', // (bool) True if the connection banner has been dismissed
67
					'ab_connect_banner_green_bar', // (int) Version displayed of the A/B test for the green bar at the top of the connect banner.
68
					'onboarding',                  // (string) Auth token to be used in the onboarding connection flow
69
					'tos_agreed',                  // (bool)   Whether or not the TOS for connection has been agreed upon.
70
					'static_asset_cdn_files',      // (array) An nested array of files that we can swap out for cdn versions.
71
					'mapbox_api_key',              // (string) Mapbox API Key, for use with Map block.
72
					'mailchimp',                   // (string) Mailchimp keyring data, for mailchimp block.
73
					'xmlrpc_errors',               // (array) Keys are XML-RPC signature error codes. Values are truthy.
74
					'dismissed_wizard_banner',     // (int) True if the Wizard banner has been dismissed.
75
				);
76
77
			case 'private':
78
				return array(
79
					'blog_token',  // (string) The Client Secret/Blog Token of this site.
80
					'user_token',  // (string) The User Token of this site. (deprecated)
81
					'user_tokens',  // (array)  User Tokens for each user of this site who has connected to jetpack.wordpress.com.
82
				);
83
84
			case 'network':
85
				return array(
86
					'onboarding',                   // (string) Auth token to be used in the onboarding connection flow
87
					'file_data',                     // (array) List of absolute paths to all Jetpack modules
88
				);
89
		}
90
91
		return array(
92
			'id',                           // (int)    The Client ID/WP.com Blog ID of this site.
93
			'publicize_connections',        // (array)  An array of Publicize connections from WordPress.com.
94
			'master_user',                  // (int)    The local User ID of the user who connected this site to jetpack.wordpress.com.
95
			'version',                      // (string) Used during upgrade procedure to auto-activate new modules. version:time.
96
			'old_version',                  // (string) Used to determine which modules are the most recently added. previous_version:time.
97
			'fallback_no_verify_ssl_certs', // (int)    Flag for determining if this host must skip SSL Certificate verification due to misconfigured SSL.
98
			'time_diff',                    // (int)    Offset between Jetpack server's clocks and this server's clocks. Jetpack Server Time = time() + (int) Jetpack_Options::get_option( 'time_diff' )
99
			'public',                       // (int|bool) If we think this site is public or not (1, 0), false if we haven't yet tried to figure it out.
100
			'videopress',                   // (array)  VideoPress options array.
101
			'is_network_site',              // (int|bool) If we think this site is a network or a single blog (1, 0), false if we haven't yet tried to figue it out.
102
			'social_links',                 // (array)  The specified links for each social networking site.
103
			'identity_crisis_whitelist',    // (array)  An array of options, each having an array of the values whitelisted for it.
104
			'gplus_authors',                // (array)  The Google+ authorship information for connected users.
105
			'last_heartbeat',               // (int)    The timestamp of the last heartbeat that fired.
106
			'hide_jitm',                    // (array)  A list of just in time messages that we should not show because they have been dismissed by the user.
107
			'custom_css_4.7_migration',     // (bool)   Whether Custom CSS has scanned for and migrated any legacy CSS CPT entries to the new Core format.
108
			'image_widget_migration',       // (bool)   Whether any legacy Image Widgets have been converted to the new Core widget.
109
			'gallery_widget_migration',     // (bool)   Whether any legacy Gallery Widgets have been converted to the new Core widget.
110
			'sso_first_login',              // (bool)   Is this the first time the user logins via SSO.
111
			'dismissed_hints',              // (array)  Part of Plugin Search Hints. List of cards that have been dismissed.
112
			'first_admin_view',             // (bool)   Set to true the first time the user views the admin. Usually after the initial connection.
113
			'setup_wizard_questionnaire',   // (array)  List of user choices from the setup wizard.
114
			'setup_wizard_status',          // (string) Status of the setup wizard.
115
		);
116
	}
117
118
	/**
119
	 * Is the option name valid?
120
	 *
121
	 * @param string      $name  The name of the option.
122
	 * @param string|null $group The name of the group that the option is in. Default to null, which will search non_compact.
123
	 *
124
	 * @return bool Is the option name valid?
125
	 */
126
	public static function is_valid( $name, $group = null ) {
127
		if ( is_array( $name ) ) {
128
			$compact_names = array();
129
			foreach ( array_keys( self::$grouped_options ) as $_group ) {
130
				$compact_names = array_merge( $compact_names, self::get_option_names( $_group ) );
131
			}
132
133
			$result = array_diff( $name, self::get_option_names( 'non_compact' ), $compact_names );
134
135
			return empty( $result );
136
		}
137
138 View Code Duplication
		if ( is_null( $group ) || 'non_compact' === $group ) {
139
			if ( in_array( $name, self::get_option_names( $group ), true ) ) {
140
				return true;
141
			}
142
		}
143
144
		foreach ( array_keys( self::$grouped_options ) as $_group ) {
145 View Code Duplication
			if ( is_null( $group ) || $group === $_group ) {
146
				if ( in_array( $name, self::get_option_names( $_group ), true ) ) {
147
					return true;
148
				}
149
			}
150
		}
151
152
		return false;
153
	}
154
155
	/**
156
	 * Checks if an option must be saved for the whole network in WP Multisite
157
	 *
158
	 * @param string $option_name Option name. It must come _without_ `jetpack_%` prefix. The method will prefix the option name.
159
	 *
160
	 * @return bool
161
	 */
162
	public static function is_network_option( $option_name ) {
163
		if ( ! is_multisite() ) {
164
			return false;
165
		}
166
		return in_array( $option_name, self::get_option_names( 'network' ), true );
167
	}
168
169
	/**
170
	 * Filters the requested option.
171
	 * This is a wrapper around `get_option_from_database` so that we can filter the option.
172
	 *
173
	 * @param string $name Option name. It must come _without_ `jetpack_%` prefix. The method will prefix the option name.
174
	 * @param mixed  $default (optional).
175
	 *
176
	 * @return mixed
177
	 */
178
	public static function get_option( $name, $default = false ) {
179
		return apply_filters( 'jetpack_options', self::get_option_from_database( $name, $default ), $name );
0 ignored issues
show
Unused Code introduced by
The call to apply_filters() has too many arguments starting with $name.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
180
	}
181
182
	/**
183
	 * Returns the requested option.  Looks in jetpack_options or jetpack_$name as appropriate.
184
	 *
185
	 * @param string $name Option name. It must come _without_ `jetpack_%` prefix. The method will prefix the option name.
186
	 * @param mixed  $default (optional).
187
	 *
188
	 * @return mixed
189
	 */
190
	private static function get_option_from_database( $name, $default = false ) {
191 View Code Duplication
		if ( self::is_valid( $name, 'non_compact' ) ) {
192
			if ( self::is_network_option( $name ) ) {
193
				return get_site_option( "jetpack_$name", $default );
194
			}
195
196
			return get_option( "jetpack_$name", $default );
197
		}
198
199
		foreach ( array_keys( self::$grouped_options ) as $group ) {
200
			if ( self::is_valid( $name, $group ) ) {
201
				return self::get_grouped_option( $group, $name, $default );
202
			}
203
		}
204
205
		trigger_error( sprintf( 'Invalid Jetpack option name: %s', esc_html( $name ) ), E_USER_WARNING ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error -- Don't wish to change legacy behavior.
206
207
		return $default;
208
	}
209
210
	/**
211
	 * Returns the requested option, and ensures it's autoloaded in the future.
212
	 * This does _not_ adjust the prefix in any way (does not prefix jetpack_%)
213
	 *
214
	 * @param string $name Option name.
215
	 * @param mixed  $default (optional).
216
	 *
217
	 * @return mixed
218
	 */
219
	public static function get_option_and_ensure_autoload( $name, $default ) {
220
		// In this function the name is not adjusted by prefixing jetpack_
221
		// so if it has already prefixed, we'll replace it and then
222
		// check if the option name is a network option or not.
223
		$jetpack_name      = preg_replace( '/^jetpack_/', '', $name, 1 );
224
		$is_network_option = self::is_network_option( $jetpack_name );
225
		$value             = $is_network_option ? get_site_option( $name ) : get_option( $name );
226
227
		if ( false === $value && false !== $default ) {
228
			if ( $is_network_option ) {
229
				add_site_option( $name, $default );
230
			} else {
231
				add_option( $name, $default );
232
			}
233
			$value = $default;
234
		}
235
236
		return $value;
237
	}
238
239
	/**
240
	 * Update grouped option
241
	 *
242
	 * @param string $group Options group.
243
	 * @param string $name Options name.
244
	 * @param mixed  $value Options value.
245
	 *
246
	 * @return bool Success or failure.
247
	 */
248
	private static function update_grouped_option( $group, $name, $value ) {
249
		$options = get_option( self::$grouped_options[ $group ] );
250
		if ( ! is_array( $options ) ) {
251
			$options = array();
252
		}
253
		$options[ $name ] = $value;
254
255
		return update_option( self::$grouped_options[ $group ], $options );
256
	}
257
258
	/**
259
	 * Updates the single given option.  Updates jetpack_options or jetpack_$name as appropriate.
260
	 *
261
	 * @param string $name Option name. It must come _without_ `jetpack_%` prefix. The method will prefix the option name.
262
	 * @param mixed  $value Option value.
263
	 * @param string $autoload If not compact option, allows specifying whether to autoload or not.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $autoload not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
264
	 *
265
	 * @return bool Was the option successfully updated?
266
	 */
267
	public static function update_option( $name, $value, $autoload = null ) {
268
		/**
269
		 * Fires before Jetpack updates a specific option.
270
		 *
271
		 * @since 3.0.0
272
		 *
273
		 * @param str $name The name of the option being updated.
274
		 * @param mixed $value The new value of the option.
275
		 */
276
		do_action( 'pre_update_jetpack_option_' . $name, $name, $value );
277 View Code Duplication
		if ( self::is_valid( $name, 'non_compact' ) ) {
278
			if ( self::is_network_option( $name ) ) {
279
				return update_site_option( "jetpack_$name", $value );
280
			}
281
282
			return update_option( "jetpack_$name", $value, $autoload );
283
284
		}
285
286
		foreach ( array_keys( self::$grouped_options ) as $group ) {
287
			if ( self::is_valid( $name, $group ) ) {
288
				return self::update_grouped_option( $group, $name, $value );
289
			}
290
		}
291
292
		trigger_error( sprintf( 'Invalid Jetpack option name: %s', esc_html( $name ) ), E_USER_WARNING ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error -- Don't want to change legacy behavior.
293
294
		return false;
295
	}
296
297
	/**
298
	 * Updates the multiple given options.  Updates jetpack_options and/or jetpack_$name as appropriate.
299
	 *
300
	 * @param array $array array( option name => option value, ... ).
301
	 */
302
	public static function update_options( $array ) {
303
		$names = array_keys( $array );
304
305
		foreach ( array_diff( $names, self::get_option_names(), self::get_option_names( 'non_compact' ), self::get_option_names( 'private' ) ) as $unknown_name ) {
306
			trigger_error( sprintf( 'Invalid Jetpack option name: %s', esc_html( $unknown_name ) ), E_USER_WARNING ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error -- Don't change legacy behavior.
307
			unset( $array[ $unknown_name ] );
308
		}
309
310
		foreach ( $names as $name ) {
311
			self::update_option( $name, $array[ $name ] );
312
		}
313
	}
314
315
	/**
316
	 * Deletes the given option.  May be passed multiple option names as an array.
317
	 * Updates jetpack_options and/or deletes jetpack_$name as appropriate.
318
	 *
319
	 * @param string|array $names Option names. They must come _without_ `jetpack_%` prefix. The method will prefix the option names.
320
	 *
321
	 * @return bool Was the option successfully deleted?
322
	 */
323
	public static function delete_option( $names ) {
324
		$result = true;
325
		$names  = (array) $names;
326
327
		if ( ! self::is_valid( $names ) ) {
0 ignored issues
show
Documentation introduced by
$names is of type array, but the function expects a string.

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...
328
			// phpcs:disable -- This line triggers a handful of errors; ignoring to avoid changing legacy behavior.
329
			trigger_error( sprintf( 'Invalid Jetpack option names: %s', print_r( $names, 1 ) ), E_USER_WARNING );
330
			// phpcs:enable
331
			return false;
332
		}
333
334
		foreach ( array_intersect( $names, self::get_option_names( 'non_compact' ) ) as $name ) {
335
			if ( self::is_network_option( $name ) ) {
336
				$result = delete_site_option( "jetpack_$name" );
337
			} else {
338
				$result = delete_option( "jetpack_$name" );
339
			}
340
		}
341
342
		foreach ( array_keys( self::$grouped_options ) as $group ) {
343
			if ( ! self::delete_grouped_option( $group, $names ) ) {
344
				$result = false;
345
			}
346
		}
347
348
		return $result;
349
	}
350
351
	/**
352
	 * Get group option.
353
	 *
354
	 * @param string $group Option group name.
355
	 * @param string $name Option name.
356
	 * @param mixed  $default Default option value.
357
	 *
358
	 * @return mixed Option.
359
	 */
360
	private static function get_grouped_option( $group, $name, $default ) {
361
		$options = get_option( self::$grouped_options[ $group ] );
362
		if ( is_array( $options ) && isset( $options[ $name ] ) ) {
363
			return $options[ $name ];
364
		}
365
366
		return $default;
367
	}
368
369
	/**
370
	 * Delete grouped option.
371
	 *
372
	 * @param string $group Option group name.
373
	 * @param array  $names Option names.
374
	 *
375
	 * @return bool Success or failure.
376
	 */
377
	private static function delete_grouped_option( $group, $names ) {
378
		$options = get_option( self::$grouped_options[ $group ], array() );
379
380
		$to_delete = array_intersect( $names, self::get_option_names( $group ), array_keys( $options ) );
381
		if ( $to_delete ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $to_delete of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
382
			foreach ( $to_delete as $name ) {
383
				unset( $options[ $name ] );
384
			}
385
386
			return update_option( self::$grouped_options[ $group ], $options );
387
		}
388
389
		return true;
390
	}
391
392
	/*
393
	 * Raw option methods allow Jetpack to get / update / delete options via direct DB queries, including options
394
	 * that are not created by the Jetpack plugin. This is helpful only in rare cases when we need to bypass
395
	 * cache and filters.
396
	 */
397
398
	/**
399
	 * Deletes an option via $wpdb query.
400
	 *
401
	 * @param string $name Option name.
402
	 *
403
	 * @return bool Is the option deleted?
404
	 */
405
	public static function delete_raw_option( $name ) {
406
		if ( self::bypass_raw_option( $name ) ) {
407
			return delete_option( $name );
408
		}
409
		global $wpdb;
410
		$result = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->options WHERE option_name = %s", $name ) );
411
		return $result;
412
	}
413
414
	/**
415
	 * Updates an option via $wpdb query.
416
	 *
417
	 * @param string $name Option name.
418
	 * @param mixed  $value Option value.
419
	 * @param bool   $autoload Specifying whether to autoload or not.
420
	 *
421
	 * @return bool Is the option updated?
422
	 */
423
	public static function update_raw_option( $name, $value, $autoload = false ) {
424
		if ( self::bypass_raw_option( $name ) ) {
425
			return update_option( $name, $value, $autoload );
426
		}
427
		global $wpdb;
428
		$autoload_value = $autoload ? 'yes' : 'no';
429
430
		$old_value = $wpdb->get_var(
431
			$wpdb->prepare(
432
				"SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1",
433
				$name
434
			)
435
		);
436
		if ( $old_value === $value ) {
437
			return false;
438
		}
439
440
		$serialized_value = maybe_serialize( $value );
441
		// below we used "insert ignore" to at least suppress the resulting error.
442
		$updated_num = $wpdb->query(
443
			$wpdb->prepare(
444
				"UPDATE $wpdb->options SET option_value = %s WHERE option_name = %s",
445
				$serialized_value,
446
				$name
447
			)
448
		);
449
450
		// Try inserting the option if the value doesn't exits.
451
		if ( ! $updated_num ) {
452
			$updated_num = $wpdb->query(
453
				$wpdb->prepare(
454
					"INSERT IGNORE INTO $wpdb->options ( option_name, option_value, autoload ) VALUES ( %s, %s, %s )",
455
					$name,
456
					$serialized_value,
457
					$autoload_value
458
				)
459
			);
460
		}
461
		return (bool) $updated_num;
462
	}
463
464
	/**
465
	 * Gets an option via $wpdb query.
466
	 *
467
	 * @since 5.4.0
468
	 *
469
	 * @param string $name Option name.
470
	 * @param mixed  $default Default option value if option is not found.
471
	 *
472
	 * @return mixed Option value, or null if option is not found and default is not specified.
473
	 */
474
	public static function get_raw_option( $name, $default = null ) {
475
		if ( self::bypass_raw_option( $name ) ) {
476
			return get_option( $name, $default );
477
		}
478
479
		global $wpdb;
480
		$value = $wpdb->get_var(
481
			$wpdb->prepare(
482
				"SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1",
483
				$name
484
			)
485
		);
486
		$value = maybe_unserialize( $value );
487
488
		if ( null === $value && null !== $default ) {
489
			return $default;
490
		}
491
492
		return $value;
493
	}
494
495
	/**
496
	 * This function checks for a constant that, if present, will disable direct DB queries Jetpack uses to manage certain options and force Jetpack to always use Options API instead.
497
	 * Options can be selectively managed via a blocklist by filtering option names via the jetpack_disabled_raw_option filter.
498
	 *
499
	 * @param string $name Option name.
500
	 *
501
	 * @return bool
502
	 */
503
	public static function bypass_raw_option( $name ) {
504
505
		if ( Constants::get_constant( 'JETPACK_DISABLE_RAW_OPTIONS' ) ) {
506
			return true;
507
		}
508
		/**
509
		 * Allows to disable particular raw options.
510
		 *
511
		 * @since 5.5.0
512
		 *
513
		 * @param array $disabled_raw_options An array of option names that you can selectively blocklist from being managed via direct database queries.
514
		 */
515
		$disabled_raw_options = apply_filters( 'jetpack_disabled_raw_options', array() );
516
		return isset( $disabled_raw_options[ $name ] );
517
	}
518
519
	/**
520
	 * Gets all known options that are used by Jetpack and managed by Jetpack_Options.
521
	 *
522
	 * @since 5.4.0
523
	 *
524
	 * @param boolean $strip_unsafe_options If true, and by default, will strip out options necessary for the connection to WordPress.com.
525
	 * @return array An array of all options managed via the Jetpack_Options class.
526
	 */
527
	public static function get_all_jetpack_options( $strip_unsafe_options = true ) {
528
		$jetpack_options            = self::get_option_names();
529
		$jetpack_options_non_compat = self::get_option_names( 'non_compact' );
530
		$jetpack_options_private    = self::get_option_names( 'private' );
531
532
		$all_jp_options = array_merge( $jetpack_options, $jetpack_options_non_compat, $jetpack_options_private );
533
534
		if ( $strip_unsafe_options ) {
535
			// Flag some Jetpack options as unsafe.
536
			$unsafe_options = array(
537
				'id',                           // (int)    The Client ID/WP.com Blog ID of this site.
538
				'master_user',                  // (int)    The local User ID of the user who connected this site to jetpack.wordpress.com.
539
				'version',                      // (string) Used during upgrade procedure to auto-activate new modules. version:time
540
541
				// non_compact.
542
				'activated',
543
544
				// private.
545
				'register',
546
				'blog_token',                  // (string) The Client Secret/Blog Token of this site.
547
				'user_token',                  // (string) The User Token of this site. (deprecated)
548
				'user_tokens',
549
			);
550
551
			// Remove the unsafe Jetpack options.
552
			foreach ( $unsafe_options as $unsafe_option ) {
553
				$key = array_search( $unsafe_option, $all_jp_options, true );
554
				if ( false !== $key ) {
555
					unset( $all_jp_options[ $key ] );
556
				}
557
			}
558
		}
559
560
		return $all_jp_options;
561
	}
562
563
	/**
564
	 * Get all options that are not managed by the Jetpack_Options class that are used by Jetpack.
565
	 *
566
	 * @since 5.4.0
567
	 *
568
	 * @return array
569
	 */
570
	public static function get_all_wp_options() {
571
		// A manual build of the wp options.
572
		return array(
573
			'sharing-options',
574
			'disabled_likes',
575
			'disabled_reblogs',
576
			'jetpack_comments_likes_enabled',
577
			'stats_options',
578
			'stats_dashboard_widget',
579
			'safecss_preview_rev',
580
			'safecss_rev',
581
			'safecss_revision_migrated',
582
			'nova_menu_order',
583
			'jetpack_portfolio',
584
			'jetpack_portfolio_posts_per_page',
585
			'jetpack_testimonial',
586
			'jetpack_testimonial_posts_per_page',
587
			'sharedaddy_disable_resources',
588
			'sharing-options',
589
			'sharing-services',
590
			'site_icon_temp_data',
591
			'featured-content',
592
			'site_logo',
593
			'jetpack_dismissed_notices',
594
			'jetpack-twitter-cards-site-tag',
595
			'jetpack-sitemap-state',
596
			'jetpack_sitemap_post_types',
597
			'jetpack_sitemap_location',
598
			'jetpack_protect_key',
599
			'jetpack_protect_blocked_attempts',
600
			'jetpack_protect_activating',
601
			'jetpack_connection_banner_ab',
602
			'jetpack_active_plan',
603
			'jetpack_activation_source',
604
			'jetpack_sso_match_by_email',
605
			'jetpack_sso_require_two_step',
606
			'jetpack_sso_remove_login_form',
607
			'jetpack_last_connect_url_check',
608
			'jpo_business_address',
609
			'jpo_site_type',
610
			'jpo_homepage_format',
611
			'jpo_contact_page',
612
			'jetpack_excluded_extensions',
613
		);
614
	}
615
616
	/**
617
	 * Gets all options that can be safely reset by CLI.
618
	 *
619
	 * @since 5.4.0
620
	 *
621
	 * @return array array Associative array containing jp_options which are managed by the Jetpack_Options class and wp_options which are not.
622
	 */
623
	public static function get_options_for_reset() {
624
		$all_jp_options = self::get_all_jetpack_options();
625
626
		$wp_options = self::get_all_wp_options();
627
628
		$options = array(
629
			'jp_options' => $all_jp_options,
630
			'wp_options' => $wp_options,
631
		);
632
633
		return $options;
634
	}
635
636
	/**
637
	 * Delete all known options
638
	 *
639
	 * @since 5.4.0
640
	 *
641
	 * @return void
642
	 */
643
	public static function delete_all_known_options() {
644
		// Delete all compact options.
645
		foreach ( (array) self::$grouped_options as $option_name ) {
646
			delete_option( $option_name );
647
		}
648
649
		// Delete all non-compact Jetpack options.
650
		foreach ( (array) self::get_option_names( 'non-compact' ) as $option_name ) {
651
			self::delete_option( $option_name );
652
		}
653
654
		// Delete all options that can be reset via CLI, that aren't Jetpack options.
655
		foreach ( (array) self::get_all_wp_options() as $option_name ) {
656
			delete_option( $option_name );
657
		}
658
	}
659
}
660