Completed
Push — update/split-class-jetpack ( 2a34fb )
by
unknown
13:38
created

Jetpack_Functions::glob_php()   C

Complexity

Conditions 7
Paths 6

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 6
nop 1
dl 0
loc 29
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Class Jetpack_Constants
5
 * This class is not meant to be used directly
6
 * but the Jetpack class inherits from it for clarity's sanitize_key
7
 *
8
 * If you need to use any of the methods here just use them likes
9
 * Jetpack::method_name() for using it statically.
10
 * Jetpack::init()->method_name() for using it from an instance.
11
 */
12
abstract class Jetpack_Functions {
13
14
	/**
15
	 * Determine whether the active plan supports a particular feature
16
	 *
17
	 * @uses Jetpack::get_active_plan()
18
	 *
19
	 * @access public
20
	 * @static
21
	 *
22
	 * @return bool True if plan supports feature, false if not
23
	 */
24
	public static function active_plan_supports( $feature ) {
25
		$plan = Jetpack::get_active_plan();
26
27
		// Manually mapping WordPress.com features to Jetpack module slugs
28
		foreach ( $plan['features']['active'] as $wpcom_feature ) {
29
			switch ( $wpcom_feature ) {
30
				case 'wordads-jetpack';
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
31
32
				// WordAds are supported for this site
33
				if ( 'wordads' === $feature ) {
34
					return true;
35
				}
36
				break;
37
			}
38
		}
39
40
		if (
41
			in_array( $feature, $plan['supports'] )
42
			|| in_array( $feature, $plan['features']['active'] )
43
		) {
44
			return true;
45
		}
46
47
		return false;
48
	}
49
50
	public static function admin_url( $args = null ) {
51
		$args = wp_parse_args( $args, array( 'page' => 'jetpack' ) );
52
		$url = add_query_arg( $args, admin_url( 'admin.php' ) );
53
		return $url;
54
	}
55
56
	/**
57
	 * Converts any url in a stylesheet, to the correct absolute url.
58
	 *
59
	 * Considerations:
60
	 *  - Normal, relative URLs     `feh.png`
61
	 *  - Data URLs                 `data:image/gif;base64,eh129ehiuehjdhsa==`
62
	 *  - Schema-agnostic URLs      `//domain.com/feh.png`
63
	 *  - Absolute URLs             `http://domain.com/feh.png`
64
	 *  - Domain root relative URLs `/feh.png`
65
	 *
66
	 * @param $css string: The raw CSS -- should be read in directly from the file.
67
	 * @param $css_file_url : The URL that the file can be accessed at, for calculating paths from.
68
	 *
69
	 * @return mixed|string
70
	 */
71
	public static function absolutize_css_urls( $css, $css_file_url ) {
72
		$pattern = '#url\((?P<path>[^)]*)\)#i';
73
		$css_dir = dirname( $css_file_url );
74
		$p       = parse_url( $css_dir );
75
		$domain  = sprintf(
76
					'%1$s//%2$s%3$s%4$s',
77
					isset( $p['scheme'] )           ? "{$p['scheme']}:" : '',
78
					isset( $p['user'], $p['pass'] ) ? "{$p['user']}:{$p['pass']}@" : '',
79
					$p['host'],
80
					isset( $p['port'] )             ? ":{$p['port']}" : ''
81
				);
82
83
		if ( preg_match_all( $pattern, $css, $matches, PREG_SET_ORDER ) ) {
84
			$find = $replace = array();
85
			foreach ( $matches as $match ) {
86
				$url = trim( $match['path'], "'\" \t" );
87
88
				// If this is a data url, we don't want to mess with it.
89
				if ( 'data:' === substr( $url, 0, 5 ) ) {
90
					continue;
91
				}
92
93
				// If this is an absolute or protocol-agnostic url,
94
				// we don't want to mess with it.
95
				if ( preg_match( '#^(https?:)?//#i', $url ) ) {
96
					continue;
97
				}
98
99
				switch ( substr( $url, 0, 1 ) ) {
100
					case '/':
101
						$absolute = $domain . $url;
102
						break;
103
					default:
104
						$absolute = $css_dir . '/' . $url;
105
				}
106
107
				$find[]    = $match[0];
108
				$replace[] = sprintf( 'url("%s")', $absolute );
109
			}
110
			$css = str_replace( $find, $replace, $css );
111
		}
112
113
		return $css;
114
	}
115
116
	/*
117
	 * Strip http:// or https:// from a url, replaces forward slash with ::,
118
	 * so we can bring them directly to their site in calypso.
119
	 *
120
	 * @param string | url
121
	 * @return string | url without the guff
122
	 */
123
	public static function build_raw_urls( $url ) {
124
		$strip_http = '/.*?:\/\//i';
125
		$url = preg_replace( $strip_http, '', $url  );
126
		$url = str_replace( '/', '::', $url );
127
		return $url;
128
	}
129
130
	/**
131
	 * Checks if the site is currently in an identity crisis.
132
	 *
133
	 * @return array|bool Array of options that are in a crisis, or false if everything is OK.
134
	 */
135
	public static function check_identity_crisis() {
136
		if ( ! Jetpack::is_active() || Jetpack::is_development_mode() || ! Jetpack::validate_sync_error_idc_option() ) {
137
			return false;
138
		}
139
140
		return Jetpack_Options::get_option( 'sync_error_idc' );
141
	}
142
143
	/**
144
	 * Gets current user IP address.
145
	 *
146
	 * @param  bool $check_all_headers Check all headers? Default is `false`.
147
	 *
148
	 * @return string                  Current user IP address.
149
	 */
150
	public static function current_user_ip( $check_all_headers = false ) {
151
		if ( $check_all_headers ) {
152
			foreach ( array(
153
				'HTTP_CF_CONNECTING_IP',
154
				'HTTP_CLIENT_IP',
155
				'HTTP_X_FORWARDED_FOR',
156
				'HTTP_X_FORWARDED',
157
				'HTTP_X_CLUSTER_CLIENT_IP',
158
				'HTTP_FORWARDED_FOR',
159
				'HTTP_FORWARDED',
160
				'HTTP_VIA',
161
			) as $key ) {
162
				if ( ! empty( $_SERVER[ $key ] ) ) {
163
					return $_SERVER[ $key ];
164
				}
165
			}
166
		}
167
168
		return ! empty( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : '';
169
	}
170
171
	function current_user_is_connection_owner() {
172
		$user_token = Jetpack_Data::get_access_token( JETPACK_MASTER_USER );
173
		return $user_token && is_object( $user_token ) && isset( $user_token->external_user_id ) && get_current_user_id() === $user_token->external_user_id;
174
	}
175
176
	/**
177
	 * Determines whether the current theme supports featured images or not.
178
	 * @return string ( '1' | '0' )
179
	 */
180
	public static function featured_images_enabled() {
181
		_deprecated_function( __METHOD__, 'jetpack-4.2' );
182
		return current_theme_supports( 'post-thumbnails' ) ? '1' : '0';
183
	}
184
185
	/**
186
	 * Returns true if the site has file write access false otherwise.
187
	 * @return string ( '1' | '0' )
188
	 **/
189
	public static function file_system_write_access() {
190
		if ( ! function_exists( 'get_filesystem_method' ) ) {
191
			require_once( ABSPATH . 'wp-admin/includes/file.php' );
192
		}
193
194
		require_once( ABSPATH . 'wp-admin/includes/template.php' );
195
196
		$filesystem_method = get_filesystem_method();
197
		if ( $filesystem_method === 'direct' ) {
198
			return 1;
199
		}
200
201
		ob_start();
202
		$filesystem_credentials_are_stored = request_filesystem_credentials( self_admin_url() );
203
		ob_end_clean();
204
		if ( $filesystem_credentials_are_stored ) {
205
			return 1;
206
		}
207
		return 0;
208
	}
209
210
	/**
211
	 * Get a list of activated modules as an array of module slugs.
212
	 */
213
	public static function get_active_modules() {
214
		$active = Jetpack_Options::get_option( 'active_modules' );
215
216
		if ( ! is_array( $active ) ) {
217
			$active = array();
218
		}
219
220
		if ( class_exists( 'VaultPress' ) || function_exists( 'vaultpress_contact_service' ) ) {
221
			$active[] = 'vaultpress';
222
		} else {
223
			$active = array_diff( $active, array( 'vaultpress' ) );
224
		}
225
226
		//If protect is active on the main site of a multisite, it should be active on all sites.
227
		if ( ! in_array( 'protect', $active ) && is_multisite() && get_site_option( 'jetpack_protect_active' ) ) {
228
			$active[] = 'protect';
229
		}
230
231
		/**
232
		 * Allow filtering of the active modules.
233
		 *
234
		 * Gives theme and plugin developers the power to alter the modules that
235
		 * are activated on the fly.
236
		 *
237
		 * @since 5.8.0
238
		 *
239
		 * @param array $active Array of active module slugs.
240
		 */
241
		$active = apply_filters( 'jetpack_active_modules', $active );
242
243
		return array_unique( $active );
244
	}
245
246
	/**
247
	 * Get the plan that this Jetpack site is currently using
248
	 *
249
	 * @uses get_option()
250
	 *
251
	 * @access public
252
	 * @static
253
	 *
254
	 * @return array Active Jetpack plan details
255
	 */
256
	public static function get_active_plan() {
257
		global $active_plan_cache;
258
259
		// this can be expensive to compute so we cache for the duration of a request
260
		if ( is_array( $active_plan_cache ) && ! empty( $active_plan_cache ) ) {
261
			return $active_plan_cache;
262
		}
263
264
		$plan = get_option( 'jetpack_active_plan', array() );
265
266
		// Set the default options
267
		$plan = wp_parse_args( $plan, array(
268
			'product_slug' => 'jetpack_free',
269
			'class'        => 'free',
270
			'features'     => array(
271
				'active' => array()
272
			),
273
		) );
274
275
		$supports = array();
276
277
		// Define what paid modules are supported by personal plans
278
		$personal_plans = array(
279
			'jetpack_personal',
280
			'jetpack_personal_monthly',
281
			'personal-bundle',
282
		);
283
284
		if ( in_array( $plan['product_slug'], $personal_plans ) ) {
285
			// special support value, not a module but a separate plugin
286
			$supports[] = 'akismet';
287
			$plan['class'] = 'personal';
288
		}
289
290
		// Define what paid modules are supported by premium plans
291
		$premium_plans = array(
292
			'jetpack_premium',
293
			'jetpack_premium_monthly',
294
			'value_bundle',
295
		);
296
297 View Code Duplication
		if ( in_array( $plan['product_slug'], $premium_plans ) ) {
298
			$supports[] = 'akismet';
299
			$supports[] = 'vaultpress';
300
			$plan['class'] = 'premium';
301
		}
302
303
		// Define what paid modules are supported by professional plans
304
		$business_plans = array(
305
			'jetpack_business',
306
			'jetpack_business_monthly',
307
			'business-bundle',
308
			'vip',
309
		);
310
311 View Code Duplication
		if ( in_array( $plan['product_slug'], $business_plans ) ) {
312
			$supports[] = 'akismet';
313
			$supports[] = 'vaultpress';
314
			$plan['class'] = 'business';
315
		}
316
317
		// get available features
318
		foreach ( Jetpack::get_available_modules() as $module_slug ) {
319
			$module = Jetpack::get_module( $module_slug );
320
			if ( ! isset( $module ) || ! is_array( $module ) ) {
321
				continue;
322
			}
323
			if ( in_array( 'free', $module['plan_classes'] ) || in_array( $plan['class'], $module['plan_classes'] ) ) {
324
				$supports[] = $module_slug;
325
			}
326
		}
327
328
		$plan['supports'] = $supports;
329
330
		$active_plan_cache = $plan;
331
332
		return $plan;
333
	}
334
335
	/**
336
	 * Gets all plugins currently active in values, regardless of whether they're
337
	 * traditionally activated or network activated.
338
	 *
339
	 * @todo Store the result in core's object cache maybe?
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
340
	 */
341
	public static function get_active_plugins() {
342
		$active_plugins = (array) get_option( 'active_plugins', array() );
343
344
		if ( is_multisite() ) {
345
			// Due to legacy code, active_sitewide_plugins stores them in the keys,
346
			// whereas active_plugins stores them in the values.
347
			$network_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
348
			if ( $network_plugins ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $network_plugins 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...
349
				$active_plugins = array_merge( $active_plugins, $network_plugins );
350
			}
351
		}
352
353
		sort( $active_plugins );
354
355
		return array_unique( $active_plugins );
356
	}
357
358
	/**
359
	 * Wrapper for core's get_avatar_url().  This one is deprecated.
360
	 *
361
	 * @deprecated 4.7 use get_avatar_url instead.
362
	 * @param int|string|object $id_or_email A user ID,  email address, or comment object
363
	 * @param int $size Size of the avatar image
364
	 * @param string $default URL to a default image to use if no avatar is available
365
	 * @param bool $force_display Whether to force it to return an avatar even if show_avatars is disabled
366
	 *
367
	 * @return array
368
	 */
369
	public static function get_avatar_url( $id_or_email, $size = 96, $default = '', $force_display = false ) {
370
		_deprecated_function( __METHOD__, 'jetpack-4.7', 'get_avatar_url' );
371
		return get_avatar_url( $id_or_email, array(
372
			'size' => $size,
373
			'default' => $default,
374
			'force_default' => $force_display,
375
		) );
376
	}
377
378
	/**
379
	 * Get the wpcom user data of the current|specified connected user.
380
	 */
381
	public static function get_connected_user_data( $user_id = null ) {
382
		if ( ! $user_id ) {
383
			$user_id = get_current_user_id();
384
		}
385
386
		$transient_key = "jetpack_connected_user_data_$user_id";
387
388
		if ( $cached_user_data = get_transient( $transient_key ) ) {
389
			return $cached_user_data;
390
		}
391
392
		Jetpack::load_xml_rpc_client();
393
		$xml = new Jetpack_IXR_Client( array(
394
			'user_id' => $user_id,
395
		) );
396
		$xml->query( 'wpcom.getUser' );
397
		if ( ! $xml->isError() ) {
398
			$user_data = $xml->getResponse();
399
			set_transient( $transient_key, $xml->getResponse(), DAY_IN_SECONDS );
400
			return $user_data;
401
		}
402
403
		return false;
404
	}
405
406
	/**
407
	 * Get the wpcom email of the current|specified connected user.
408
	 */
409 View Code Duplication
	public static function get_connected_user_email( $user_id = null ) {
410
		if ( ! $user_id ) {
411
			$user_id = get_current_user_id();
412
		}
413
		Jetpack::load_xml_rpc_client();
414
		$xml = new Jetpack_IXR_Client( array(
415
			'user_id' => $user_id,
416
		) );
417
		$xml->query( 'wpcom.getUserEmail' );
418
		if ( ! $xml->isError() ) {
419
			return $xml->getResponse();
420
		}
421
		return false;
422
	}
423
424
	/**
425
	 * Get $content_width, but with a <s>twist</s> filter.
426
	 */
427
	public static function get_content_width() {
428
		$content_width = isset( $GLOBALS['content_width'] ) ? $GLOBALS['content_width'] : false;
429
		/**
430
		 * Filter the Content Width value.
431
		 *
432
		 * @since 2.2.3
433
		 *
434
		 * @param string $content_width Content Width value.
435
		 */
436
		return apply_filters( 'jetpack_content_width', $content_width );
437
	}
438
439
440
		/**
441
		 * Like core's get_file_data implementation, but caches the result.
442
		 */
443
		public static function get_file_data( $file, $headers ) {
444
			//Get just the filename from $file (i.e. exclude full path) so that a consistent hash is generated
445
			$file_name = basename( $file );
446
447
			$cache_key = 'jetpack_file_data_' . JETPACK__VERSION;
448
449
			$file_data_option = get_transient( $cache_key );
450
451
			if ( false === $file_data_option ) {
452
				$file_data_option = array();
453
			}
454
455
			$key           = md5( $file_name . serialize( $headers ) );
456
			$refresh_cache = is_admin() && isset( $_GET['page'] ) && 'jetpack' === substr( $_GET['page'], 0, 7 );
457
458
			// If we don't need to refresh the cache, and already have the value, short-circuit!
459
			if ( ! $refresh_cache && isset( $file_data_option[ $key ] ) ) {
460
				return $file_data_option[ $key ];
461
			}
462
463
			$data = get_file_data( $file, $headers );
464
465
			$file_data_option[ $key ] = $data;
466
467
			set_transient( $cache_key, $file_data_option, 29 * DAY_IN_SECONDS );
468
469
			return $data;
470
		}
471
472
	/**
473
	 * Given a minified path, and a non-minified path, will return
474
	 * a minified or non-minified file URL based on whether SCRIPT_DEBUG is set and truthy.
475
	 *
476
	 * Both `$min_base` and `$non_min_base` are expected to be relative to the
477
	 * root Jetpack directory.
478
	 *
479
	 * @since 5.6.0
480
	 *
481
	 * @param string $min_path
482
	 * @param string $non_min_path
483
	 * @return string The URL to the file
484
	 */
485
	public static function get_file_url_for_environment( $min_path, $non_min_path ) {
486
		$path = ( Jetpack_Constants::is_defined( 'SCRIPT_DEBUG' ) && Jetpack_Constants::get_constant( 'SCRIPT_DEBUG' ) )
487
			? $non_min_path
488
			: $min_path;
489
490
		return plugins_url( $path, JETPACK__PLUGIN_FILE );
491
	}
492
493
	/**
494
	 * Return string containing the Jetpack logo.
495
	 *
496
	 * @since 3.9.0
497
	 *
498
	 * @return string
499
	 */
500
	public static function get_jp_emblem() {
501
		return '<svg id="jetpack-logo__icon" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 32 32"><path fill="#00BE28" d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16c8.8,0,16-7.2,16-16S24.8,0,16,0z M15.2,18.7h-8l8-15.5V18.7z M16.8,28.8 V13.3h8L16.8,28.8z"/></svg>';
502
	}
503
504
	/*
505
	 * This method is used to organize all options that can be reset
506
	 * without disconnecting Jetpack.
507
	 *
508
	 * It is used in class.jetpack-cli.php to reset options
509
	 *
510
	 * @since 5.4.0 Logic moved to Jetpack_Options class. Method left in Jetpack class for backwards compat.
511
	 *
512
	 * @return array of options to delete.
513
	 */
514
	public static function get_jetpack_options_for_reset() {
515
		return Jetpack_Options::get_options_for_reset();
516
	}
517
518
	/**
519
	 * Get the locale.
520
	 *
521
	 * @return string|bool
522
	 */
523
	function get_locale() {
524
		$locale = $this->guess_locale_from_lang( get_locale() );
525
526
		if ( ! $locale ) {
527
			$locale = 'en_US';
528
		}
529
530
		return $locale;
531
	}
532
533
	/**
534
	 * Get the wpcom email of the master user.
535
	 */
536
	public static function get_master_user_email() {
537
		$master_user_id = Jetpack_Options::get_option( 'master_user' );
538
		if ( $master_user_id ) {
539
			return Jetpack::get_connected_user_email( $master_user_id );
540
		}
541
		return '';
542
	}
543
544
	/**
545
	 * Builds the timeout limit for queries talking with the wpcom servers.
546
	 *
547
	 * Based on local php max_execution_time in php.ini
548
	 *
549
	 * @since 5.4
550
	 * @return int
551
	 **/
552
	public static function get_max_execution_time() {
553
		$timeout = (int) ini_get( 'max_execution_time' );
554
555
		// Ensure exec time set in php.ini
556
		if ( ! $timeout ) {
557
			$timeout = 30;
558
		}
559
		return $timeout;
560
	}
561
562
	/**
563
	 * Extract a module's slug from its full path.
564
	 */
565
	public static function get_module_slug( $file ) {
566
		return str_replace( '.php', '', basename( $file ) );
567
	}
568
569
	/**
570
	 * Generate a module's path from its slug.
571
	 */
572
	public static function get_module_path( $slug ) {
573
		return JETPACK__PLUGIN_DIR . "modules/$slug.php";
574
	}
575
576
	/**
577
	 * Load module data from module file. Headers differ from WordPress
578
	 * plugin headers to avoid them being identified as standalone
579
	 * plugins on the WordPress plugins page.
580
	 */
581
	public static function get_module( $module ) {
582
		$headers = array(
583
			'name'                      => 'Module Name',
584
			'description'               => 'Module Description',
585
			'jumpstart_desc'            => 'Jumpstart Description',
586
			'sort'                      => 'Sort Order',
587
			'recommendation_order'      => 'Recommendation Order',
588
			'introduced'                => 'First Introduced',
589
			'changed'                   => 'Major Changes In',
590
			'deactivate'                => 'Deactivate',
591
			'free'                      => 'Free',
592
			'requires_connection'       => 'Requires Connection',
593
			'auto_activate'             => 'Auto Activate',
594
			'module_tags'               => 'Module Tags',
595
			'feature'                   => 'Feature',
596
			'additional_search_queries' => 'Additional Search Queries',
597
			'plan_classes'              => 'Plans',
598
		);
599
600
		$file = Jetpack::get_module_path( Jetpack::get_module_slug( $module ) );
601
602
		$mod = Jetpack::get_file_data( $file, $headers );
603
		if ( empty( $mod['name'] ) ) {
604
			return false;
605
		}
606
607
		$mod['sort']                    = empty( $mod['sort'] ) ? 10 : (int) $mod['sort'];
608
		$mod['recommendation_order']    = empty( $mod['recommendation_order'] ) ? 20 : (int) $mod['recommendation_order'];
609
		$mod['deactivate']              = empty( $mod['deactivate'] );
610
		$mod['free']                    = empty( $mod['free'] );
611
		$mod['requires_connection']     = ( ! empty( $mod['requires_connection'] ) && 'No' == $mod['requires_connection'] ) ? false : true;
612
613
		if ( empty( $mod['auto_activate'] ) || ! in_array( strtolower( $mod['auto_activate'] ), array( 'yes', 'no', 'public' ) ) ) {
614
			$mod['auto_activate'] = 'No';
615
		} else {
616
			$mod['auto_activate'] = (string) $mod['auto_activate'];
617
		}
618
619
		if ( $mod['module_tags'] ) {
620
			$mod['module_tags'] = explode( ',', $mod['module_tags'] );
621
			$mod['module_tags'] = array_map( 'trim', $mod['module_tags'] );
622
			$mod['module_tags'] = array_map( array( 'Jetpack', 'translate_module_tag' ), $mod['module_tags'] );
623
		} else {
624
			$mod['module_tags'] = array( Jetpack::translate_module_tag( 'Other' ) );
625
		}
626
627
		if ( $mod['plan_classes'] ) {
628
			$mod['plan_classes'] = explode( ',', $mod['plan_classes'] );
629
			$mod['plan_classes'] = array_map( 'strtolower', array_map( 'trim', $mod['plan_classes'] ) );
630
		} else {
631
			$mod['plan_classes'] = array( 'free' );
632
		}
633
634
		if ( $mod['feature'] ) {
635
			$mod['feature'] = explode( ',', $mod['feature'] );
636
			$mod['feature'] = array_map( 'trim', $mod['feature'] );
637
		} else {
638
			$mod['feature'] = array( Jetpack::translate_module_tag( 'Other' ) );
639
		}
640
641
		/**
642
		 * Filters the feature array on a module.
643
		 *
644
		 * This filter allows you to control where each module is filtered: Recommended,
645
		 * Jumpstart, and the default "Other" listing.
646
		 *
647
		 * @since 3.5.0
648
		 *
649
		 * @param array   $mod['feature'] The areas to feature this module:
650
		 *     'Jumpstart' adds to the "Jumpstart" option to activate many modules at once.
651
		 *     'Recommended' shows on the main Jetpack admin screen.
652
		 *     'Other' should be the default if no other value is in the array.
653
		 * @param string  $module The slug of the module, e.g. sharedaddy.
654
		 * @param array   $mod All the currently assembled module data.
655
		 */
656
		$mod['feature'] = apply_filters( 'jetpack_module_feature', $mod['feature'], $module, $mod );
657
658
		/**
659
		 * Filter the returned data about a module.
660
		 *
661
		 * This filter allows overriding any info about Jetpack modules. It is dangerous,
662
		 * so please be careful.
663
		 *
664
		 * @since 3.6.0
665
		 *
666
		 * @param array   $mod    The details of the requested module.
667
		 * @param string  $module The slug of the module, e.g. sharedaddy
668
		 * @param string  $file   The path to the module source file.
669
		 */
670
		return apply_filters( 'jetpack_get_module', $mod, $module, $file );
671
	}
672
673
	/**
674
	 * Gets and parses additional plugin data to send with the heartbeat data
675
	 *
676
	 * @since 3.8.1
677
	 *
678
	 * @return array Array of plugin data
679
	 */
680
	public static function get_parsed_plugin_data() {
681
		if ( ! function_exists( 'get_plugins' ) ) {
682
			require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
683
		}
684
		/** This filter is documented in wp-admin/includes/class-wp-plugins-list-table.php */
685
		$all_plugins    = apply_filters( 'all_plugins', get_plugins() );
686
		$active_plugins = Jetpack::get_active_plugins();
687
688
		$plugins = array();
689
		foreach ( $all_plugins as $path => $plugin_data ) {
690
			$plugins[ $path ] = array(
691
					'is_active' => in_array( $path, $active_plugins ),
692
					'file'      => $path,
693
					'name'      => $plugin_data['Name'],
694
					'version'   => $plugin_data['Version'],
695
					'author'    => $plugin_data['Author'],
696
			);
697
		}
698
699
		return $plugins;
700
	}
701
702
	/**
703
	 * Gets and parses theme data to send with the heartbeat data
704
	 *
705
	 * @since 3.8.1
706
	 *
707
	 * @return array Array of theme data
708
	 */
709
	public static function get_parsed_theme_data() {
710
		$all_themes = wp_get_themes( array( 'allowed' => true ) );
711
		$header_keys = array( 'Name', 'Author', 'Version', 'ThemeURI', 'AuthorURI', 'Status', 'Tags' );
712
713
		$themes = array();
714
		foreach ( $all_themes as $slug => $theme_data ) {
715
			$theme_headers = array();
716
			foreach ( $header_keys as $header_key ) {
717
				$theme_headers[ $header_key ] = $theme_data->get( $header_key );
718
			}
719
720
			$themes[ $slug ] = array(
721
					'is_active_theme' => $slug == wp_get_theme()->get_template(),
722
					'slug' => $slug,
723
					'theme_root' => $theme_data->get_theme_root_uri(),
724
					'parent' => $theme_data->parent(),
725
					'headers' => $theme_headers
726
			);
727
		}
728
729
		return $themes;
730
	}
731
732
	/**
733
	 * Guess locale from language code.
734
	 *
735
	 * @param string $lang Language code.
736
	 * @return string|bool
737
	 */
738 View Code Duplication
	function guess_locale_from_lang( $lang ) {
739
		if ( 'en' === $lang || 'en_US' === $lang || ! $lang ) {
740
			return 'en_US';
741
		}
742
743
		if ( ! class_exists( 'GP_Locales' ) ) {
744
			if ( ! defined( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) || ! file_exists( JETPACK__GLOTPRESS_LOCALES_PATH ) ) {
745
				return false;
746
			}
747
748
			require JETPACK__GLOTPRESS_LOCALES_PATH;
749
		}
750
751
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
752
			// WP.com: get_locale() returns 'it'
753
			$locale = GP_Locales::by_slug( $lang );
754
		} else {
755
			// Jetpack: get_locale() returns 'it_IT';
756
			$locale = GP_Locales::by_field( 'facebook_locale', $lang );
757
		}
758
759
		if ( ! $locale ) {
760
			return false;
761
		}
762
763
		if ( empty( $locale->facebook_locale ) ) {
764
			if ( empty( $locale->wp_locale ) ) {
765
				return false;
766
			} else {
767
				// Facebook SDK is smart enough to fall back to en_US if a
768
				// locale isn't supported. Since supported Facebook locales
769
				// can fall out of sync, we'll attempt to use the known
770
				// wp_locale value and rely on said fallback.
771
				return $locale->wp_locale;
772
			}
773
		}
774
775
		return $locale->facebook_locale;
776
	}
777
778
	private static function get_site_user_count() {
779
		global $wpdb;
780
781
		if ( function_exists( 'wp_is_large_network' ) ) {
782
			if ( wp_is_large_network( 'users' ) ) {
783
				return -1; // Not a real value but should tell us that we are dealing with a large network.
784
			}
785
		}
786 View Code Duplication
		if ( false === ( $user_count = get_transient( 'jetpack_site_user_count' ) ) ) {
787
			// It wasn't there, so regenerate the data and save the transient
788
			$user_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '{$wpdb->prefix}capabilities'" );
789
			set_transient( 'jetpack_site_user_count', $user_count, DAY_IN_SECONDS );
790
		}
791
		return $user_count;
792
	}
793
794
	/**
795
	 * Returns an array of all PHP files in the specified absolute path.
796
	 * Equivalent to glob( "$absolute_path/*.php" ).
797
	 *
798
	 * @param string $absolute_path The absolute path of the directory to search.
799
	 * @return array Array of absolute paths to the PHP files.
800
	 */
801
	public static function glob_php( $absolute_path ) {
802
		if ( function_exists( 'glob' ) ) {
803
			return glob( "$absolute_path/*.php" );
804
		}
805
806
		$absolute_path = untrailingslashit( $absolute_path );
807
		$files = array();
808
		if ( ! $dir = @opendir( $absolute_path ) ) {
809
			return $files;
810
		}
811
812
		while ( false !== $file = readdir( $dir ) ) {
813
			if ( '.' == substr( $file, 0, 1 ) || '.php' != substr( $file, -4 ) ) {
814
				continue;
815
			}
816
817
			$file = "$absolute_path/$file";
818
819
			if ( ! is_file( $file ) ) {
820
				continue;
821
			}
822
823
			$files[] = $file;
824
		}
825
826
		closedir( $dir );
827
828
		return $files;
829
	}
830
831
	/**
832
	 * Checks if Akismet is active and working.
833
	 *
834
	 * We dropped support for Akismet 3.0 with Jetpack 6.1.1 while introducing a check for an Akismet valid key
835
	 * that implied usage of methods present since more recent version.
836
	 * See https://github.com/Automattic/jetpack/pull/9585
837
	 *
838
	 * @since  5.1.0
839
	 *
840
	 * @return bool True = Akismet available. False = Aksimet not available.
841
	 */
842
	public static function is_akismet_active() {
843
		if ( method_exists( 'Akismet' , 'http_post' ) ) {
844
			$akismet_key = Akismet::get_api_key();
845
			if ( ! $akismet_key ) {
846
				return false;
847
			}
848
			$akismet_key_state = Akismet::verify_key( $akismet_key );
849
			if ( 'invalid' === $akismet_key_state || 'failed' === $akismet_key_state ) {
850
				return false;
851
			}
852
			return true;
853
		}
854
		return false;
855
	}
856
857
	/**
858
	 * Is Jetpack in development (offline) mode?
859
	 */
860
	public static function is_development_mode() {
861
		$development_mode = false;
862
863
		if ( defined( 'JETPACK_DEV_DEBUG' ) ) {
864
			$development_mode = JETPACK_DEV_DEBUG;
865
		} elseif ( $site_url = site_url() ) {
866
			$development_mode = false === strpos( $site_url, '.' );
867
		}
868
869
		/**
870
		 * Filters Jetpack's development mode.
871
		 *
872
		 * @see https://jetpack.com/support/development-mode/
873
		 *
874
		 * @since 2.2.1
875
		 *
876
		 * @param bool $development_mode Is Jetpack's development mode active.
877
		 */
878
		$development_mode = ( bool ) apply_filters( 'jetpack_development_mode', $development_mode );
879
		return $development_mode;
880
	}
881
882
	/**
883
	 * Whether Jetpack's version maps to a public release, or a development version.
884
	 */
885
	public static function is_development_version() {
886
		/**
887
		 * Allows filtering whether this is a development version of Jetpack.
888
		 *
889
		 * This filter is especially useful for tests.
890
		 *
891
		 * @since 4.3.0
892
		 *
893
		 * @param bool $development_version Is this a develoment version of Jetpack?
894
		 */
895
		return (bool) apply_filters(
896
			'jetpack_development_version',
897
			! preg_match( '/^\d+(\.\d+)+$/', Jetpack_Constants::get_constant( 'JETPACK__VERSION' ) )
898
		);
899
	}
900
901
	/**
902
	 * Check whether or not a Jetpack module is active.
903
	 *
904
	 * @param string $module The slug of a Jetpack module.
905
	 * @return bool
906
	 *
907
	 * @static
908
	 */
909
	public static function is_module_active( $module ) {
910
		return in_array( $module, Jetpack::get_active_modules() );
911
	}
912
913
	public static function is_module( $module ) {
914
		return ! empty( $module ) && ! validate_file( $module, Jetpack::get_available_modules() );
915
	}
916
917
	/**
918
	 * Implemented since there is no core is multi network function
919
	 * Right now there is no way to tell if we which network is the dominant network on the system
920
	 *
921
	 * @since  3.3
922
	 * @return boolean
923
	 */
924
	public static function is_multi_network() {
925
		global  $wpdb;
926
927
		// if we don't have a multi site setup no need to do any more
928
		if ( ! is_multisite() ) {
929
			return false;
930
		}
931
932
		$num_sites = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->site}" );
933
		if ( $num_sites > 1 ) {
934
			return true;
935
		} else {
936
			return false;
937
		}
938
	}
