Completed
Push — simple-payments/rename ( 6c50a8...f7ec96 )
by
unknown
26:51 queued 17:10
created

Jetpack_Network::body_class()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFilename
2
/**
3
 * Jetpack Network Manager class file.
4
 *
5
 * @package jetpack
6
 */
7
8
use Automattic\Jetpack\Connection\Client;
9
use Automattic\Jetpack\Connection\Manager;
10
use Automattic\Jetpack\Connection\Utils as Connection_Utils;
11
use Automattic\Jetpack\Constants;
12
use Automattic\Jetpack\Status;
13
14
/**
15
 * Used to manage Jetpack installation on Multisite Network installs
16
 *
17
 * SINGLETON: To use call Jetpack_Network::init()
18
 *
19
 * DO NOT USE ANY STATIC METHODS IN THIS CLASS!!!!!!
20
 *
21
 * @since 2.9
22
 */
23
class Jetpack_Network {
24
25
	/**
26
	 * Holds a static copy of Jetpack_Network for the singleton
27
	 *
28
	 * @since 2.9
29
	 * @var Jetpack_Network
30
	 */
31
	private static $instance = null;
32
33
	/**
34
	 * An instance of the connection manager object.
35
	 *
36
	 * @since 7.7
37
	 * @var Automattic\Jetpack\Connection\Manager
38
	 */
39
	private $connection;
40
41
	/**
42
	 * Name of the network wide settings
43
	 *
44
	 * @since 2.9
45
	 * @var string
46
	 */
47
	private $settings_name = 'jetpack-network-settings';
48
49
	/**
50
	 * Defaults for settings found on the Jetpack > Settings page
51
	 *
52
	 * @since 2.9
53
	 * @var array
54
	 */
55
	private $setting_defaults = array(
56
		'auto-connect'                 => 0,
57
		'sub-site-connection-override' => 1,
58
	);
59
60
	/**
61
	 * Constructor
62
	 *
63
	 * @since 2.9
64
	 */
65
	private function __construct() {
66
		require_once ABSPATH . '/wp-admin/includes/plugin.php'; // For the is_plugin... check.
67
		require_once JETPACK__PLUGIN_DIR . 'modules/protect/shared-functions.php'; // For managing the global whitelist.
68
69
		/**
70
		 * Sanity check to ensure the install is Multisite and we
71
		 * are in Network Admin
72
		 */
73
		if ( is_multisite() && is_network_admin() ) {
74
			add_action( 'network_admin_menu', array( $this, 'add_network_admin_menu' ) );
75
			add_action( 'network_admin_edit_jetpack-network-settings', array( $this, 'save_network_settings_page' ), 10, 0 );
76
			add_filter( 'admin_body_class', array( $this, 'body_class' ) );
77
78
			if ( isset( $_GET['page'] ) && 'jetpack' == $_GET['page'] ) {
79
				add_action( 'admin_init', array( $this, 'jetpack_sites_list' ) );
80
			}
81
		}
82
83
		/*
84
		 * Things that should only run on multisite
85
		 */
86
		if ( is_multisite() && is_plugin_active_for_network( 'jetpack/jetpack.php' ) ) {
87
			add_action( 'wp_before_admin_bar_render', array( $this, 'add_to_menubar' ) );
88
			add_filter( 'jetpack_disconnect_cap', array( $this, 'set_multisite_disconnect_cap' ) );
89
90
			/*
91
			 * If admin wants to automagically register new sites set the hook here
92
			 *
93
			 * This is a hacky way because xmlrpc is not available on wp_initialize_site
94
			 */
95
			if ( 1 === $this->get_option( 'auto-connect' ) ) {
96
				add_action( 'wp_initialize_site', array( $this, 'do_automatically_add_new_site' ) );
97
			}
98
		}
99
	}
100
101
	/**
102
	 * Sets a connection object.
103
	 *
104
	 * @param Automattic\Jetpack\Connection\Manager $connection the connection manager object.
105
	 */
106
	public function set_connection( Manager $connection ) {
107
		$this->connection = $connection;
108
	}
109
110
	/**
111
	 * Sets which modules get activated by default on subsite connection.
112
	 * Modules can be set in Network Admin > Jetpack > Settings
113
	 *
114
	 * @since 2.9
115
	 * @deprecated since 7.7.0
116
	 *
117
	 * @param array $modules List of modules.
118
	 */
119
	public function set_auto_activated_modules( $modules ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
120
		_deprecated_function( __METHOD__, 'jetpack-7.7' );
121
	}
122
123
	/**
124
	 * Registers new sites upon creation
125
	 *
126
	 * @since 2.9
127
	 * @since 7.4.0 Uses a WP_Site object.
128
	 * @uses  wp_initialize_site
129
	 *
130
	 * @param WP_Site $site the WordPress site object.
131
	 **/
132
	public function do_automatically_add_new_site( $site ) {
133
		if ( is_a( $site, 'WP_Site' ) ) {
134
			$this->do_subsiteregister( $site->id );
135
		}
136
	}
137
138
	/**
139
	 * Adds .network-admin class to the body tag
140
	 * Helps distinguish network admin JP styles from regular site JP styles
141
	 *
142
	 * @since 2.9
143
	 *
144
	 * @param String $classes current assigned body classes.
145
	 * @return String amended class string.
146
	 */
147
	public function body_class( $classes ) {
148
		return trim( $classes ) . ' network-admin ';
149
	}
150
151
	/**
152
	 * Provides access to an instance of Jetpack_Network
153
	 *
154
	 * This is how the Jetpack_Network object should *always* be accessed
155
	 *
156
	 * @since 2.9
157
	 * @return Jetpack_Network
158
	 */
159
	public static function init() {
160
		if ( ! self::$instance || ! is_a( self::$instance, 'Jetpack_Network' ) ) {
161
			self::$instance = new Jetpack_Network();
162
		}
163
164
		return self::$instance;
165
	}
166
167
	/**
168
	 * Registers the Multisite admin bar menu item shortcut.
169
	 * This shortcut helps users quickly and easily navigate to the Jetpack Network Admin
170
	 * menu from anywhere in their network.
171
	 *
172
	 * @since 2.9
173
	 */
174
	public function register_menubar() {
175
		add_action( 'wp_before_admin_bar_render', array( $this, 'add_to_menubar' ) );
176
	}
177
178
	/**
179
	 * Runs when Jetpack is deactivated from the network admin plugins menu.
180
	 * Each individual site will need to have Jetpack::disconnect called on it.
181
	 * Site that had Jetpack individually enabled will not be disconnected as
182
	 * on Multisite individually activated plugins are still activated when
183
	 * a plugin is deactivated network wide.
184
	 *
185
	 * @since 2.9
186
	 **/
187
	public function deactivate() {
188
		// Only fire if in network admin.
189
		if ( ! is_network_admin() ) {
190
			return;
191
		}
192
193
		$sites = get_sites();
194
195
		foreach ( $sites as $s ) {
196
			switch_to_blog( $s->blog_id );
197
			$active_plugins = get_option( 'active_plugins' );
198
199
			/*
200
			 * If this plugin was activated in the subsite individually
201
			 * we do not want to call disconnect. Plugins activated
202
			 * individually (before network activation) stay activated
203
			 * when the network deactivation occurs
204
			 */
205
			if ( ! in_array( 'jetpack/jetpack.php', $active_plugins, true ) ) {
206
				Jetpack::disconnect();
207
			}
208
		}
209
		restore_current_blog();
210
	}
211
212
	/**
213
	 * Adds a link to the Jetpack Network Admin page in the network admin menu bar.
214
	 *
215
	 * @since 2.9
216
	 **/
217
	public function add_to_menubar() {
218
		global $wp_admin_bar;
219
		// Don't show for logged out users or single site mode.
220
		if ( ! is_user_logged_in() || ! is_multisite() ) {
221
			return;
222
		}
223
224
		$wp_admin_bar->add_node(
225
			array(
226
				'parent' => 'network-admin',
227
				'id'     => 'network-admin-jetpack',
228
				'title'  => 'Jetpack',
229
				'href'   => $this->get_url( 'network_admin_page' ),
230
			)
231
		);
232
	}
233
234
	/**
235
	 * Returns various URL strings. Factory like
236
	 *
237
	 * $args can be a string or an array.
238
	 * If $args is an array there must be an element called name for the switch statement
239
	 *
240
	 * Currently supports:
241
	 * - subsiteregister: Pass array( 'name' => 'subsiteregister', 'site_id' => SITE_ID )
242
	 * - network_admin_page: Provides link to /wp-admin/network/JETPACK
243
	 * - subsitedisconnect: Pass array( 'name' => 'subsitedisconnect', 'site_id' => SITE_ID )
244
	 *
245
	 * @since 2.9
246
	 *
247
	 * @param Mixed $args URL parameters.
248
	 *
249
	 * @return String
250
	 **/
251
	public function get_url( $args ) {
252
		$url = null; // Default url value.
253
254
		if ( is_string( $args ) ) {
255
			$name = $args;
256
		} else if ( is_array( $args ) ) {
257
			$name = $args['name'];
258
		} else {
259
			return $url;
260
		}
261
262
		switch ( $name ) {
263
			case 'subsiteregister':
264
				if ( ! isset( $args['site_id'] ) ) {
265
					break; // If there is not a site id present we cannot go further.
266
				}
267
				$url = network_admin_url(
268
					'admin.php?page=jetpack&action=subsiteregister&site_id='
269
					. $args['site_id']
270
				);
271
				break;
272
273
			case 'network_admin_page':
274
				$url = network_admin_url( 'admin.php?page=jetpack' );
275
				break;
276
277
			case 'subsitedisconnect':
278
				if ( ! isset( $args['site_id'] ) ) {
279
					break; // If there is not a site id present we cannot go further.
280
				}
281
				$url = network_admin_url(
282
					'admin.php?page=jetpack&action=subsitedisconnect&site_id='
283
					. $args['site_id']
284
				);
285
				break;
286
		}
287
288
		return $url;
289
	}
290
291
	/**
292
	 * Adds the Jetpack  menu item to the Network Admin area
293
	 *
294
	 * @since 2.9
295
	 */
296
	public function add_network_admin_menu() {
297
		add_menu_page( 'Jetpack', 'Jetpack', 'jetpack_network_admin_page', 'jetpack', array( $this, 'wrap_network_admin_page' ), 'div', 3 );
298
		$jetpack_sites_page_hook    = add_submenu_page( 'jetpack', __( 'Jetpack Sites', 'jetpack' ), __( 'Sites', 'jetpack' ), 'jetpack_network_sites_page', 'jetpack', array( $this, 'wrap_network_admin_page' ) );
299
		$jetpack_settings_page_hook = add_submenu_page( 'jetpack', __( 'Settings', 'jetpack' ), __( 'Settings', 'jetpack' ), 'jetpack_network_settings_page', 'jetpack-settings', array( $this, 'wrap_render_network_admin_settings_page' ) );
300
		add_action( "admin_print_styles-$jetpack_sites_page_hook", array( 'Jetpack_Admin_Page', 'load_wrapper_styles' ) );
301
		add_action( "admin_print_styles-$jetpack_settings_page_hook", array( 'Jetpack_Admin_Page', 'load_wrapper_styles' ) );
302
		/**
303
		 * As jetpack_register_genericons is by default fired off a hook,
304
		 * the hook may have already fired by this point.
305
		 * So, let's just trigger it manually.
306
		 */
307
		require_once JETPACK__PLUGIN_DIR . '_inc/genericons.php';
308
		jetpack_register_genericons();
309
310 View Code Duplication
		if ( ! wp_style_is( 'jetpack-icons', 'registered' ) ) {
311
			wp_register_style( 'jetpack-icons', plugins_url( 'css/jetpack-icons.min.css', JETPACK__PLUGIN_FILE ), false, JETPACK__VERSION );
312
		}
313
314
		add_action( 'admin_enqueue_scripts', array( $this, 'admin_menu_css' ) );
315
	}
316
317
	/**
318
	 * Adds JP menu icon
319
	 *
320
	 * @since 2.9
321
	 **/
322
	public function admin_menu_css() {
323
		wp_enqueue_style( 'jetpack-icons' );
324
	}
325
326
	/**
327
	 * Provides functionality for the Jetpack > Sites page.
328
	 * Does not do the display!
329
	 *
330
	 * @since 2.9
331
	 */
332
	public function jetpack_sites_list() {
333
		Jetpack::init();
334
335
		if ( isset( $_GET['action'] ) ) {
336
			switch ( $_GET['action'] ) {
337
				case 'subsiteregister':
338
					/**
339
					 * Add actual referrer checking.
340
					 *
341
					 * @todo check_admin_referer( 'jetpack-subsite-register' );
342
					 */
343
					Jetpack::log( 'subsiteregister' );
344
345
					// If !$_GET['site_id'] stop registration and error.
346 View Code Duplication
					if ( ! isset( $_GET['site_id'] ) || empty( $_GET['site_id'] ) ) {
347
						/**
348
						 * Log error to state cookie for display later.
349
						 *
350
						 * @todo Make state messages show on Jetpack NA pages
351
						 */
352
						Jetpack::state( 'missing_site_id', esc_html__( 'Site ID must be provided to register a sub-site.', 'jetpack' ) );
353
						break;
354
					}
355
356
					// Send data to register endpoint and retrieve shadow blog details.
357
					$result = $this->do_subsiteregister();
358
					$url    = $this->get_url( 'network_admin_page' );
359
360
					if ( is_wp_error( $result ) ) {
361
						$url = add_query_arg( 'action', 'connection_failed', $url );
362
					} else {
363
						$url = add_query_arg( 'action', 'connected', $url );
364
					}
365
366
					wp_safe_redirect( $url );
367
					exit;
368
369
				case 'subsitedisconnect':
370
					Jetpack::log( 'subsitedisconnect' );
371
372 View Code Duplication
					if ( ! isset( $_GET['site_id'] ) || empty( $_GET['site_id'] ) ) {
373
						Jetpack::state( 'missing_site_id', esc_html__( 'Site ID must be provided to disconnect a sub-site.', 'jetpack' ) );
374
						break;
375
					}
376
377
					$this->do_subsitedisconnect();
378
					break;
379
380
				case 'connected':
381
				case 'connection_failed':
382
					add_action( 'jetpack_notices', array( $this, 'show_jetpack_notice' ) );
383
					break;
384
			}
385
		}
386
	}
387
388
	/**
389
	 * Set the disconnect capability for multisite.
390
	 *
391
	 * @param array $caps The capabilities array.
392
	 */
393
	public function set_multisite_disconnect_cap( $caps ) {
394
		// Can individual site admins manage their own connection?
395
		if ( ! is_super_admin() && ! $this->get_option( 'sub-site-connection-override' ) ) {
396
			/*
397
			 * We need to update the option name -- it's terribly unclear which
398
			 * direction the override goes.
399
			 *
400
			 * @todo: Update the option name to `sub-sites-can-manage-own-connections`
401
			 */
402
			return array( 'do_not_allow' );
403
		}
404
405
		return $caps;
406
	}
407
408
	/**
409
	 * Shows the Jetpack plugin notices.
410
	 */
411
	public function show_jetpack_notice() {
412
		if ( isset( $_GET['action'] ) && 'connected' == $_GET['action'] ) {
413
			$notice    = __( 'Site successfully connected.', 'jetpack' );
414
			$classname = 'updated';
415
		} elseif ( isset( $_GET['action'] ) && 'connection_failed' == $_GET['action'] ) {
416
			$notice    = __( 'Site connection failed!', 'jetpack' );
417
			$classname = 'error';
418
		}
419
		?>
420
		<div id="message" class="<?php echo esc_attr( $classname ); ?> jetpack-message jp-connect" style="display:block !important;">
0 ignored issues
show
Bug introduced by
The variable $classname does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
421
			<p><?php echo esc_html( $notice ); ?></p>
0 ignored issues
show
Bug introduced by
The variable $notice does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
422
		</div>
423
		<?php
424
	}
425
426
	/**
427
	 * Disconnect functionality for an individual site
428
	 *
429
	 * @since 2.9
430
	 * @see   Jetpack_Network::jetpack_sites_list()
431
	 *
432
	 * @param int $site_id the site identifier.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $site_id not be integer|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...
433
	 */
434
	public function do_subsitedisconnect( $site_id = null ) {
435
		if ( ! current_user_can( 'jetpack_disconnect' ) ) {
436
			return;
437
		}
438
		$site_id = ( is_null( $site_id ) ) ? $_GET['site_id'] : $site_id;
439
		switch_to_blog( $site_id );
440
		Jetpack::disconnect();
441
		restore_current_blog();
442
	}
443
444
	/**
445
	 * Registers a subsite with the Jetpack servers
446
	 *
447
	 * @since 2.9
448
	 * @todo  Break apart into easier to manage chunks that can be unit tested
449
	 * @see   Jetpack_Network::jetpack_sites_list();
450
	 *
451
	 * @param int $site_id the site identifier.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $site_id not be integer|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...
452
	 */
453
	public function do_subsiteregister( $site_id = null ) {
454
		if ( ! current_user_can( 'jetpack_disconnect' ) ) {
455
			return;
456
		}
457
458
		if ( ( new Status() )->is_development_mode() ) {
459
			return;
460
		}
461
462
		// Figure out what site we are working on.
463
		$site_id = ( is_null( $site_id ) ) ? $_GET['site_id'] : $site_id;
464
465
		/*
466
		 * Here we need to switch to the subsite
467
		 * For the registration process we really only hijack how it
468
		 * works for an individual site and pass in some extra data here
469
		 */
470
		switch_to_blog( $site_id );
471
472
		add_filter( 'jetpack_register_request_body', array( $this, 'filter_register_request_body' ) );
473
		add_action( 'jetpack_site_registered_user_token', array( $this, 'filter_register_user_token' ) );
474
475
		// Save the secrets in the subsite so when the wpcom server does a pingback it
476
		// will be able to validate the connection.
477
		$result = $this->connection->register( 'subsiteregister' );
478
479
		if ( is_wp_error( $result ) || ! $result ) {
480
			restore_current_blog();
481
			return $result;
482
		}
483
484
		Jetpack::activate_default_modules( false, false, array(), false );
485
486
		restore_current_blog();
487
	}
488
489
	/**
490
	 * Receives the registration response token.
491
	 *
492
	 * @param Object $token the received token.
493
	 */
494
	public function filter_register_user_token( $token ) {
495
		$is_master_user = ! Jetpack::is_active();
496
		Connection_Utils::update_user_token(
497
			get_current_user_id(),
498
			sprintf( '%s.%d', $token->secret, get_current_user_id() ),
499
			$is_master_user
500
		);
501
	}
502
503
	/**
504
	 * Filters the registration request body to include additional properties.
505
	 *
506
	 * @param array $properties standard register request body properties.
507
	 * @return array amended properties.
508
	 */
509
	public function filter_register_request_body( $properties ) {
510
		$blog_details = get_blog_details();
511
512
		$network = get_network();
513
514
		switch_to_blog( $network->blog_id );
515
		// The blog id on WordPress.com of the primary network site.
516
		$network_wpcom_blog_id = Jetpack_Options::get_option( 'id' );
517
		restore_current_blog();
518
519
		/**
520
		 * Both `state` and `user_id` need to be sent in the request, even though they are the same value.
521
		 * Connecting via the network admin combines `register()` and `authorize()` methods into one step,
522
		 * because we assume the main site is already authorized. `state` is used to verify the `register()`
523
		 * request, while `user_id()` is used to create the token in the `authorize()` request.
524
		 */
525
		return array_merge(
526
			$properties,
527
			array(
528
				'network_url'           => $this->get_url( 'network_admin_page' ),
529
				'network_wpcom_blog_id' => $network_wpcom_blog_id,
530
				'user_id'               => get_current_user_id(),
531
532
				/*
533
				 * Use the subsite's registration date as the site creation date.
534
				 *
535
				 * This is in contrast to regular standalone sites, where we use the helper
536
				 * `Jetpack::get_assumed_site_creation_date()` to assume the site's creation date.
537
				 */
538
				'site_created'          => $blog_details->registered,
539
			)
540
		);
541
	}
542
543
	/**
544
	 * A hook handler for adding admin pages and subpages.
545
	 */
546
	public function wrap_network_admin_page() {
547
		Jetpack_Admin_Page::wrap_ui( array( $this, 'network_admin_page' ) );
548
	}
549
550
	/**
551
	 * Handles the displaying of all sites on the network that are
552
	 * dis/connected to Jetpack
553
	 *
554
	 * @since 2.9
555
	 * @see   Jetpack_Network::jetpack_sites_list()
556
	 */
557
	public function network_admin_page() {
558
		global $current_site;
559
		$this->network_admin_page_header();
560
561
		$jp = Jetpack::init();
562
563
		// We should be, but ensure we are on the main blog.
564
		switch_to_blog( $current_site->blog_id );
565
		$main_active = $jp->is_active();
566
		restore_current_blog();
567
568
		// If we are in dev mode, just show the notice and bail.
569
		if ( ( new Status() )->is_development_mode() ) {
570
			Jetpack::show_development_mode_notice();
571
			return;
572
		}
573
574
		/*
575
		 * Ensure the main blog is connected as all other subsite blog
576
		 * connections will feed off this one
577
		 */
578
		if ( ! $main_active ) {
579
			$url  = $this->get_url(
0 ignored issues
show
Unused Code introduced by
$url is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
580
				array(
581
					'name'    => 'subsiteregister',
582
					'site_id' => 1,
583
				)
584
			);
585
			$data = array( 'url' => $jp->build_connect_url() );
586
			Jetpack::init()->load_view( 'admin/must-connect-main-blog.php', $data );
587
588
			return;
589
		}
590
591
		require_once 'class.jetpack-network-sites-list-table.php';
592
593
		$network_sites_table = new Jetpack_Network_Sites_List_Table();
594
		echo '<div class="wrap"><h2>' . esc_html__( 'Sites', 'jetpack' ) . '</h2>';
595
		echo '<form method="post">';
596
		$network_sites_table->prepare_items();
597
		$network_sites_table->display();
598
		echo '</form></div>';
599
600
	}
601
602
	/**
603
	 * Stylized JP header formatting
604
	 *
605
	 * @since 2.9
606
	 */
607
	public function network_admin_page_header() {
608
		$is_connected = Jetpack::is_active();
609
610
		$data = array(
611
			'is_connected' => $is_connected,
612
		);
613
		Jetpack::init()->load_view( 'admin/network-admin-header.php', $data );
614
	}
615
616
	/**
617
	 * Fires when the Jetpack > Settings page is saved.
618
	 *
619
	 * @since 2.9
620
	 */
621
	public function save_network_settings_page() {
622
623
		if ( ! wp_verify_nonce( $_POST['_wpnonce'], 'jetpack-network-settings' ) ) {
624
			// No nonce, push back to settings page.
625
			wp_safe_redirect(
626
				add_query_arg(
627
					array( 'page' => 'jetpack-settings' ),
628
					network_admin_url( 'admin.php' )
629
				)
630
			);
631
			exit();
632
		}
633
634
		// Try to save the Protect whitelist before anything else, since that action can result in errors.
635
		$whitelist = str_replace( ' ', '', $_POST['global-whitelist'] );
636
		$whitelist = explode( PHP_EOL, $whitelist );
637
		$result    = jetpack_protect_save_whitelist( $whitelist, true );
638
		if ( is_wp_error( $result ) ) {
639
			wp_safe_redirect(
640
				add_query_arg(
641
					array(
642
						'page'  => 'jetpack-settings',
643
						'error' => 'jetpack_protect_whitelist',
644
					),
645
					network_admin_url( 'admin.php' )
646
				)
647
			);
648
			exit();
649
		}
650
651
		/*
652
		 * Fields
653
		 *
654
		 * auto-connect - Checkbox for global Jetpack connection
655
		 * sub-site-connection-override - Allow sub-site admins to (dis)reconnect with their own Jetpack account
656
		 */
657
		$auto_connect = 0;
658
		if ( isset( $_POST['auto-connect'] ) ) {
659
			$auto_connect = 1;
660
		}
661
662
		$sub_site_connection_override = 0;
663
		if ( isset( $_POST['sub-site-connection-override'] ) ) {
664
			$sub_site_connection_override = 1;
665
		}
666
667
		$data = array(
668
			'auto-connect'                 => $auto_connect,
669
			'sub-site-connection-override' => $sub_site_connection_override,
670
		);
671
672
		update_site_option( $this->settings_name, $data );
673
		wp_safe_redirect(
674
			add_query_arg(
675
				array(
676
					'page'    => 'jetpack-settings',
677
					'updated' => 'true',
678
				),
679
				network_admin_url( 'admin.php' )
680
			)
681
		);
682
		exit();
683
	}
684
685
	/**
686
	 * A hook handler for adding admin pages and subpages.
687
	 */
688
	public function wrap_render_network_admin_settings_page() {
689
		Jetpack_Admin_Page::wrap_ui( array( $this, 'render_network_admin_settings_page' ) );
690
	}
691
692
	/**
693
	 * A hook rendering the admin settings page.
694
	 */
695
	public function render_network_admin_settings_page() {
696
		$this->network_admin_page_header();
697
		$options = wp_parse_args( get_site_option( $this->settings_name ), $this->setting_defaults );
0 ignored issues
show
Documentation introduced by
$this->setting_defaults is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
698
699
		$modules      = array();
700
		$module_slugs = Jetpack::get_available_modules();
701
		foreach ( $module_slugs as $slug ) {
702
			$module           = Jetpack::get_module( $slug );
703
			$module['module'] = $slug;
704
			$modules[]        = $module;
705
		}
706
707
		usort( $modules, array( 'Jetpack', 'sort_modules' ) );
708
709
		if ( ! isset( $options['modules'] ) ) {
710
			$options['modules'] = $modules;
711
		}
712
713
		$data = array(
714
			'modules'                   => $modules,
715
			'options'                   => $options,
716
			'jetpack_protect_whitelist' => jetpack_protect_format_whitelist(),
717
		);
718
719
		Jetpack::init()->load_view( 'admin/network-settings.php', $data );
720
	}
721
722
	/**
723
	 * Updates a site wide option
724
	 *
725
	 * @since 2.9
726
	 *
727
	 * @param string $key option name.
728
	 * @param mixed  $value option value.
729
	 *
730
	 * @return boolean
731
	 **/
732
	public function update_option( $key, $value ) {
733
		$options         = get_site_option( $this->settings_name, $this->setting_defaults );
734
		$options[ $key ] = $value;
735
736
		return update_site_option( $this->settings_name, $options );
737
	}
738
739
	/**
740
	 * Retrieves a site wide option
741
	 *
742
	 * @since 2.9
743
	 *
744
	 * @param string $name - Name of the option in the database.
745
	 **/
746
	public function get_option( $name ) {
747
		$options = get_site_option( $this->settings_name, $this->setting_defaults );
748
		$options = wp_parse_args( $options, $this->setting_defaults );
0 ignored issues
show
Documentation introduced by
$this->setting_defaults is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
749
750
		if ( ! isset( $options[ $name ] ) ) {
751
			$options[ $name ] = null;
752
		}
753
754
		return $options[ $name ];
755
	}
756
}
757