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

Hooks   F

Complexity

Total Complexity 98

Size/Duplication

Total Lines 686
Duplicated Lines 0.87 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 0
Metric Value
dl 6
loc 686
rs 1.914
c 0
b 0
f 0
wmc 98
lcom 2
cbo 5

25 Methods

Rating   Name   Duplication   Size   Complexity  
A instance() 0 7 2
A __construct() 0 28 2
A upgrader_process_complete() 0 15 6
A is_network_enabled() 0 5 2
A override_active_plugins() 0 9 3
A plugin_deactivated() 0 7 2
A remove_activate_dev() 3 6 3
A remove_activate_stable() 3 6 3
A update_all_plugins() 0 18 5
A get_plugin_info() 0 27 4
A activate() 0 7 2
A deactivate() 0 12 2
A remove_dev_plugin() 0 25 5
B admin_bar_menu() 0 54 6
B maybe_plugins_update_transient() 0 38 7
A upgrader_post_install() 0 16 4
A switch_active() 0 3 1
A clear_autoupdate_cron() 0 10 3
A schedule_hourly_autoupdate() 0 4 1
A maybe_schedule_autoupdate() 0 13 4
C run_autoupdate() 0 58 13
B send_autoupdate_email() 0 74 6
B check_for_main_files() 0 20 6
A add_to_options_whitelist() 0 7 1
A custom_error_handler() 0 25 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Hooks often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Hooks, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Hooks class class file for the Jetpack Beta plugin.
4
 *
5
 * @package automattic/jetpack-beta
6
 */
7
8
namespace Automattic\JetpackBeta;
9
10
use Jetpack;
11
use Language_Pack_Upgrader;
12
use Plugin_Upgrader;
13
use WP_Ajax_Upgrader_Skin;
14
use WP_Error;
15
16
/**
17
 * Hooks class class file for the Jetpack Beta plugin.
18
 */
19
class Hooks {
20
21
	/**
22
	 * Singleton class instance.
23
	 *
24
	 * @var static
25
	 */
26
	protected static $instance = null;
27
28
	/**
29
	 * WP Options string: jetpack_beta_active
30
	 *
31
	 * @var string
32
	 */
33
	protected static $option = 'jetpack_beta_active';
34
35
	/**
36
	 * WP Options string: jetpack_beta_dev_currently_installed
37
	 *
38
	 * @var string
39
	 */
40
	protected static $option_dev_installed = 'jetpack_beta_dev_currently_installed';
41
42
	/**
43
	 * WP Options string: jp_beta_autoupdate
44
	 *
45
	 * @var string
46
	 */
47
	protected static $option_autoupdate = 'jp_beta_autoupdate';
48
49
	/**
50
	 * WP Options string: jp_beta_email_notifications
51
	 *
52
	 * @var string
53
	 */
54
	protected static $option_email_notif = 'jp_beta_email_notifications';
55
56
	/**
57
	 * WP-Cron string: jetpack_beta_autoupdate_hourly_cron
58
	 *
59
	 * @var string
60
	 */
61
	protected static $auto_update_cron_hook = 'jetpack_beta_autoupdate_hourly_cron';
62
63
	/**
64
	 * Main Instance
65
	 */
66
	public static function instance() {
67
		if ( null === self::$instance ) {
68
			self::$instance = new self();
69
		}
70
71
		return self::$instance;
72
	}
73
74
	/**
75
	 * Constructor
76
	 */
77
	public function __construct() {
78
		add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'maybe_plugins_update_transient' ) );
79
		add_filter( 'upgrader_post_install', array( $this, 'upgrader_post_install' ), 10, 3 );
80
81
		add_action( 'admin_bar_menu', array( $this, 'admin_bar_menu' ) );
82
		add_action( 'deactivate_plugin', array( $this, 'plugin_deactivated' ), 10, 2 );
83
84
		add_action( 'upgrader_process_complete', array( $this, 'upgrader_process_complete' ), 10, 2 );
