/includes/admin/pages/addons.php

  1. <?php 
  2. /** 
  3. * Addons class. 
  4. * 
  5. * @since 6.0.0 
  6. * 
  7. * @package MonsterInsights 
  8. * @author Chris Christoff 
  9. */ 
  10.  
  11. // Exit if accessed directly 
  12. if ( ! defined( 'ABSPATH' ) ) { 
  13. exit; 
  14.  
  15. function monsterinsights_is_addons_page() { 
  16. $current_screen = get_current_screen(); 
  17. global $admin_page_hooks; 
  18.  
  19. if ( ! is_object( $current_screen ) || empty( $current_screen->id ) || empty( $admin_page_hooks ) ) { 
  20. return false; 
  21.  
  22. $settings_page = false; 
  23. if ( ! empty( $admin_page_hooks['monsterinsights_dashboard'] ) && $current_screen->id === $admin_page_hooks['monsterinsights_dashboard'] . '_page_monsterinsights_addons' ) { 
  24. $settings_page = true; 
  25.  
  26. if ( ! empty( $admin_page_hooks['monsterinsights_settings'] ) && $current_screen->id === $admin_page_hooks['monsterinsights_settings'] . '_page_monsterinsights_addons' ) { 
  27. $settings_page = true; 
  28.  
  29. if ( ! empty( $admin_page_hooks['monsterinsights_network'] ) && $current_screen->id === $admin_page_hooks['monsterinsights_network'] . '_page_monsterinsights_addons-network' ) { 
  30. $settings_page = true; 
  31.  
  32. return $settings_page; 
  33.  
  34. /** 
  35. * Maybe refreshes the addons page. 
  36. * 
  37. * @since 6.0.0 
  38. * 
  39. * @return null Return early if not refreshing the addons. 
  40. */ 
  41. function monsterinsights_maybe_refresh_addons() { 
  42. if ( ! monsterinsights_is_addons_page() ) { 
  43. return; 
  44.  
  45.  
  46. if ( ! monsterinsights_is_refreshing_addons() ) { 
  47. return; 
  48.  
  49. if ( ! monsterinsights_refresh_addons_action() ) { 
  50. return; 
  51.  
  52. monsterinsights_get_addons_data( monsterinsights_get_license_key() ); 
  53.  
  54. add_action( 'current_screen', 'monsterinsights_maybe_refresh_addons' ); 
  55.  
  56. /** 
  57. * Callback to output the MonsterInsights addons page. 
  58. * 
  59. * @since 6.0.0 
  60. */ 
  61. function monsterinsights_addons_page() { 
  62. /**  
  63. * Developer Alert: 
  64. * 
  65. * Per the README, this is considered an internal hook and should 
  66. * not be used by other developers. This hook's behavior may be modified 
  67. * or the hook may be removed at any time, without warning. 
  68. */ 
  69. do_action('monsterinsights_head'); 
  70. ?> 
  71. <?php echo monsterinsights_ublock_notice(); ?> 
  72. <div id="monsterinsights-addon-heading" class="monsterinsights-addons-subheading monsterinsights-clearfix-after"> 
  73. <h1><?php esc_html_e( 'MonsterInsights Addons', 'google-analytics-for-wordpress' ); ?></h1> 
  74. <form id="add-on-search"> 
  75. <span class="spinner"></span> 
  76. <input id="add-on-searchbox" name="monsterinsights-addon-search" value="" placeholder="<?php esc_attr_e( 'Search MI Addons', 'google-analytics-for-wordpress' ); ?>" /> 
  77. <select id="monsterinsights-filter-select"> 
  78. <option value="asc"><?php esc_html_e( 'Sort Ascending (A-Z)', 'google-analytics-for-wordpress' ); ?></option> 
  79. <option value="desc"><?php esc_html_e( 'Sort Descending (Z-A)', 'google-analytics-for-wordpress' ); ?></option> 
  80. </select> 
  81. </form> 
  82. </div> 
  83. <div id="monsterinsights-addons" class="wrap"> 
  84. <div class="monsterinsights-clear"> 
  85. <?php 
  86. /**  
  87. * Developer Alert: 
  88. * 
  89. * Per the README, this is considered an internal hook and should 
  90. * not be used by other developers. This hook's behavior may be modified 
  91. * or the hook may be removed at any time, without warning. 
  92. */ 
  93. ?> 
  94. <?php do_action( 'monsterinsights_addons_section' ); ?> 
  95. </div> 
  96. </div> 
  97. <?php 
  98.  
  99.  
  100. /** 
  101. * Callback for displaying the UI for Addons. 
  102. * 
  103. * @since 6.0.0 
  104. */ 
  105. function monsterinsights_addons_content() { 
  106.  
  107. // If error(s) occured during license key verification, display them and exit now. 
  108. if ( false !== monsterinsights_get_license_key_errors() ) { 
  109. ?> 
  110. <div class="error below-h2"> 
  111. <p> 
  112. <?php esc_html_e( 'In order to get access to Addons, you need to resolve your license key errors.', 'google-analytics-for-wordpress' ); ?> 
  113. </p> 
  114. </div> 
  115. <?php 
  116. return; 
  117.  
  118. // Get Addons 
  119. $addons = monsterinsights_get_addons(); 
  120.  
  121. // If no Addon(s) were returned, our API call returned an error. 
  122. // Show an error message with a button to reload the page, which will trigger another API call. 
  123. if ( ! $addons ) { 
  124. ?> 
  125. <form id="monsterinsights-addons-refresh-addons-form" method="post"> 
  126. <p> 
  127. <?php esc_html_e( 'There was an issue retrieving the addons for this site. Please click on the button below the refresh the addons data.', 'google-analytics-for-wordpress' ); ?> 
  128. </p> 
  129. <p> 
  130. <a href="<?php echo esc_url( $_SERVER['REQUEST_URI'] ); ?>" class="button button-primary"><?php esc_html_e( 'Refresh Addons', 'google-analytics-for-wordpress' ); ?></a> 
  131. </p> 
  132. </form> 
  133. <?php 
  134. return; 
  135.  
  136. // If here, we have Addons to display, so let's output them now. 
  137. // Get installed plugins and upgrade URL 
  138. $installed_plugins = get_plugins(); 
  139. $upgrade_url = monsterinsights_get_upgrade_link(); 
  140. ?> 
  141. <div id="monsterinsights-addons"> 
  142. <?php 
  143. // Output Addons the User is licensed to use. 
  144. if ( count( $addons['licensed'] )> 0 ) { 
  145. ?> 
  146. <div class="monsterinsights-addons-area licensed" class="monsterinsights-clear"> 
  147. <h3><?php esc_html_e( 'Available Addons:', 'google-analytics-for-wordpress' ); ?></h3> 
  148.  
  149. <div id="monsterinsights-addons-licensed" class="monsterinsights-addons"> 
  150. <!-- list container class required for list.js --> 
  151. <div class="list"> 
  152. <?php 
  153. foreach ( (array) $addons['licensed'] as $i => $addon ) { 
  154. monsterinsights_get_addon_card( $addon, $i, true, $installed_plugins ); 
  155. ?> 
  156. </div> 
  157. </div> 
  158. </div> 
  159. <?php 
  160. } // Close licensed addons 
  161.  
  162. // Output Addons the User isn't licensed to use. 
  163. if ( count( $addons['unlicensed'] ) > 0 ) { 
  164. ?> 
  165. <div class="monsterinsights-addons-area unlicensed" class="monsterinsights-clear"> 
  166. <h3><?php esc_html_e( 'Unlock More Addons', 'google-analytics-for-wordpress' ); ?></h3> 
  167. <p><?php echo sprintf( esc_html__( '%1$sWant even more addons?%2$sUpgrade your MonsterInsights account%3$s and unlock the following addons:', 'google-analytics-for-wordpress' ), '<strong>', '</strong> <a href="' . $upgrade_url. '">', '</a>' ); ?></p> 
  168.  
  169. <div id="monsterinsights-addons-unlicensed" class="monsterinsights-addons"> 
  170. <!-- list container class required for list.js --> 
  171. <div class="list"> 
  172. <?php 
  173. foreach ( (array) $addons['unlicensed'] as $i => $addon ) { 
  174. monsterinsights_get_addon_card( $addon, $i, false, $installed_plugins ); 
  175. ?> 
  176. </div> 
  177. </div> 
  178. </div> 
  179. <?php 
  180. } // Close unlicensed addons 
  181. ?> 
  182. </div> 
  183. <?php 
  184.  
  185. add_action( 'monsterinsights_addons_section', 'monsterinsights_addons_content' ); 
  186.  
  187. /** 
  188. * Retrieves addons from the stored transient or remote server. 
  189. * 
  190. * @since 6.0.0 
  191. * 
  192. * @return bool | array false | Array of licensed and unlicensed Addons. 
  193. */ 
  194. function monsterinsights_get_addons() { 
  195.  
  196. // Get license key and type. 
  197. $key = monsterinsights_get_license_key(); 
  198. $type = monsterinsights_get_license_key_type(); 
  199.  
  200. // Get addons data from transient or perform API query if no transient. 
  201. if ( false === ( $addons = get_transient( '_monsterinsights_addons' ) ) ) { 
  202. $addons = monsterinsights_get_addons_data( $key ); 
  203.  
  204. // If no Addons exist, return false 
  205. if ( ! $addons ) { 
  206. return false; 
  207.  
  208. // Iterate through Addons, to build two arrays:  
  209. // - Addons the user is licensed to use,  
  210. // - Addons the user isn't licensed to use. 
  211. $results = array( 
  212. 'licensed' => array(),  
  213. 'unlicensed'=> array(),  
  214. ); 
  215. foreach ( (array) $addons as $i => $addon ) { 
  216.  
  217. // Determine whether the user is licensed to use this Addon or not. 
  218. if (  
  219. empty( $type ) || 
  220. ( in_array( 'Pro', $addon->categories ) && ( $type != 'pro' && $type != 'master' ) ) || 
  221. ( in_array( 'Plus', $addon->categories ) && $type != 'plus' && $type != 'pro' && $type != 'master' ) || 
  222. ( in_array( 'Basic', $addon->categories ) && ( $type != 'basic' && $type != 'plus' && $type != 'pro' && $type != 'master' ) ) 
  223. ) { 
  224. // Unlicensed 
  225. $results['unlicensed'][] = $addon; 
  226. continue; 
  227.  
  228. // Licensed 
  229. $results['licensed'][] = $addon; 
  230.  
  231.  
  232. // Return Addons, split by licensed and unlicensed. 
  233. return $results; 
  234.  
  235.  
  236. /** 
  237. * Pings the remote server for addons data. 
  238. * 
  239. * @since 6.0.0 
  240. * 
  241. * @param string $key The user license key. 
  242. * @return array Array of addon data otherwise. 
  243. */ 
  244. function monsterinsights_get_addons_data( $key ) { 
  245. // Get the base class object. 
  246. $base = MonsterInsights(); 
  247. $type = monsterinsights_get_license_key_type(); 
  248.  
  249. // Get Addons 
  250. // If the key is valid, we'll get personalised upgrade URLs for each Addon (if necessary) and plugin update information. 
  251. if ( $key && $type !== 'basic' ) { 
  252. $addons = $base->license->perform_remote_request( 'get-addons-data-v600', array( 'tgm-updater-key' => $key ) );  
  253. } else { 
  254. $addons = $base->license->perform_remote_request( 'get-all-addons-data', array() );  
  255.  
  256. // If there was an API error, set transient for only 10 minutes. 
  257. if ( ! $addons ) { 
  258. set_transient( '_monsterinsights_addons', false, 10 * MINUTE_IN_SECONDS ); 
  259. return false; 
  260.  
  261. // If there was an error retrieving the addons, set the error. 
  262. if ( isset( $addons->error ) ) { 
  263. set_transient( '_monsterinsights_addons', false, 10 * MINUTE_IN_SECONDS ); 
  264. return false; 
  265.  
  266. // Otherwise, our request worked. Save the data and return it. 
  267. set_transient( '_monsterinsights_addons', $addons, 4 * HOUR_IN_SECONDS ); 
  268. return $addons; 
  269.  
  270.  
  271. /** 
  272. * Flag to determine if addons are being refreshed. 
  273. * 
  274. * @since 6.0.0 
  275. * 
  276. * @return bool True if being refreshed, false otherwise. 
  277. */ 
  278. function monsterinsights_is_refreshing_addons() { 
  279. return isset( $_POST['google-analytics-for-wordpress-refresh-addons-submit'] ); 
  280.  
  281. /** 
  282. * Verifies nonces that allow addon refreshing. 
  283. * 
  284. * @since 6.0.0 
  285. * 
  286. * @return bool True if nonces check out, false otherwise. 
  287. */ 
  288. function monsterinsights_refresh_addons_action() { 
  289. return isset( $_POST['google-analytics-for-wordpress-refresh-addons-submit'] ) && wp_verify_nonce( $_POST['google-analytics-for-wordpress-refresh-addons'], 'google-analytics-for-wordpress-refresh-addons' ); 
  290.  
  291. /** 
  292. * Retrieve the plugin basename from the plugin slug. 
  293. * 
  294. * @since 6.0.0 
  295. * 
  296. * @param string $slug The plugin slug. 
  297. * @return string The plugin basename if found, else the plugin slug. 
  298. */ 
  299. function monsterinsights_get_plugin_basename_from_slug( $slug ) { 
  300. $keys = array_keys( get_plugins() ); 
  301.  
  302. foreach ( $keys as $key ) { 
  303. if ( preg_match( '|^' . $slug . '|', $key ) ) { 
  304. return $key; 
  305.  
  306. return $slug; 
  307.  
  308.  
  309. /** 
  310. * Outputs the addon "box" on the addons page. 
  311. * 
  312. * @since 6.0.0 
  313. * 
  314. * @param object $addon Addon data from the API / transient call 
  315. * @param int $counter Index of this Addon in the collection 
  316. * @param bool $is_licensed Whether the Addon is licensed for use 
  317. * @param array $installed_plugins Installed WordPress Plugins 
  318. */ 
  319. function monsterinsights_get_addon_card( $addon, $counter = 0, $is_licensed = false, $installed_plugins = false ) { 
  320.  
  321. // Setup some vars 
  322. $slug = str_replace( 'monsterinsights-', '', $addon->slug ); 
  323. $slug = 'monsterinsights-' . $addon->slug; 
  324. if ( $slug === 'monsterinsights-ecommerce' ) { 
  325. $slug = 'ga-ecommerce'; 
  326. }  
  327.  
  328. $plugin_basename = monsterinsights_get_plugin_basename_from_slug( $slug ); 
  329. $categories = implode( ', ', $addon->categories ); 
  330. if ( ! $installed_plugins ) { 
  331. $installed_plugins = get_plugins(); 
  332.  
  333. // If the Addon doesn't supply an upgrade_url key, it's because the user hasn't provided a license 
  334. // get_upgrade_link() will return the Lite or Pro link as necessary for us. 
  335. if ( ! isset( $addon->upgrade_url ) ) { 
  336. $addon->upgrade_url = monsterinsights_get_upgrade_link(); 
  337.  
  338. // Link user to doc to install MI pro to install addons 
  339. if ( ! monsterinsights_is_pro_version() && $is_licensed && ! isset( $installed_plugins[ $plugin_basename ] ) ) { 
  340. $addon->url = 'https://www.monsterinsights.com/docs/install-monsterinsights-pro-to-use-addons'; 
  341.  
  342. // Output the card 
  343. ?> 
  344. <div class="monsterinsights-addon"> 
  345. <h3 class="monsterinsights-addon-title"><?php echo esc_html( $addon->title ); ?></h3> 
  346. <?php 
  347. if ( ! empty( $addon->image ) ) { 
  348. ?> 
  349. <img class="monsterinsights-addon-thumb" src="<?php echo esc_attr( esc_url( $addon->image ) ); ?>" alt="<?php echo esc_attr( $addon->title ); ?>" /> 
  350. <?php 
  351. ?> 
  352.  
  353. <p class="monsterinsights-addon-excerpt"><?php echo esc_html( $addon->excerpt ); ?></p> 
  354.  
  355. <?php 
  356. // If the Addon is unlicensed, show the upgrade button  
  357. if ( ! $is_licensed ) { 
  358. ?> 
  359. <div class="monsterinsights-addon-active monsterinsights-addon-message"> 
  360. <div class="interior"> 
  361. <div class="monsterinsights-addon-upgrade"> 
  362. <a href="<?php echo esc_attr( esc_url( $addon->upgrade_url ) ); ?>" target="_blank" rel="noopener noreferrer" referrer="no-referrer" class="button button-primary monsterinsights-addon-upgrade-button" rel="<?php echo esc_attr( $plugin_basename ); ?>"> 
  363. <?php esc_html_e( 'Upgrade Now', 'google-analytics-for-wordpress' ); ?> 
  364. </a> 
  365. <span class="spinner monsterinsights-spinner"></span> 
  366. </div> 
  367. </div> 
  368. </div> 
  369. <?php 
  370. } else { 
  371. // Addon is licensed 
  372.  
  373. // If the plugin is not installed, display an install message and button. 
  374. if ( ! isset( $installed_plugins[ $plugin_basename ] ) ) { 
  375. if ( empty( $addon->url ) ) { 
  376. $addon->url = ''; 
  377. ?> 
  378. <div class="monsterinsights-addon-not-installed monsterinsights-addon-message"> 
  379. <div class="interior"> 
  380. <?php if ( monsterinsights_is_pro_version() ) { ?> 
  381. <span class="addon-status"><?php echo sprintf( esc_html__( 'Status: %1$sNot Installed%2$s', 'google-analytics-for-wordpress' ), '<span>', '</span>' ); ?></span> 
  382. <?php } ?> 
  383. <div class="monsterinsights-addon-action"> 
  384. <?php if ( monsterinsights_is_pro_version() ) { ?> 
  385. <a class="button button-primary monsterinsights-addon-action-button monsterinsights-install-addon" href="#" rel="<?php echo esc_attr( esc_url( $addon->url ) ); ?>"> 
  386. <i class="monsterinsights-cloud-download"></i> 
  387. <?php esc_html_e( 'Install', 'google-analytics-for-wordpress' ); ?>  
  388. </a> 
  389. <?php } else { ?> 
  390. <a class="button button-primary monsterinsights-addon-action-button" href="<?php echo esc_url( $addon->url ); ?>" rel="noopener noreferrer" referrer="no-referrer" target="_blank"> 
  391. <i class="monsterinsights-cloud-download"></i> 
  392. <?php esc_html_e( "Why can't I install addons?", 'google-analytics-for-wordpress' ); ?>  
  393. </a> 
  394. <?php } ?> 
  395. <span class="spinner monsterinsights-spinner"></span> 
  396. </div> 
  397. </div> 
  398. </div> 
  399. <?php 
  400. } else { 
  401. // Plugin is installed. 
  402.  
  403. $active = false; 
  404. $ms_active = is_plugin_active_for_network( $plugin_basename ); 
  405. $ss_active = is_plugin_active( $plugin_basename ); 
  406.  
  407. if ( is_multisite() && is_network_admin() ) { 
  408. $active = is_plugin_active_for_network( $plugin_basename ); 
  409. } else { 
  410. $active = is_plugin_active( $plugin_basename ); 
  411.  
  412. if ( $active ) { 
  413. // Plugin is active. Display the active message and deactivate button. 
  414. ?> 
  415. <div class="monsterinsights-addon-active monsterinsights-addon-message"> 
  416. <div class="interior"> 
  417. <?php if ( $ms_active ) { ?> 
  418. <span class="addon-status"><?php echo sprintf( esc_html__( 'Status: %1$sNetwork Active%2$s', 'google-analytics-for-wordpress'), '<span>', '</span>' ); ?></span> 
  419. <?php } else { ?> 
  420. <span class="addon-status"><?php echo sprintf( esc_html__( 'Status: %1$sActive%2$s', 'google-analytics-for-wordpress'), '<span>', '</span>' ); ?></span> 
  421. <?php } ?>  
  422. <?php if ( ( is_multisite() && is_network_admin() && $ms_active ) || ! is_multisite() || ( is_multisite() && !is_network_admin() && !$ms_active && $ss_active ) ) { ?> 
  423. <div class="monsterinsights-addon-action"> 
  424. <a class="button button-primary monsterinsights-addon-action-button monsterinsights-deactivate-addon" href="#" rel="<?php echo esc_attr( $plugin_basename ); ?>"> 
  425. <i class="monsterinsights-toggle-on"></i> 
  426. <?php if ( is_multisite() && is_network_admin() && $ms_active ) { ?> 
  427. <?php esc_html_e( 'Network deactivate', 'google-analytics-for-wordpress' ); ?>  
  428. <?php } else if ( is_multisite() && !is_network_admin() && !$ms_active && $ss_active ) { ?> 
  429. <?php esc_html_e( 'Deactivate', 'google-analytics-for-wordpress' ); ?>  
  430. <?php } else { ?> 
  431. <?php esc_html_e( 'Deactivate', 'google-analytics-for-wordpress' ); ?>  
  432. <?php } ?>  
  433. </a> 
  434. <span class="spinner google-analytics-for-wordpress-spinner"></span> 
  435. </div> 
  436. <?php } ?> 
  437. </div> 
  438. </div> 
  439. <?php 
  440. } else { 
  441. // Plugin is inactivate. Display the inactivate mesage and activate button. 
  442. ?> 
  443. <div class="monsterinsights-addon-inactive monsterinsights-addon-message"> 
  444. <div class="interior"> 
  445. <?php if ( $ms_active ) { ?> 
  446. <span class="addon-status"><?php echo sprintf( esc_html__( 'Status: %1$sNetwork Inactive%2$s', 'google-analytics-for-wordpress'), '<span>', '</span>' ); ?></span> 
  447. <?php } else { ?> 
  448. <span class="addon-status"><?php echo sprintf( esc_html__( 'Status: %1$sInactive%2$s', 'google-analytics-for-wordpress'), '<span>', '</span>' ); ?></span> 
  449. <?php } ?>  
  450. <div class="monsterinsights-addon-action"> 
  451. <a class="button button-primary monsterinsights-addon-action-button monsterinsights-activate-addon" href="#" rel="<?php echo esc_attr( $plugin_basename ); ?>"> 
  452. <i class="monsterinsights-toggle-on"></i> 
  453. <?php if ( is_multisite() && is_network_admin() && ! $ms_active ) { ?> 
  454. <?php esc_html_e( 'Network activate', 'google-analytics-for-wordpress' ); ?>  
  455. <?php } else { ?> 
  456. <?php esc_html_e( 'Activate', 'google-analytics-for-wordpress' ); ?>  
  457. <?php } ?> 
  458. </a> 
  459. <span class="spinner monsterinsights-spinner"></span> 
  460. </div> 
  461.  
  462. </div> 
  463. </div> 
  464. <?php 
  465. ?> 
  466. </div> 
  467. <?php 
.