PluginProbe
Module Control for Jetpack / 1.0
Module Control for Jetpack v1.0
1.7.4 1.7.3 trunk 0.4 1.0 1.2 1.3 1.4 1.4.1 1.4.2 1.5 1.6 1.7 1.7.1 1.7.2
jetpack-module-control / jetpack-module-control.php

jetpack-module-control.php in Module Control for Jetpack 1.0, at jetpack-module-control.php

706 lines 22.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Jetpack Module Control
4 Plugin URI: http://status301.net/wordpress-plugins/jetpack-module-control/
5 Description: This plugin brings additional control over Jetpack modules. You can blacklist / remove individual modules, prevent auto-activation or allow activation without a WordPress.com account.
6 Text Domain: jetpack-mc
7 Domain Path: languages
8 Network: true
9 Version: 1.0
10 Author: RavanH
11 Author URI: http://status301.net/
12 */
13
14 /*
15 * ROADMAP
16 *
17 * version 2.0
18 * Replace "Prevent the Jetpack plugin from auto-activating (new) modules" with
19 * finer grained "Select which modules to auto-activate"
20 * see http://jeremy.hu/customize-the-list-of-modules-available-in-jetpack/
21 * function jeherve_auto_activate_stats() {
22 return array( 'stats' );
23 }
24 add_filter( 'jetpack_get_default_modules', 'jeherve_auto_activate_stats' );
25 *
26 * TO CONSIDER
27 *
28 * Make blacklist or whitelist optional
29 *
30 * Option to disable JUMPSTART with "Jetpack_Options::update_option( 'jumpstart', 'jumpstart_dismissed' );" ??
31 * or do we need to go through apply_filters( 'jetpack_module_feature' ...
32 * If we want to be able to select which modules should appear in Jumpstart later!
33 *
34 * Can we disable Debug link in the footer menu? No...
35 *
36 * Option to "force_deactivate" (same as blacklist?) as described on https://github.com/Automattic/jetpack/issues/1452
37 *
38 */
39
40
41 /**
42 * Jetpack Module Control Class
43 *
44 * since 0.1
45 */
46 class Jetpack_Module_Control {
47
48 /**
49 * The single instance.
50 * @var object
51 * @access private
52 * @since 0.1
53 */
54 private static $instance = null;
55
56 /**
57 * The plugins basename.
58 * @var string
59 * @access private
60 * @since 0.1
61 */
62 private static $plugin_basename = null;
63
64 /**
65 * Current plugin version.
66 * @since 0.1
67 * @var string
68 */
69 public $version = '1.0';
70
71 /**
72 * Available modules array
73 * @since 0.1
74 * @access private
75 * @var array
76 */
77 private static $modules = null;
78
79 /**
80 * Know modules array with names
81 * @since 0.2
82 * @access private
83 * @var array
84 */
85 private static $known_modules = array(
86 'after-the-deadline' => array( 'name' => 'Spelling and Grammar',
87 'requires_connection' => true
88 ),
89 'carousel' => array( 'name' => 'Carousel',
90 'requires_connection' => false
91 ),
92 'comments' => array( 'name' => 'Jetpack Comments',
93 'requires_connection' => true
94 ),
95 'contact-form' => array( 'name' => 'Contact Form',
96 'requires_connection' => false
97 ),
98 'custom-content-types' => array( 'name' => 'Custom Content Types',
99 'requires_connection' => false
100 ),
101 'custom-css' => array( 'name' => 'Custom CSS',
102 'requires_connection' => false
103 ),
104 'enhanced-distribution' => array( 'name' => 'Enhanced Distribution',
105 'requires_connection' => true
106 ),
107 'gravatar-hovercards' => array( 'name' => 'Gravatar Hovercards',
108 'requires_connection' => false
109 ),
110 'infinite-scroll' => array( 'name' => 'Infinite Scroll',
111 'requires_connection' => false
112 ),
113 'json-api' => array( 'name' => 'JSON API',
114 'requires_connection' => true
115 ),
116 'latex' => array( 'name' => 'Beautiful Math',
117 'requires_connection' => false
118 ),
119 'likes' => array( 'name' => 'Likes',
120 'requires_connection' => true
121 ),
122 'manage' => array( 'name' => 'Manage',
123 'requires_connection' => true
124 ),
125 'markdown' => array( 'name' => 'Markdown',
126 'requires_connection' => false
127 ),
128 'minileven' => array( 'name' => 'Mobile Theme',
129 'requires_connection' => false
130 ),
131 'monitor' => array( 'name' => 'Monitor',
132 'requires_connection' => true
133 ),
134 'notes' => array( 'name' => 'Notifications',
135 'requires_connection' => true
136 ),
137 'omnisearch' => array( 'name' => 'Omnisearch',
138 'requires_connection' => false
139 ),
140 'photon' => array( 'name' => 'Photon',
141 'requires_connection' => true
142 ),
143 'post-by-email' => array( 'name' => 'Post by Email',
144 'requires_connection' => true
145 ),
146 'protect' => array( 'name' => 'Protect',
147 'requires_connection' => true
148 ),
149 'publicize' => array( 'name' => 'Publicize',
150 'requires_connection' => true
151 ),
152 'related-posts' => array( 'name' => 'Related Posts',
153 'requires_connection' => true
154 ),
155 'sharedaddy' => array( 'name' => 'Sharing',
156 'requires_connection' => false
157 ),
158 'shortcodes' => array( 'name' => 'Shortcode Embeds',
159 'requires_connection' => false
160 ),
161 'shortlinks' => array( 'name' => 'WP.me Shortlinks',
162 'requires_connection' => true
163 ),
164 'site-icon' => array( 'name' => 'Site Icon',
165 'requires_connection' => false
166 ),
167 'sso' => array( 'name' => 'Jetpack Single Sign On',
168 'requires_connection' => true
169 ),
170 'stats' => array( 'name' => 'WordPress.com Stats',
171 'requires_connection' => true
172 ),
173 'subscriptions' => array( 'name' => 'Subscriptions',
174 'requires_connection' => true
175 ),
176 'tiled-gallery' => array( 'name' => 'Tiled Galleries',
177 'requires_connection' => false
178 ),
179 'vaultpress' => array( 'name' => 'VaultPress',
180 'requires_connection' => false
181 ),
182 'verification-tools' => array( 'name' => 'Site Verification',
183 'requires_connection' => false
184 ),
185 'videopress' => array( 'name' => 'VideoPress',
186 'requires_connection' => true
187 ),
188 'widget-visibility' => array( 'name' => 'Widget Visibility',
189 'requires_connection' => false
190 ),
191 'widgets' => array( 'name' => 'Extra Sidebar Widgets',
192 'requires_connection' => false
193 )
194 );
195
196 /**
197 * Know modules array with dashicons
198 * @since 0.3
199 * @access private
200 * @var array
201 */
202 private static $known_modules_icons = array(
203 'after-the-deadline' => 'edit',
204 'carousel' => 'camera',
205 'comments' => 'format-chat',
206 'contact-form' => 'feedback',
207 'custom-content-types' => 'media-default',
208 'custom-css' => 'admin-appearance',
209 'enhanced-distribution' => 'share',
210 'gravatar-hovercards' => 'id', // not available
211 'infinite-scroll' => 'star-filled',
212 'json-api' => 'share-alt',
213 'latex' => 'star-filled',
214 'likes' => 'star-filled',
215 'manage' => 'wordpress-alt',
216 'markdown' => 'editor-code',
217 'minileven' => 'smartphone',
218 'monitor' => 'flag',
219 'notes' => 'admin-comments',
220 'omnisearch' => 'search',
221 'photon' => 'visibility',
222 'post-by-email' => 'email',
223 'protect' => 'lock',
224 'publicize' => 'share',
225 'related-posts' => 'update',
226 'sharedaddy' => 'share-alt',
227 'shortcodes' => 'text',
228 'shortlinks' => 'admin-links',
229 'site-icon' => 'admin-site',
230 'sso' => 'wordpress-alt',
231 'stats' => 'wordpress-alt',
232 'subscriptions' => 'email',
233 'tiled-gallery' => 'schedule', // not available. maybe tagcloud ?
234 'vaultpress' => 'shield-alt', // not availabe
235 'verification-tools' => 'clipboard', // maye yes
236 'videopress' => 'controls-play',
237 'widget-visibility' => 'welcome-widgets-menus',
238 'widgets' => 'welcome-widgets-menus'
239 );
240
241 /**
242 * Default dashicon
243 * @since 1.0
244 * @access private
245 * @var string
246 */
247 private static $default_icon = 'star-empty';
248
249 /**
250 * Return Jetpack available modules
251 * @since 0.1
252 * @return array
253 */
254 private function get_available_modules() {
255 if ( null === self::$modules ) {
256 if ( class_exists('Jetpack') ) {
257 //remove_filter( 'jetpack_get_available_modules', array($this, 'blacklist') ); // remove filter useless here because of bug in Jetpack
258 $modules = array();
259 foreach ( Jetpack::get_available_modules() as $slug ) {
260 $module = Jetpack::get_module( $slug );
261 if ( $module )
262 $modules[$slug] = $module;
263 }
264 self::$modules = $modules;
265 //add_filter( 'jetpack_get_available_modules', array($this, 'blacklist') );
266 } else {
267 self::$modules = self::$known_modules;
268 }
269 }
270 return self::$modules;
271 }
272
273 /**
274 * Return plugin basename
275 *
276 * @since 0.1
277 *
278 * @return string Plugin basename
279 */
280 private function plugin_basename() {
281 if ( null === self::$plugin_basename ) {
282 self::$plugin_basename = plugin_basename( __FILE__ );
283 }
284 return self::$plugin_basename;
285 }
286
287 /**
288 * MANUAL CONTROL
289 */
290
291 /**
292 * Adds the Manual Control option
293 *
294 * @since 0.1
295 * @see get_site_option(), checked(), disabled()
296 *
297 * @uses jetpack_mc_manual_control network option
298 * @echo Html Checkbox input field for jetpack_mc_manual_control option
299 * @return void
300 */
301 public function manual_control_settings() {
302
303 $cws_manual_control = class_exists('CWS_Manual_Control_for_Jetpack_Plugin') ? true : false;
304 $option = $cws_manual_control ? '1' : get_site_option('jetpack_mc_manual_control');
305 $disabled = $cws_manual_control || ( defined('JETPACK_MC_LOCKDOWN') && JETPACK_MC_LOCKDOWN ) ? true : false;
306
307 ?>
308 <label>
309 <input type='checkbox' name='jetpack_mc_manual_control' value='1'
310 <?php checked( $option, '1' ); ?>
311 <?php disabled( $disabled ); ?>>
312 <?php _e('Prevent the Jetpack plugin from auto-activating (new) modules.','jetpack-mc'); ?>
313 </label>
314 <?php
315
316 } // END manual_control_settings()
317
318 /**
319 * Activates Manual Control by returning an empty array on module auto-activation.
320 * First modelled after Manual Control for Jetpack by Mark Jaquith http://coveredwebservices.com/
321 * To be converted to allow selected modules instead of all or none.
322 *
323 * @since 0.1
324 * @see add_filter()
325 */
326 public function manual_control( $modules ) {
327
328 return get_site_option('jetpack_mc_manual_control', false) ? array() : $modules;
329
330 } // END manual_control()
331
332 /**
333 * DEVELOPMENT MODE
334 */
335
336 /**
337 * Adds the Jetpack Without WordPress.com option
338 *
339 * @since 1.0
340 * @see get_site_option(), checked(), disabled()
341 *
342 * @echo Html Checkbox input field for jetpack_mc_development_mode option
343 * @return void
344 */
345 public function development_mode_settings() {
346
347 $forced = is_plugin_active('slimjetpack/slimjetpack.php') || ( defined('JETPACK_DEV_DEBUG') && JETPACK_DEV_DEBUG ) ? true : false;
348 $option = $forced ? '1' : get_site_option('jetpack_mc_development_mode');
349 $disabled = $forced || ( defined('JETPACK_MC_LOCKDOWN') && JETPACK_MC_LOCKDOWN ) ? true : false;
350
351 ?>
352 <label>
353 <input type='checkbox' name='jetpack_mc_development_mode' value='1'
354 <?php checked( $option, '1' ); ?>
355 <?php disabled( $disabled ); ?>>
356 <?php _e('Allow activating Jetpack modules without a WordPress.com connection.','jetpack-mc'); ?>
357 </label>
358 <p class="description"><?php _e('By forcing Jetpack into development mode, modules are used without a WordPress.com account. All modules that require a WordPress.com connection will be unavailable. These modules are marked with an asterisk (*) below. The admin message about Jetpack running in development mode will be hidden.','jetpack-mc'); ?></p>
359 <?php
360
361 } // END development_mode_settings()
362
363 /**
364 * Activates Development Mode by returning true on jetpack_development_mode filter.
365 * Based on http://jeremy.hu/customize-the-list-of-modules-available-in-jetpack/
366 *
367 * @since 1.0
368 * @see add_filter()
369 */
370 public function development_mode() {
371
372 return get_site_option('jetpack_mc_development_mode', false) ? true : false;
373
374 } // END development_mode()
375
376 /**
377 * ADMIN NOTICES
378 */
379
380 /**
381 * Disables Centralized Site Management banner by returning false on can_display_jetpack_manage_notice filter.
382 *
383 * @since 0.1
384 * @see add_filter()
385 */
386 private function no_manage_notice() {
387
388 $blacklist = get_site_option('jetpack_mc_blacklist', array() );
389
390 if ( in_array('manage', (array)$blacklist ) )
391 add_filter( 'can_display_jetpack_manage_notice', '__return_false' );
392
393 } // END no_manage_notice()
394
395 /**
396 * Disables Centralized Site Management banner by returning false on can_display_jetpack_manage_notice filter.
397 *
398 * @since 0.1
399 * @see add_filter()
400 */
401 private function no_dev_notice() {
402
403 if ( get_site_option('jetpack_mc_development_mode', false) && class_exists('Jetpack') )
404 remove_action( 'jetpack_notices', array( Jetpack::init(), 'show_development_mode_notice' ) );
405
406 } // END no_dev_notice()
407
408 /**
409 * BLACKLIST
410 */
411
412 /**
413 * Adds a checkmark list of modules to blacklist
414 *
415 * @since 0.1
416 * @see get_site_option(), checked()
417 *
418 * @uses jetpack_mc_blacklist network option
419 * @echo Html Checkbox input field table for jetpack_mc_blacklist option
420 */
421 public function blacklist_settings() {
422
423 $blacklist = get_site_option( 'jetpack_mc_blacklist', array() );
424
425 $dev_mode = get_site_option( 'jetpack_mc_development_mode' );
426
427 $modules = $this->get_available_modules();
428 asort($modules);
429
430 $icons = self::$known_modules_icons;
431
432 $lockdown = defined('JETPACK_MC_LOCKDOWN') ? JETPACK_MC_LOCKDOWN : false;
433
434 ?>
435 <fieldset><legend class="screen-reader-text"><span><?php _e('Blacklist Modules','jetpack-mc'); ?></span></legend>
436 <?php
437 foreach ( $modules as $slug => $module ) {
438 $icon = isset($icons[$slug]) ? $icons[$slug] : self::$default_icon;
439 ?>
440 <label>
441 <input type='checkbox' name='jetpack_mc_blacklist[]' value='<?php echo $slug; ?>'
442 <?php checked( in_array($slug,(array)$blacklist), true ); ?>
443 <?php disabled( $lockdown ); ?>>
444 <span class="dashicons dashicons-<?php echo $icon; ?>"></span> <?php echo $module['name']; ?>
445 </label><?php echo !empty($module['requires_connection']) && true === $module['requires_connection'] ? ' <a href="#jmc-note-1" style="text-decoration:none" title="' . __('Requires a WordPress.com connection','jetpack-mc') . '">*</a>' : ''; ?><br>
446 <?php
447 }
448 ?>
449 <aside role="note" id="jmc-note-1"><p class="description"><?php _e('*) Modules marked with an asterisk require a WordPress.com connection. They will be unavailable if Jetpack is forced into development mode.','jetpack-mc'); ?></p></aside>
450 </fieldset>
451 <?php
452
453 } // END blacklist_settings()
454
455 /**
456 * Blacklist Jetpack modules
457 * Modelled after ParhamG's blacklist_jetpack_modules.php https://gist.github.com/ParhamG/6494979
458 *
459 * @since 0.1
460 * @param $modules
461 *
462 * @return Array Allowed modules after unsetting blacklisted modules from all modules array
463 */
464 public function blacklist ( $modules ) {
465
466 $blacklist = get_site_option('jetpack_mc_blacklist');
467
468 foreach ( (array)$blacklist as $mod ) {
469 if ( isset( $modules[$mod] ) ) {
470 unset( $modules[$mod] );
471 }
472 }
473
474 return $modules;
475
476 } // END blacklist()
477
478 /**
479 * ADMIN
480 */
481
482 /**
483 * Initiate plugins admin stuff
484 *
485 * @since 0.1
486 */
487
488 public function admin_init(){
489
490 $this->no_manage_notice();
491
492 $this->no_dev_notice();
493
494 if ( is_plugin_active_for_network( $this->plugin_basename() ) ) {
495
496 add_filter( 'network_admin_plugin_action_links_' . $this->plugin_basename(), array($this, 'add_action_link') );
497
498 // Add settings to Network Settings
499 // thanks to http://zao.is/2013/07/adding-settings-to-network-settings-for-wordpress-multisite/
500 if ( is_network_admin() ) {
501 add_filter( 'wpmu_options', array( $this, 'show_network_settings' ) );
502 if ( defined('JETPACK_MC_LOCKDOWN') && JETPACK_MC_LOCKDOWN ) {
503 // do not add action to save network settings
504 } else {
505 add_action( 'update_wpmu_options', array( $this, 'save_network_settings' ) );
506 }
507 }
508
509 } else {
510
511 add_filter( 'plugin_action_links_' . $this->plugin_basename(), array($this, 'add_action_link') );
512
513 // Do regular register/add_settings stuff in 'general' settings on options-general.php
514 $settings = 'general';
515
516 add_settings_section('jetpack-mc', '<a name="jetpack-mc"></a>' . __('Jetpack Module Control','jetpack-mc'), array($this, 'add_settings_section'), $settings);
517
518 // register settings
519 if ( defined('JETPACK_MC_LOCKDOWN') && JETPACK_MC_LOCKDOWN ) {
520 // do not register settings to prevent them being updated
521 } else {
522 register_setting( $settings, 'jetpack_mc_manual_control' ); // sanitize_callback 'boolval' ?
523 register_setting( $settings, 'jetpack_mc_development_mode' ); // sanitize_callback 'boolval' ?
524 register_setting( $settings, 'jetpack_mc_blacklist', 'array_values' );
525 }
526
527 // add settings fields
528 add_settings_field( 'jetpack_mc_manual_control', __('Manual Control','jetpack-mc'), array($this, 'manual_control_settings'), $settings, 'jetpack-mc' ); // array('label_for' => 'elementid')
529 add_settings_field( 'jetpack_mc_development_mode', __('Development Mode','jetpack-mc'), array($this, 'development_mode_settings'), $settings, 'jetpack-mc' ); // array('label_for' => 'elementid')
530 add_settings_field( 'jetpack_mc_blacklist', __('Blacklist Modules','jetpack-mc'), array($this, 'blacklist_settings'), $settings, 'jetpack-mc' );
531
532 }
533
534 }
535
536 /**
537 * Saves the network settings
538 *
539 * @since 0.2
540 */
541 public function save_network_settings() {
542
543 $posted_settings = array();
544
545 if( isset( $_POST['jetpack_mc_manual_control'] ) )
546 $posted_settings['jetpack_mc_manual_control'] = '1';
547
548 if( isset( $_POST['jetpack_mc_development_mode'] ) )
549 $posted_settings['jetpack_mc_development_mode'] = '1';
550
551 if( isset( $_POST['jetpack_mc_blacklist'] ) )
552 $posted_settings['jetpack_mc_blacklist'] = array_values($_POST['jetpack_mc_blacklist']);
553
554 foreach ( $posted_settings as $name => $value )
555 update_site_option( $name, $value );
556
557 }
558
559 /**
560 * Prints the network settings
561 *
562 * @since 0.2
563 */
564 public function show_network_settings() {
565
566 ?>
567 <h3><a name="jetpack-mc"></a><?php _e('Jetpack Module Control','jetpack-mc'); ?></h3>
568 <?php
569 $this->add_settings_section();
570 ?>
571 <table class="form-table">
572 <tbody>
573 <tr>
574 <th scope="row"><?php _e('Manual Control','jetpack-mc'); ?></th>
575 <td>
576 <?php
577 $this->manual_control_settings();
578 ?>
579 </td>
580 </tr>
581 <tr>
582 <th scope="row"><?php _e('Development Mode','jetpack-mc'); ?></th>
583 <td>
584 <?php
585 $this->development_mode_settings();
586 ?>
587 </td>
588 </tr>
589 <tr>
590 <th scope="row"><?php _e('Blacklist Modules','jetpack-mc'); ?></th>
591 <td>
592 <?php
593 $this->blacklist_settings();
594 ?>
595 </td>
596 </tr>
597 </tbody>
598 </table>
599 <?php
600 }
601
602 /**
603 * Echos a settings section header
604 *
605 * @since 0.1
606 *
607 * @param $option (unused)
608 * @echo Html
609 */
610 public function add_settings_section( $option ) {
611 echo '<p><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ravanhagen%40gmail%2ecom&item_name=Jetpack%20Module%20Control&item_number='
612 . $this->version
613 . '&no_shipping=0&tax=0&charset=UTF%2d8&currency_code=EUR" title="'
614 . __('Donate to keep plugin development going!','jetpack-mc')
615 . '"><img src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" style="border:none;float:right;margin:5px 0 0 10px" alt="'
616 . __('Donate to keep plugin development going!','jetpack-mc') . '" width="92" height="26" /></a>'
617 . sprintf(__('The options in this section are provided by %s.','jetpack-mc'),'<strong><a href="http://status301.net/wordpress-plugins/jetpack-module-control/">'
618 . __('Jetpack Module Control','jetpack-mc') . ' ' . $this->version . '</a></strong>') . ' '
619 . __('This plugin brings additional control over Jetpack modules. You can blacklist / remove individual modules, prevent auto-activation or allow activation without a WordPress.com account.','jetpack-mc') . ' '
620 . sprintf(__('These settings can be locked down by adding %s to your wp-config.php file.','jetpack-mc'),'<code>define(\'JETPACK_MC_LOCKDOWN\', true);</code>')
621 . '</p>';
622
623 } // END add_setting_section()
624
625 /**
626 * Adds an action link on the Plugins page
627 *
628 * @since 0.1
629 * @see is_plugin_active_for_network(), admin_url(), network_admin_url()
630 *
631 * @param array $links Plugin de/activation and deletion links
632 * @return array Plugin links plus Settings link
633 */
634 public function add_action_link( $links ) {
635 $settings_link = is_plugin_active_for_network( $this->plugin_basename() ) ?
636 '<a href="' . network_admin_url('settings.php#jetpack-mc') . '">' . translate('Network Settings') . '</a>' :
637 '<a href="' . admin_url('options-general.php#jetpack-mc') . '">' . translate('Settings') . '</a>';
638 return array_merge(
639 array( 'settings' => $settings_link ),
640 $links
641 );
642 return $links;
643 }
644
645 /**
646 * Routines to execute on plugins_loaded
647 *
648 * We need to add our jetpack_get_available_modules filter
649 * AFTER running get_available_modules() because of bug in Jetpack
650 * https://github.com/Automattic/jetpack/issues/2026
651 * https://github.com/Automattic/jetpack/pull/2027
652 *
653 * @since 0.1
654 */
655 public function plugins_loaded() {
656 global $pagenow;
657
658 // only need translations on admin page
659 if ( is_admin() ) {
660 load_plugin_textdomain('jetpack-mc', false, $this->plugin_basename() . '/languages/');
661
662 // populate jetpack modules list before filter is added
663 if ( in_array( $pagenow, array( 'options-general.php', 'settings.php' ) ) )
664 $this->get_available_modules();
665 }
666
667 add_filter( 'jetpack_get_default_modules', array( $this, 'manual_control' ), 99 );
668 add_filter( 'jetpack_development_mode', array( $this, 'development_mode' ) );
669 add_filter( 'jetpack_get_available_modules', array( $this, 'blacklist' ) );
670 }
671
672 /**
673 * Getter method for retrieving single object instance.
674 *
675 * @since 0.1
676 *
677 * @return Jetpack_Module_Control|null instance object
678 */
679 public static function instance() {
680 if(is_null(self::$instance)) {
681 self::$instance = new self();
682 }
683 return self::$instance;
684 } // End instance ()
685
686 /**
687 * Constructor
688 *
689 * @since 0.1
690 */
691 private function __construct() {
692 add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 0 );
693 add_action( 'admin_init', array($this,'admin_init'), 11 );
694 }
695
696 /**
697 * Cloning
698 *
699 * @since 0.1
700 */
701 private function __clone() { }
702
703 }
704
705 Jetpack_Module_Control::instance();
706