85
86
		add_filter( 'plugin_action_links_' . JETPACK_PLUGIN_FILE, array( $this, 'remove_activate_stable' ) );
87
		add_filter( 'plugin_action_links_' . JETPACK_DEV_PLUGIN_FILE, array( $this, 'remove_activate_dev' ) );
88
89
		add_filter( 'network_admin_plugin_action_links_' . JETPACK_PLUGIN_FILE, array( $this, 'remove_activate_stable' ) );
90
		add_filter( 'network_admin_plugin_action_links_' . JETPACK_DEV_PLUGIN_FILE, array( $this, 'remove_activate_dev' ) );
91
92
		add_filter( 'all_plugins', array( $this, 'update_all_plugins' ) );
93
94
		add_filter( 'plugins_api', array( $this, 'get_plugin_info' ), 10, 3 );
95
96
		add_action( 'jetpack_beta_autoupdate_hourly_cron', array( self::class, 'run_autoupdate' ) );
97
98
		add_filter( 'jetpack_options_whitelist', array( $this, 'add_to_options_whitelist' ) );
99
100
		if ( is_admin() ) {
101
			self::maybe_schedule_autoupdate();
102
			Admin::init();
103
		}
104
	}
105
106
	/**
107
	 * Fired when the upgrader process is complete; sets option jetpack_beta_dev_currently_installed
108
	 *
109
	 * @param WP_Upgrader $upgrader          - An upgrader instance.
110
	 * @param array       $updates_completed - Array of bulk item update data.
111
	 */
112
	public function upgrader_process_complete( $upgrader, $updates_completed ) {
113
		if ( ! isset( $updates_completed['plugins'] ) ) {
114
			return;
115
		}
116
117
		if ( 'update' === $updates_completed['action'] &&
118
			'plugin' === $updates_completed['type'] &&
119
		in_array( JETPACK_DEV_PLUGIN_FILE, $updates_completed['plugins'], true ) ) {
120
			list( $branch, $section ) = Utils::get_branch_and_section_dev();
121
			if ( Utils::should_update_dev_to_master() ) {
122
				list( $branch, $section ) = array( 'master', 'master' );
123
			}
124
			update_option( self::$option_dev_installed, array( $branch, $section, Utils::get_manifest_data( $branch, $section ) ) );
125
		}
126
	}
127
128
	/**
129
	 * If Jetpack or JP Dev plugin is network activated, update active_plugins option.
130
	 */
131
	public static function is_network_enabled() {
132
		if ( Utils::is_network_active() ) {
133
			add_filter( 'option_active_plugins', array( self::class, 'override_active_plugins' ) );
134
		}
135
	}
136
137
	/**
138
	 * This filter is only applied if Jetpack is network activated,
139
	 * makes sure that you can't have Jetpack or Jetpack Dev plugins versions loaded.
140
	 *
141
	 * @param array $active_plugins - Currently activated plugins.
142
	 *
143
	 * @return array Updated array of active plugins.
144
	 */
145
	public static function override_active_plugins( $active_plugins ) {
146
		$new_active_plugins = array();
147
		foreach ( $active_plugins as $active_plugin ) {
148
			if ( ! Utils::is_jetpack_plugin( $active_plugin ) ) {
149
				$new_active_plugins[] = $active_plugin;
150
			}
151
		}
152
		return $new_active_plugins;
153
	}
154
155
	/**
156
	 * Actions taken when the Jetpack Beta plugin is deactivated.
157
	 *
158
	 * @param string $plugin       - Plugin path being deactivated.
159
	 */
160
	public function plugin_deactivated( $plugin ) {
161
		if ( ! Utils::is_jetpack_plugin( $plugin ) ) {
162
			return;
163
		}
164
165
		delete_option( self::$option );
166
	}
167
168
	/**
169
	 * Filter JP Dev plugin action links.
170
	 *
171
	 * @param array $actions - Array of plugin action links.
172
	 */
