Completed
Push — master ( d0212e...d16ebc )
by
unknown
19:29 queued 09:04
created

Utils::get_url()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 10
nop 2
dl 0
loc 21
rs 8.9617
c 0
b 0
f 0
1
<?php
2
/**
3
 * Utilities class file for the Jetpack Beta plugin.
4
 *
5
 * @package automattic/jetpack-beta
6
 */
7
8
namespace Automattic\JetpackBeta;
9
10
/**
11
 * Utilities class file for the Jetpack Beta plugin.
12
 */
13
class Utils {
14
15
	/**
16
	 * WP Options string: jetpack_beta_active
17
	 *
18
	 * @var string
19
	 */
20
	protected static $option = 'jetpack_beta_active';
21
22
	/**
23
	 * WP Options string: jetpack_beta_dev_currently_installed
24
	 *
25
	 * @var string
26
	 */
27
	protected static $option_dev_installed = 'jetpack_beta_dev_currently_installed';
28
29
	/**
30
	 * WP Options string: jp_beta_autoupdate
31
	 *
32
	 * @var string
33
	 */
34
	protected static $option_autoupdate = 'jp_beta_autoupdate';
35
36
	/**
37
	 * WP Options string: jp_beta_email_notifications
38
	 *
39
	 * @var string
40
	 */
41
	protected static $option_email_notif = 'jp_beta_email_notifications';
42
43
	/**
44
	 * Checks if passed plugin matches JP or JP Dev paths.
45
	 *
46
	 * @param string $plugin - A plugin path.
47
	 */
48
	public static function is_jetpack_plugin( $plugin ) {
49
		return in_array( $plugin, array( JETPACK_PLUGIN_FILE, JETPACK_DEV_PLUGIN_FILE ), true );
50
	}
51
52
	/**
53
	 * Returns active Jetpack plugin file partial path string (jetpack/jetpack.php|jetpack-dev/jetpack.php).
54
	 */
55
	public static function get_plugin_file() {
56
		return self::get_plugin_slug() . '/jetpack.php';
57
	}
58
59
	/**
60
	 * Returns active plugin slug string (jetpack|jetpack-dev).
61
	 */
62 View Code Duplication
	public static function get_plugin_slug() {
63
		$installed = self::get_branch_and_section();
64
		if ( empty( $installed ) || 'stable' === $installed[1] || 'tags' === $installed[1] ) {
65
			return 'jetpack';
66
		}
67
		return JETPACK_DEV_PLUGIN_SLUG;
68
	}
69
70
	/**
71
	 * Builds URL to the admin area for the current site and specified query param.
72
	 *
73
	 * @param string $query - Path relative to the admin URL.
74
	 */
75
	public static function admin_url( $query = '?page=jetpack-beta' ) {
76
		return self::is_network_active()
77
			? network_admin_url( 'admin.php' . $query )
78
			: admin_url( 'admin.php' . $query );
79
	}
80
81
	/**
82
	 * Determine if JP dev version should be updated.
83
	 */
84
	public static function should_update_dev_version() {
85
		return version_compare( self::get_new_jetpack_version( true ), self::get_jetpack_plugin_version( true ), '>' );
86
	}
87
88
	/**
89
	 * Build plugin update data response for dev plugin.
90
	 */
91
	public static function get_jepack_dev_update_response() {
92
		return (object) array(
93
			'id'          => JETPACK_DEV_PLUGIN_SLUG,
94
			'plugin'      => JETPACK_DEV_PLUGIN_SLUG,
95
			'new_version' => self::get_new_jetpack_version( true ),
96
			'slug'        => JETPACK_DEV_PLUGIN_SLUG,
97
			'url'         => self::get_url_dev(),
98
			'package'     => self::get_install_url_dev(),
99
		);
100
	}
101
102
	/**
103
	 * Build plugin update data response for JP dev master.
104
	 */
105
	public static function get_jepack_dev_master_update_response() {
106
		$response = self::get_jepack_dev_update_response();
107
108
		$master_manifest       = self::get_manifest_data( 'master', 'master' );
109
		$response->new_version = $master_manifest->version;
110
		$response->url         = self::get_url( 'master', 'master' );
111
		$response->package     = $master_manifest->download_url;
112
		return $response;
113
	}
114
115
	/**
116
	 * Get the active JP or JP Dev plugin version.
117
	 *
118
	 * @param bool $is_dev_version - If dev plugin version is being queried.
119
	 *
120
	 * @return string|0 Plugin version.
0 ignored issues
show
Documentation introduced by
The doc-type string|0 could not be parsed: Unknown type name "0" at position 7. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
121
	 */
122
	public static function get_jetpack_plugin_version( $is_dev_version = false ) {
123
		if ( $is_dev_version ) {
124
			$info = self::get_jetpack_plugin_info_dev();
125
		} else {
126
			$info = self::get_jetpack_plugin_info();
127
		}
128
129
		return isset( $info['Version'] ) ? $info['Version'] : 0;
130
	}
131
132
	/**
133
	 * Get WP Option: jetpack_beta_active
134
	 */
135
	public static function get_option() {
136
		return get_option( self::$option );
137
	}
138
139
	/**
140
	 * Get WP Option: jetpack_beta_dev_currently_installed
141
	 */
142
	public static function get_dev_installed() {
143
		return get_option( self::$option_dev_installed );
144
	}
145
146
	/**
147
	 * Get active Jetpack branch/section.
148
	 */
149
	public static function get_branch_and_section() {
150
		$option = (array) self::get_option();
151
		if ( false === $option[0] ) {
152
			// See if the Jetpack plugin is enabled.
153
			if ( ! function_exists( 'is_plugin_active' ) ) {
154
				require_once ABSPATH . 'wp-admin/includes/plugin.php';
155
			}
156
			if ( is_plugin_active( JETPACK_PLUGIN_FILE ) ) {
157
				return array( 'stable', 'stable' );
158
			}
159
			return array( false, false );
160
		}
161
		// Branch and section.
162
		return $option;
163
	}
164
165
	/**
166
	 * Check if Jetpack version is 'stable' version.
167
	 */
168 View Code Duplication
	public static function is_on_stable() {
169
		$branch_and_section = self::get_branch_and_section();
170
		if ( empty( $branch_and_section[0] ) || 'stable' === $branch_and_section[0] ) {
171
			return true;
172
		}
173
		return false;
174
	}
175
176
	/**
177
	 * Check if Jetpack active version is a tag version.
178
	 */
179
	public static function is_on_tag() {
180
		$option = (array) self::get_option();
181
		if ( isset( $option[1] ) && 'tags' === $option[1] ) {
182
			return true;
183
		}
184
		return false;
185
	}
186
187
	/**
188
	 * Get active Jetpack Dev branch/section.
189
	 */
190
	public static function get_branch_and_section_dev() {
191
		$option = (array) self::get_dev_installed();
192
		if ( false !== $option[0] && isset( $option[1] ) ) {
193
			return array( $option[0], $option[1] );
194
		}
195
		if ( is_plugin_active( JETPACK_DEV_PLUGIN_FILE ) ) {
196
			return array( 'stable', 'stable' );
197
		}
198
		return array( false, false );
199
	}
200
201
	/**
202
	 * Massage JP plugin version string.
203
	 *
204
	 * @param bool $is_dev_version - If JP Dev version is being queried.
205
	 */
206
	public static function get_jetpack_plugin_pretty_version( $is_dev_version = false ) {
207
		if ( $is_dev_version ) {
208
			list( $branch, $section ) = self::get_branch_and_section_dev();
209
		} else {
210
			list( $branch, $section ) = self::get_branch_and_section();
211
		}
212
213
		if ( ! $section ) {
214
			return '';
215
		}
216
217
		if ( 'master' === $section ) {
218
			return 'Bleeding Edge';
219
		}
220
221
		if ( 'stable' === $section ) {
222
			return 'Latest Stable';
223
		}
224
225
		if ( 'tags' === $section ) {
226
			return sprintf(
227
				// translators: %1$s: a tagged Jetpack plugin version.
228
				__( 'Public release (<a href="https://plugins.trac.wordpress.org/browser/jetpack/tags/%1$s" target="_blank" rel="noopener noreferrer">available on WordPress.org</a>)', 'jetpack-beta' ),
229
				esc_attr( $branch )
230
			);
231
		}
232
233
		if ( 'rc' === $section ) {
234
			return 'Release Candidate';
235
		}
236
237
		if ( 'pr' === $section ) {
238
			$branch = str_replace( '-', ' ', $branch );
239
			return 'Feature Branch: ' . str_replace( '_', ' / ', $branch );
240
		}
241
242
		return self::get_jetpack_plugin_version();
243
	}
244
245
	/**
246
	 * Fetch latest Jetpack version.
247
	 *
248
	 * @param bool $is_dev_version - If JP Dev version is being queried.
249
	 */
250
	public static function get_new_jetpack_version( $is_dev_version = false ) {
251
		$manifest = self::get_beta_manifest();
252
		if ( $is_dev_version ) {
253
			list( $branch, $section ) = self::get_branch_and_section_dev();
254
		} else {
255
			list( $branch, $section ) = self::get_branch_and_section();
256
		}
257
258
		if ( 'master' === $section && isset( $manifest->{$section}->version ) ) {
259
			return $manifest->{$section}->version;
260
		}
261
262
		if ( 'rc' === $section && isset( $manifest->{$section}->version ) ) {
263
			return $manifest->{$section}->version;
264
		}
265
266
		if ( isset( $manifest->{$section} ) &&
267
		isset( $manifest->{$section}->{$branch} ) &&
268
		isset( $manifest->{$section}->{$branch}->version )
269
		) {
270
			return $manifest->{$section}->{$branch}->version;
271
		}
272
		return 0;
273
	}
274
275
	/**
276
	 * Get JP Dev plugin repo URL.
277
	 */
278
	public static function get_url_dev() {
279
		list( $branch, $section ) = self::get_branch_and_section_dev();
280
		return self::get_url( $branch, $section );
281
	}
282
283
	/**
284
	 * Get JP plugin repo URL.
285
	 *
286
	 * @param string $branch  - Branch.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $branch 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...
287
	 * @param string $section - Section.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $section 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...
288
	 */
289
	public static function get_url( $branch = null, $section = null ) {
290
		if ( is_null( $section ) ) {
291
			list( $branch, $section ) = self::get_branch_and_section();
292
		}
293
294
		if ( 'master' === $section ) {
295
			return JETPACK_GITHUB_URL . '/tree/master-build';
296
		}
297
298
		if ( 'rc' === $section ) {
299
			return JETPACK_GITHUB_URL . '/tree/' . $section . '-build';
300
		}
301
302
		if ( 'pr' === $section ) {
303
			$manifest = self::get_beta_manifest();
304
			return isset( $manifest->{$section}->{$branch}->pr )
305
			? JETPACK_GITHUB_URL . '/pull/' . $manifest->{$section}->{$branch}->pr
306
			: JETPACK_DEFAULT_URL;
307
		}
308
		return JETPACK_DEFAULT_URL;
309
	}
310
311
	/**
312
	 * Get install URL for JP dev.
313
	 */
314
	public static function get_install_url_dev() {
315
		list( $branch, $section ) = self::get_branch_and_section_dev();
316
		return self::get_install_url( $branch, $section );
317
	}
318
319
	/**
320
	 * Get install URL for JP.
321
	 *
322
	 * @param string $branch  - Branch.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $branch 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...
323
	 * @param string $section - Section.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $section 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...
324
	 */
325
	public static function get_install_url( $branch = null, $section = null ) {
326
		if ( is_null( $section ) ) {
327
			list( $branch, $section ) = self::get_branch_and_section();
328
		}
329
330
		if ( 'stable' === $section ) {
331
			$org_data = self::get_org_data();
332
			return $org_data->download_link;
333
		} elseif ( 'tags' === $section ) {
334
			$org_data = self::get_org_data();
335
			return $org_data->versions->{$branch} ? $org_data->versions->{$branch} : false;
336
		}
337
		$manifest = self::get_beta_manifest( true );
338
339
		if ( 'master' === $section && isset( $manifest->{$section}->download_url ) ) {
340
			return $manifest->{$section}->download_url;
341
		}
342
343
		if ( 'rc' === $section ) {
344
			if ( isset( $manifest->{$section}->download_url ) ) {
345
				return $manifest->{$section}->download_url;
346
			}
347
			$branches = array_keys( (array) $manifest->{$section} );
348
			foreach ( $branches as $branch ) {
349
				if ( isset( $manifest->{$section}->{$branch}->download_url ) ) {
350
					return $manifest->{$section}->{$branch}->download_url;
351
				}
352
			}
353
			return null;
354
		}
355
356
		if ( isset( $manifest->{$section}->{$branch}->download_url ) ) {
357
			return $manifest->{$section}->{$branch}->download_url;
358
		}
359
		return null;
360
	}
361
362
	/**
363
	 * Get stable JP version plugin data.
364
	 */
365
	public static function get_jetpack_plugin_info_stable() {
366
		return self::get_jetpack_plugin_info( JETPACK_PLUGIN_FILE );
367
	}
368
369
	/**
370
	 * Get dev JP version plugin data.
371
	 */
372
	public static function get_jetpack_plugin_info_dev() {
373
		return self::get_jetpack_plugin_info( JETPACK_DEV_PLUGIN_FILE );
374
	}
375
376
	/**
377
	 * Get JP plugin data.
378
	 *
379
	 * @param mixed $plugin_file - JP or JP Dev plugin path.
380
	 */
381
	public static function get_jetpack_plugin_info( $plugin_file = null ) {
382
383
		if ( is_null( $plugin_file ) ) {
384
			$plugin_file = self::get_plugin_file();
385
		}
386
387
		if ( ! function_exists( 'get_plugin_data' ) ) {
388
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
389
		}
390
		$plugin_file_path = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $plugin_file;
391
392
		if ( file_exists( $plugin_file_path ) ) {
393
			return get_plugin_data( WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $plugin_file );
394
		}
395
396
		return null;
397
	}
398
399
	/**
400
	 * Fetch the Jetpack beta manifest.
401
	 *
402
	 * @param bool $force_refresh - Whether to bypass cached response.
403
	 */
404
	public static function get_beta_manifest( $force_refresh = false ) {
405
		return self::get_remote_data( JETPACK_BETA_MANIFEST_URL, 'manifest', $force_refresh );
406
	}
407
408
	/**
409
	 * Fetch WordPress.org Jetpack plugin info.
410
	 */
411
	public static function get_org_data() {
412
		return self::get_remote_data( JETPACK_ORG_API_URL, 'org_data' );
413
	}
414
415
	/**
416
	 * Helper function used to fetch remote data from WordPress.org, GitHub, and betadownload.jetpack.me
417
	 *
418
	 * @param string $url       - Url being fetched.
419
	 * @param string $transient - Transient name (manifest|org_data|github_commits_).
420
	 * @param bool   $bypass    - Whether to bypass cached response.
421
	 */
422
	public static function get_remote_data( $url, $transient, $bypass = false ) {
423
		$prefix = 'jetpack_beta_';
424
		$cache  = get_site_transient( $prefix . $transient );
425
		if ( $cache && ! $bypass ) {
426
			return $cache;
427
		}
428
429
		$remote_manifest = wp_remote_get( $url );
430
431
		if ( is_wp_error( $remote_manifest ) ) {
432
			return false;
433
		}
434
435
		$cache = json_decode( wp_remote_retrieve_body( $remote_manifest ) );
436
		set_site_transient( $prefix . $transient, $cache, MINUTE_IN_SECONDS * 15 );
437
438
		return $cache;
439
	}
440
441
	/**
442
	 * Delete set transients when plugin is deactivated.
443
	 */
444
	public static function delete_all_transiants() {
445
		$prefix = 'jetpack_beta_';
446
447
		delete_site_transient( $prefix . 'org_data' );
448
		delete_site_transient( $prefix . 'manifest' );
449
450
		delete_site_transient( AutoupdateSelf::TRANSIENT_NAME );
451
452
	}
453
454
	/**
455
	 * Install & activate JP for the given branch/section.
456
	 *
457
	 * @param string $branch  - Branch.
458
	 * @param string $section - Section.
459
	 */
460
	public static function install_and_activate( $branch, $section ) {
461
		// Cleanup previous version of the beta plugin.
462
		if ( file_exists( WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . 'jetpack-pressable-beta' ) ) {
463
			// Delete the Jetpack dev plugin.
464
			require_once ABSPATH . 'wp-admin/includes/file.php';
465
			$creds = request_filesystem_credentials( site_url() . '/wp-admin/', '', false, false, array() );
466
			if ( ! WP_Filesystem( $creds ) ) {
467
				// Any problems and we exit.
468
				return new WP_error( 'Filesystem Problem' );
469
			}
470
			global $wp_filesystem;
471
			if ( ! $wp_filesystem ) {
472
				return new WP_error( '$wp_filesystem is not global' );
473
			}
474
475
			$working_dir = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . 'jetpack-pressable-beta';
476
			// Delete the folder `JETPACK_BETA_PLUGIN_FOLDER`.
477
			if ( $wp_filesystem->is_dir( $working_dir ) ) {
478
				$wp_filesystem->delete( $working_dir, true );
479
			}
480
			// Deactivate the plugin.
481
			self::replace_active_plugin( 'jetpack-pressable-beta/jetpack.php' );
482
		}
483
484 View Code Duplication
		if ( 'stable' === $section &&
485
		file_exists( WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . JETPACK_PLUGIN_FILE ) ) {
486
			self::replace_active_plugin( JETPACK_DEV_PLUGIN_FILE, JETPACK_PLUGIN_FILE, true );
487
			self::update_option( $branch, $section );
488
			return;
489
		}
490
491 View Code Duplication
		if ( self::get_branch_and_section_dev() === array( $branch, $section )
492
		&& file_exists( WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . JETPACK_DEV_PLUGIN_FILE ) ) {
493
			self::replace_active_plugin( JETPACK_PLUGIN_FILE, JETPACK_DEV_PLUGIN_FILE, true );
494
			self::update_option( $branch, $section );
495
			return;
496
		}
497
498
		self::proceed_to_install_and_activate(
499
			self::get_install_url( $branch, $section ),
500
			self::get_plugin_slug( $section ),
0 ignored issues
show
Unused Code introduced by
The call to Utils::get_plugin_slug() has too many arguments starting with $section.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
501
			$section
502
		);
503
		self::update_option( $branch, $section );
504
	}
505
506
	/**
507
	 * Update to the latest version.
508
	 *
509
	 * @param string $branch  - Branch.
510
	 * @param string $section - Section.
511
	 */
512
	public static function update_plugin( $branch, $section ) {
513
		self::proceed_to_install(
514
			self::get_install_url( $branch, $section ),
515
			self::get_plugin_slug( $section ),
0 ignored issues
show
Unused Code introduced by
The call to Utils::get_plugin_slug() has too many arguments starting with $section.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
516
			$section
517
		);
518
519 View Code Duplication
		if ( 'stable' !== $section ) {
520
			update_option( self::$option_dev_installed, array( $branch, $section, self::get_manifest_data( $branch, $section ) ) );
521
		}
522
	}
523
524
	/**
525
	 * Helper function to update installed version option.
526
	 *
527
	 * @param string $branch  - Branch.
528
	 * @param string $section - Section.
529
	 */
530
	public static function update_option( $branch, $section ) {
531 View Code Duplication
		if ( 'stable' !== $section ) {
532
			update_option( self::$option_dev_installed, array( $branch, $section, self::get_manifest_data( $branch, $section ) ) );
533
		}
534
		update_option( self::$option, array( $branch, $section ) );
535
	}
536
537
	/**
538
	 * Return manifest info for specififed branch/section.
539
	 *
540
	 * @param string $branch  - Branch.
541
	 * @param string $section - Section.
542
	 */
543
	public static function get_manifest_data( $branch, $section ) {
544
		$installed             = get_option( self::$option_dev_installed );
545
		$current_manifest_data = isset( $installed[2] ) ? $installed[2] : false;
546
547
		$manifest_data = self::get_beta_manifest();
548
549
		if ( ! isset( $manifest_data->{$section} ) ) {
550
			return $current_manifest_data;
551
		}
552
553
		if ( 'master' === $section ) {
554
			return $manifest_data->{$section};
555
		}
556
557
		if ( 'rc' === $section ) {
558
			return $manifest_data->{$section};
559
		}
560
561
		if ( isset( $manifest_data->{$section}->{$branch} ) ) {
562
			return $manifest_data->{$section}->{$branch};
563
		}
564
565
		return $current_manifest_data;
566
	}
567
568
	/**
569
	 * Install specified plugin version.
570
	 *
571
	 * @param string $url           - Url for plugin version.
572
	 * @param string $plugin_folder - Path JP or JP Dev plugin folder.
573
	 * @param string $section       - Section.
574
	 */
575
	public static function proceed_to_install_and_activate( $url, $plugin_folder, $section ) {
576
		self::proceed_to_install( $url, $plugin_folder, $section );
577
578
		if ( 'stable' === $section || 'tags' === $section ) {
579
			self::replace_active_plugin( JETPACK_DEV_PLUGIN_FILE, JETPACK_PLUGIN_FILE, true );
580
		} else {
581
			self::replace_active_plugin( JETPACK_PLUGIN_FILE, JETPACK_DEV_PLUGIN_FILE, true );
582
		}
583
	}
584
585
	/**
586
	 * Download plugin files.
587
	 *
588
	 * @param string $url           - Url for plugin version.
589
	 * @param string $plugin_folder - Path JP or JP Dev plugin folder.
590
	 * @param string $section       - Section.
591
	 */
592
	public static function proceed_to_install( $url, $plugin_folder, $section ) {
593
		$temp_path = download_url( $url );
594
595 View Code Duplication
		if ( is_wp_error( $temp_path ) ) {
596
			// translators: %1$s: download url, %2$s: error message.
597
			wp_die( wp_kses_post( sprintf( __( 'Error Downloading: <a href="%1$s">%1$s</a> - Error: %2$s', 'jetpack-beta' ), $url, $temp_path->get_error_message() ) ) );
598
		}
599
		require_once ABSPATH . 'wp-admin/includes/file.php';
600
		$creds = request_filesystem_credentials( site_url() . '/wp-admin/', '', false, false, array() );
601
		/* initialize the API */
602
		if ( ! WP_Filesystem( $creds ) ) {
603
			/* any problems and we exit */
604
			wp_die( esc_html( __( 'Jetpack Beta: No File System access', 'jetpack-beta' ) ) );
605
		}
606
607
		global $wp_filesystem;
608
		if ( 'stable' === $section || 'tags' === $section ) {
609
			$plugin_path = WP_PLUGIN_DIR;
610
		} else {
611
			$plugin_path = str_replace( ABSPATH, $wp_filesystem->abspath(), WP_PLUGIN_DIR );
612
		}
613
614
		$result = unzip_file( $temp_path, $plugin_path );
615
616 View Code Duplication
		if ( is_wp_error( $result ) ) {
617
			// translators: %1$s: error message.
618
			wp_die( esc_html( sprintf( __( 'Error Unziping file: Error: %1$s', 'jetpack-beta' ), $result->get_error_message() ) ) );
619
		}
620
	}
621
622
	/**
623
	 * Check if plugin is network activated.
624
	 */
625
	public static function is_network_active() {
626
		if ( ! is_multisite() ) {
627
			return false;
628
		}
629
630
		if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
631
			return false;
632
		}
633
634
		if ( is_plugin_active_for_network( JETPACK_PLUGIN_FILE ) || is_plugin_active_for_network( JETPACK_DEV_PLUGIN_FILE ) ) {
635
			return true;
636
		}
637
638
		return false;
639
	}