939
940
	/**
941
	 * Return true if we are with multi-site or multi-network false if we are dealing with single site.
942
	 *
943
	 * @param  string  $option
944
	 * @return boolean
945
	 */
946
	public function is_multisite( $option ) {
947
		return (string) (bool) is_multisite();
948
	}
949
950
	/**
951
	 * Whether the site is currently onboarding or not.
952
	 * A site is considered as being onboarded if it currently has an onboarding token.
953
	 *
954
	 * @since 5.8
955
	 *
956
	 * @access public
957
	 * @static
958
	 *
959
	 * @return bool True if the site is currently onboarding, false otherwise
960
	 */
961
	public static function is_onboarding() {
962
		return Jetpack_Options::get_option( 'onboarding' ) !== false;
963
	}
964
965
	/**
966
	 * Checks whether a specific plugin is active.
967
	 *
968
	 * We don't want to store these in a static variable, in case
969
	 * there are switch_to_blog() calls involved.
970
	 */
971
	public static function is_plugin_active( $plugin = 'jetpack/jetpack.php' ) {
972
		return in_array( $plugin, Jetpack::get_active_plugins() );
973
	}
974
975
	/**
976
	 * Checks for whether Jetpack Rewind is enabled.
977
	 * Will return true if the state of Rewind is anything except "unavailable".
978
	 * @return bool|int|mixed
979
	 */
