Completed
Push — try/add-jetpack-purchase-token ( 0a4d98...ef8438 )
by
unknown
10:51
created

Functions::normalize_www_in_url()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Utility functions to generate data synced to wpcom
4
 *
5
 * @package automattic/jetpack-sync
6
 */
7
8
namespace Automattic\Jetpack\Sync;
9
10
use Automattic\Jetpack\Connection\Urls;
11
use Automattic\Jetpack\Constants;
12
13
/**
14
 * Utility functions to generate data synced to wpcom
15
 */
16
class Functions {
17
	const HTTPS_CHECK_OPTION_PREFIX = 'jetpack_sync_https_history_';
18
	const HTTPS_CHECK_HISTORY       = 5;
19
20
	/**
21
	 * Return array of Jetpack modules.
22
	 *
23
	 * @return array
24
	 */
25
	public static function get_modules() {
26
		if ( defined( 'JETPACK__PLUGIN_DIR' ) ) {
27
			require_once JETPACK__PLUGIN_DIR . 'class.jetpack-admin.php';
28
29
			return \Jetpack_Admin::init()->get_modules();
30
		}
31
32
		return array();
33
	}
34
35
	/**
36
	 * Return array of taxonomies registered on the site.
37
	 *
38
	 * @return array
39
	 */
40
	public static function get_taxonomies() {
41
		global $wp_taxonomies;
42
		$wp_taxonomies_without_callbacks = array();
43
		foreach ( $wp_taxonomies as $taxonomy_name => $taxonomy ) {
44
			$sanitized_taxonomy = self::sanitize_taxonomy( $taxonomy );
45
			if ( ! empty( $sanitized_taxonomy ) ) {
46
				$wp_taxonomies_without_callbacks[ $taxonomy_name ] = $sanitized_taxonomy;
47
			}
48
		}
49
		return $wp_taxonomies_without_callbacks;
50
	}
51
52
	/**
53
	 * Return array of registered shortcodes.
54
	 *
55
	 * @return array
56
	 */
57
	public static function get_shortcodes() {
58
		global $shortcode_tags;
59
		return array_keys( $shortcode_tags );
60
	}
61
62
	/**
63
	 * Removes any callback data since we will not be able to process it on our side anyways.
64
	 *
65
	 * @param \WP_Taxonomy $taxonomy \WP_Taxonomy item.
66
	 *
67
	 * @return mixed|null
68
	 */
69
	public static function sanitize_taxonomy( $taxonomy ) {
70
71
		// Lets clone the taxonomy object instead of modifing the global one.
72
		$cloned_taxonomy = json_decode( wp_json_encode( $taxonomy ) );
73
74
		// recursive taxonomies are no fun.
75
		if ( is_null( $cloned_taxonomy ) ) {
76
			return null;
77
		}
78
		// Remove any meta_box_cb if they are not the default wp ones.
79
		if ( isset( $cloned_taxonomy->meta_box_cb ) &&
80
			! in_array( $cloned_taxonomy->meta_box_cb, array( 'post_tags_meta_box', 'post_categories_meta_box' ), true ) ) {
81
			$cloned_taxonomy->meta_box_cb = null;
82
		}
83
		// Remove update call back.
84
		if ( isset( $cloned_taxonomy->update_count_callback ) &&
85
			! is_null( $cloned_taxonomy->update_count_callback ) ) {
86
			$cloned_taxonomy->update_count_callback = null;
87
		}
88
		// Remove rest_controller_class if it something other then the default.
89
		if ( isset( $cloned_taxonomy->rest_controller_class ) &&
90
			'WP_REST_Terms_Controller' !== $cloned_taxonomy->rest_controller_class ) {
91
			$cloned_taxonomy->rest_controller_class = null;
92
		}
93
		return $cloned_taxonomy;
94
	}
95
96
	/**
97
	 * Return array of registered post types.
98
	 *
99
	 * @return array
100
	 */
101
	public static function get_post_types() {
102
		global $wp_post_types;
103
104
		$post_types_without_callbacks = array();
105
		foreach ( $wp_post_types as $post_type_name => $post_type ) {
106
			$sanitized_post_type = self::sanitize_post_type( $post_type );
107
			if ( ! empty( $sanitized_post_type ) ) {
108
				$post_types_without_callbacks[ $post_type_name ] = $sanitized_post_type;
109
			}
110
		}
111
		return $post_types_without_callbacks;
112
	}
113
114
	/**
115
	 * Sanitizes by cloning post type object.
116
	 *
117
	 * @param object $post_type \WP_Post_Type.
118
	 *
119
	 * @return object
120
	 */
121
	public static function sanitize_post_type( $post_type ) {
122
		// Lets clone the post type object instead of modifing the global one.
123
		$sanitized_post_type = array();
124
		foreach ( Defaults::$default_post_type_attributes as $attribute_key => $default_value ) {
125
			if ( isset( $post_type->{ $attribute_key } ) ) {
126
				$sanitized_post_type[ $attribute_key ] = $post_type->{ $attribute_key };
127
			}
128
		}
129
		return (object) $sanitized_post_type;
130
	}
131
132
	/**
133
	 * Return information about a synced post type.
134
	 *
135
	 * @param array  $sanitized_post_type Array of args used in constructing \WP_Post_Type.
136
	 * @param string $post_type Post type name.
137
	 *
138
	 * @return object \WP_Post_Type
139
	 */
140
	public static function expand_synced_post_type( $sanitized_post_type, $post_type ) {
141
		$post_type        = sanitize_key( $post_type );
142
		$post_type_object = new \WP_Post_Type( $post_type, $sanitized_post_type );
143
		$post_type_object->add_supports();
144
		$post_type_object->add_rewrite_rules();
145
		$post_type_object->add_hooks();
146
		$post_type_object->register_taxonomies();
147
		return (object) $post_type_object;
148
	}
149
150
	/**
151
	 * Returns site's post_type_features.
152
	 *
153
	 * @return array
154
	 */
155
	public static function get_post_type_features() {
156
		global $_wp_post_type_features;
157
158
		return $_wp_post_type_features;
159
	}
160
161
	/**
162
	 * Return hosting provider.
163
	 *
164
	 * Uses a set of known constants, classes, or functions to help determine the hosting platform.
165
	 *
166
	 * @return string Hosting provider.
167
	 */
168
	public static function get_hosting_provider() {
169
		$hosting_provider_detection_methods = array(
170
			'get_hosting_provider_by_known_constant',
171
			'get_hosting_provider_by_known_class',
172
			'get_hosting_provider_by_known_function',
173
		);
174
175
		$functions = new Functions();
176
		foreach ( $hosting_provider_detection_methods as $method ) {
177
			$hosting_provider = call_user_func( array( $functions, $method ) );
178
			if ( false !== $hosting_provider ) {
179
				return $hosting_provider;
180
			}
181
		}
182
183
		return 'unknown';
184
	}
185
186
	/**
187
	 * Return a hosting provider using a set of known constants.
188
	 *
189
	 * @return mixed A host identifier string or false.
190
	 */
191
	public function get_hosting_provider_by_known_constant() {
192
		$hosting_provider_constants = array(
193
			'GD_SYSTEM_PLUGIN_DIR' => 'gd-managed-wp',
194
			'MM_BASE_DIR'          => 'bh',
195
			'PAGELYBIN'            => 'pagely',
196
			'KINSTAMU_VERSION'     => 'kinsta',
197
			'FLYWHEEL_CONFIG_DIR'  => 'flywheel',
198
			'IS_PRESSABLE'         => 'pressable',
199
			'VIP_GO_ENV'           => 'vip-go',
200
		);
201
202
		foreach ( $hosting_provider_constants as $constant => $constant_value ) {
203
			if ( Constants::is_defined( $constant ) ) {
204
				if ( 'VIP_GO_ENV' === $constant && false === Constants::get_constant( 'VIP_GO_ENV' ) ) {
205
					continue;
206
				}
207
				return $constant_value;
208
			}
209
		}
210
211
		return false;
212
	}
213
214
	/**
215
	 * Return a hosting provider using a set of known classes.
216
	 *
217
	 * @return mixed A host identifier string or false.
218
	 */
219
	public function get_hosting_provider_by_known_class() {
220
		$hosting_provider = false;
221
222
		switch ( true ) {
223
			case ( class_exists( '\\WPaaS\\Plugin' ) ):
224
				$hosting_provider = 'gd-managed-wp';
225
				break;
226
		}
227
228
		return $hosting_provider;
229
	}
230
231
	/**
232
	 * Return a hosting provider using a set of known functions.
233
	 *
234
	 * @return mixed A host identifier string or false.
235
	 */
236
	public function get_hosting_provider_by_known_function() {
237
		$hosting_provider = false;
238
239
		switch ( true ) {
240
			case ( function_exists( 'is_wpe' ) || function_exists( 'is_wpe_snapshot' ) ):
241
				$hosting_provider = 'wpe';
242
				break;
243
		}
244
245
		return $hosting_provider;
246
	}
247
248
	/**
249
	 * Return array of allowed REST API post types.
250
	 *
251
	 * @return array Array of allowed post types.
252
	 */
253
	public static function rest_api_allowed_post_types() {
254
		/** This filter is already documented in class.json-api-endpoints.php */
255
		return apply_filters( 'rest_api_allowed_post_types', array( 'post', 'page', 'revision' ) );
256
	}
257
258
	/**
259
	 * Return array of allowed REST API public metadata.
260
	 *
261
	 * @return array Array of allowed metadata.
262
	 */
263
	public static function rest_api_allowed_public_metadata() {
264
		/**
265
		 * Filters the meta keys accessible by the REST API.
266
		 *
267
		 * @see https://developer.wordpress.com/2013/04/26/custom-post-type-and-metadata-support-in-the-rest-api/
268
		 *
269
		 * @module json-api
270
		 *
271
		 * @since 2.2.3
272
		 *
273
		 * @param array $whitelisted_meta Array of metadata that is accessible by the REST API.
274
		 */
275
		return apply_filters( 'rest_api_allowed_public_metadata', array() );
276
	}
277
278
	/**
279
	 * Finds out if a site is using a version control system.
280
	 *
281
	 * @return bool
282
	 **/
283
	public static function is_version_controlled() {
284
285
		if ( ! class_exists( 'WP_Automatic_Updater' ) ) {
286
			require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
287
		}
288
		$updater = new \WP_Automatic_Updater();
289
290
		return (bool) (string) $updater->is_vcs_checkout( ABSPATH );
291
	}
292
293
	/**
294
	 * Returns true if the site has file write access false otherwise.
295
	 *
296
	 * @return bool
297
	 **/
298
	public static function file_system_write_access() {
299
		if ( ! function_exists( 'get_filesystem_method' ) ) {
300
			require_once ABSPATH . 'wp-admin/includes/file.php';
301
		}
302
303
		require_once ABSPATH . 'wp-admin/includes/template.php';
304
305
		$filesystem_method = get_filesystem_method();
306
		if ( 'direct' === $filesystem_method ) {
307
			return true;
308
		}
309
310
		ob_start();
311
312
		if ( ! function_exists( 'request_filesystem_credentials' ) ) {
313
			require_once ABSPATH . 'wp-admin/includes/file.php';
314
		}
315
316
		$filesystem_credentials_are_stored = request_filesystem_credentials( self_admin_url() );
317
		ob_end_clean();
318
		if ( $filesystem_credentials_are_stored ) {
319
			return true;
320
		}
321
322
		return false;
323
	}
324
325
	/**
326
	 * Helper function that is used when getting home or siteurl values. Decides
327
	 * whether to get the raw or filtered value.
328
	 *
329
	 * @param string $url_type URL to get, home or siteurl.
330
	 * @return string
331
	 */
332
	public static function get_raw_or_filtered_url( $url_type ) {
333
		_deprecated_function( __METHOD__, 'jetpack-9.9', '\\Automattic\\Jetpack\\Connection\\Urls::get_raw_or_filtered_url' );
334
		return Urls::get_raw_or_filtered_url( $url_type );
335
	}
336
337
	/**
338
	 * Return the escaped home_url.
339
	 *
340
	 * @return string
341
	 */
342
	public static function home_url() {
343
		_deprecated_function( __METHOD__, 'jetpack-9.9', '\\Automattic\\Jetpack\\Connection\\Urls::home_url' );
344
		return Urls::home_url();
345
	}
346
347
	/**
348
	 * Return the escaped siteurl.
349
	 *
350
	 * @return string
351
	 */
352
	public static function site_url() {
353
		_deprecated_function( __METHOD__, 'jetpack-9.9', '\\Automattic\\Jetpack\\Connection\\Urls::site_url' );
354
		return Urls::site_url();
355
	}
356
357
	/**
358
	 * Return main site URL with a normalized protocol.
359
	 *
360
	 * @return string
361
	 */
362
	public static function main_network_site_url() {
363
		_deprecated_function( __METHOD__, 'jetpack-9.9', '\\Automattic\\Jetpack\\Connection\\Urls::main_network_site_url' );
364
		return Urls::main_network_site_url();
365
	}
366
367
	/**
368
	 * Return main site WordPress.com site ID.
369
	 *
370
	 * @return string
371
	 */
372
	public static function main_network_site_wpcom_id() {
373
		/**
374
		 * Return the current site WPCOM ID for single site installs
375
		 */
376
		if ( ! is_multisite() ) {
377
			return \Jetpack_Options::get_option( 'id' );
378
		}
379
380
		/**
381
		 * Return the main network site WPCOM ID for multi-site installs
382
		 */
383
		$current_network = get_network();
384
		switch_to_blog( $current_network->blog_id );
385
		$wpcom_blog_id = \Jetpack_Options::get_option( 'id' );
386
		restore_current_blog();
387
		return $wpcom_blog_id;
388
	}
389
390
	/**
391
	 * Return URL with a normalized protocol.
392
	 *
393
	 * @param callable $callable Function to retrieve URL option.
394
	 * @param string   $new_value URL Protocol to set URLs to.
395
	 * @return string Normalized URL.
396
	 */
397
	public static function get_protocol_normalized_url( $callable, $new_value ) {
398
		_deprecated_function( __METHOD__, 'jetpack-9.9', '\\Automattic\\Jetpack\\Connection\\Urls::get_protocol_normalized_url' );
399
		return Urls::get_protocol_normalized_url( $callable, $new_value );
400
	}
401
402
	/**
403
	 * Return URL from option or PHP constant.
404
	 *
405
	 * @param string $option_name (e.g. 'home').
406
	 *
407
	 * @return mixed|null URL.
408
	 */
409
	public static function get_raw_url( $option_name ) {
410
		_deprecated_function( __METHOD__, 'jetpack-9.9', '\\Automattic\\Jetpack\\Connection\\Urls::get_raw_url' );
411
		return Urls::get_raw_url( $option_name );
412
	}
413
414
	/**
415
	 * Normalize domains by removing www unless declared in the site's option.
416
	 *
417
	 * @param string   $option Option value from the site.
418
	 * @param callable $url_function Function retrieving the URL to normalize.
419
	 * @return mixed|string URL.
420
	 */
421
	public static function normalize_www_in_url( $option, $url_function ) {
422
		_deprecated_function( __METHOD__, 'jetpack-9.9', '\\Automattic\\Jetpack\\Connection\\Urls::normalize_www_in_url' );
423
		return Urls::normalize_www_in_url( $option, $url_function );
424
	}
425
426
	/**
427
	 * Return filtered value of get_plugins.
428
	 *
429
	 * @return mixed|void
430
	 */
431
	public static function get_plugins() {
432
		if ( ! function_exists( 'get_plugins' ) ) {
433
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
434
		}
435
436
		/** This filter is documented in wp-admin/includes/class-wp-plugins-list-table.php */
437
		return apply_filters( 'all_plugins', get_plugins() );
438
	}
439
440
	/**
441
	 * Get custom action link tags that the plugin is using
442
	 * Ref: https://codex.wordpress.org/Plugin_API/Filter_Reference/plugin_action_links_(plugin_file_name)
443
	 *
444
	 * @param string $plugin_file_singular Particular plugin.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $plugin_file_singular not be string|null?

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

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

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

Loading history...
445
	 * @return array of plugin action links (key: link name value: url)
446
	 */
447
	public static function get_plugins_action_links( $plugin_file_singular = null ) {
448
		// Some sites may have DOM disabled in PHP fail early.
449
		if ( ! class_exists( 'DOMDocument' ) ) {
450
			return array();
451
		}
452
		$plugins_action_links = get_option( 'jetpack_plugin_api_action_links', array() );
453
		if ( ! empty( $plugins_action_links ) ) {
454
			if ( is_null( $plugin_file_singular ) ) {
455
				return $plugins_action_links;
456
			}
457
			return ( isset( $plugins_action_links[ $plugin_file_singular ] ) ? $plugins_action_links[ $plugin_file_singular ] : null );
458
		}
459
		return array();
460
	}
461
462
	/**
463
	 * Return the WP version as defined in the $wp_version global.
464
	 *
465
	 * @return string
466
	 */
467
	public static function wp_version() {
468
		global $wp_version;
469
		return $wp_version;
470
	}
471
472
	/**
473
	 * Return site icon url used on the site.
474
	 *
475
	 * @param int $size Size of requested icon in pixels.
476
	 * @return mixed|string|void
477
	 */
478
	public static function site_icon_url( $size = 512 ) {
479
		$site_icon = get_site_icon_url( $size );
480
		return $site_icon ? $site_icon : get_option( 'jetpack_site_icon_url' );
481
	}
482
483
	/**
484
	 * Return roles registered on the site.
485
	 *
486
	 * @return array
487
	 */
488
	public static function roles() {
489
		$wp_roles = wp_roles();
490
		return $wp_roles->roles;
491
	}
492
493
	/**
494
	 * Determine time zone from WordPress' options "timezone_string"
495
	 * and "gmt_offset".
496
	 *
497
	 * 1. Check if `timezone_string` is set and return it.
498
	 * 2. Check if `gmt_offset` is set, formats UTC-offset from it and return it.
499
	 * 3. Default to "UTC+0" if nothing is set.
500
	 *
501
	 * Note: This function is specifically not using wp_timezone() to keep consistency with
502
	 * the existing formatting of the timezone string.
503
	 *
504
	 * @return string
505
	 */
506
	public static function get_timezone() {
507
		$timezone_string = get_option( 'timezone_string' );
508
509
		if ( ! empty( $timezone_string ) ) {
510
			return str_replace( '_', ' ', $timezone_string );
511
		}
512
513
		$gmt_offset = get_option( 'gmt_offset', 0 );
514
515
		$formatted_gmt_offset = sprintf( '%+g', (float) $gmt_offset );
516
517
		$formatted_gmt_offset = str_replace(
518
			array( '.25', '.5', '.75' ),
519
			array( ':15', ':30', ':45' ),
520
			(string) $formatted_gmt_offset
521
		);
522
523
		/* translators: %s is UTC offset, e.g. "+1" */
524
		return sprintf( __( 'UTC%s', 'jetpack' ), $formatted_gmt_offset );
525
	}
526
527
	/**
528
	 * Return list of paused themes.
529
	 *
530
	 * @return array|bool Array of paused themes or false if unsupported.
531
	 */
532
	public static function get_paused_themes() {
533
		$paused_themes = wp_paused_themes();
534
		return $paused_themes->get_all();
535
	}
536
537
	/**
538
	 * Return list of paused plugins.
539
	 *
540
	 * @return array|bool Array of paused plugins or false if unsupported.
541
	 */
542
	public static function get_paused_plugins() {
543
		$paused_plugins = wp_paused_plugins();
544
		return $paused_plugins->get_all();
545
	}
546
547
	/**
548
	 * Return the theme's supported features.
549
	 * Used for syncing the supported feature that we care about.
550
	 *
551
	 * @return array List of features that the theme supports.
552
	 */
553
	public static function get_theme_support() {
554
		global $_wp_theme_features;
555
556
		$theme_support = array();
557
		foreach ( Defaults::$default_theme_support_whitelist as $theme_feature ) {
558
			$has_support = current_theme_supports( $theme_feature );
559
			if ( $has_support ) {
560
				$theme_support[ $theme_feature ] = $_wp_theme_features[ $theme_feature ];
561
			}
562
		}
563
564
		return $theme_support;
565
	}
566
567
	/**
568
	 * Wraps data in a way so that we can distinguish between objects and array and also prevent object recursion.
569
	 *
570
	 * @since 9.5.0
571
	 *
572
	 * @param array|obj $any        Source data to be cleaned up.
573
	 * @param array     $seen_nodes Built array of nodes.
574
	 *
575
	 * @return array
576
	 */
577
	public static function json_wrap( &$any, $seen_nodes = array() ) {
578
		if ( is_object( $any ) ) {
579
			$input        = get_object_vars( $any );
580
			$input['__o'] = 1;
581
		} else {
582
			$input = &$any;
583
		}
584
585
		if ( is_array( $input ) ) {
586
			$seen_nodes[] = &$any;
587
588
			$return = array();
589
590
			foreach ( $input as $k => &$v ) {
591
				if ( ( is_array( $v ) || is_object( $v ) ) ) {
592
					if ( in_array( $v, $seen_nodes, true ) ) {
593
						continue;
594
					}
595
					$return[ $k ] = self::json_wrap( $v, $seen_nodes );
0 ignored issues
show
Bug introduced by
It seems like $v can also be of type object; however, Automattic\Jetpack\Sync\Functions::json_wrap() does only seem to accept array|object<Automattic\Jetpack\Sync\obj>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
596
				} else {
597
					$return[ $k ] = $v;
598
				}
599
			}
600
601
			return $return;
602
		}
603
604
		return $any;
605
606
	}
607
}
608