173
	public function remove_activate_dev( $actions ) {
174 View Code Duplication
		if ( is_plugin_active( JETPACK_PLUGIN_FILE ) || Utils::is_network_active() ) {
175
			$actions['activate'] = __( 'Plugin Already Active', 'jetpack-beta' );
176
		}
177
		return $actions;
178
	}
179
180
	/**
181
	 * Filter JP Stable plugin action links.
182
	 *
183
	 * @param array $actions - Array of plugin action links.
184
	 */
185
	public function remove_activate_stable( $actions ) {
186 View Code Duplication
		if ( is_plugin_active( JETPACK_DEV_PLUGIN_FILE ) || Utils::is_network_active() ) {
187
			$actions['activate'] = __( 'Plugin Already Active', 'jetpack-beta' );
188
		}
189
		return $actions;
190
	}
191
192
	/**
193
	 * Filters plugins to list in the Plugins list table.
194
	 *
195
	 * @param array $plugins - Array of arrays of plugin data.
196
	 *
197
	 * @return array Updated array of plugin data.
198
	 */
199
	public function update_all_plugins( $plugins ) {
200
		// WP.com requests away show regular plugin.
201
		if ( defined( 'REST_API_REQUEST' ) && REST_API_REQUEST ) {
202
			// Ensure that Jetpack reports the version it's using on account of the Jetpack Beta plugin to Calypso.
203
			if ( is_plugin_active( JETPACK_DEV_PLUGIN_FILE ) ) {
204
				$plugins[ JETPACK_PLUGIN_FILE ]['Version'] = $plugins[ JETPACK_DEV_PLUGIN_FILE ]['Version'];
205
			}
206
			unset( $plugins[ JETPACK_DEV_PLUGIN_FILE ] );
207
			return $plugins;
208
		}
209
210
		if ( is_plugin_active( JETPACK_DEV_PLUGIN_FILE ) ) {
211
			unset( $plugins[ JETPACK_PLUGIN_FILE ] );
212
		} else {
213
			unset( $plugins[ JETPACK_DEV_PLUGIN_FILE ] );
214
		}
215
		return $plugins;
216
	}
217
218
	/**
219
	 * Filter WordPress.org Plugins API results.
220
	 *
221
	 * @param false|object|array $false    - The result object or array. Default false.
222
	 * @param string             $action   - The type of information being requested from the Plugin Installation API.
223
	 * @param object             $response - Plugin API arguments.
224
	 */
225
	public function get_plugin_info( $false, $action, $response ) {
226
227
		// Check if this call API is for the right plugin.
228
		if ( ! isset( $response->slug ) || JETPACK_DEV_PLUGIN_SLUG !== $response->slug ) {
229
			return false;
230
		}
231
		$update_date  = null;
232
		$download_zip = null;
233
		$dev_data     = Utils::get_dev_installed();
234
		if ( isset( $dev_data[2] ) ) {
235
			$update_date  = $dev_data[2]->update_date;
236
			$download_zip = $dev_data[2]->download_url;
237
		}
238
		// Update tags.
239
		$response->slug          = JETPACK_DEV_PLUGIN_SLUG;
240
		$response->plugin        = JETPACK_DEV_PLUGIN_SLUG;
241
		$response->name          = 'Jetpack | ' . Utils::get_jetpack_plugin_pretty_version( true );
242
		$response->plugin_name   = 'Jetpack | ' . Utils::get_jetpack_plugin_pretty_version( true );
243
		$response->version       = Utils::get_jetpack_plugin_version( true );
244
		$response->author        = 'Automattic';
245
		$response->homepage      = 'https://jetpack.com/contact-support/beta-group/';
246
		$response->downloaded    = false;
247
		$response->last_updated  = $update_date;
248
		$response->sections      = array( 'description' => Admin::to_test_content() );
249
		$response->download_link = $download_zip;
250
		return $response;
251
	}