980
	public static function is_rewind_enabled() {
981
		if ( ! Jetpack::is_active() ) {
982
			return false;
983
		}
984
985
		$rewind_enabled = get_transient( 'jetpack_rewind_enabled' );
986
		if ( false === $rewind_enabled ) {
987
			jetpack_require_lib( 'class.core-rest-api-endpoints' );
988
			$rewind_data = (array) Jetpack_Core_Json_Api_Endpoints::rewind_data();
989
			$rewind_enabled = ( ! is_wp_error( $rewind_data )
990
				&& ! empty( $rewind_data['state'] )
991
				&& 'active' === $rewind_data['state'] )
992
				? 1
993
				: 0;
994
995
			set_transient( 'jetpack_rewind_enabled', $rewind_enabled, 10 * MINUTE_IN_SECONDS );
996
		}
997
		return $rewind_enabled;
998
	}
999
1000
	/**
1001
	 * Get back if the current site is single user site.
1002
	 *
1003
	 * @return bool
1004
	 */
1005
	public static function is_single_user_site() {
1006
		global $wpdb;
1007
1008 View Code Duplication
		if ( false === ( $some_users = get_transient( 'jetpack_is_single_user' ) ) ) {
1009
			$some_users = $wpdb->get_var( "SELECT COUNT(*) FROM (SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '{$wpdb->prefix}capabilities' LIMIT 2) AS someusers" );
1010
			set_transient( 'jetpack_is_single_user', (int) $some_users, 12 * HOUR_IN_SECONDS );
1011
		}
1012
		return 1 === (int) $some_users;
1013
	}