640
641
	/**
642
	 * Swap plugin files.
643
	 *
644
	 * @param string $current_plugin      - Current plugin path.
645
	 * @param string $replace_with_plugin - Plugin path to replace with.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $replace_with_plugin 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...
646
	 * @param bool   $force_activate      - Whether to force activate plguin.
647
	 */
648
	public static function replace_active_plugin( $current_plugin, $replace_with_plugin = null, $force_activate = false ) {
649
		// The autoloader sets the cache in a shutdown hook. Clear it after the autoloader sets it.
650
		add_action( 'shutdown', array( self::class, 'clear_autoloader_plugin_cache' ), 99 );
651
652
		if ( self::is_network_active() ) {
653
			$new_active_plugins     = array();
654
			$network_active_plugins = get_site_option( 'active_sitewide_plugins' );
655
			foreach ( $network_active_plugins as $plugin => $date ) {
656
				$key                        = ( $plugin === $current_plugin ? $replace_with_plugin : $plugin );
657
				$new_active_plugins[ $key ] = $date;
658
			}
659
			update_site_option( 'active_sitewide_plugins', $new_active_plugins );
660
			return;
661
		}
662
663
		$active_plugins     = (array) get_option( 'active_plugins', array() );
664
		$new_active_plugins = array();
665
666
		if ( empty( $replace_with_plugin ) ) {
667
			$new_active_plugins = array_diff( $active_plugins, array( $current_plugin ) );
668
		} else {
669
			foreach ( $active_plugins as $plugin ) {
670
				$new_active_plugins[] = ( $plugin === $current_plugin ? $replace_with_plugin : $plugin );
671
			}
672
		}
673
674
		if ( $force_activate && ! in_array( $replace_with_plugin, $new_active_plugins, true ) ) {
675
			$new_active_plugins[] = $replace_with_plugin;
676
		}
677
		update_option( 'active_plugins', $new_active_plugins );
678
	}