252
253
	/**
254
	 * Run on activation to flush update cache.
255
	 */
256
	public static function activate() {
257
		// Don't do anyting funnly.
258
		if ( defined( 'DOING_CRON' ) ) {
259
			return;
260
		}
261
		delete_site_transient( 'update_plugins' );
262
	}
263
264
	/**
265
	 * Handler ran for Jetpack Beta plugin deactivation hook.
266
	 */
267
	public static function deactivate() {
268
		// Don't do anyting funnly.
269
		if ( defined( 'DOING_CRON' ) ) {
270
			return;
271
		}
272
273
		self::clear_autoupdate_cron();
274
		Utils::delete_all_transiants();
275
		add_action( 'shutdown', array( self::class, 'switch_active' ), 5 );
276
		add_action( 'shutdown', array( self::class, 'remove_dev_plugin' ), 20 );
277
		delete_option( self::$option );
278
	}
279
280
	/**
281
	 * When Jetpack Beta plugin is deactivated, remove the jetpack-dev plugin directory and cleanup.
282
	 */
283
	public static function remove_dev_plugin() {
284
		if ( is_multisite() ) {
285
			return;
286
		}
287
288
		// Delete the jetpack dev plugin.
289
		require_once ABSPATH . 'wp-admin/includes/file.php';
290
		$creds = request_filesystem_credentials( site_url() . '/wp-admin/', '', false, false, array() );
291
		if ( ! WP_Filesystem( $creds ) ) {
292
			// Any problems and we exit.
293
			return;
294
		}
295
		global $wp_filesystem;
296
		if ( ! $wp_filesystem ) {
297
			return;
298
		}
299
300
		$working_dir = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . JETPACK_DEV_PLUGIN_SLUG;
301
		// Delete the folder JETPACK_BETA_PLUGIN_FOLDER.
302
		if ( $wp_filesystem->is_dir( $working_dir ) ) {
303
			$wp_filesystem->delete( $working_dir, true );
304
		}
305
		// Since we are removing this dev plugin we should also clean up this data.
306
		delete_option( self::$option_dev_installed );
307
	}
308
309
	/**
310
	 * Build the "Jetpack Beta" admin bar menu items.
311
	 */
312
	public function admin_bar_menu() {
313
		global $wp_admin_bar;
314
315
		if ( ! is_object( $wp_admin_bar ) ) {
316
			return;
317
		}
318
319
		// Nothing got activated yet.
320
		if ( ! Utils::get_option() ) {
321
			return;
322
		}
323
324
		$args = array(
325
			'id'     => 'jetpack-beta_admin_bar',
326
			'title'  => 'Jetpack Beta',
327
			'parent' => 'top-secondary',
328
			'href'   => current_user_can( 'update_plugins' ) ? Utils::admin_url() : '',
329
		);
330
		$wp_admin_bar->add_node( $args );
331
332
		// Add a child item to our parent item.
333
		$args = array(
334
			'id'     => 'jetpack-beta_version',
335
			// translators: %s: active Jetpack plugin branch/tag.
336
			'title'  => sprintf( __( 'Running %s', 'jetpack-beta' ), Utils::get_jetpack_plugin_pretty_version() ),
337
			'parent' => 'jetpack-beta_admin_bar',
338
		);
339
340
		$wp_admin_bar->add_node( $args );
341
342
		if ( Utils::get_plugin_slug() === JETPACK_DEV_PLUGIN_SLUG ) {
343
			// Highlight the menu if you are running the BETA Versions..
344
			echo sprintf( '<style>#wpadminbar #wp-admin-bar-jetpack-beta_admin_bar { background: %s; }</style>', esc_attr( JETPACK_GREEN ) );
345
		}
346
347
		$args = array(
348
			'id'     => 'jetpack-beta_report',
349
			'title'  => __( 'Report Bug', 'jetpack-beta' ),
350
			'href'   => JETPACK_BETA_REPORT_URL,
351
			'parent' => 'jetpack-beta_admin_bar',
352
		);
353
		$wp_admin_bar->add_node( $args );
354
355
		list( $branch, $section ) = Utils::get_branch_and_section();
356
		if ( 'pr' === $section ) {
357
			$args = array(
358
				'id'     => 'jetpack-beta_report_more_info',
359
				'title'  => __( 'More Info ', 'jetpack-beta' ),
360
				'href'   => Utils::get_url( $branch, $section ),
361
				'parent' => 'jetpack-beta_admin_bar',
362
			);
363
			$wp_admin_bar->add_node( $args );
364
		}
365
	}
