class.jetpack-admin.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <?php
  2. // Build the Jetpack admin menu as a whole
  3. class Jetpack_Admin {
  4. /**
  5. * @var Jetpack_Admin
  6. **/
  7. private static $instance = null;
  8. /**
  9. * @var Jetpack
  10. **/
  11. private $jetpack;
  12. static function init() {
  13. if( isset( $_GET['page'] ) && $_GET['page'] === 'jetpack' ) {
  14. add_filter( 'nocache_headers', array( 'Jetpack_Admin', 'add_no_store_header' ), 100 );
  15. }
  16. if ( is_null( self::$instance ) ) {
  17. self::$instance = new Jetpack_Admin;
  18. }
  19. return self::$instance;
  20. }
  21. static function add_no_store_header( $headers ) {
  22. $headers['Cache-Control'] .= ', no-store';
  23. return $headers;
  24. }
  25. private function __construct() {
  26. $this->jetpack = Jetpack::init();
  27. jetpack_require_lib( 'admin-pages/class.jetpack-react-page' );
  28. $this->jetpack_react = new Jetpack_React_Page;
  29. jetpack_require_lib( 'admin-pages/class.jetpack-settings-page' );
  30. $this->fallback_page = new Jetpack_Settings_Page;
  31. add_action( 'admin_menu', array( $this->jetpack_react, 'add_actions' ), 998 );
  32. add_action( 'jetpack_admin_menu', array( $this->jetpack_react, 'jetpack_add_dashboard_sub_nav_item' ) );
  33. add_action( 'jetpack_admin_menu', array( $this->jetpack_react, 'jetpack_add_settings_sub_nav_item' ) );
  34. add_action( 'jetpack_admin_menu', array( $this, 'admin_menu_debugger' ) );
  35. add_action( 'jetpack_admin_menu', array( $this->fallback_page, 'add_actions' ) );
  36. // Add redirect to current page for activation/deactivation of modules
  37. add_action( 'jetpack_pre_activate_module', array( $this, 'fix_redirect' ), 10, 2 );
  38. add_action( 'jetpack_pre_deactivate_module', array( $this, 'fix_redirect' ) );
  39. // Add module bulk actions handler
  40. add_action( 'jetpack_unrecognized_action', array( $this, 'handle_unrecognized_action' ) );
  41. }
  42. static function sort_requires_connection_last( $module1, $module2 ) {
  43. if ( $module1['requires_connection'] == $module2['requires_connection'] ) {
  44. return 0;
  45. } elseif ( $module1['requires_connection'] ) {
  46. return 1;
  47. } elseif ( $module2['requires_connection'] ) {
  48. return -1;
  49. }
  50. return 0;
  51. }
  52. // Produce JS understandable objects of modules containing information for
  53. // presentation like description, name, configuration url, etc.
  54. function get_modules() {
  55. include_once( JETPACK__PLUGIN_DIR . 'modules/module-info.php' );
  56. $available_modules = Jetpack::get_available_modules();
  57. $active_modules = Jetpack::get_active_modules();
  58. $modules = array();
  59. $jetpack_active = Jetpack::is_active() || Jetpack::is_development_mode();
  60. $overrides = Jetpack_Modules_Overrides::instance();
  61. foreach ( $available_modules as $module ) {
  62. if ( $module_array = Jetpack::get_module( $module ) ) {
  63. /**
  64. * Filters each module's short description.
  65. *
  66. * @since 3.0.0
  67. *
  68. * @param string $module_array['description'] Module description.
  69. * @param string $module Module slug.
  70. */
  71. $short_desc = apply_filters( 'jetpack_short_module_description', $module_array['description'], $module );
  72. // Fix: correct multibyte strings truncate with checking for mbstring extension
  73. $short_desc_trunc = ( function_exists( 'mb_strlen' ) )
  74. ? ( ( mb_strlen( $short_desc ) > 143 )
  75. ? mb_substr( $short_desc, 0, 140 ) . '...'
  76. : $short_desc )
  77. : ( ( strlen( $short_desc ) > 143 )
  78. ? substr( $short_desc, 0, 140 ) . '...'
  79. : $short_desc );
  80. $module_array['module'] = $module;
  81. $module_array['activated'] = ( $jetpack_active ? in_array( $module, $active_modules ) : false );
  82. $module_array['deactivate_nonce'] = wp_create_nonce( 'jetpack_deactivate-' . $module );
  83. $module_array['activate_nonce'] = wp_create_nonce( 'jetpack_activate-' . $module );
  84. $module_array['available'] = self::is_module_available( $module_array );
  85. $module_array['short_description'] = $short_desc_trunc;
  86. $module_array['configure_url'] = Jetpack::module_configuration_url( $module );
  87. $module_array['override'] = $overrides->get_module_override( $module );
  88. ob_start();
  89. /**
  90. * Allow the display of a "Learn More" button.
  91. * The dynamic part of the action, $module, is the module slug.
  92. *
  93. * @since 3.0.0
  94. */
  95. do_action( 'jetpack_learn_more_button_' . $module );
  96. $module_array['learn_more_button'] = ob_get_clean();
  97. ob_start();
  98. /**
  99. * Allow the display of information text when Jetpack is connected to WordPress.com.
  100. * The dynamic part of the action, $module, is the module slug.
  101. *
  102. * @since 3.0.0
  103. */
  104. do_action( 'jetpack_module_more_info_' . $module );
  105. /**
  106. * Filter the long description of a module.
  107. *
  108. * @since 3.5.0
  109. *
  110. * @param string ob_get_clean() The module long description.
  111. * @param string $module The module name.
  112. */
  113. $module_array['long_description'] = apply_filters( 'jetpack_long_module_description', ob_get_clean(), $module );
  114. ob_start();
  115. /**
  116. * Filter the search terms for a module
  117. *
  118. * Search terms are typically added to the module headers, under "Additional Search Queries".
  119. *
  120. * Use syntax:
  121. * function jetpack_$module_search_terms( $terms ) {
  122. * $terms = _x( 'term 1, term 2', 'search terms', 'jetpack' );
  123. * return $terms;
  124. * }
  125. * add_filter( 'jetpack_search_terms_$module', 'jetpack_$module_search_terms' );
  126. *
  127. * @since 3.5.0
  128. *
  129. * @param string The search terms (comma separated).
  130. */
  131. echo apply_filters( 'jetpack_search_terms_' . $module, $module_array['additional_search_queries'] );
  132. $module_array['search_terms'] = ob_get_clean();
  133. $module_array['configurable'] = false;
  134. if (
  135. current_user_can( 'manage_options' ) &&
  136. /**
  137. * Allow the display of a configuration link in the Jetpack Settings screen.
  138. *
  139. * @since 3.0.0
  140. *
  141. * @param string $module Module name.
  142. * @param bool false Should the Configure module link be displayed? Default to false.
  143. */
  144. apply_filters( 'jetpack_module_configurable_' . $module, false )
  145. ) {
  146. $module_array['configurable'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( Jetpack::module_configuration_url( $module ) ), __( 'Configure', 'jetpack' ) );
  147. }
  148. $modules[ $module ] = $module_array;
  149. }
  150. }
  151. uasort( $modules, array( $this->jetpack, 'sort_modules' ) );
  152. if ( ! Jetpack::is_active() ) {
  153. uasort( $modules, array( __CLASS__, 'sort_requires_connection_last' ) );
  154. }
  155. return $modules;
  156. }
  157. static function is_module_available( $module ) {
  158. if ( ! is_array( $module ) || empty( $module ) )
  159. return false;
  160. /**
  161. * We never want to show VaultPress as activatable through Jetpack.
  162. */
  163. if ( 'vaultpress' === $module['module'] ) {
  164. return false;
  165. }
  166. if ( Jetpack::is_development_mode() ) {
  167. return ! ( $module['requires_connection'] );
  168. } else {
  169. if ( ! Jetpack::is_active() ) {
  170. return false;
  171. }
  172. return Jetpack::active_plan_supports( $module['module'] );
  173. }
  174. }
  175. function handle_unrecognized_action( $action ) {
  176. switch( $action ) {
  177. case 'bulk-activate' :
  178. if ( ! current_user_can( 'jetpack_activate_modules' ) ) {
  179. break;
  180. }
  181. $modules = (array) $_GET['modules'];
  182. $modules = array_map( 'sanitize_key', $modules );
  183. check_admin_referer( 'bulk-jetpack_page_jetpack_modules' );
  184. foreach( $modules as $module ) {
  185. Jetpack::log( 'activate', $module );
  186. Jetpack::activate_module( $module, false );
  187. }
  188. // The following two lines will rarely happen, as Jetpack::activate_module normally exits at the end.
  189. wp_safe_redirect( wp_get_referer() );
  190. exit;
  191. case 'bulk-deactivate' :
  192. if ( ! current_user_can( 'jetpack_deactivate_modules' ) ) {
  193. break;
  194. }
  195. $modules = (array) $_GET['modules'];
  196. $modules = array_map( 'sanitize_key', $modules );
  197. check_admin_referer( 'bulk-jetpack_page_jetpack_modules' );
  198. foreach ( $modules as $module ) {
  199. Jetpack::log( 'deactivate', $module );
  200. Jetpack::deactivate_module( $module );
  201. Jetpack::state( 'message', 'module_deactivated' );
  202. }
  203. Jetpack::state( 'module', $modules );
  204. wp_safe_redirect( wp_get_referer() );
  205. exit;
  206. default:
  207. return;
  208. }
  209. }
  210. function fix_redirect( $module, $redirect = true ) {
  211. if ( ! $redirect ) {
  212. return;
  213. }
  214. if ( wp_get_referer() ) {
  215. add_filter( 'wp_redirect', 'wp_get_referer' );
  216. }
  217. }
  218. function admin_menu_debugger() {
  219. Jetpack_Debugger::disconnect_and_redirect();
  220. $debugger_hook = add_submenu_page( null, __( 'Jetpack Debugging Center', 'jetpack' ), '', 'manage_options', 'jetpack-debugger', array( $this, 'debugger_page' ) );
  221. add_action( "admin_head-$debugger_hook", array( 'Jetpack_Debugger', 'jetpack_debug_admin_head' ) );
  222. }
  223. function debugger_page() {
  224. nocache_headers();
  225. if ( ! current_user_can( 'manage_options' ) ) {
  226. die( '-1' );
  227. }
  228. Jetpack_Debugger::jetpack_debug_display_handler();
  229. }
  230. }
  231. Jetpack_Admin::init();