1014
1015
	/**
1016
	 * Checks whether the home and siteurl specifically are whitelisted
1017
	 * Written so that we don't have re-check $key and $value params every time
1018
	 * we want to check if this site is whitelisted, for example in footer.php
1019
	 *
1020
	 * @since  3.8.0
1021
	 * @return bool True = already whitelisted False = not whitelisted
1022
	 */
1023
	public static function is_staging_site() {
1024
		$is_staging = false;
1025
1026
		$known_staging = array(
1027
			'urls' => array(
1028
				'#\.staging\.wpengine\.com$#i', // WP Engine
1029
				'#\.staging\.kinsta\.com$#i',   // Kinsta.com
1030
				),
1031
			'constants' => array(
1032
				'IS_WPE_SNAPSHOT',      // WP Engine
1033
				'KINSTA_DEV_ENV',       // Kinsta.com
1034
				'WPSTAGECOACH_STAGING', // WP Stagecoach
1035
				'JETPACK_STAGING_MODE', // Generic
1036
				)
1037
			);
1038
		/**
1039
		 * Filters the flags of known staging sites.
1040
		 *
1041
		 * @since 3.9.0
1042
		 *
1043
		 * @param array $known_staging {
1044
		 *     An array of arrays that each are used to check if the current site is staging.
1045
		 *     @type array $urls      URLs of staging sites in regex to check against site_url.
1046
		 *     @type array $constants PHP constants of known staging/developement environments.
1047
		 *  }
1048
		 */
1049
		$known_staging = apply_filters( 'jetpack_known_staging', $known_staging );
1050
1051
		if ( isset( $known_staging['urls'] ) ) {
1052
			foreach ( $known_staging['urls'] as $url ){
1053
				if ( preg_match( $url, site_url() ) ) {
1054
					$is_staging = true;
1055
					break;
1056
				}
1057
			}
1058
		}
1059
1060
		if ( isset( $known_staging['constants'] ) ) {
1061
			foreach ( $known_staging['constants'] as $constant ) {
1062
				if ( defined( $constant ) && constant( $constant ) ) {
1063
					$is_staging = true;
1064
				}
1065
			}
1066
		}
1067
1068
		// Last, let's check if sync is erroring due to an IDC. If so, set the site to staging mode.
1069
		if ( ! $is_staging && Jetpack::validate_sync_error_idc_option() ) {
1070
			$is_staging = true;
1071
		}
1072
1073
		/**
1074
		 * Filters is_staging_site check.
1075
		 *
1076
		 * @since 3.9.0
1077
		 *
1078
		 * @param bool $is_staging If the current site is a staging site.
1079
		 */
1080
		return apply_filters( 'jetpack_is_staging_site', $is_staging );
1081
	}