366
367
	/**
368
	 * Filters `update_plugins` transient.
369
	 *
370
	 * @param object $transient - Plugin update data.
371
	 */
372
	public function maybe_plugins_update_transient( $transient ) {
373
		if ( ! isset( $transient->no_update ) ) {
374
			return $transient;
375
		}
376
377
		// Do not try to update things that do not exist.
378
		if ( ! file_exists( WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . JETPACK_DEV_PLUGIN_FILE ) ) {
379
			return $transient;
380
		}
381
382
		// Do not look for update if we are stable branch.
383
		if ( Utils::is_on_stable() ) {
384
			return $transient;
385
		}
386
387
		// Lets always grab the latest.
388
		delete_site_transient( 'jetpack_beta_manifest' );
389
390
		// Check if there is a new version.
391
		if ( Utils::should_update_dev_to_master() ) {
392
			// If response is false, don't alter the transient.
393
			$transient->response[ JETPACK_DEV_PLUGIN_FILE ] = Utils::get_jepack_dev_master_update_response();
394
			// Unset the that it doesn't need an update.
395
			unset( $transient->no_update[ JETPACK_DEV_PLUGIN_FILE ] );
396
		} elseif ( Utils::should_update_dev_version() ) {
397
			// If response is false, don't alter the transient.
398
			$transient->response[ JETPACK_DEV_PLUGIN_FILE ] = Utils::get_jepack_dev_update_response();
399
			// Unset the that it doesn't need an update.
400
			unset( $transient->no_update[ JETPACK_DEV_PLUGIN_FILE ] );
401
		} else {
402
			unset( $transient->response[ JETPACK_DEV_PLUGIN_FILE ] );
403
			if ( isset( $transient->no_update ) ) {
404
				$transient->no_update[ JETPACK_DEV_PLUGIN_FILE ] = Utils::get_jepack_dev_update_response();
405
			}
406
		}
407
408
		return $transient;
409
	}
410
411
	/**
412
	 * Moves the newly downloaded folder into jetpack-dev.
413
	 *
414
	 * @param bool  $worked      - Installation response.
415
	 * @param array $hook_extras - Extra args passed to hooked filters.
416
	 * @param array $result      - Installation result data.
417
	 *
418
	 * @return WP_Error
419
	 */
420
	public function upgrader_post_install( $worked, $hook_extras, $result ) {
421
		global $wp_filesystem;
422
423
		if (
424
		! isset( $hook_extras['plugin'] )
425
		|| JETPACK_DEV_PLUGIN_FILE !== $hook_extras['plugin']
426
		) {
427
			return $worked;
428
		}
429
430
		if ( $wp_filesystem->move( $result['destination'], WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . JETPACK_DEV_PLUGIN_SLUG, true ) ) {
431
			return $worked;
432
		} else {
433
			return new WP_Error();
434
		}
435
	}
436
437
	/**
438
	 * Switch active JP plugin version when JP Beta plugin is deactivated.
439
	 * This needs to happen on `shutdown`, otherwise it doesn't work.
440
	 */
441
	public static function switch_active() {
442
		Utils::replace_active_plugin( JETPACK_DEV_PLUGIN_FILE, JETPACK_PLUGIN_FILE );
443
	}
