PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.1-beta.2
Jetpack – WP Security, Backup, Speed, & Growth v16.1-beta.2
16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 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 / jetpack_vendor / automattic / jetpack-connection / legacy / class-jetpack-options.php
jetpack / jetpack_vendor / automattic / jetpack-connection / legacy Last commit date
class-jetpack-ixr-client.php 9 months ago class-jetpack-ixr-clientmulticall.php 9 months ago class-jetpack-options.php 9 months ago class-jetpack-signature.php 3 months ago class-jetpack-tracks-client.php 3 months ago class-jetpack-tracks-event.php 3 years ago class-jetpack-xmlrpc-server.php 3 months ago
class-jetpack-options.php
727 lines
1 <?php
2 /**
3 * Legacy Jetpack_Options class.
4 *
5 * @package automattic/jetpack-connection
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 'active_modules_initialized', // (bool) used to determine that all the default modules were activated, so we know how to act on a reconnection.
40 'allowed_xsite_search_ids', // (array) Array of WP.com blog ids that are allowed to search the content of this site
41 'available_modules',
42 'do_activate',
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 occurred
61 'unique_registrations', // (integer) A counter of how many times the site was registered
62 'protect_whitelist', // (array) IP Address for the Protect module to ignore
63 'sync_error_idc', // (bool|array) false or array containing the site's home and siteurl at time of IDC error
64 'sync_health_status', // (bool|array) An array of data relating to Jetpack's sync health.
65 'safe_mode_confirmed', // (bool) True if someone confirms that this site was correctly put into safe mode automatically after an identity crisis is discovered.
66 'migrate_for_idc', // (bool) True if someone confirms that this site should migrate stats and subscribers from its previous URL
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 'tos_agreed', // (bool) Whether or not the TOS for connection has been agreed upon.
69 'static_asset_cdn_files', // (array) An nested array of files that we can swap out for cdn versions.
70 'mapbox_api_key', // (string) Mapbox API Key, for use with Map block.
71 'mailchimp', // (string) Mailchimp keyring data, for mailchimp block.
72 'xmlrpc_errors', // (array) Keys are XML-RPC signature error codes. Values are truthy.
73 'dismissed_wizard_banner', // (int) (DEPRECATED) True if the Wizard banner has been dismissed.
74 );
75
76 case 'private':
77 return array(
78 'blog_token', // (string) The Client Secret/Blog Token of this site.
79 'user_token', // (string) The User Token of this site. (deprecated)
80 'user_tokens', // (array) User Tokens for each user of this site who has connected to jetpack.wordpress.com.
81 'purchase_token', // (string) Token for logged out user purchases.
82 'token_lock', // (string) Token lock in format `expiration_date|||site_url`.
83 );
84
85 case 'network':
86 return array(
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) (DEPRECATED) List of user choices from the setup wizard.
114 'setup_wizard_status', // (string) (DEPRECATED) Status of the setup wizard.
115 'licensing_error', // (string) Last error message occurred while attaching licenses that is yet to be surfaced to the user.
116 'recommendations_data', // (array) The user choice and other data for the recommendations.
117 'recommendations_step', // (string) The current step of the recommendations.
118 'recommendations_conditional', // (array) An array of action-based recommendations.
119 'licensing_activation_notice_dismiss', // (array) The `last_detached_count` and the `last_dismissed_time` for the user-license activation notice.
120 'has_seen_wc_connection_modal', // (bool) Whether the site has displayed the WooCommerce Connection modal
121 'partner_coupon', // (string) A Jetpack partner issued coupon to promote a sale together with Jetpack.
122 'partner_coupon_added', // (string) A date for when `partner_coupon` was added, so we can auto-purge after a certain time interval.
123 'dismissed_backup_review_restore', // (bool) Determines if the component review request is dismissed for successful restore requests.
124 'dismissed_backup_review_backups', // (bool) Determines if the component review request is dismissed for successful backup requests.
125 'identity_crisis_url_secret', // (array) The IDC URL secret and its expiration date.
126 'identity_crisis_ip_requester', // (array) The IDC IP address and its expiration date.
127 'dismissed_welcome_banner', // (bool) Determines if the welcome banner has been dismissed or not.
128 'recommendations_evaluation', // (object) Catalog of recommended modules with corresponding score following successful site evaluation in Welcome Banner.
129 'dismissed_recommendations', // (bool) Determines if the recommendations have been dismissed or not.
130 'recommendations_first_run', // (bool) Determines if the current recommendations are the initial default auto-loaded ones (without user input).
131 'historically_active_modules', // (array) List of installed plugins/enabled modules that have at one point in time been active and working
132 );
133 }
134
135 /**
136 * Is the option name valid?
137 *
138 * @param string $name The name of the option.
139 * @param string|null $group The name of the group that the option is in. Default to null, which will search non_compact.
140 *
141 * @return bool Is the option name valid?
142 */
143 public static function is_valid( $name, $group = null ) {
144 if ( is_array( $name ) ) {
145 $compact_names = array();
146 foreach ( array_keys( self::$grouped_options ) as $_group ) {
147 $compact_names = array_merge( $compact_names, self::get_option_names( $_group ) );
148 }
149
150 $result = array_diff( $name, self::get_option_names( 'non_compact' ), $compact_names );
151
152 return empty( $result );
153 }
154
155 if ( $group === null || 'non_compact' === $group ) {
156 if ( in_array( $name, self::get_option_names( $group ), true ) ) {
157 return true;
158 }
159 }
160
161 foreach ( array_keys( self::$grouped_options ) as $_group ) {
162 if ( $group === null || $group === $_group ) {
163 if ( in_array( $name, self::get_option_names( $_group ), true ) ) {
164 return true;
165 }
166 }
167 }
168
169 return false;
170 }
171
172 /**
173 * Checks if an option must be saved for the whole network in WP Multisite
174 *
175 * @param string $option_name Option name. It must come _without_ `jetpack_%` prefix. The method will prefix the option name.
176 *
177 * @return bool
178 */
179 public static function is_network_option( $option_name ) {
180 if ( ! is_multisite() ) {
181 return false;
182 }
183 return in_array( $option_name, self::get_option_names( 'network' ), true );
184 }
185
186 /**
187 * Filters the requested option.
188 * This is a wrapper around `get_option_from_database` so that we can filter the option.
189 *
190 * @param string $name Option name. It must come _without_ `jetpack_%` prefix. The method will prefix the option name.
191 * @param mixed $default (optional).
192 *
193 * @return mixed
194 */
195 public static function get_option( $name, $default = false ) {
196 // Check if external storage should be used for this option
197 if ( self::should_use_external_storage( $name ) ) {
198 // Try external storage
199 if ( class_exists( 'Automattic\Jetpack\Connection\External_Storage' ) ) {
200 $external_value = \Automattic\Jetpack\Connection\External_Storage::get_value( $name );
201 if ( null !== $external_value ) {
202 return $external_value;
203 }
204 }
205 }
206
207 /**
208 * Filter Jetpack Options.
209 * Can be useful in environments when Jetpack is running with a different setup
210 *
211 * @since 1.7.0
212 *
213 * @param string $value The value from the database.
214 * @param string $name Option name, _without_ `jetpack_%` prefix.
215 * @return string $value, unless the filters modify it.
216 */
217 return apply_filters( 'jetpack_options', self::get_option_from_database( $name, $default ), $name );
218 }
219
220 /**
221 * Returns the requested option. Looks in jetpack_options or jetpack_$name as appropriate.
222 *
223 * @param string $name Option name. It must come _without_ `jetpack_%` prefix. The method will prefix the option name.
224 * @param mixed $default (optional).
225 *
226 * @return mixed
227 */
228 private static function get_option_from_database( $name, $default = false ) {
229 if ( self::is_valid( $name, 'non_compact' ) ) {
230 if ( self::is_network_option( $name ) ) {
231 return get_site_option( "jetpack_$name", $default );
232 }
233
234 return get_option( "jetpack_$name", $default );
235 }
236
237 foreach ( array_keys( self::$grouped_options ) as $group ) {
238 if ( self::is_valid( $name, $group ) ) {
239 return self::get_grouped_option( $group, $name, $default );
240 }
241 }
242
243 return $default;
244 }
245
246 /**
247 * Options that can be stored in external storage.
248 *
249 * @since 6.18.0
250 *
251 * @var array
252 */
253 private static $external_storage_allowlist = array( 'blog_token', 'id', 'master_user', 'user_tokens' );
254
255 /**
256 * Determines if external storage should be used for a given option.
257 * Simple allowlist check with global killswitch.
258 *
259 * @since 6.17.0
260 *
261 * @param string $name Option name, _without_ `jetpack_%` prefix.
262 * @return bool True if external storage should be checked for this option.
263 */
264 private static function should_use_external_storage( $name ) {
265 // Check allowlist and global killswitch
266 if ( ! in_array( $name, self::$external_storage_allowlist, true ) ||
267 ( defined( 'JETPACK_EXTERNAL_STORAGE_DISABLED' ) && constant( 'JETPACK_EXTERNAL_STORAGE_DISABLED' ) ) ) {
268 return false;
269 }
270
271 return true;
272 }
273
274 /**
275 * Returns the requested option, and ensures it's autoloaded in the future.
276 * This does _not_ adjust the prefix in any way (does not prefix jetpack_%)
277 *
278 * @param string $name Option name.
279 * @param mixed $default (optional).
280 *
281 * @return mixed
282 */
283 public static function get_option_and_ensure_autoload( $name, $default ) {
284 // In this function the name is not adjusted by prefixing jetpack_
285 // so if it has already prefixed, we'll replace it and then
286 // check if the option name is a network option or not.
287 $jetpack_name = preg_replace( '/^jetpack_/', '', $name, 1 );
288 $is_network_option = self::is_network_option( $jetpack_name );
289 $value = $is_network_option ? get_site_option( $name ) : get_option( $name );
290
291 if ( false === $value && false !== $default ) {
292 if ( $is_network_option ) {
293 add_site_option( $name, $default );
294 } else {
295 add_option( $name, $default );
296 }
297 $value = $default;
298 }
299
300 return $value;
301 }
302
303 /**
304 * Update grouped option
305 *
306 * @param string $group Options group.
307 * @param string $name Options name.
308 * @param mixed $value Options value.
309 *
310 * @return bool Success or failure.
311 */
312 private static function update_grouped_option( $group, $name, $value ) {
313 $options = get_option( self::$grouped_options[ $group ] );
314 if ( ! is_array( $options ) ) {
315 $options = array();
316 }
317 $options[ $name ] = $value;
318
319 return update_option( self::$grouped_options[ $group ], $options );
320 }
321
322 /**
323 * Updates the single given option. Updates jetpack_options or jetpack_$name as appropriate.
324 *
325 * @param string $name Option name. It must come _without_ `jetpack_%` prefix. The method will prefix the option name.
326 * @param mixed $value Option value.
327 * @param bool|null $autoload If not compact option, allows specifying whether to autoload or not.
328 *
329 * @return bool Was the option successfully updated?
330 */
331 public static function update_option( $name, $value, $autoload = null ) {
332 /**
333 * Fires before Jetpack updates a specific option.
334 *
335 * @since 1.1.2
336 * @since-jetpack 3.0.0
337 *
338 * @param string $name The name of the option being updated.
339 * @param mixed $value The new value of the option.
340 */
341 do_action( 'pre_update_jetpack_option_' . $name, $name, $value );
342 if ( self::is_valid( $name, 'non_compact' ) ) {
343 if ( self::is_network_option( $name ) ) {
344 return update_site_option( "jetpack_$name", $value );
345 }
346
347 return update_option( "jetpack_$name", $value, $autoload );
348
349 }
350
351 foreach ( array_keys( self::$grouped_options ) as $group ) {
352 if ( self::is_valid( $name, $group ) ) {
353 return self::update_grouped_option( $group, $name, $value );
354 }
355 }
356
357 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.
358
359 return false;
360 }
361
362 /**
363 * Updates the multiple given options. Updates jetpack_options and/or jetpack_$name as appropriate.
364 *
365 * @param array $array array( option name => option value, ... ).
366 */
367 public static function update_options( $array ) {
368 $names = array_keys( $array );
369
370 foreach ( array_diff( $names, self::get_option_names(), self::get_option_names( 'non_compact' ), self::get_option_names( 'private' ) ) as $unknown_name ) {
371 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.
372 unset( $array[ $unknown_name ] );
373 }
374
375 foreach ( $names as $name ) {
376 self::update_option( $name, $array[ $name ] );
377 }
378 }
379
380 /**
381 * Deletes the given option. May be passed multiple option names as an array.
382 * Updates jetpack_options and/or deletes jetpack_$name as appropriate.
383 *
384 * @param string|array $names Option names. They must come _without_ `jetpack_%` prefix. The method will prefix the option names.
385 *
386 * @return bool Was the option successfully deleted?
387 */
388 public static function delete_option( $names ) {
389 $result = true;
390 $names = (array) $names;
391
392 if ( ! self::is_valid( $names ) ) {
393 // phpcs:disable -- This line triggers a handful of errors; ignoring to avoid changing legacy behavior.
394 trigger_error( sprintf( 'Invalid Jetpack option names: %s', print_r( $names, 1 ) ), E_USER_WARNING );
395 // phpcs:enable
396 return false;
397 }
398
399 foreach ( array_intersect( $names, self::get_option_names( 'non_compact' ) ) as $name ) {
400 if ( self::is_network_option( $name ) ) {
401 $result = delete_site_option( "jetpack_$name" );
402 } else {
403 $result = delete_option( "jetpack_$name" );
404 }
405 }
406
407 foreach ( array_keys( self::$grouped_options ) as $group ) {
408 if ( ! self::delete_grouped_option( $group, $names ) ) {
409 $result = false;
410 }
411 }
412
413 return $result;
414 }
415
416 /**
417 * Get group option.
418 *
419 * @param string $group Option group name.
420 * @param string $name Option name.
421 * @param mixed $default Default option value.
422 *
423 * @return mixed Option.
424 */
425 private static function get_grouped_option( $group, $name, $default ) {
426 $options = get_option( self::$grouped_options[ $group ] );
427 if ( is_array( $options ) && isset( $options[ $name ] ) ) {
428 return $options[ $name ];
429 }
430
431 return $default;
432 }
433
434 /**
435 * Delete grouped option.
436 *
437 * @param string $group Option group name.
438 * @param array $names Option names.
439 *
440 * @return bool Success or failure.
441 */
442 private static function delete_grouped_option( $group, $names ) {
443 $options = get_option( self::$grouped_options[ $group ], array() );
444
445 $to_delete = array_intersect( $names, self::get_option_names( $group ), array_keys( $options ) );
446 if ( $to_delete ) {
447 foreach ( $to_delete as $name ) {
448 unset( $options[ $name ] );
449 }
450
451 return update_option( self::$grouped_options[ $group ], $options );
452 }
453
454 return true;
455 }
456
457 /*
458 * Raw option methods allow Jetpack to get / update / delete options via direct DB queries, including options
459 * that are not created by the Jetpack plugin. This is helpful only in rare cases when we need to bypass
460 * cache and filters.
461 */
462
463 /**
464 * Deletes an option via $wpdb query.
465 *
466 * @param string $name Option name.
467 *
468 * @return bool Is the option deleted?
469 */
470 public static function delete_raw_option( $name ) {
471 if ( self::bypass_raw_option( $name ) ) {
472 return delete_option( $name );
473 }
474 global $wpdb;
475 $result = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->options WHERE option_name = %s", $name ) );
476 return $result;
477 }
478
479 /**
480 * Updates an option via $wpdb query.
481 *
482 * @param string $name Option name.
483 * @param mixed $value Option value.
484 * @param bool $autoload Specifying whether to autoload or not.
485 *
486 * @return bool Is the option updated?
487 */
488 public static function update_raw_option( $name, $value, $autoload = false ) {
489 if ( self::bypass_raw_option( $name ) ) {
490 return update_option( $name, $value, $autoload );
491 }
492 global $wpdb;
493 $autoload_value = $autoload ? 'yes' : 'no';
494
495 $old_value = $wpdb->get_var(
496 $wpdb->prepare(
497 "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1",
498 $name
499 )
500 );
501 if ( $old_value === $value ) {
502 return false;
503 }
504
505 $serialized_value = maybe_serialize( $value );
506 // below we used "insert ignore" to at least suppress the resulting error.
507 $updated_num = $wpdb->query(
508 $wpdb->prepare(
509 "UPDATE $wpdb->options SET option_value = %s WHERE option_name = %s",
510 $serialized_value,
511 $name
512 )
513 );
514
515 // Try inserting the option if the value doesn't exits.
516 if ( ! $updated_num ) {
517 $updated_num = $wpdb->query(
518 $wpdb->prepare(
519 "INSERT IGNORE INTO $wpdb->options ( option_name, option_value, autoload ) VALUES ( %s, %s, %s )",
520 $name,
521 $serialized_value,
522 $autoload_value
523 )
524 );
525 }
526 return (bool) $updated_num;
527 }
528
529 /**
530 * Gets an option via $wpdb query.
531 *
532 * @since 1.1.2
533 * @since-jetpack 5.4.0
534 *
535 * @param string $name Option name.
536 * @param mixed $default Default option value if option is not found.
537 *
538 * @return mixed Option value, or null if option is not found and default is not specified.
539 */
540 public static function get_raw_option( $name, $default = null ) {
541 if ( self::bypass_raw_option( $name ) ) {
542 return get_option( $name, $default );
543 }
544
545 global $wpdb;
546 $value = $wpdb->get_var(
547 $wpdb->prepare(
548 "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1",
549 $name
550 )
551 );
552 $value = maybe_unserialize( $value );
553
554 if ( null === $value && null !== $default ) {
555 return $default;
556 }
557
558 return $value;
559 }
560
561 /**
562 * 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.
563 * Options can be selectively managed via a blocklist by filtering option names via the jetpack_disabled_raw_option filter.
564 *
565 * @param string $name Option name.
566 *
567 * @return bool
568 */
569 public static function bypass_raw_option( $name ) {
570
571 if ( Constants::get_constant( 'JETPACK_DISABLE_RAW_OPTIONS' ) ) {
572 return true;
573 }
574 /**
575 * Allows to disable particular raw options.
576 *
577 * @since 1.1.2
578 * @since-jetpack 5.5.0
579 *
580 * @param array $disabled_raw_options An array of option names that you can selectively blocklist from being managed via direct database queries.
581 */
582 $disabled_raw_options = apply_filters( 'jetpack_disabled_raw_options', array() );
583 return isset( $disabled_raw_options[ $name ] );
584 }
585
586 /**
587 * Gets all known options that are used by Jetpack and managed by Jetpack_Options.
588 *
589 * @since 1.1.2
590 * @since-jetpack 5.4.0
591 *
592 * @param boolean $strip_unsafe_options If true, and by default, will strip out options necessary for the connection to WordPress.com.
593 * @return array An array of all options managed via the Jetpack_Options class.
594 */
595 public static function get_all_jetpack_options( $strip_unsafe_options = true ) {
596 $jetpack_options = self::get_option_names();
597 $jetpack_options_non_compat = self::get_option_names( 'non_compact' );
598 $jetpack_options_private = self::get_option_names( 'private' );
599
600 $all_jp_options = array_merge( $jetpack_options, $jetpack_options_non_compat, $jetpack_options_private );
601
602 if ( $strip_unsafe_options ) {
603 // Flag some Jetpack options as unsafe.
604 $unsafe_options = array(
605 'id', // (int) The Client ID/WP.com Blog ID of this site.
606 'master_user', // (int) The local User ID of the user who connected this site to jetpack.wordpress.com.
607 'version', // (string) Used during upgrade procedure to auto-activate new modules. version:time
608
609 // non_compact.
610 'activated',
611
612 // private.
613 'register',
614 'blog_token', // (string) The Client Secret/Blog Token of this site.
615 'user_token', // (string) The User Token of this site. (deprecated)
616 'user_tokens',
617 );
618
619 // Remove the unsafe Jetpack options.
620 foreach ( $unsafe_options as $unsafe_option ) {
621 $key = array_search( $unsafe_option, $all_jp_options, true );
622 if ( false !== $key ) {
623 unset( $all_jp_options[ $key ] );
624 }
625 }
626 }
627
628 return $all_jp_options;
629 }
630
631 /**
632 * Get all options that are not managed by the Jetpack_Options class that are used by Jetpack.
633 *
634 * @since 1.1.2
635 * @since-jetpack 5.4.0
636 *
637 * @return array
638 */
639 public static function get_all_wp_options() {
640 // A manual build of the wp options.
641 return array(
642 'sharing-options',
643 'disabled_likes',
644 'disabled_reblogs',
645 'jetpack_comments_likes_enabled',
646 'stats_options',
647 'stats_dashboard_widget',
648 'safecss_preview_rev',
649 'safecss_rev',
650 'safecss_revision_migrated',
651 'nova_menu_order',
652 'jetpack_portfolio',
653 'jetpack_portfolio_posts_per_page',
654 'jetpack_testimonial',
655 'jetpack_testimonial_posts_per_page',
656 'sharedaddy_disable_resources',
657 'sharing-options',
658 'sharing-services',
659 'site_icon_temp_data',
660 'featured-content',
661 'site_logo',
662 'jetpack_dismissed_notices',
663 'jetpack-twitter-cards-site-tag',
664 'jetpack-sitemap-state',
665 'jetpack_sitemap_post_types',
666 'jetpack_sitemap_location',
667 'jetpack_protect_key',
668 'jetpack_protect_blocked_attempts',
669 'jetpack_protect_activating',
670 'jetpack_active_plan',
671 'jetpack_activation_source',
672 'jetpack_site_products',
673 'jetpack_sso_match_by_email',
674 'jetpack_sso_require_two_step',
675 'jetpack_sso_remove_login_form',
676 'jetpack_last_connect_url_check',
677 'jetpack_excluded_extensions',
678 );
679 }
680
681 /**
682 * Gets all options that can be safely reset by CLI.
683 *
684 * @since 1.1.2
685 * @since-jetpack 5.4.0
686 *
687 * @return array array Associative array containing jp_options which are managed by the Jetpack_Options class and wp_options which are not.
688 */
689 public static function get_options_for_reset() {
690 $all_jp_options = self::get_all_jetpack_options();
691
692 $wp_options = self::get_all_wp_options();
693
694 $options = array(
695 'jp_options' => $all_jp_options,
696 'wp_options' => $wp_options,
697 );
698
699 return $options;
700 }
701
702 /**
703 * Delete all known options
704 *
705 * @since 1.1.2
706 * @since-jetpack 5.4.0
707 *
708 * @return void
709 */
710 public static function delete_all_known_options() {
711 // Delete all compact options.
712 foreach ( (array) self::$grouped_options as $option_name ) {
713 delete_option( $option_name );
714 }
715
716 // Delete all non-compact Jetpack options.
717 foreach ( (array) self::get_option_names( 'non-compact' ) as $option_name ) {
718 self::delete_option( $option_name );
719 }
720
721 // Delete all options that can be reset via CLI, that aren't Jetpack options.
722 foreach ( (array) self::get_all_wp_options() as $option_name ) {
723 delete_option( $option_name );
724 }
725 }
726 }
727