PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-status / src / class-status.php

class-status.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.7, at jetpack_vendor/automattic/jetpack-status/src/class-status.php

482 lines 14.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * A status class for Jetpack.
4 *
5 * @package automattic/jetpack-status
6 */
7
8 namespace Automattic\Jetpack;
9
10 use Automattic\Jetpack\Status\Cache;
11 use Automattic\Jetpack\Status\Host;
12 use WPCOM_Masterbar;
13
14 /**
15 * Class Automattic\Jetpack\Status
16 *
17 * Used to retrieve information about the current status of Jetpack and the site overall.
18 */
19 class Status {
20 /**
21 * Is Jetpack in offline mode?
22 *
23 * This was formerly called "Development Mode", but sites "in development" aren't always offline/localhost.
24 *
25 * @since 1.3.0
26 *
27 * @return bool Whether Jetpack's offline mode is active.
28 */
29 public function is_offline_mode() {
30 $cached = Cache::get( 'is_offline_mode' );
31 if ( null !== $cached ) {
32 return $cached;
33 }
34
35 $offline_mode = false;
36
37 if ( defined( '\\JETPACK_DEV_DEBUG' ) ) {
38 $offline_mode = constant( '\\JETPACK_DEV_DEBUG' );
39 } elseif ( defined( '\\WP_LOCAL_DEV' ) ) {
40 $offline_mode = constant( '\\WP_LOCAL_DEV' );
41 } elseif ( $this->is_local_site() ) {
42 $offline_mode = true;
43 }
44
45 /**
46 * Filters Jetpack's offline mode.
47 *
48 * @see https://jetpack.com/support/offline-mode/
49 *
50 * @since 1.3.0
51 *
52 * @param bool $offline_mode Is Jetpack's offline mode active.
53 */
54 $offline_mode = (bool) apply_filters( 'jetpack_offline_mode', $offline_mode );
55
56 if ( ! $offline_mode ) {
57 // Sentinel default so an absent option isn't confused with a stored null/false.
58 $sentinel = new \stdClass();
59 $option = get_option( 'jetpack_offline_mode', $sentinel );
60
61 if ( $sentinel === $option ) {
62 // Seed an autoloaded default to stop per-request reads, but only where it helps
63 // (no persistent object cache) and writes are safe (keep front-end reads read-only).
64 if ( ! wp_using_ext_object_cache() && ( is_admin() || wp_doing_cron() || ( defined( 'WP_CLI' ) && WP_CLI ) ) ) {
65 add_option( 'jetpack_offline_mode', false, '', true );
66 }
67 } else {
68 // A default_option filter could return a non-scalar; only a scalar is a real value.
69 $offline_mode = is_scalar( $option ) ? (bool) $option : false;
70 }
71 }
72
73 Cache::set( 'is_offline_mode', $offline_mode );
74 return $offline_mode;
75 }
76
77 /**
78 * Whether this is a system with a multiple networks.
79 * Implemented since there is no core is_multi_network function.
80 * Right now there is no way to tell which network is the dominant network on the system.
81 *
82 * @return boolean
83 */
84 public function is_multi_network() {
85 global $wpdb;
86
87 $cached = Cache::get( 'is_multi_network' );
88 if ( null !== $cached ) {
89 return $cached;
90 }
91
92 // If we don't have a multi site setup no need to do any more.
93 if ( ! is_multisite() ) {
94 Cache::set( 'is_multi_network', false );
95 return false;
96 }
97
98 $num_sites = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->site}" );
99 if ( $num_sites > 1 ) {
100 Cache::set( 'is_multi_network', true );
101 return true;
102 }
103
104 Cache::set( 'is_multi_network', false );
105 return false;
106 }
107
108 /**
109 * Whether the current site is single user site.
110 *
111 * @return bool
112 */
113 public function is_single_user_site() {
114 global $wpdb;
115
116 $ret = Cache::get( 'is_single_user_site' );
117 if ( null === $ret ) {
118 $some_users = get_transient( 'jetpack_is_single_user' );
119 if ( false === $some_users ) {
120 $some_users = $wpdb->get_var( "SELECT COUNT(*) FROM (SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '{$wpdb->prefix}capabilities' LIMIT 2) AS someusers" );
121 set_transient( 'jetpack_is_single_user', (int) $some_users, 12 * HOUR_IN_SECONDS );
122 }
123 $ret = 1 === (int) $some_users;
124 Cache::set( 'is_single_user_site', $ret );
125 }
126 return $ret;
127 }
128
129 /**
130 * If the site is a local site.
131 *
132 * @since 1.3.0
133 *
134 * @return bool
135 */
136 public function is_local_site() {
137 $cached = Cache::get( 'is_local_site' );
138 if ( null !== $cached ) {
139 return $cached;
140 }
141
142 $site_url = trim( (string) site_url() );
143
144 /*
145 * Every check below cares about the host, not the rest of the URL. Matching the host
146 * alone means a port, a subdirectory install, or a trailing slash can't defeat them,
147 * and a known local domain sitting in the path can't trigger them by accident.
148 */
149 $host = wp_parse_url( $site_url, PHP_URL_HOST );
150 if ( ( ! is_string( $host ) || '' === $host ) && ! preg_match( '#^[a-z][a-z0-9+.\-]*:#i', $site_url ) ) {
151 /*
152 * No scheme, so site_url() isn't absolute. Read the value as a bare host.
153 * A value that does carry a scheme but still won't parse is malformed, and
154 * guessing at it would read "https:/example.com" as the host "https".
155 */
156 $host = wp_parse_url( '//' . ltrim( $site_url, '/' ), PHP_URL_HOST );
157 }
158 if ( ! is_string( $host ) ) {
159 /*
160 * Nothing host-shaped to test. Treat the site as remote rather than matching the
161 * raw URL: a false "local" silently drops a live site into offline mode.
162 */
163 $host = '';
164 }
165
166 /*
167 * Check for localhost and sites using an IP only first. No dot means it can't be a
168 * public domain. Dotless IPv6 literals land here too, routable ones included:
169 * WordPress.com won't register an IPv6 site URL, so offline mode is where they belong.
170 * An IPv4-mapped literal like [::ffff:127.0.0.1] keeps its dots and reads as remote.
171 */
172 $is_local = '' !== $host && false === strpos( $host, '.' );
173
174 // Use Core's environment check, if available.
175 if ( 'local' === wp_get_environment_type() ) {
176 $is_local = true;
177 }
178
179 // Then check for usual domains used by local dev tools.
180 $known_local = array(
181 '#\.local$#i',
182 '#(^|\.)localhost$#i', // localhost and any subdomain of it.
183 '#\.test$#i',
184 '#\.docksal$#i', // Docksal.
185 '#\.docksal\.site$#i', // Docksal.
186 '#\.dev\.cc$#i', // ServerPress.
187 '#\.lndo\.site$#i', // Lando.
188 '#\.ddev\.site$#i', // DDEV.
189 // The whole 127.0.0.0/8 range is loopback; each octet is capped at 255.
190 '#^127\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){2}$#',
191 '#^0\.0\.0\.0$#', // All-interfaces bind, common under Docker and `wp server`.
192 '#^playground\.wordpress\.net$#i', // WordPress Playground, which runs entirely in the browser.
193 );
194
195 if ( ! $is_local && '' !== $host ) {
196 foreach ( $known_local as $pattern ) {
197 if ( preg_match( $pattern, $host ) ) {
198 $is_local = true;
199 break;
200 }
201 }
202 }
203
204 /**
205 * Filters is_local_site check.
206 *
207 * @since 1.3.0
208 *
209 * @param bool $is_local If the current site is a local site.
210 */
211 $is_local = apply_filters( 'jetpack_is_local_site', $is_local );
212
213 Cache::set( 'is_local_site', $is_local );
214 return $is_local;
215 }
216
217 /**
218 * If is a staging site.
219 *
220 * @deprecated since 3.3.0
221 *
222 * @return bool
223 */
224 public function is_staging_site() {
225 _deprecated_function( __FUNCTION__, '3.3.0', 'in_safe_mode' );
226 $cached = Cache::get( 'is_staging_site' );
227 if ( null !== $cached ) {
228 return $cached;
229 }
230
231 /*
232 * Core's wp_get_environment_type allows for a few specific options.
233 * We should default to bowing out gracefully for anything other than production or local.
234 */
235 $is_staging = ! in_array( wp_get_environment_type(), array( 'production', 'local' ), true );
236
237 $known_staging = array(
238 'urls' => array(
239 '#\.staging\.wpengine\.com$#i', // WP Engine. This is their legacy staging URL structure. Their new platform does not have a common URL. https://github.com/Automattic/jetpack/issues/21504
240 '#\.staging\.kinsta\.com$#i', // Kinsta.com.
241 '#\.kinsta\.cloud$#i', // Kinsta.com.
242 '#\.stage\.site$#i', // DreamPress.
243 '#\.newspackstaging\.com$#i', // Newspack.
244 '#^(?!live-)([a-zA-Z0-9-]+)\.pantheonsite\.io$#i', // Pantheon.
245 '#\.flywheelsites\.com$#i', // Flywheel.
246 '#\.flywheelstaging\.com$#i', // Flywheel.
247 '#\.cloudwaysapps\.com$#i', // Cloudways.
248 '#\.azurewebsites\.net$#i', // Azure.
249 '#\.wpserveur\.net$#i', // WPServeur.
250 '#\-liquidwebsites\.com$#i', // Liquidweb.
251 ),
252 'constants' => array(
253 'IS_WPE_SNAPSHOT', // WP Engine. This is used on their legacy staging environment. Their new platform does not have a constant. https://github.com/Automattic/jetpack/issues/21504
254 'KINSTA_DEV_ENV', // Kinsta.com.
255 'WPSTAGECOACH_STAGING', // WP Stagecoach.
256 'JETPACK_STAGING_MODE', // Generic.
257 'WP_LOCAL_DEV', // Generic.
258 ),
259 );
260 /**
261 * Filters the flags of known staging sites.
262 *
263 * @since 1.1.1
264 * @since-jetpack 3.9.0
265 *
266 * @param array $known_staging {
267 * An array of arrays that each are used to check if the current site is staging.
268 * @type array $urls URLs of staging sites in regex to check against site_url.
269 * @type array $constants PHP constants of known staging/developement environments.
270 * }
271 */
272 $known_staging = apply_filters( 'jetpack_known_staging', $known_staging );
273
274 if ( isset( $known_staging['urls'] ) ) {
275 $site_url = site_url();
276 foreach ( $known_staging['urls'] as $url ) {
277 if ( preg_match( $url, wp_parse_url( $site_url, PHP_URL_HOST ) ) ) {
278 $is_staging = true;
279 break;
280 }
281 }
282 }
283
284 if ( isset( $known_staging['constants'] ) ) {
285 foreach ( $known_staging['constants'] as $constant ) {
286 if ( defined( $constant ) && constant( $constant ) ) {
287 $is_staging = true;
288 }
289 }
290 }
291
292 // Last, let's check if sync is erroring due to an IDC. If so, set the site to staging mode.
293 if ( ! $is_staging && method_exists( 'Automattic\\Jetpack\\Identity_Crisis', 'validate_sync_error_idc_option' ) && \Automattic\Jetpack\Identity_Crisis::validate_sync_error_idc_option() ) {
294 $is_staging = true;
295 }
296
297 /**
298 * Filters is_staging_site check.
299 *
300 * @since 1.1.1
301 * @since-jetpack 3.9.0
302 *
303 * @param bool $is_staging If the current site is a staging site.
304 */
305 $is_staging = apply_filters( 'jetpack_is_staging_site', $is_staging );
306
307 Cache::set( 'is_staging_site', $is_staging );
308 return $is_staging;
309 }
310
311 /**
312 * If the site is in safe mode.
313 *
314 * @since 3.3.0
315 *
316 * @return bool
317 */
318 public function in_safe_mode() {
319 $cached = Cache::get( 'in_safe_mode' );
320 if ( null !== $cached ) {
321 return $cached;
322 }
323 $in_safe_mode = false;
324 if ( method_exists( 'Automattic\\Jetpack\\Identity_Crisis', 'validate_sync_error_idc_option' ) && \Automattic\Jetpack\Identity_Crisis::validate_sync_error_idc_option() ) {
325 $in_safe_mode = true;
326 }
327 /**
328 * Filters in_safe_mode check.
329 *
330 * @since 3.3.0
331 *
332 * @param bool $in_safe_mode If the current site is in safe mode.
333 */
334 $in_safe_mode = apply_filters( 'jetpack_is_in_safe_mode', $in_safe_mode );
335
336 Cache::set( 'in_safe_mode', $in_safe_mode );
337 return $in_safe_mode;
338 }
339
340 /**
341 * If the site is a development/staging site.
342 * This is a new version of is_staging_site added to separate safe mode from the legacy staging mode.
343 * This method checks for core WP_ENVIRONMENT_TYPE setting
344 * Using the jetpack_is_development_site filter.
345 *
346 * @since 3.3.0
347 *
348 * @return bool
349 */
350 public static function is_development_site() {
351 $cached = Cache::get( 'is_development_site' );
352 if ( null !== $cached ) {
353 return $cached;
354 }
355 $is_dev_site = ! in_array( wp_get_environment_type(), array( 'production', 'local' ), true );
356 /**
357 * Filters is_development_site check.
358 *
359 * @since 3.3.0
360 *
361 * @param bool $is_dev_site If the current site is a staging or dev site.
362 */
363 $is_dev_site = apply_filters( 'jetpack_is_development_site', $is_dev_site );
364
365 Cache::set( 'is_development_site', $is_dev_site );
366 return $is_dev_site;
367 }
368
369 /**
370 * Whether the site is currently onboarding or not.
371 * A site is considered as being onboarded if it currently has an onboarding token.
372 *
373 * @since-jetpack 5.8
374 *
375 * @deprecated since 4.0.0
376 *
377 * @access public
378 * @static
379 *
380 * @return bool True if the site is currently onboarding, false otherwise
381 */
382 public function is_onboarding() {
383 return \Jetpack_Options::get_option( 'onboarding' ) !== false;
384 }
385
386 /**
387 * Whether the site is currently private or not.
388 * On WordPress.com and WoA, sites can be marked as private
389 *
390 * @since 1.16.0
391 *
392 * @return bool True if the site is private.
393 */
394 public function is_private_site() {
395 $ret = Cache::get( 'is_private_site' );
396 if ( null === $ret ) {
397 $is_private_site = '-1' === get_option( 'blog_public' );
398
399 /**
400 * Filters the is_private_site check.
401 *
402 * @since 1.16.1
403 *
404 * @param bool $is_private_site True if the site is private.
405 */
406 $is_private_site = apply_filters( 'jetpack_is_private_site', $is_private_site );
407
408 Cache::set( 'is_private_site', $is_private_site );
409 return $is_private_site;
410 }
411 return $ret;
412 }
413
414 /**
415 * Whether the site is currently unlaunched or not.
416 * On WordPress.com and WoA, sites can be marked as "coming soon", aka unlaunched
417 *
418 * @since 1.16.0
419 *
420 * @return bool True if the site is not launched.
421 */
422 public function is_coming_soon() {
423 $ret = Cache::get( 'is_coming_soon' );
424 if ( null === $ret ) {
425 $is_coming_soon = ( function_exists( 'site_is_coming_soon' ) && \site_is_coming_soon() )
426 || get_option( 'wpcom_public_coming_soon' );
427
428 /**
429 * Filters the is_coming_soon check.
430 *
431 * @since 1.16.1
432 *
433 * @param bool $is_coming_soon True if the site is coming soon (i.e. unlaunched).
434 */
435 $is_coming_soon = apply_filters( 'jetpack_is_coming_soon', $is_coming_soon );
436
437 Cache::set( 'is_coming_soon', $is_coming_soon );
438 return $is_coming_soon;
439 }
440 return $ret;
441 }
442
443 /**
444 * Returns the site slug suffix to be used as part of Calypso URLs.
445 *
446 * Strips http:// or https:// from a url, replaces forward slash with ::.
447 *
448 * @since 1.6.0
449 *
450 * @param string $url Optional. URL to build the site suffix from. Default: Home URL.
451 *
452 * @return string
453 */
454 public function get_site_suffix( $url = '' ) {
455 // On WordPress.com, site suffixes are a bit different.
456 if ( method_exists( 'WPCOM_Masterbar', 'get_calypso_site_slug' ) ) {
457 return WPCOM_Masterbar::get_calypso_site_slug( get_current_blog_id() );
458 }
459
460 // Grab the 'site_url' option for WoA sites to avoid plugins to interfere with the site
461 // identifier (e.g. i18n plugins may change the main url to '<DOMAIN>/<LOCALE>', but we
462 // want to exclude the locale since it's not part of the site suffix).
463 if ( ( new Host() )->is_woa_site() ) {
464 $url = \site_url();
465 }
466
467 if ( empty( $url ) ) {
468 // WordPress can be installed in subdirectories (e.g. make.wordpress.org/plugins)
469 // where the 'site_url' option points to the root domain (e.g. make.wordpress.org)
470 // which could collide with another site in the same domain but with WordPress
471 // installed in a different subdirectory (e.g. make.wordpress.org/core). To avoid
472 // such collision, we identify the site with the 'home_url' option.
473 $url = \home_url();
474 }
475
476 $url = preg_replace( '#^.*?://#', '', $url );
477 $url = str_replace( '/', '::', $url );
478
479 return rtrim( $url, ':' );
480 }
481 }
482