679
680
	/**
681
	 * Check if `stable` should be updated.
682
	 *
683
	 * @return bool
684
	 */
685
	public static function should_update_stable_version() {
686
		// Pressable Jetpack version is manage via Pressable.
687
		if ( defined( 'IS_PRESSABLE' ) && IS_PRESSABLE ) {
688
			return false;
689
		}
690
691
		// Check if running in a docker instance.
692
		if ( defined( 'JETPACK_DOCKER_ENV' ) && JETPACK_DOCKER_ENV ) {
693
			return false;
694
		}
695
696
		// Check if we are Jetpack plugin is installed via git.
697
		if ( file_exists( WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . 'jetpack/.git' ) ) {
698
			return false;
699
		}
700
701
		// Check if running a tag directly from svn.
702
		if ( self::is_on_tag() ) {
703
			return false;
704
		}
705
706
		$updates = get_site_transient( 'update_plugins' );
707
708
		if ( isset( $updates->response, $updates->response[ JETPACK_PLUGIN_FILE ] ) ) {
709
			return true;
710
		}
711
		$org_data    = self::get_org_data();
712
		$plugin_data = self::get_jetpack_plugin_info_stable();
713
714
		return ( isset( $plugin_data['Version'], $org_data->version )
715
			&& $org_data->version !== $plugin_data['Version'] );
716
	}