444
445
	/**
446
	 * Clear scheduled WP-Cron jobs on plugin deactivation.
447
	 */
448
	public static function clear_autoupdate_cron() {
449
		if ( ! is_main_site() ) {
450
			return;
451
		}
452
		wp_clear_scheduled_hook( self::$auto_update_cron_hook );
453
454
		if ( function_exists( 'wp_unschedule_hook' ) ) { // New in WP `4.9`.
455
			wp_unschedule_hook( self::$auto_update_cron_hook );
456
		}
457
	}
458
459
	/**
460
	 * Schedule plugin update jobs.
461
	 */
462
	public static function schedule_hourly_autoupdate() {
463
		wp_clear_scheduled_hook( self::$auto_update_cron_hook );
464
		wp_schedule_event( time(), 'hourly', self::$auto_update_cron_hook );
465
	}
466
467
	/**
468
	 * Determine if plugin update jobs should be scheduled.
469
	 */
470
	public static function maybe_schedule_autoupdate() {
471
		if ( ! Utils::is_set_to_autoupdate() ) {
472
			return;
473
		}
474
475
		if ( ! is_main_site() ) {
476
			return;
477
		}
478
		$has_schedule_already = wp_get_schedule( self::$auto_update_cron_hook );
479
		if ( ! $has_schedule_already ) {
480
			self::schedule_hourly_autoupdate();
481
		}
482
	}
483
484
	/**
485
	 * The jetpack_beta_autoupdate_hourly_cron job - does not update Stable.
486
	 */
487
	public static function run_autoupdate() {
488
		if ( ! Utils::is_set_to_autoupdate() ) {
489
			return;
490
		}
491
492
		if ( ! is_main_site() ) {
493
			return;
494
		}
495
496
		require_once ABSPATH . 'wp-admin/includes/file.php';
497
		require_once ABSPATH . 'wp-admin/includes/plugin.php';
498
		require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
499
		wp_clean_plugins_cache();
500
		ob_start();
501
		wp_update_plugins(); // Check for Plugin updates.
502
		ob_end_clean();
503
		$plugins = array();
504
		if (
505
		! Utils::is_on_stable() &&
506
		( Utils::should_update_dev_to_master() || Utils::should_update_dev_version() )
507
		) {
508
			add_filter( 'upgrader_source_selection', array( self::class, 'check_for_main_files' ), 10, 2 );
509
510
			// If response is false, don't alter the transient.
511
			$plugins[] = JETPACK_DEV_PLUGIN_FILE;
512
		}
513
		$autupdate = AutoupdateSelf::instance();
514
		if ( $autupdate->has_never_version() ) {
515
			$plugins[] = JPBETA__PLUGIN_FOLDER . '/jetpack-beta.php';
516
		}
517
518
		if ( empty( $plugins ) ) {
519
			return;
520
		}
521
522
		// Unhook this functions that output things before we send our response header.
523
		remove_action( 'upgrader_process_complete', array( Language_Pack_Upgrader::class, 'async_upgrade' ), 20 );
524
		remove_action( 'upgrader_process_complete', 'wp_version_check' );
525
		remove_action( 'upgrader_process_complete', 'wp_update_themes' );
526
527
		$skin = new WP_Ajax_Upgrader_Skin();
528
		// The Automatic_Upgrader_Skin skin shouldn't output anything.
529
		$upgrader = new Plugin_Upgrader( $skin );
530
		$upgrader->init();
531
		// This avoids the plugin to be deactivated.
532
		// Using bulk upgrade puts the site into maintenance mode during the upgrades.
533
		$result = $upgrader->bulk_upgrade( $plugins );
534
		$errors = $upgrader->skin->get_errors();
535
		$log    = $upgrader->skin->get_upgrade_messages();
536
537
		if ( is_wp_error( $errors ) && $errors->get_error_code() ) {
538
			return $errors;
539
		}
540
541
		if ( $result && ! defined( 'JETPACK_BETA_SKIP_EMAIL' ) && Utils::is_set_to_email_notifications() ) {
542
			self::send_autoupdate_email( $plugins, $log );
543
		}
544
	}