1082
1083
	/**
1084
	 * Is a given user (or the current user if none is specified) linked to a WordPress.com user?
1085
	 */
1086
	public static function is_user_connected( $user_id = false ) {
1087
		$user_id = false === $user_id ? get_current_user_id() : absint( $user_id );
1088
		if ( ! $user_id ) {
1089
			return false;
1090
		}
1091
1092
		return (bool) Jetpack_Data::get_access_token( $user_id );
1093
	}
1094
1095
	/**
1096
	 * Finds out if a site is using a version control system.
1097
	 * @return string ( '1' | '0' )
1098
	 **/
1099
	public static function is_version_controlled() {
1100
		_deprecated_function( __METHOD__, 'jetpack-4.2', 'Jetpack_Sync_Functions::is_version_controlled' );
1101
		return (string) (int) Jetpack_Sync_Functions::is_version_controlled();
1102
	}
1103
1104
	/**
1105
	 * Return the network_site_url so that .com knows what network this site is a part of.
1106
	 * @param  bool $option
1107
	 * @return string
1108
	 */
1109
	public function jetpack_main_network_site_option( $option ) {
1110
		return network_site_url();
1111
	}
1112
1113
	/**
1114
	 * Checks whether or not TOS has been agreed upon.
1115
	 * Will return true if a user has clicked to register, or is already connected.
1116
	 */