717
718
	/**
719
	 * Here we are checking if the DEV branch that we are currenly on is not something that is available in the manifest
720
	 * Meaning that the DEV branch was merged into master and so we need to update it.
721
	 *
722
	 * @return bool
723
	 */
724
	public static function should_update_dev_to_master() {
725
		list( $branch, $section ) = self::get_branch_and_section_dev();
726
727
		if ( false === $branch || 'master' === $section || 'rc' === $section || 'tags' === $section ) {
728
			return false;
729
		}
730
		$manifest = self::get_beta_manifest();
731
		return ! isset( $manifest->{$section}->{$branch} );
732
	}
733
734
	/**
735
	 * Get WP Option: jp_beta_autoupdate
736
	 */
737
	public static function is_set_to_autoupdate() {
738
		return get_option( self::$option_autoupdate, false );
739
	}
740
741
	/**
742
	 * Get WP Option: jp_beta_email_notifications
743
	 */
744
	public static function is_set_to_email_notifications() {
745
		return get_option( self::$option_email_notif, true );
746
	}
747
748
	/**
749
	 * Get "What changed" info for display.
750
	 *
751
	 * @return string|false
752
	 */
753
	public static function what_changed() {
754
		$commit = self::get_version_commit();
755
		if ( $commit ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $commit of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
756
			$html        = '';
757
			$commit_data = self::get_commit_data_from_github( $commit );
758
			if ( isset( $commit_data->commit->message ) ) {
759
				$html .= sprintf(
760
					__( "\n %1\$s \n\n[Commit](%2\$s)", 'jetpack-beta' ),
761
					esc_html( $commit_data->commit->message ),
762
					esc_url( $commit_data->html_url )
763
				);
764
				"\n\n";
765
			}
766
			if ( ! empty( $commit_data->files ) ) {
767
				$html .= "\n\n";
768
				// translators: %d: number of files changed.
769
				$html .= sprintf( _n( '%d file changed ', '%d files changed', count( $commit_data->files ), 'jetpack-beta' ) );
770
				$html .= "\n";
771
				foreach ( $commit_data->files as $file ) {
772
					$added_deleted_changed = array();
773
					if ( $file->additions ) {
774
						$added_deleted_changed[] = '+' . $file->additions;
775
					}
776
					if ( $file->deletions ) {
777
						$added_deleted_changed[] = '-' . $file->deletions;
778
					}
779
					$html .= sprintf( "- %s ... (%s %s) \n", esc_html( $file->filename ), esc_html( $file->status ), implode( ' ', $added_deleted_changed ) );
780
				}
781
				$html .= "\n\n";
782
			}
783
			if ( ! empty( $html ) ) {
784
				return $html;
785
			}
786
		}
787
		return false;
788
	}
789
790
	/**
791
	 * Get version commit if available.
792
	 *
793
	 * @return string|false
794
	 */
795
	public static function get_version_commit() {
796
		$split_version = explode( '-', self::get_jetpack_plugin_version() );
797
		if ( isset( $split_version[3] ) ) {
798
			return $split_version[3];
799
		}
800
		return false;
801
	}
802
803
	/**
804
	 * Fetch commit data from GitHub.
805
	 *
806
	 * @param string $commit - The commit to fetch.
807
	 */
808
	public static function get_commit_data_from_github( $commit ) {
809
		return self::get_remote_data( JETPACK_GITHUB_API_URL . 'commits/' . $commit, 'github_commits_' . $commit );
810
	}
811
812
	/**
813
	 * Checks if a dir is empty.
814
	 *
815
	 * @param [type] $dir The absolute directory path to check.
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
816
	 * @return boolean
817
	 */
818
	public static function is_dir_empty( $dir ) {
819
		return ( count( scandir( $dir ) ) === 2 );
820
	}
821
822
	/**
823
	 * Clears the autoloader transient.
824
	 */
825
	public static function clear_autoloader_plugin_cache() {
826
		delete_transient( 'jetpack_autoloader_plugin_paths' );
827
	}
828
}
829