545
546
	/**
547
	 * Builds and sends an email about succesfull plugin autoupdate.
548
	 *
549
	 * @param Array  $plugins - List of plugins that were updated.
550
	 * @param String $log     - Upgrade message from core's plugin upgrader.
551
	 */
552
	private static function send_autoupdate_email( $plugins, $log ) {
553
		$admin_email = get_site_option( 'admin_email' );
554
555
		if ( empty( $admin_email ) ) {
556
			return;
557
		}
558
559
		// Calling empty() on a function return value crashes in PHP < 5.5.
560
		// Thus we assign the return value explicitly and then check with empty().
561
		$bloginfo_name = get_bloginfo( 'name' );
562
		$site_title    = ! empty( $bloginfo_name ) ? get_bloginfo( 'name' ) : get_site_url();
563
		$what_updated  = 'Jetpack Beta Tester Plugin';
564
		// translators: %s: The site title.
565
		$subject = sprintf( __( '[%s] Autoupdated Jetpack Beta Tester', 'jetpack-beta' ), $site_title );
566
567
		if ( in_array( JETPACK_DEV_PLUGIN_FILE, $plugins, true ) ) {
568
			$subject = sprintf(
569
				// translators: %1$s: site title, %2$s: pretty plugin version (eg 9.3).
570
				__( '[%1$s] Autoupdated Jetpack %2$s ', 'jetpack-beta' ),
571
				$site_title,
572
				Utils::get_jetpack_plugin_pretty_version()
573
			);
574
575
			$what_updated = sprintf(
576
				// translators: $1$s: pretty plugin version, $2$s: raw plugin version (eg 9.3.2-beta).
577
				__( 'Jetpack %1$s (%2$s)', 'jetpack-beta' ),
578
				Utils::get_jetpack_plugin_pretty_version(),
579
				Utils::get_jetpack_plugin_version()
580
			);
581
582
			if ( count( $plugins ) > 1 ) {
583
				$subject = sprintf(
584
					// translators: %1$s: site title, %2$s: pretty plugin version.
585
					__( '[%1$s] Autoupdated Jetpack %2$s and the Jetpack Beta Tester', 'jetpack-beta' ),
586
					$site_title,
587
					Utils::get_jetpack_plugin_pretty_version()
588
				);
589
590
				$what_updated = sprintf(
591
					// translators: $1$s: pretty plugin version, $2$s: raw plugin version.
592
					__( 'Jetpack %1$s (%2$s) and the Jetpack Beta Tester', 'jetpack-beta' ),
593
					Utils::get_jetpack_plugin_pretty_version(),
594
					Utils::get_jetpack_plugin_version()
595
				);
596
			}
597
		}
598
599
		$message = sprintf(
600
			// translators: %1$s: site url, $2$s: text of what has updated.
601
			__( 'Howdy! Your site at %1$s has autoupdated %2$s.', 'jetpack-beta' ),
602
			home_url(),
603
			$what_updated
604
		);
605
		$message .= "\n\n";
606
607
		$what_changed = Utils::what_changed();
608
		if ( $what_changed ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $what_changed 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...
609
			$message .= __( 'What changed?', 'jetpack-beta' );
610
			$message .= wp_strip_all_tags( $what_changed );
611
		}
612
613
		$message .= __( 'During the autoupdate the following happened:', 'jetpack-beta' );
614
		$message .= "\n\n";
615
		// Can only reference the About screen if their update was successful.
616
		$log      = array_map( 'html_entity_decode', $log );
617
		$message .= ' - ' . implode( "\n - ", $log );
618
		$message .= "\n\n";
619
620
		// Adds To test section. for PR's it's a PR description, for master/RC - it's a to_test.md file contents.
621
		$message .= Admin::to_test_content();
622
		$message .= "\n\n";
623
624
		wp_mail( $admin_email, $subject, $message );
625
	}
