PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 7.3.1.1
Jetpack – WP Security, Backup, Speed, & Growth v7.3.1.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 7 years ago _inc 7 years ago bin 7 years ago css 7 years ago extensions 7 years ago images 7 years ago json-endpoints 7 years ago languages 7 years ago logs 9 years ago modules 7 years ago sal 7 years ago scss 7 years ago sync 7 years ago views 7 years ago wp-cli-templates 7 years ago .svnignore 12 years ago CODE-OF-CONDUCT.md 9 years ago changelog.txt 7 years ago class.frame-nonce-preview.php 9 years ago class.jetpack-admin.php 7 years ago class.jetpack-affiliate.php 7 years ago class.jetpack-autoupdate.php 7 years ago class.jetpack-bbpress-json-api-compat.php 9 years ago class.jetpack-cli.php 7 years ago class.jetpack-client-server.php 8 years ago class.jetpack-client.php 7 years ago class.jetpack-connection-banner.php 7 years ago class.jetpack-constants.php 8 years ago class.jetpack-data.php 7 years ago class.jetpack-debugger.php 7 years ago class.jetpack-error.php 10 years ago class.jetpack-gutenberg.php 7 years ago class.jetpack-heartbeat.php 7 years ago class.jetpack-idc.php 8 years ago class.jetpack-ixr-client.php 10 years ago class.jetpack-jitm.php 7 years ago class.jetpack-modules-list-table.php 7 years ago class.jetpack-network-sites-list-table.php 9 years ago class.jetpack-network.php 7 years ago class.jetpack-options.php 7 years ago class.jetpack-plan.php 7 years ago class.jetpack-post-images.php 7 years ago class.jetpack-signature.php 7 years ago class.jetpack-tracks.php 7 years ago class.jetpack-twitter-cards.php 7 years ago class.jetpack-user-agent.php 8 years ago class.jetpack-xmlrpc-server.php 7 years ago class.jetpack.php 7 years ago class.json-api-endpoints.php 7 years ago class.json-api.php 7 years ago class.photon.php 7 years ago composer.json 7 years ago functions.compat.php 7 years ago functions.gallery.php 8 years ago functions.global.php 7 years ago functions.opengraph.php 7 years ago functions.photon.php 7 years ago jest.config.js 7 years ago jetpack.php 7 years ago json-api-config.php 10 years ago json-endpoints.php 7 years ago locales.php 7 years ago readme.txt 7 years ago require-lib.php 7 years ago uninstall.php 7 years ago wpml-config.xml 10 years ago
class.jetpack-network.php
777 lines
1 <?php
2
3 /**
4 * Used to manage Jetpack installation on Multisite Network installs
5 *
6 * SINGLETON: To use call Jetpack_Network::init()
7 *
8 * DO NOT USE ANY STATIC METHODS IN THIS CLASS!!!!!!
9 *
10 * @since 2.9
11 */
12 class Jetpack_Network {
13
14 /**
15 * Holds a static copy of Jetpack_Network for the singleton
16 *
17 * @since 2.9
18 * @var Jetpack_Network
19 */
20 private static $instance = null;
21
22 /**
23 * Name of the network wide settings
24 *
25 * @since 2.9
26 * @var string
27 */
28 private $settings_name = 'jetpack-network-settings';
29
30 /**
31 * Defaults for settings found on the Jetpack > Settings page
32 *
33 * @since 2.9
34 * @var array
35 */
36 private $setting_defaults = array(
37 'auto-connect' => 0,
38 'sub-site-connection-override' => 1,
39 //'manage_auto_activated_modules' => 0,
40 );
41
42 /**
43 * Constructor
44 *
45 * @since 2.9
46 */
47 private function __construct() {
48 require_once( ABSPATH . '/wp-admin/includes/plugin.php' ); // For the is_plugin... check
49 require_once( JETPACK__PLUGIN_DIR . 'modules/protect/shared-functions.php' ); // For managing the global whitelist
50 /*
51 * Sanity check to ensure the install is Multisite and we
52 * are in Network Admin
53 */
54 if ( is_multisite() && is_network_admin() ) {
55 add_action( 'network_admin_menu', array( $this, 'add_network_admin_menu' ) );
56 add_action( 'network_admin_edit_jetpack-network-settings', array( $this, 'save_network_settings_page' ), 10, 0 );
57 add_filter( 'admin_body_class', array( $this, 'body_class' ) );
58
59 if ( isset( $_GET['page'] ) && 'jetpack' == $_GET['page'] ) {
60 add_action( 'admin_init', array( $this, 'jetpack_sites_list' ) );
61 }
62 }
63
64 /*
65 * Things that should only run on multisite
66 */
67 if ( is_multisite() && is_plugin_active_for_network( 'jetpack/jetpack.php' ) ) {
68 add_action( 'wp_before_admin_bar_render', array( $this, 'add_to_menubar' ) );
69
70 /*
71 * If admin wants to automagically register new sites set the hook here
72 *
73 * This is a hacky way because xmlrpc is not available on wpmu_new_blog
74 */
75 if ( $this->get_option( 'auto-connect' ) == 1 ) {
76 add_action( 'wpmu_new_blog', array( $this, 'do_automatically_add_new_site' ) );
77 }
78 }
79
80 // Remove the toggles for 2.9, re-evaluate how they're done and added for a 3.0 release. They don't feel quite right yet.
81 // add_filter( 'jetpack_get_default_modules', array( $this, 'set_auto_activated_modules' ) );
82 }
83
84 /**
85 * Sets which modules get activated by default on subsite connection.
86 * Modules can be set in Network Admin > Jetpack > Settings
87 *
88 * @since 2.9
89 *
90 * @param array $modules
91 *
92 * @return array
93 **/
94 public function set_auto_activated_modules( $modules ) {
95 return $modules;
96
97 /* Remove the toggles for 2.9, re-evaluate how they're done and added for a 3.0 release. They don't feel quite right yet.
98 if( 1 == $this->get_option( 'manage_auto_activated_modules' ) ) {
99 return (array) $this->get_option( 'modules' );
100 } else {
101 return $modules;
102 }
103 */
104 }
105
106 /**
107 * Registers new sites upon creation
108 *
109 * @since 2.9
110 * @uses wpmu_new_blog
111 *
112 * @param int $blog_id
113 **/
114 public function do_automatically_add_new_site( $blog_id ) {
115 $this->do_subsiteregister( $blog_id );
116 }
117
118 /**
119 * Adds .network-admin class to the body tag
120 * Helps distinguish network admin JP styles from regular site JP styles
121 *
122 * @since 2.9
123 */
124 public function body_class( $classes ) {
125 return trim( $classes ) . ' network-admin ';
126 }
127
128 /**
129 * Provides access to an instance of Jetpack_Network
130 *
131 * This is how the Jetpack_Network object should *always* be accessed
132 *
133 * @since 2.9
134 * @return Jetpack_Network
135 */
136 public static function init() {
137 if ( ! self::$instance || ! is_a( self::$instance, 'Jetpack_Network' ) ) {
138 self::$instance = new Jetpack_Network;
139 }
140
141 return self::$instance;
142 }
143
144 /**
145 * Registers the Multisite admin bar menu item shortcut.
146 * This shortcut helps users quickly and easily navigate to the Jetpack Network Admin
147 * menu from anywhere in their network.
148 *
149 * @since 2.9
150 */
151 public function register_menubar() {
152 add_action( 'wp_before_admin_bar_render', array( $this, 'add_to_menubar' ) );
153 }
154
155 /**
156 * Runs when Jetpack is deactivated from the network admin plugins menu.
157 * Each individual site will need to have Jetpack::disconnect called on it.
158 * Site that had Jetpack individually enabled will not be disconnected as
159 * on Multisite individually activated plugins are still activated when
160 * a plugin is deactivated network wide.
161 *
162 * @since 2.9
163 **/
164 public function deactivate() {
165 // Only fire if in network admin
166 if ( ! is_network_admin() ) {
167 return;
168 }
169
170 $sites = get_sites();
171
172 foreach ( $sites as $s ) {
173 switch_to_blog( $s->blog_id );
174 $active_plugins = get_option( 'active_plugins' );
175
176 /*
177 * If this plugin was activated in the subsite individually
178 * we do not want to call disconnect. Plugins activated
179 * individually (before network activation) stay activated
180 * when the network deactivation occurs
181 */
182 if ( ! in_array( 'jetpack/jetpack.php', $active_plugins ) ) {
183 Jetpack::disconnect();
184 }
185 }
186 restore_current_blog();
187 }
188
189 /**
190 * Adds a link to the Jetpack Network Admin page in the network admin menu bar.
191 *
192 * @since 2.9
193 **/
194 public function add_to_menubar() {
195 global $wp_admin_bar;
196 // Don't show for logged out users or single site mode.
197 if ( ! is_user_logged_in() || ! is_multisite() ) {
198 return;
199 }
200
201 $wp_admin_bar->add_node( array(
202 'parent' => 'network-admin',
203 'id' => 'network-admin-jetpack',
204 'title' => 'Jetpack',
205 'href' => $this->get_url( 'network_admin_page' ),
206 ) );
207 }
208
209 /**
210 * Returns various URL strings. Factory like
211 *
212 * $args can be a string or an array.
213 * If $args is an array there must be an element called name for the switch statement
214 *
215 * Currently supports:
216 * - subsiteregister: Pass array( 'name' => 'subsiteregister', 'site_id' => SITE_ID )
217 * - network_admin_page: Provides link to /wp-admin/network/JETPACK
218 * - subsitedisconnect: Pass array( 'name' => 'subsitedisconnect', 'site_id' => SITE_ID )
219 *
220 * @since 2.9
221 *
222 * @param Mixed $args
223 *
224 * @return String
225 **/
226 public function get_url( $args ) {
227 $url = null; // Default url value
228
229 if ( is_string( $args ) ) {
230 $name = $args;
231 } else {
232 $name = $args['name'];
233 }
234
235 switch ( $name ) {
236 case 'subsiteregister':
237 if ( ! isset( $args['site_id'] ) ) {
238 break; // If there is not a site id present we cannot go further
239 }
240 $url = network_admin_url(
241 'admin.php?page=jetpack&action=subsiteregister&site_id='
242 . $args['site_id']
243 );
244 break;
245
246 case 'network_admin_page':
247 $url = network_admin_url( 'admin.php?page=jetpack' );
248 break;
249
250 case 'subsitedisconnect':
251 if ( ! isset( $args['site_id'] ) ) {
252 break; // If there is not a site id present we cannot go further
253 }
254 $url = network_admin_url(
255 'admin.php?page=jetpack&action=subsitedisconnect&site_id='
256 . $args['site_id']
257 );
258 break;
259 }
260
261 return $url;
262 }
263
264 /**
265 * Adds the Jetpack menu item to the Network Admin area
266 *
267 * @since 2.9
268 */
269 public function add_network_admin_menu() {
270 add_menu_page( 'Jetpack', 'Jetpack', 'jetpack_network_admin_page', 'jetpack', array( $this, 'wrap_network_admin_page' ), 'div', 3 );
271 $jetpack_sites_page_hook = add_submenu_page( 'jetpack', __( 'Jetpack Sites', 'jetpack' ), __( 'Sites', 'jetpack' ), 'jetpack_network_sites_page', 'jetpack', array( $this, 'wrap_network_admin_page' ) );
272 $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' ) );
273 add_action( "admin_print_styles-$jetpack_sites_page_hook", array( 'Jetpack_Admin_Page', 'load_wrapper_styles' ) );
274 add_action( "admin_print_styles-$jetpack_settings_page_hook", array( 'Jetpack_Admin_Page', 'load_wrapper_styles' ) );
275 /**
276 * As jetpack_register_genericons is by default fired off a hook,
277 * the hook may have already fired by this point.
278 * So, let's just trigger it manually.
279 */
280 require_once( JETPACK__PLUGIN_DIR . '_inc/genericons.php' );
281 jetpack_register_genericons();
282
283 if ( ! wp_style_is( 'jetpack-icons', 'registered' ) ) {
284 wp_register_style( 'jetpack-icons', plugins_url( 'css/jetpack-icons.min.css', JETPACK__PLUGIN_FILE ), false, JETPACK__VERSION );
285 }
286
287 add_action( 'admin_enqueue_scripts', array( $this, 'admin_menu_css' ) );
288 }
289
290 /**
291 * Adds JP menu icon
292 *
293 * @since 2.9
294 **/
295 function admin_menu_css() {
296 wp_enqueue_style( 'jetpack-icons' );
297 }
298
299 /**
300 * Provides functionality for the Jetpack > Sites page.
301 * Does not do the display!
302 *
303 * @since 2.9
304 */
305 public function jetpack_sites_list() {
306 Jetpack::init();
307
308 if ( isset( $_GET['action'] ) ) {
309 switch ( $_GET['action'] ) {
310 case 'subsiteregister':
311 /*
312 * @todo check_admin_referer( 'jetpack-subsite-register' );
313 */
314 Jetpack::log( 'subsiteregister' );
315
316 // If !$_GET['site_id'] stop registration and error
317 if ( ! isset( $_GET['site_id'] ) || empty( $_GET['site_id'] ) ) {
318 // Log error to state cookie for display later
319 /**
320 * @todo Make state messages show on Jetpack NA pages
321 **/
322 Jetpack::state( 'missing_site_id', esc_html__( 'Site ID must be provided to register a sub-site.', 'jetpack' ) );
323 break;
324 }
325
326 // Send data to register endpoint and retrieve shadow blog details
327 $result = $this->do_subsiteregister();
328 $url = $this->get_url( 'network_admin_page' );
329
330 if ( is_wp_error( $result ) ) {
331 $url = add_query_arg( 'action', 'connection_failed', $url );
332 } else {
333 $url = add_query_arg( 'action', 'connected', $url );
334 }
335
336 wp_safe_redirect( $url );
337 exit;
338
339 case 'subsitedisconnect':
340 Jetpack::log( 'subsitedisconnect' );
341
342 if ( ! isset( $_GET['site_id'] ) || empty( $_GET['site_id'] ) ) {
343 Jetpack::state( 'missing_site_id', esc_html__( 'Site ID must be provided to disconnect a sub-site.', 'jetpack' ) );
344 break;
345 }
346
347 $this->do_subsitedisconnect();
348 break;
349
350 case 'connected':
351 case 'connection_failed':
352 add_action( 'jetpack_notices', array( $this, 'show_jetpack_notice' ) );
353 break;
354 }
355 }
356 }
357
358 public function show_jetpack_notice() {
359 if ( isset( $_GET['action'] ) && 'connected' == $_GET['action'] ) {
360 $notice = __( 'Site successfully connected.', 'jetpack' );
361 $classname = 'updated';
362 } else if ( isset( $_GET['action'] ) && 'connection_failed' == $_GET['action'] ) {
363 $notice = __( 'Site connection failed!', 'jetpack' );
364 $classname = 'error';
365 }
366 ?>
367 <div id="message" class="<?php echo esc_attr( $classname );?> jetpack-message jp-connect" style="display:block !important;">
368 <p><?php echo esc_html( $notice ); ?></p>
369 </div>
370 <?php
371 }
372
373 /**
374 * Disconnect functionality for an individual site
375 *
376 * @since 2.9
377 * @see Jetpack_Network::jetpack_sites_list()
378 */
379 public function do_subsitedisconnect( $site_id = null ) {
380 if ( ! current_user_can( 'jetpack_disconnect' ) ) {
381 return;
382 }
383 $site_id = ( is_null( $site_id ) ) ? $_GET['site_id'] : $site_id;
384 switch_to_blog( $site_id );
385 Jetpack::disconnect();
386 restore_current_blog();
387 }
388
389 /**
390 * Registers a subsite with the Jetpack servers
391 *
392 * @since 2.9
393 * @todo Break apart into easier to manage chunks that can be unit tested
394 * @see Jetpack_Network::jetpack_sites_list();
395 */
396 public function do_subsiteregister( $site_id = null ) {
397 if ( ! current_user_can( 'jetpack_disconnect' ) ) {
398 return;
399 }
400
401 if ( Jetpack::is_development_mode() ) {
402 return;
403 }
404
405 $jp = Jetpack::init();
406
407 // Figure out what site we are working on
408 $site_id = ( is_null( $site_id ) ) ? $_GET['site_id'] : $site_id;
409
410 // better to try (and fail) to set a higher timeout than this system
411 // supports than to have register fail for more users than it should
412 $timeout = Jetpack::set_min_time_limit( 60 ) / 2;
413
414 // The blog id on WordPress.com of the primary network site
415 $network_wpcom_blog_id = Jetpack_Options::get_option( 'id' );
416
417 /*
418 * Here we need to switch to the subsite
419 * For the registration process we really only hijack how it
420 * works for an individual site and pass in some extra data here
421 */
422 switch_to_blog( $site_id );
423
424 // Save the secrets in the subsite so when the wpcom server does a pingback it
425 // will be able to validate the connection
426 $secrets = $jp->generate_secrets( 'register' );
427 if (
428 empty( $secrets['secret_1'] ) ||
429 empty( $secrets['secret_2'] ) ||
430 empty( $secrets['exp'] )
431 ) {
432 return new Jetpack_Error( 'missing_secrets' );
433 }
434
435 // Gra info for gmt offset
436 $gmt_offset = get_option( 'gmt_offset' );
437 if ( ! $gmt_offset ) {
438 $gmt_offset = 0;
439 }
440
441 /*
442 * Get the stats_option option from the db.
443 * It looks like the server strips this out so maybe it is not necessary?
444 * Does it match the Jetpack site with the old stats plugin id?
445 *
446 * @todo Find out if sending the stats_id is necessary
447 */
448 $stat_options = get_option( 'stats_options' );
449 $stat_id = $stat_options = isset( $stats_options['blog_id'] ) ? $stats_options['blog_id'] : null;
450 $user_id = get_current_user_id();
451
452 $tracks_identity = jetpack_tracks_get_identity( $user_id );
453
454 /*
455 * Use the subsite's registration date as the site creation date.
456 *
457 * This is in contrast to regular standalone sites, where we use the helper
458 * `Jetpack::get_assumed_site_creation_date()` to assume the site's creation date.
459 */
460 $blog_details = get_blog_details();
461 $site_creation_date = $blog_details->registered;
462
463 /**
464 * Both `state` and `user_id` need to be sent in the request, even though they are the same value.
465 * Connecting via the network admin combines `register()` and `authorize()` methods into one step,
466 * because we assume the main site is already authorized. `state` is used to verify the `register()`
467 * request, while `user_id()` is used to create the token in the `authorize()` request.
468 */
469 $args = array(
470 'method' => 'POST',
471 'body' => array(
472 'network_url' => $this->get_url( 'network_admin_page' ),
473 'network_wpcom_blog_id' => $network_wpcom_blog_id,
474 'siteurl' => site_url(),
475 'home' => home_url(),
476 'gmt_offset' => $gmt_offset,
477 'timezone_string' => (string) get_option( 'timezone_string' ),
478 'site_name' => (string) get_option( 'blogname' ),
479 'secret_1' => $secrets['secret_1'],
480 'secret_2' => $secrets['secret_2'],
481 'site_lang' => get_locale(),
482 'timeout' => $timeout,
483 'stats_id' => $stat_id, // Is this still required?
484 'user_id' => $user_id,
485 'state' => $user_id,
486 '_ui' => $tracks_identity['_ui'],
487 '_ut' => $tracks_identity['_ut'],
488 'site_created' => $site_creation_date,
489 'jetpack_version' => JETPACK__VERSION
490 ),
491 'headers' => array(
492 'Accept' => 'application/json',
493 ),
494 'timeout' => $timeout,
495 );
496
497 Jetpack::apply_activation_source_to_args( $args['body'] );
498
499 // Attempt to retrieve shadow blog details
500 $response = Jetpack_Client::_wp_remote_request(
501 Jetpack::fix_url_for_bad_hosts( Jetpack::api_url( 'subsiteregister' ) ), $args, true
502 );
503
504 /*
505 * $response should either be invalid or contain:
506 * - jetpack_id => id
507 * - jetpack_secret => blog_token
508 * - jetpack_public
509 *
510 * Store the wpcom site details
511 */
512 $valid_response = $jp->validate_remote_register_response( $response );
513
514 if ( is_wp_error( $valid_response ) || ! $valid_response ) {
515 restore_current_blog();
516 return $valid_response;
517 }
518
519 // Grab the response values to work with
520 $code = wp_remote_retrieve_response_code( $response );
521 $entity = wp_remote_retrieve_body( $response );
522 if ( $entity ) {
523 $json = json_decode( $entity );
524 } else {
525 $json = false;
526 }
527
528 if ( empty( $json->jetpack_secret ) || ! is_string( $json->jetpack_secret ) ) {
529 restore_current_blog();
530 return new Jetpack_Error( 'jetpack_secret', '', $code );
531 }
532
533 if ( isset( $json->jetpack_public ) ) {
534 $jetpack_public = (int) $json->jetpack_public;
535 } else {
536 $jetpack_public = false;
537 }
538
539 Jetpack_Options::update_options( array(
540 'id' => (int) $json->jetpack_id,
541 'blog_token' => (string) $json->jetpack_secret,
542 'public' => $jetpack_public,
543 ) );
544
545 /*
546 * Update the subsiteregister method on wpcom so that it also sends back the
547 * token in this same request
548 */
549 $is_master_user = ! Jetpack::is_active();
550 Jetpack::update_user_token(
551 get_current_user_id(),
552 sprintf( '%s.%d', $json->token->secret, get_current_user_id() ),
553 $is_master_user
554 );
555
556 Jetpack::activate_default_modules();
557
558 restore_current_blog();
559 }
560
561 function wrap_network_admin_page() {
562 Jetpack_Admin_Page::wrap_ui( array( $this, 'network_admin_page' ) );
563 }
564
565 /**
566 * Handles the displaying of all sites on the network that are
567 * dis/connected to Jetpack
568 *
569 * @since 2.9
570 * @see Jetpack_Network::jetpack_sites_list()
571 */
572 function network_admin_page() {
573 global $current_site;
574 $this->network_admin_page_header();
575
576 $jp = Jetpack::init();
577
578 // We should be, but ensure we are on the main blog
579 switch_to_blog( $current_site->blog_id );
580 $main_active = $jp->is_active();
581 restore_current_blog();
582
583 // If we are in dev mode, just show the notice and bail
584 if ( Jetpack::is_development_mode() ) {
585 Jetpack::show_development_mode_notice();
586 return;
587 }
588
589 /*
590 * Ensure the main blog is connected as all other subsite blog
591 * connections will feed off this one
592 */
593 if ( ! $main_active ) {
594 $url = $this->get_url( array(
595 'name' => 'subsiteregister',
596 'site_id' => 1,
597 ) );
598 $data = array( 'url' => $jp->build_connect_url() );
599 Jetpack::init()->load_view( 'admin/must-connect-main-blog.php', $data );
600
601 return;
602 }
603
604 require_once( 'class.jetpack-network-sites-list-table.php' );
605 $myListTable = new Jetpack_Network_Sites_List_Table();
606 echo '<div class="wrap"><h2>' . __( 'Sites', 'jetpack' ) . '</h2>';
607 echo '<form method="post">';
608 $myListTable->prepare_items();
609 $myListTable->display();
610 echo '</form></div>';
611
612 }
613
614 /**
615 * Stylized JP header formatting
616 *
617 * @since 2.9
618 */
619 function network_admin_page_header() {
620 global $current_user;
621
622 $is_connected = Jetpack::is_active();
623
624 $data = array(
625 'is_connected' => $is_connected
626 );
627 Jetpack::init()->load_view( 'admin/network-admin-header.php', $data );
628 }
629
630
631 /**
632 * Fires when the Jetpack > Settings page is saved.
633 *
634 * @since 2.9
635 */
636 public function save_network_settings_page() {
637
638 if ( ! wp_verify_nonce( $_POST['_wpnonce'], 'jetpack-network-settings' ) ) {
639 // no nonce, push back to settings page
640 wp_safe_redirect(
641 add_query_arg(
642 array( 'page' => 'jetpack-settings' ),
643 network_admin_url( 'admin.php' )
644 )
645 );
646 exit();
647 }
648
649 // try to save the Protect whitelist before anything else, since that action can result in errors
650 $whitelist = str_replace( ' ', '', $_POST['global-whitelist'] );
651 $whitelist = explode( PHP_EOL, $whitelist );
652 $result = jetpack_protect_save_whitelist( $whitelist, $global = true );
653 if ( is_wp_error( $result ) ) {
654 wp_safe_redirect(
655 add_query_arg(
656 array( 'page' => 'jetpack-settings', 'error' => 'jetpack_protect_whitelist' ),
657 network_admin_url( 'admin.php' )
658 )
659 );
660 exit();
661 }
662
663 /*
664 * Fields
665 *
666 * auto-connect - Checkbox for global Jetpack connection
667 * sub-site-connection-override - Allow sub-site admins to (dis)reconnect with their own Jetpack account
668 */
669 $auto_connect = 0;
670 if ( isset( $_POST['auto-connect'] ) ) {
671 $auto_connect = 1;
672 }
673
674 $sub_site_connection_override = 0;
675 if ( isset( $_POST['sub-site-connection-override'] ) ) {
676 $sub_site_connection_override = 1;
677 }
678
679 /* Remove the toggles for 2.9, re-evaluate how they're done and added for a 3.0 release. They don't feel quite right yet.
680 $manage_auto_activated_modules = 0;
681 if ( isset( $_POST['manage_auto_activated_modules'] ) ) {
682 $manage_auto_activated_modules = 1;
683 }
684
685 $modules = array();
686 if ( isset( $_POST['modules'] ) ) {
687 $modules = $_POST['modules'];
688 }
689 */
690
691 $data = array(
692 'auto-connect' => $auto_connect,
693 'sub-site-connection-override' => $sub_site_connection_override,
694 //'manage_auto_activated_modules' => $manage_auto_activated_modules,
695 //'modules' => $modules,
696 );
697
698 update_site_option( $this->settings_name, $data );
699 wp_safe_redirect(
700 add_query_arg(
701 array( 'page' => 'jetpack-settings', 'updated' => 'true' ),
702 network_admin_url( 'admin.php' )
703 )
704 );
705 exit();
706 }
707
708 public function wrap_render_network_admin_settings_page() {
709 Jetpack_Admin_Page::wrap_ui( array( $this, 'render_network_admin_settings_page' ) );
710 }
711
712 public function render_network_admin_settings_page() {
713 $this->network_admin_page_header();
714 $options = wp_parse_args( get_site_option( $this->settings_name ), $this->setting_defaults );
715
716 $modules = array();
717 $module_slugs = Jetpack::get_available_modules();
718 foreach ( $module_slugs as $slug ) {
719 $module = Jetpack::get_module( $slug );
720 $module['module'] = $slug;
721 $modules[] = $module;
722 }
723
724 usort( $modules, array( 'Jetpack', 'sort_modules' ) );
725
726 if ( ! isset( $options['modules'] ) ) {
727 $options['modules'] = $modules;
728 }
729
730 $data = array(
731 'modules' => $modules,
732 'options' => $options,
733 'jetpack_protect_whitelist' => jetpack_protect_format_whitelist(),
734 );
735
736 Jetpack::init()->load_view( 'admin/network-settings.php', $data );
737 }
738
739 /**
740 * Updates a site wide option
741 *
742 * @since 2.9
743 *
744 * @param string $key
745 * @param mixed $value
746 *
747 * @return boolean
748 **/
749 public function update_option( $key, $value ) {
750 $options = get_site_option( $this->settings_name, $this->setting_defaults );
751 $options[ $key ] = $value;
752
753 return update_site_option( $this->settings_name, $options );
754 }
755
756 /**
757 * Retrieves a site wide option
758 *
759 * @since 2.9
760 *
761 * @param string $name - Name of the option in the database
762 **/
763 public function get_option( $name ) {
764 $options = get_site_option( $this->settings_name, $this->setting_defaults );
765 $options = wp_parse_args( $options, $this->setting_defaults );
766
767 if ( ! isset( $options[ $name ] ) ) {
768 $options[ $name ] = null;
769 }
770
771 return $options[ $name ];
772 }
773
774 }
775
776 // end class
777