1117
	public static function jetpack_tos_agreed() {
1118
		return Jetpack_Options::get_option( 'tos_agreed' ) || Jetpack::is_active();
1119
	}
1120
1121
	/**
1122
	 * Loads a view file from the views
1123
	 *
1124
	 * Data passed in with the $data parameter will be available in the
1125
	 * template file as $data['value']
1126
	 *
1127
	 * @param string $template - Template file to load
1128
	 * @param array $data - Any data to pass along to the template
1129
	 * @return boolean - If template file was found
1130
	 **/
1131
	public function load_view( $template, $data = array() ) {
1132
		$views_dir = JETPACK__PLUGIN_DIR . 'views/';
1133
1134
		if( file_exists( $views_dir . $template ) ) {
1135
			require_once( $views_dir . $template );
1136
			return true;
1137
		}
1138
1139
		error_log( "Jetpack: Unable to find view file $views_dir$template" );
1140
		return false;
1141
	}
1142
1143
	/**
1144
	 * Network Name.
1145
	 */
1146
	static function network_name( $option = null ) {
1147
		global $current_site;
1148
		return $current_site->site_name;
1149
	}
1150
	/**
1151
	 * Does the network allow new user and site registrations.
1152
	 * @return string
1153
	 */
1154
	static function network_allow_new_registrations( $option = null ) {
1155
		return ( in_array( get_site_option( 'registration' ), array('none', 'user', 'blog', 'all' ) ) ? get_site_option( 'registration') : 'none' );
1156
	}