626
627
	/**
628
	 * This checks intends to fix errors in our build server when Jetpack.
629
	 *
630
	 * @param string $source        - Source path.
631
	 * @param string $remote_source - Remote path.
632
	 *
633
	 * @return WP_Error
634
	 */
635
	public static function check_for_main_files( $source, $remote_source ) {
636
		if ( $source === $remote_source . '/jetpack-dev/' ) {
637
			if ( ! file_exists( $source . 'jetpack.php' ) ) {
638
				return new WP_Error( 'plugin_file_does_not_exist', __( 'Main Plugin File does not exist', 'jetpack-beta' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'plugin_file_does_not_exist'.

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...
639
			}
640
			if ( ! file_exists( $source . '_inc/build/static.html' ) ) {
641
				return new WP_Error( 'static_admin_page_does_not_exist', __( 'Static Admin Page File does not exist', 'jetpack-beta' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'static_admin_page_does_not_exist'.

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...
642
			}
643
			if ( ! file_exists( $source . '_inc/build/admin.js' ) ) {
644
				return new WP_Error( 'admin_page_does_not_exist', __( 'Admin Page File does not exist', 'jetpack-beta' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'admin_page_does_not_exist'.

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...
645
			}
646
			// It has happened that sometimes a generated bundle from the master branch ends up with an empty
647
			// vendor directory. Used to be a problem in the beta building process.
648
			if ( Utils::is_dir_empty( $source . 'vendor' ) ) {
649
				return new WP_Error( 'vendor_dir_is_empty', __( 'The dependencies dir (vendor) is empty', 'jetpack-beta' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'vendor_dir_is_empty'.

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...
650
			}
651
		}
652
653
		return $source;
654
	}
655
656
	/**
657
	 * Callback function to include Jetpack beta options into Jetpack sync whitelist.
658
	 *
659
	 * @param Array $whitelist List of whitelisted options to sync.
660
	 */
661
	public function add_to_options_whitelist( $whitelist ) {
662
		$whitelist[] = self::$option;
663
		$whitelist[] = self::$option_dev_installed;
664
		$whitelist[] = self::$option_autoupdate;
665
		$whitelist[] = self::$option_email_notif;
666
		return $whitelist;
667
	}
668
669
	/**
670
	 * Custom error handler to intercept errors and log them using Jetpack's own logger.
671
	 *
672
	 * @param int    $errno   - Error code.
673
	 * @param string $errstr  - Error message.
674
	 * @param string $errfile - File name where the error happened.
675
	 * @param int    $errline - Line in the code.
676
	 *
677
	 * @return bool Whether to make the default handler handle the error as well.
678
	 */
679
	public static function custom_error_handler( $errno, $errstr, $errfile, $errline ) {
680
681
		if ( class_exists( Jetpack::class ) && method_exists( Jetpack::class, 'log' ) ) {
682
			$error_string = sprintf( '%s, %s:%d', $errstr, $errfile, $errline );
683
684
			// Only adding to log if the message is related to Jetpack.
685
			if ( false !== stripos( $error_string, 'jetpack' ) ) {
686
				Jetpack::log( $errno, $error_string );
687
			}
688
		}
689
690
		/**
691
		 * The error_reporting call returns current error reporting level as an integer. Bitwise
692
		 * AND lets us determine whether the current error is included in the current error
693
		 * reporting level
694
		 */
695
		if ( ! ( error_reporting() & $errno ) ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.prevent_path_disclosure_error_reporting,WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting
696
697
			// If this error is not being reported in the current settings, stop reporting here by returning true.
698
			return true;
699
		}
700
701
		// Returning false makes the error go through the standard error handler as well.
702
		return false;
703
	}
704
}
705