PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 9.8.1
Jetpack – WP Security, Backup, Speed, & Growth v9.8.1
15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / class.jetpack-network.php
jetpack Last commit date
3rd-party 5 years ago _inc 4 years ago css 4 years ago extensions 4 years ago images 5 years ago json-endpoints 4 years ago modules 4 years ago sal 5 years ago src 5 years ago vendor 4 years ago views 5 years ago CHANGELOG.md 4 years ago LICENSE.txt 5 years ago SECURITY.md 5 years ago class-jetpack-connection-status.php 5 years ago class-jetpack-pre-connection-jitms.php 5 years ago class-jetpack-recommendations-banner.php 5 years ago class-jetpack-wizard-banner.php 5 years ago class-jetpack-xmlrpc-methods.php 5 years ago class.frame-nonce-preview.php 6 years ago class.jetpack-admin.php 5 years ago class.jetpack-affiliate.php 6 years ago class.jetpack-autoupdate.php 5 years ago class.jetpack-bbpress-json-api.compat.php 5 years ago class.jetpack-cli.php 5 years ago class.jetpack-client-server.php 5 years ago class.jetpack-connection-banner.php 5 years ago class.jetpack-data.php 5 years ago class.jetpack-gutenberg.php 5 years ago class.jetpack-heartbeat.php 5 years ago class.jetpack-idc.php 6 years ago class.jetpack-ixr-client.php 5 years ago class.jetpack-modules-list-table.php 5 years ago class.jetpack-network-sites-list-table.php 5 years ago class.jetpack-network.php 5 years ago class.jetpack-plan.php 5 years ago class.jetpack-post-images.php 5 years ago class.jetpack-twitter-cards.php 5 years ago class.jetpack-user-agent.php 5 years ago class.jetpack.php 5 years ago class.json-api-endpoints.php 5 years ago class.json-api.php 5 years ago class.photon.php 5 years ago composer.json 4 years ago functions.compat.php 5 years ago functions.cookies.php 5 years ago functions.gallery.php 6 years ago functions.global.php 5 years ago functions.opengraph.php 5 years ago functions.photon.php 5 years ago jest.config.js 5 years ago jetpack.php 4 years ago json-api-config.php 5 years ago json-endpoints.php 7 years ago load-jetpack.php 5 years ago locales.php 7 years ago readme.txt 4 years ago require-lib.php 5 years ago uninstall.php 5 years ago wpml-config.xml 10 years ago
class.jetpack-network.php
756 lines
1 <?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFilename
2 /**
3 * Jetpack Network Manager class file.
4 *
5 * @package automattic/jetpack
6 */
7
8 use Automattic\Jetpack\Connection\Manager;
9 use Automattic\Jetpack\Connection\Tokens;
10 use Automattic\Jetpack\Status;
11
12 /**
13 * Used to manage Jetpack installation on Multisite Network installs
14 *
15 * SINGLETON: To use call Jetpack_Network::init()
16 *
17 * DO NOT USE ANY STATIC METHODS IN THIS CLASS!!!!!!
18 *
19 * @since 2.9
20 */
21 class Jetpack_Network {
22
23 /**
24 * Holds a static copy of Jetpack_Network for the singleton
25 *
26 * @since 2.9
27 * @var Jetpack_Network
28 */
29 private static $instance = null;
30
31 /**
32 * An instance of the connection manager object.
33 *
34 * @since 7.7
35 * @var Automattic\Jetpack\Connection\Manager
36 */
37 private $connection;
38
39 /**
40 * Name of the network wide settings
41 *
42 * @since 2.9
43 * @var string
44 */
45 private $settings_name = 'jetpack-network-settings';
46
47 /**
48 * Defaults for settings found on the Jetpack > Settings page
49 *
50 * @since 2.9
51 * @var array
52 */
53 private $setting_defaults = array(
54 'auto-connect' => 0,
55 'sub-site-connection-override' => 1,
56 );
57
58 /**
59 * Constructor
60 *
61 * @since 2.9
62 */
63 private function __construct() {
64 require_once ABSPATH . '/wp-admin/includes/plugin.php'; // For the is_plugin... check.
65 require_once JETPACK__PLUGIN_DIR . 'modules/protect/shared-functions.php'; // For managing the global whitelist.
66
67 /**
68 * Sanity check to ensure the install is Multisite and we
69 * are in Network Admin
70 */
71 if ( is_multisite() && is_network_admin() ) {
72 add_action( 'network_admin_menu', array( $this, 'add_network_admin_menu' ) );
73 add_action( 'network_admin_edit_jetpack-network-settings', array( $this, 'save_network_settings_page' ), 10, 0 );
74 add_filter( 'admin_body_class', array( $this, 'body_class' ) );
75
76 if ( isset( $_GET['page'] ) && 'jetpack' == $_GET['page'] ) {
77 add_action( 'admin_init', array( $this, 'jetpack_sites_list' ) );
78 }
79 }
80
81 /*
82 * Things that should only run on multisite
83 */
84 if ( is_multisite() && is_plugin_active_for_network( 'jetpack/jetpack.php' ) ) {
85 add_action( 'wp_before_admin_bar_render', array( $this, 'add_to_menubar' ) );
86 add_filter( 'jetpack_disconnect_cap', array( $this, 'set_multisite_disconnect_cap' ) );
87
88 /*
89 * If admin wants to automagically register new sites set the hook here
90 *
91 * This is a hacky way because xmlrpc is not available on wp_initialize_site
92 */
93 if ( 1 === $this->get_option( 'auto-connect' ) ) {
94 add_action( 'wp_initialize_site', array( $this, 'do_automatically_add_new_site' ) );
95 }
96 }
97 }
98
99 /**
100 * Sets a connection object.
101 *
102 * @param Automattic\Jetpack\Connection\Manager $connection the connection manager object.
103 */
104 public function set_connection( Manager $connection ) {
105 $this->connection = $connection;
106 }
107
108 /**
109 * Sets which modules get activated by default on subsite connection.
110 * Modules can be set in Network Admin > Jetpack > Settings
111 *
112 * @since 2.9
113 * @deprecated since 7.7.0
114 *
115 * @param array $modules List of modules.
116 */
117 public function set_auto_activated_modules( $modules ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
118 _deprecated_function( __METHOD__, 'jetpack-7.7' );
119 }
120
121 /**
122 * Registers new sites upon creation
123 *
124 * @since 2.9
125 * @since 7.4.0 Uses a WP_Site object.
126 * @uses wp_initialize_site
127 *
128 * @param WP_Site $site the WordPress site object.
129 **/
130 public function do_automatically_add_new_site( $site ) {
131 if ( is_a( $site, 'WP_Site' ) ) {
132 $this->do_subsiteregister( $site->id );
133 }
134 }
135
136 /**
137 * Adds .network-admin class to the body tag
138 * Helps distinguish network admin JP styles from regular site JP styles
139 *
140 * @since 2.9
141 *
142 * @param String $classes current assigned body classes.
143 * @return String amended class string.
144 */
145 public function body_class( $classes ) {
146 return trim( $classes ) . ' network-admin ';
147 }
148
149 /**
150 * Provides access to an instance of Jetpack_Network
151 *
152 * This is how the Jetpack_Network object should *always* be accessed
153 *
154 * @since 2.9
155 * @return Jetpack_Network
156 */
157 public static function init() {
158 if ( ! self::$instance || ! is_a( self::$instance, 'Jetpack_Network' ) ) {
159 self::$instance = new Jetpack_Network();
160 }
161
162 return self::$instance;
163 }
164
165 /**
166 * Registers the Multisite admin bar menu item shortcut.
167 * This shortcut helps users quickly and easily navigate to the Jetpack Network Admin
168 * menu from anywhere in their network.
169 *
170 * @since 2.9
171 */
172 public function register_menubar() {
173 add_action( 'wp_before_admin_bar_render', array( $this, 'add_to_menubar' ) );
174 }
175
176 /**
177 * Runs when Jetpack is deactivated from the network admin plugins menu.
178 * Each individual site will need to have Jetpack::disconnect called on it.
179 * Site that had Jetpack individually enabled will not be disconnected as
180 * on Multisite individually activated plugins are still activated when
181 * a plugin is deactivated network wide.
182 *
183 * @since 2.9
184 **/
185 public function deactivate() {
186 // Only fire if in network admin.
187 if ( ! is_network_admin() ) {
188 return;
189 }
190
191 $sites = get_sites();
192
193 foreach ( $sites as $s ) {
194 switch_to_blog( $s->blog_id );
195 $active_plugins = get_option( 'active_plugins' );
196
197 /*
198 * If this plugin was activated in the subsite individually
199 * we do not want to call disconnect. Plugins activated
200 * individually (before network activation) stay activated
201 * when the network deactivation occurs
202 */
203 if ( ! in_array( 'jetpack/jetpack.php', $active_plugins, true ) ) {
204 Jetpack::disconnect();
205 }
206 restore_current_blog();
207 }
208
209 }
210
211 /**
212 * Adds a link to the Jetpack Network Admin page in the network admin menu bar.
213 *
214 * @since 2.9
215 **/
216 public function add_to_menubar() {
217 global $wp_admin_bar;
218 // Don't show for logged out users or single site mode.
219 if ( ! is_user_logged_in() || ! is_multisite() ) {
220 return;
221 }
222
223 $wp_admin_bar->add_node(
224 array(
225 'parent' => 'network-admin',
226 'id' => 'network-admin-jetpack',
227 'title' => 'Jetpack',
228 'href' => $this->get_url( 'network_admin_page' ),
229 )
230 );
231 }
232
233 /**
234 * Returns various URL strings. Factory like
235 *
236 * $args can be a string or an array.
237 * If $args is an array there must be an element called name for the switch statement
238 *
239 * Currently supports:
240 * - subsiteregister: Pass array( 'name' => 'subsiteregister', 'site_id' => SITE_ID )
241 * - network_admin_page: Provides link to /wp-admin/network/JETPACK
242 * - subsitedisconnect: Pass array( 'name' => 'subsitedisconnect', 'site_id' => SITE_ID )
243 *
244 * @since 2.9
245 *
246 * @param Mixed $args URL parameters.
247 *
248 * @return String
249 **/
250 public function get_url( $args ) {
251 $url = null; // Default url value.
252
253 if ( is_string( $args ) ) {
254 $name = $args;
255 } else if ( is_array( $args ) ) {
256 $name = $args['name'];
257 } else {
258 return $url;
259 }
260
261 switch ( $name ) {
262 case 'subsiteregister':
263 if ( ! isset( $args['site_id'] ) ) {
264 break; // If there is not a site id present we cannot go further.
265 }
266 $url = network_admin_url(
267 'admin.php?page=jetpack&action=subsiteregister&site_id='
268 . $args['site_id']
269 );
270 break;
271
272 case 'network_admin_page':
273 $url = network_admin_url( 'admin.php?page=jetpack' );
274 break;
275
276 case 'subsitedisconnect':
277 if ( ! isset( $args['site_id'] ) ) {
278 break; // If there is not a site id present we cannot go further.
279 }
280 $url = network_admin_url(
281 'admin.php?page=jetpack&action=subsitedisconnect&site_id='
282 . $args['site_id']
283 );
284 break;
285 }
286
287 return $url;
288 }
289
290 /**
291 * Adds the Jetpack menu item to the Network Admin area
292 *
293 * @since 2.9
294 */
295 public function add_network_admin_menu() {
296 add_menu_page( 'Jetpack', 'Jetpack', 'jetpack_network_admin_page', 'jetpack', array( $this, 'wrap_network_admin_page' ), 'div', 3 );
297 $jetpack_sites_page_hook = add_submenu_page( 'jetpack', __( 'Jetpack Sites', 'jetpack' ), __( 'Sites', 'jetpack' ), 'jetpack_network_sites_page', 'jetpack', array( $this, 'wrap_network_admin_page' ) );
298 $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' ) );
299 add_action( "admin_print_styles-$jetpack_sites_page_hook", array( 'Jetpack_Admin_Page', 'load_wrapper_styles' ) );
300 add_action( "admin_print_styles-$jetpack_settings_page_hook", array( 'Jetpack_Admin_Page', 'load_wrapper_styles' ) );
301 /**
302 * As jetpack_register_genericons is by default fired off a hook,
303 * the hook may have already fired by this point.
304 * So, let's just trigger it manually.
305 */
306 require_once JETPACK__PLUGIN_DIR . '_inc/genericons.php';
307 jetpack_register_genericons();
308
309 if ( ! wp_style_is( 'jetpack-icons', 'registered' ) ) {
310 wp_register_style( 'jetpack-icons', plugins_url( 'css/jetpack-icons.min.css', JETPACK__PLUGIN_FILE ), false, JETPACK__VERSION );
311 }
312
313 add_action( 'admin_enqueue_scripts', array( $this, 'admin_menu_css' ) );
314 }
315
316 /**
317 * Adds JP menu icon
318 *
319 * @since 2.9
320 **/
321 public function admin_menu_css() {
322 wp_enqueue_style( 'jetpack-icons' );
323 }
324
325 /**
326 * Provides functionality for the Jetpack > Sites page.
327 * Does not do the display!
328 *
329 * @since 2.9
330 */
331 public function jetpack_sites_list() {
332 Jetpack::init();
333
334 if ( isset( $_GET['action'] ) ) {
335 switch ( $_GET['action'] ) {
336 case 'subsiteregister':
337 /**
338 * Add actual referrer checking.
339 *
340 * @todo check_admin_referer( 'jetpack-subsite-register' );
341 */
342 Jetpack::log( 'subsiteregister' );
343
344 // If !$_GET['site_id'] stop registration and error.
345 if ( ! isset( $_GET['site_id'] ) || empty( $_GET['site_id'] ) ) {
346 /**
347 * Log error to state cookie for display later.
348 *
349 * @todo Make state messages show on Jetpack NA pages
350 */
351 Jetpack::state( 'missing_site_id', esc_html__( 'Site ID must be provided to register a sub-site.', 'jetpack' ) );
352 break;
353 }
354
355 // Send data to register endpoint and retrieve shadow blog details.
356 $result = $this->do_subsiteregister();
357 $url = $this->get_url( 'network_admin_page' );
358
359 if ( is_wp_error( $result ) ) {
360 $url = add_query_arg( 'action', 'connection_failed', $url );
361 } else {
362 $url = add_query_arg( 'action', 'connected', $url );
363 }
364
365 wp_safe_redirect( $url );
366 exit;
367
368 case 'subsitedisconnect':
369 Jetpack::log( 'subsitedisconnect' );
370
371 if ( ! isset( $_GET['site_id'] ) || empty( $_GET['site_id'] ) ) {
372 Jetpack::state( 'missing_site_id', esc_html__( 'Site ID must be provided to disconnect a sub-site.', 'jetpack' ) );
373 break;
374 }
375
376 $this->do_subsitedisconnect();
377 break;
378
379 case 'connected':
380 case 'connection_failed':
381 add_action( 'jetpack_notices', array( $this, 'show_jetpack_notice' ) );
382 break;
383 }
384 }
385 }
386
387 /**
388 * Set the disconnect capability for multisite.
389 *
390 * @param array $caps The capabilities array.
391 */
392 public function set_multisite_disconnect_cap( $caps ) {
393 // Can individual site admins manage their own connection?
394 if ( ! is_super_admin() && ! $this->get_option( 'sub-site-connection-override' ) ) {
395 /*
396 * We need to update the option name -- it's terribly unclear which
397 * direction the override goes.
398 *
399 * @todo: Update the option name to `sub-sites-can-manage-own-connections`
400 */
401 return array( 'do_not_allow' );
402 }
403
404 return $caps;
405 }
406
407 /**
408 * Shows the Jetpack plugin notices.
409 */
410 public function show_jetpack_notice() {
411 if ( isset( $_GET['action'] ) && 'connected' == $_GET['action'] ) {
412 $notice = __( 'Site successfully connected.', 'jetpack' );
413 $classname = 'updated';
414 } elseif ( isset( $_GET['action'] ) && 'connection_failed' == $_GET['action'] ) {
415 $notice = __( 'Site connection failed!', 'jetpack' );
416 $classname = 'error';
417 }
418 ?>
419 <div id="message" class="<?php echo esc_attr( $classname ); ?> jetpack-message jp-connect" style="display:block !important;">
420 <p><?php echo esc_html( $notice ); ?></p>
421 </div>
422 <?php
423 }
424
425 /**
426 * Disconnect functionality for an individual site
427 *
428 * @since 2.9
429 * @see Jetpack_Network::jetpack_sites_list()
430 *
431 * @param int $site_id the site identifier.
432 */
433 public function do_subsitedisconnect( $site_id = null ) {
434 if ( ! current_user_can( 'jetpack_disconnect' ) ) {
435 return;
436 }
437 $site_id = ( is_null( $site_id ) ) ? $_GET['site_id'] : $site_id;
438 switch_to_blog( $site_id );
439 Jetpack::disconnect();
440 restore_current_blog();
441 }
442
443 /**
444 * Registers a subsite with the Jetpack servers
445 *
446 * @since 2.9
447 * @todo Break apart into easier to manage chunks that can be unit tested
448 * @see Jetpack_Network::jetpack_sites_list();
449 *
450 * @param int $site_id the site identifier.
451 */
452 public function do_subsiteregister( $site_id = null ) {
453 if ( ! current_user_can( 'jetpack_disconnect' ) ) {
454 return;
455 }
456
457 if ( ( new Status() )->is_offline_mode() ) {
458 return;
459 }
460
461 // Figure out what site we are working on.
462 $site_id = ( is_null( $site_id ) ) ? $_GET['site_id'] : $site_id;
463
464 /*
465 * Here we need to switch to the subsite
466 * For the registration process we really only hijack how it
467 * works for an individual site and pass in some extra data here
468 */
469 switch_to_blog( $site_id );
470
471 add_filter( 'jetpack_register_request_body', array( $this, 'filter_register_request_body' ) );
472 add_action( 'jetpack_site_registered_user_token', array( $this, 'filter_register_user_token' ) );
473
474 // Save the secrets in the subsite so when the wpcom server does a pingback it
475 // will be able to validate the connection.
476 $result = $this->connection->register( 'subsiteregister' );
477
478 if ( is_wp_error( $result ) || ! $result ) {
479 restore_current_blog();
480 return $result;
481 }
482
483 Jetpack::activate_default_modules( false, false, array(), false );
484
485 restore_current_blog();
486 }
487
488 /**
489 * Receives the registration response token.
490 *
491 * @param Object $token the received token.
492 */
493 public function filter_register_user_token( $token ) {
494 $is_connection_owner = ! $this->connection->has_connected_owner();
495 ( new Tokens() )->update_user_token(
496 get_current_user_id(),
497 sprintf( '%s.%d', $token->secret, get_current_user_id() ),
498 $is_connection_owner
499 );
500 }
501
502 /**
503 * Filters the registration request body to include additional properties.
504 *
505 * @param array $properties standard register request body properties.
506 * @return array amended properties.
507 */
508 public function filter_register_request_body( $properties ) {
509 $blog_details = get_blog_details();
510
511 $network = get_network();
512
513 switch_to_blog( $network->blog_id );
514 // The blog id on WordPress.com of the primary network site.
515 $network_wpcom_blog_id = Jetpack_Options::get_option( 'id' );
516 restore_current_blog();
517
518 /**
519 * Both `state` and `user_id` need to be sent in the request, even though they are the same value.
520 * Connecting via the network admin combines `register()` and `authorize()` methods into one step,
521 * because we assume the main site is already authorized. `state` is used to verify the `register()`
522 * request, while `user_id()` is used to create the token in the `authorize()` request.
523 */
524 return array_merge(
525 $properties,
526 array(
527 'network_url' => $this->get_url( 'network_admin_page' ),
528 'network_wpcom_blog_id' => $network_wpcom_blog_id,
529 'user_id' => get_current_user_id(),
530
531 /*
532 * Use the subsite's registration date as the site creation date.
533 *
534 * This is in contrast to regular standalone sites, where we use the helper
535 * `Jetpack::get_assumed_site_creation_date()` to assume the site's creation date.
536 */
537 'site_created' => $blog_details->registered,
538 )
539 );
540 }
541
542 /**
543 * A hook handler for adding admin pages and subpages.
544 */
545 public function wrap_network_admin_page() {
546 Jetpack_Admin_Page::wrap_ui( array( $this, 'network_admin_page' ) );
547 }
548
549 /**
550 * Handles the displaying of all sites on the network that are
551 * dis/connected to Jetpack
552 *
553 * @since 2.9
554 * @see Jetpack_Network::jetpack_sites_list()
555 */
556 public function network_admin_page() {
557 global $current_site;
558 $this->network_admin_page_header();
559
560 $jp = Jetpack::init();
561
562 // We should be, but ensure we are on the main blog.
563 switch_to_blog( $current_site->blog_id );
564 $main_active = $jp->is_connection_ready();
565 restore_current_blog();
566
567 // If we are in dev mode, just show the notice and bail.
568 if ( ( new Status() )->is_offline_mode() ) {
569 Jetpack::show_development_mode_notice();
570 return;
571 }
572
573 /*
574 * Ensure the main blog is connected as all other subsite blog
575 * connections will feed off this one
576 */
577 if ( ! $main_active ) {
578 $url = $this->get_url(
579 array(
580 'name' => 'subsiteregister',
581 'site_id' => 1,
582 )
583 );
584 $data = array( 'url' => $jp->build_connect_url() );
585 Jetpack::init()->load_view( 'admin/must-connect-main-blog.php', $data );
586
587 return;
588 }
589
590 require_once 'class.jetpack-network-sites-list-table.php';
591
592 $network_sites_table = new Jetpack_Network_Sites_List_Table();
593 echo '<div class="wrap"><h2>' . esc_html__( 'Sites', 'jetpack' ) . '</h2>';
594 echo '<form method="post">';
595 $network_sites_table->prepare_items();
596 $network_sites_table->display();
597 echo '</form></div>';
598
599 }
600
601 /**
602 * Stylized JP header formatting
603 *
604 * @since 2.9
605 */
606 public function network_admin_page_header() {
607 $is_connected = Jetpack::is_connection_ready();
608
609 $data = array(
610 'is_connected' => $is_connected,
611 );
612 Jetpack::init()->load_view( 'admin/network-admin-header.php', $data );
613 }
614
615 /**
616 * Fires when the Jetpack > Settings page is saved.
617 *
618 * @since 2.9
619 */
620 public function save_network_settings_page() {
621
622 if ( ! wp_verify_nonce( $_POST['_wpnonce'], 'jetpack-network-settings' ) ) {
623 // No nonce, push back to settings page.
624 wp_safe_redirect(
625 add_query_arg(
626 array( 'page' => 'jetpack-settings' ),
627 network_admin_url( 'admin.php' )
628 )
629 );
630 exit();
631 }
632
633 // Try to save the Protect whitelist before anything else, since that action can result in errors.
634 $whitelist = str_replace( ' ', '', $_POST['global-whitelist'] );
635 $whitelist = explode( PHP_EOL, $whitelist );
636 $result = jetpack_protect_save_whitelist( $whitelist, true );
637 if ( is_wp_error( $result ) ) {
638 wp_safe_redirect(
639 add_query_arg(
640 array(
641 'page' => 'jetpack-settings',
642 'error' => 'jetpack_protect_whitelist',
643 ),
644 network_admin_url( 'admin.php' )
645 )
646 );
647 exit();
648 }
649
650 /*
651 * Fields
652 *
653 * auto-connect - Checkbox for global Jetpack connection
654 * sub-site-connection-override - Allow sub-site admins to (dis)reconnect with their own Jetpack account
655 */
656 $auto_connect = 0;
657 if ( isset( $_POST['auto-connect'] ) ) {
658 $auto_connect = 1;
659 }
660
661 $sub_site_connection_override = 0;
662 if ( isset( $_POST['sub-site-connection-override'] ) ) {
663 $sub_site_connection_override = 1;
664 }
665
666 $data = array(
667 'auto-connect' => $auto_connect,
668 'sub-site-connection-override' => $sub_site_connection_override,
669 );
670
671 update_site_option( $this->settings_name, $data );
672 wp_safe_redirect(
673 add_query_arg(
674 array(
675 'page' => 'jetpack-settings',
676 'updated' => 'true',
677 ),
678 network_admin_url( 'admin.php' )
679 )
680 );
681 exit();
682 }
683
684 /**
685 * A hook handler for adding admin pages and subpages.
686 */
687 public function wrap_render_network_admin_settings_page() {
688 Jetpack_Admin_Page::wrap_ui( array( $this, 'render_network_admin_settings_page' ) );
689 }
690
691 /**
692 * A hook rendering the admin settings page.
693 */
694 public function render_network_admin_settings_page() {
695 $this->network_admin_page_header();
696 $options = wp_parse_args( get_site_option( $this->settings_name ), $this->setting_defaults );
697
698 $modules = array();
699 $module_slugs = Jetpack::get_available_modules();
700 foreach ( $module_slugs as $slug ) {
701 $module = Jetpack::get_module( $slug );
702 $module['module'] = $slug;
703 $modules[] = $module;
704 }
705
706 usort( $modules, array( 'Jetpack', 'sort_modules' ) );
707
708 if ( ! isset( $options['modules'] ) ) {
709 $options['modules'] = $modules;
710 }
711
712 $data = array(
713 'modules' => $modules,
714 'options' => $options,
715 'jetpack_protect_whitelist' => jetpack_protect_format_whitelist(),
716 );
717
718 Jetpack::init()->load_view( 'admin/network-settings.php', $data );
719 }
720
721 /**
722 * Updates a site wide option
723 *
724 * @since 2.9
725 *
726 * @param string $key option name.
727 * @param mixed $value option value.
728 *
729 * @return boolean
730 **/
731 public function update_option( $key, $value ) {
732 $options = get_site_option( $this->settings_name, $this->setting_defaults );
733 $options[ $key ] = $value;
734
735 return update_site_option( $this->settings_name, $options );
736 }
737
738 /**
739 * Retrieves a site wide option
740 *
741 * @since 2.9
742 *
743 * @param string $name - Name of the option in the database.
744 **/
745 public function get_option( $name ) {
746 $options = get_site_option( $this->settings_name, $this->setting_defaults );
747 $options = wp_parse_args( $options, $this->setting_defaults );
748
749 if ( ! isset( $options[ $name ] ) ) {
750 $options[ $name ] = null;
751 }
752
753 return $options[ $name ];
754 }
755 }
756