1157
	/**
1158
	 * Does the network allow admins to add new users.
1159
	 * @return boolian
1160
	 */
1161
	static function network_add_new_users( $option = null ) {
1162
		return (bool) get_site_option( 'add_new_users' );
1163
	}
1164
	/**
1165
	 * File upload psace left per site in MB.
1166
	 *  -1 means NO LIMIT.
1167
	 * @return number
1168
	 */
1169
	static function network_site_upload_space( $option = null ) {
1170
		// value in MB
1171
		return ( get_site_option( 'upload_space_check_disabled' ) ? -1 : get_space_allowed() );
1172
	}
1173
1174
	/**
1175
	 * Network allowed file types.
1176
	 * @return string
1177
	 */
1178
	static function network_upload_file_types( $option = null ) {
1179
		return get_site_option( 'upload_filetypes', 'jpg jpeg png gif' );
1180
	}
1181
1182
	/**
1183
	 * Maximum file upload size set by the network.
1184
	 * @return number
1185
	 */
1186
	static function network_max_upload_file_size( $option = null ) {
1187
		// value in KB
1188
		return get_site_option( 'fileupload_maxk', 300 );
1189
	}
1190
1191
	/**
1192
	 * Lets us know if a site allows admins to manage the network.
1193
	 * @return array
1194
	 */
