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'; |
|
|
|
|
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? |
|
|
|
|
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 ) { |
|
|
|
|
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 ) { |
|
|
|
|
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 ) { |
|
|
|
|
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] ) ) { |
|
|
|
|
1292
|
|
|
return false; |
1293
|
|
|
} |
1294
|
|
|
|
1295
|
|
|
return Jetpack::$capability_translations[$role]; |
|
|
|
|
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
|
|
|
|
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.
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.