1195
	static function network_enable_administration_menus( $option = null ) {
1196
		return get_site_option( 'menu_items' );
1197
	}
1198
1199
	/**
1200
	 * Normalizes a url by doing three things:
1201
	 *  - Strips protocol
1202
	 *  - Strips www
1203
	 *  - Adds a trailing slash
1204
	 *
1205
	 * @since 4.4.0
1206
	 * @param string $url
1207
	 * @return WP_Error|string
1208
	 */
1209
	public static function normalize_url_protocol_agnostic( $url ) {
1210
		$parsed_url = wp_parse_url( trailingslashit( esc_url_raw( $url ) ) );
1211
		if ( ! $parsed_url || empty( $parsed_url['host'] ) || empty( $parsed_url['path'] ) ) {
1212
			return new WP_Error( 'cannot_parse_url', sprintf( esc_html__( 'Cannot parse URL %s', 'jetpack' ), $url ) );
1213
		}
1214
1215
		// Strip www and protocols
1216
		$url = preg_replace( '/^www\./i', '', $parsed_url['host'] . $parsed_url['path'] );
1217
		return $url;
1218
	}
1219
1220
	/**
1221
	 * Sets a minimum request timeout, and returns the current timeout
1222
	 *
1223
	 * @since 5.4
1224
	 **/
1225
	public static function set_min_time_limit( $min_timeout ) {
1226
		$timeout = Jetpack::get_max_execution_time();
1227
		if ( $timeout < $min_timeout ) {
1228
			$timeout = $min_timeout;
1229
			set_time_limit( $timeout );
1230
		}
1231
		return $timeout;
1232
	}
1233
1234
	public static function staticize_subdomain( $url ) {
1235
1236
		// Extract hostname from URL
1237
		$host = parse_url( $url, PHP_URL_HOST );
1238
1239
		// Explode hostname on '.'
1240
		$exploded_host = explode( '.', $host );
1241
1242
		// Retrieve the name and TLD
1243
		if ( count( $exploded_host ) > 1 ) {
1244
			$name = $exploded_host[ count( $exploded_host ) - 2 ];
1245
			$tld = $exploded_host[ count( $exploded_host ) - 1 ];
1246
			// Rebuild domain excluding subdomains
1247
			$domain = $name . '.' . $tld;
1248
		} else {
1249
			$domain = $host;
1250
		}
1251
		// Array of Automattic domains
1252
		$domain_whitelist = array( 'wordpress.com', 'wp.com' );
1253
1254
		// Return $url if not an Automattic domain
1255
		if ( ! in_array( $domain, $domain_whitelist ) ) {
1256
			return $url;
1257
		}
1258
1259
		if ( is_ssl() ) {
1260
			return preg_replace( '|https?://[^/]++/|', 'https://s-ssl.wordpress.com/', $url );
1261
		}
1262
1263
		srand( crc32( basename( $url ) ) );
1264
		$static_counter = rand( 0, 2 );
1265
		srand(); // this resets everything that relies on this, like array_rand() and shuffle()
1266
1267
		return preg_replace( '|://[^/]+?/|', "://s$static_counter.wp.com/", $url );
1268
	}
1269
1270
	static function translate_current_user_to_role() {
1271
		foreach ( Jetpack::$capability_translations as $role => $cap ) {
0 ignored issues
show
Bug introduced by
The property capability_translations cannot be accessed from this context as it is declared private in class Jetpack.

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

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

Loading history...
1272
			if ( current_user_can( $role ) || current_user_can( $cap ) ) {
1273
				return $role;
1274
			}
1275
		}
1276
1277
		return false;
1278
	}
1279
1280
	static function translate_user_to_role( $user ) {
1281
		foreach ( Jetpack::$capability_translations as $role => $cap ) {
0 ignored issues
show
Bug introduced by
The property capability_translations cannot be accessed from this context as it is declared private in class Jetpack.

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

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

Loading history...
1282
			if ( user_can( $user, $role ) || user_can( $user, $cap ) ) {
1283
				return $role;
1284
			}
1285
		}
1286
1287
		return false;
1288
	}
1289
1290
	static function translate_role_to_cap( $role ) {
1291
		if ( ! isset( Jetpack::$capability_translations[$role] ) ) {
0 ignored issues
show
Bug introduced by
The property capability_translations cannot be accessed from this context as it is declared private in class Jetpack.

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

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

Loading history...
1292
			return false;
1293
		}
1294
1295
		return Jetpack::$capability_translations[$role];
0 ignored issues
show
Bug introduced by
The property capability_translations cannot be accessed from this context as it is declared private in class Jetpack.

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

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

Loading history...
1296
	}
1297
1298
	/**
1299
	 * Returns the Jetpack XML-RPC API
1300
	 *
1301
	 * @return string
1302
	 */
1303
	public static function xmlrpc_api_url() {
1304
		$base = preg_replace( '#(https?://[^?/]+)(/?.*)?$#', '\\1', JETPACK__API_BASE );
1305
		return untrailingslashit( $base ) . '/xmlrpc.php';
1306
	}
1307
}
1308