Google Analytics Dashboard for WP (GADWP) - Version 6.1.0

Version Description

Download this release

Release Info

Developer chriscct7
Plugin Icon 128x128 Google Analytics Dashboard for WP (GADWP)
Version 6.1.0
Comparing to
See all releases

Code changes from version 6.0.2 to 6.1.0

assets/css/admin-common.css CHANGED
@@ -46,3 +46,21 @@
46
  display: none;
47
  }
48
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  display: none;
47
  }
48
  }
49
+
50
+ #wpadminbar .exactmetrics-menu-notification-indicator,
51
+ .exactmetrics-menu-notification-indicator {
52
+ width: 12px;
53
+ height: 12px;
54
+ border-radius: 50%;
55
+ background: #C84B29;
56
+ display: inline-block;
57
+ margin-left: 8px;
58
+ }
59
+
60
+ @media (max-width: 782px) {
61
+ #wpadminbar .exactmetrics-menu-notification-indicator {
62
+ margin: 0 0 10px -13px;
63
+ z-index: 10;
64
+ position: relative;
65
+ }
66
+ }
assets/css/admin-common.min.css CHANGED
@@ -1 +1 @@
1
- .exactmetrics-wooedd-upsell-left{width:50%;display:table-cell;float:left}.exactmetrics-wooedd-upsell-right{width:50%;display:table-cell;float:left}.exactmetrics-wooedd-upsell-image{width:100%;height:auto;padding:20px}.exactmetrics-wooedd-upsell-image-small{display:none}.exactmetrics-wooedd-upsell-row{display:table}.exactmetrics-wooedd-upsell-left p{margin:1em 0;font-size:16px}@media (max-width: 900px){.exactmetrics-wooedd-upsell-left{width:100%}.exactmetrics-wooedd-upsell-right{display:none}.exactmetrics-wooedd-upsell-image-small{display:block}.exactmetrics-wooedd-upsell-image-large{display:none}}
1
+ .exactmetrics-wooedd-upsell-left{width:50%;display:table-cell;float:left}.exactmetrics-wooedd-upsell-right{width:50%;display:table-cell;float:left}.exactmetrics-wooedd-upsell-image{width:100%;height:auto;padding:20px}.exactmetrics-wooedd-upsell-image-small{display:none}.exactmetrics-wooedd-upsell-row{display:table}.exactmetrics-wooedd-upsell-left p{margin:1em 0;font-size:16px}@media (max-width: 900px){.exactmetrics-wooedd-upsell-left{width:100%}.exactmetrics-wooedd-upsell-right{display:none}.exactmetrics-wooedd-upsell-image-small{display:block}.exactmetrics-wooedd-upsell-image-large{display:none}}#wpadminbar .exactmetrics-menu-notification-indicator,.exactmetrics-menu-notification-indicator{width:12px;height:12px;border-radius:50%;background:#C84B29;display:inline-block;margin-left:8px}@media (max-width: 782px){#wpadminbar .exactmetrics-menu-notification-indicator{margin:0 0 10px -13px;z-index:10;position:relative}}
gadwp.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin URI: https://exactmetrics.com
5
  * Description: Displays Google Analytics Reports and Real-Time Statistics in your Dashboard. Automatically inserts the tracking code in every page of your website.
6
  * Author: ExactMetrics
7
- * Version: 6.0.2
8
  * Author URI: https://exactmetrics.com
9
  * Text Domain: google-analytics-dashboard-for-wp
10
  * Domain Path: /languages
@@ -42,7 +42,7 @@ final class ExactMetrics_Lite {
42
  * @access public
43
  * @var string $version Plugin version.
44
  */
45
- public $version = '6.0.2';
46
 
47
  /**
48
  * Plugin file.
@@ -89,6 +89,15 @@ final class ExactMetrics_Lite {
89
  */
90
  public $notices;
91
 
 
 
 
 
 
 
 
 
 
92
  /**
93
  * Holds instance of ExactMetrics Reporting class.
94
  *
@@ -101,7 +110,7 @@ final class ExactMetrics_Lite {
101
  /**
102
  * Holds instance of ExactMetrics Auth class.
103
  *
104
- * @since 7.0.0
105
  * @access public
106
  * @var ExactMetrics_Auth $auth Instance of Auth class.
107
  */
@@ -119,7 +128,7 @@ final class ExactMetrics_Lite {
119
  /**
120
  * Holds instance of ExactMetrics API Rest Routes class.
121
  *
122
- * @since 7.4.0
123
  * @access public
124
  * @var ExactMetrics_Rest_Routes $routes Instance of rest routes.
125
  */
@@ -180,7 +189,7 @@ final class ExactMetrics_Lite {
180
 
181
  // This does the version to version background upgrade routines and initial install
182
  $em_version = get_option( 'exactmetrics_current_version', '5.5.3' );
183
- if ( version_compare( $em_version, '6.0.0', '<' ) ) {
184
  exactmetrics_lite_call_install_and_upgrade();
185
  }
186
 
@@ -197,6 +206,7 @@ final class ExactMetrics_Lite {
197
  self::$instance->reporting = new ExactMetrics_Reporting();
198
  self::$instance->api_auth = new ExactMetrics_API_Auth();
199
  self::$instance->routes = new ExactMetrics_Rest_Routes();
 
200
  }
201
 
202
  if ( exactmetrics_is_pro_version() ) {
@@ -249,7 +259,7 @@ final class ExactMetrics_Lite {
249
  * the API & Auth frontend, so it's only loaded if user is using a plugin
250
  * that requires it.
251
  *
252
- * @since 7.0.0
253
  * @access public
254
  *
255
  * @return void
@@ -429,7 +439,7 @@ final class ExactMetrics_Lite {
429
  *
430
  * Loads license class used by ExactMetrics
431
  *
432
- * @since 7.0.0
433
  * @access public
434
  *
435
  * @return void
@@ -446,7 +456,7 @@ final class ExactMetrics_Lite {
446
  *
447
  * Loads auth used by ExactMetrics
448
  *
449
- * @since 7.0.0
450
  * @access public
451
  *
452
  * @return void
@@ -498,6 +508,12 @@ final class ExactMetrics_Lite {
498
 
499
  // Routes used by Vue
500
  require_once EXACTMETRICS_PLUGIN_DIR . 'includes/admin/routes.php';
 
 
 
 
 
 
501
  }
502
 
503
  require_once EXACTMETRICS_PLUGIN_DIR . 'includes/api-request.php';
4
  * Plugin URI: https://exactmetrics.com
5
  * Description: Displays Google Analytics Reports and Real-Time Statistics in your Dashboard. Automatically inserts the tracking code in every page of your website.
6
  * Author: ExactMetrics
7
+ * Version: 6.1.0
8
  * Author URI: https://exactmetrics.com
9
  * Text Domain: google-analytics-dashboard-for-wp
10
  * Domain Path: /languages
42
  * @access public
43
  * @var string $version Plugin version.
44
  */
45
+ public $version = '6.1.0';
46
 
47
  /**
48
  * Plugin file.
89
  */
90
  public $notices;
91
 
92
+ /**
93
+ * Holds instance of ExactMetrics Notifications class.
94
+ *
95
+ * @since 6.1
96
+ * @access public
97
+ * @var ExactMetrics_Notifications $notifications Instance of Notifications class.
98
+ */
99
+ public $notifications;
100
+
101
  /**
102
  * Holds instance of ExactMetrics Reporting class.
103
  *
110
  /**
111
  * Holds instance of ExactMetrics Auth class.
112
  *
113
+ * @since 6.0.0
114
  * @access public
115
  * @var ExactMetrics_Auth $auth Instance of Auth class.
116
  */
128
  /**
129
  * Holds instance of ExactMetrics API Rest Routes class.
130
  *
131
+ * @since 6.0.0
132
  * @access public
133
  * @var ExactMetrics_Rest_Routes $routes Instance of rest routes.
134
  */
189
 
190
  // This does the version to version background upgrade routines and initial install
191
  $em_version = get_option( 'exactmetrics_current_version', '5.5.3' );
192
+ if ( version_compare( $em_version, '6.1.0', '<' ) ) {
193
  exactmetrics_lite_call_install_and_upgrade();
194
  }
195
 
206
  self::$instance->reporting = new ExactMetrics_Reporting();
207
  self::$instance->api_auth = new ExactMetrics_API_Auth();
208
  self::$instance->routes = new ExactMetrics_Rest_Routes();
209
+ self::$instance->notifications = new ExactMetrics_Notifications();
210
  }
211
 
212
  if ( exactmetrics_is_pro_version() ) {
259
  * the API & Auth frontend, so it's only loaded if user is using a plugin
260
  * that requires it.
261
  *
262
+ * @since 6.0.0
263
  * @access public
264
  *
265
  * @return void
439
  *
440
  * Loads license class used by ExactMetrics
441
  *
442
+ * @since 6.0.0
443
  * @access public
444
  *
445
  * @return void
456
  *
457
  * Loads auth used by ExactMetrics
458
  *
459
+ * @since 6.0.0
460
  * @access public
461
  *
462
  * @return void
508
 
509
  // Routes used by Vue
510
  require_once EXACTMETRICS_PLUGIN_DIR . 'includes/admin/routes.php';
511
+
512
+ // Emails
513
+ require_once EXACTMETRICS_PLUGIN_DIR . 'includes/emails/class-emails.php';
514
+
515
+ // Notifications class.
516
+ require_once EXACTMETRICS_PLUGIN_DIR . 'includes/admin/notifications.php';
517
  }
518
 
519
  require_once EXACTMETRICS_PLUGIN_DIR . 'includes/api-request.php';
includes/admin/admin.php CHANGED
@@ -28,13 +28,13 @@ function exactmetrics_admin_menu() {
28
 
29
  if ( $hook === 'exactmetrics_settings' ) {
30
  // If dashboards disabled, first settings page
31
- add_menu_page( __( 'ExactMetrics', 'google-analytics-dashboard-for-wp' ), 'ExactMetrics', 'exactmetrics_save_settings', 'exactmetrics_settings', 'exactmetrics_settings_page', $menu_icon_inline, '100.00013467543' );
32
  $hook = 'exactmetrics_settings';
33
 
34
  add_submenu_page( $hook, __( 'ExactMetrics', 'google-analytics-dashboard-for-wp' ), __( 'Settings', 'google-analytics-dashboard-for-wp' ), 'exactmetrics_save_settings', 'exactmetrics_settings' );
35
  } else {
36
  // if dashboards enabled, first dashboard
37
- add_menu_page( __( 'General:', 'google-analytics-dashboard-for-wp' ), 'ExactMetrics', 'exactmetrics_view_dashboard', 'exactmetrics_reports', 'exactmetrics_reports_page', $menu_icon_inline, '100.00013467543' );
38
 
39
  add_submenu_page( $hook, __( 'General Reports:', 'google-analytics-dashboard-for-wp' ), __( 'Reports', 'google-analytics-dashboard-for-wp' ), 'exactmetrics_view_dashboard', 'exactmetrics_reports', 'exactmetrics_reports_page' );
40
 
@@ -88,7 +88,7 @@ function exactmetrics_network_admin_menu() {
88
  $menu_icon_inline = exactmetrics_get_inline_menu_icon();
89
  $hook = 'exactmetrics_network';
90
  $submenu_base = add_query_arg( 'page', 'exactmetrics_network', network_admin_url( 'admin.php' ) );
91
- add_menu_page( __( 'Network Settings:', 'google-analytics-dashboard-for-wp' ), 'ExactMetrics', 'exactmetrics_save_settings', 'exactmetrics_network', 'exactmetrics_network_page', $menu_icon_inline, '100.00013467543' );
92
 
93
  add_submenu_page( $hook, __( 'Network Settings:', 'google-analytics-dashboard-for-wp' ), __( 'Network Settings', 'google-analytics-dashboard-for-wp' ), 'exactmetrics_save_settings', 'exactmetrics_network', 'exactmetrics_network_page' );
94
 
@@ -179,12 +179,18 @@ function exactmetrics_add_action_links( $links ) {
179
  array_unshift( $links, $support );
180
  }
181
 
182
- $settings_link = '<a href="' . esc_url( admin_url( 'admin.php?page=exactmetrics_settings' ) ) . '">' . esc_html__( 'Settings', 'google-analytics-dashboard-for-wp' ) . '</a>';
 
 
 
 
 
183
  array_unshift( $links, $settings_link );
184
 
185
  return $links;
186
  }
187
  add_filter( 'plugin_action_links_' . plugin_basename( EXACTMETRICS_PLUGIN_FILE ), 'exactmetrics_add_action_links' );
 
188
 
189
 
190
 
@@ -271,7 +277,7 @@ function exactmetrics_admin_setup_notices() {
271
 
272
 
273
  // 1. Google Analytics not authenticated
274
- if ( ! is_network_admin() && ! exactmetrics_get_ua() ) {
275
 
276
  $submenu_base = is_network_admin() ? add_query_arg( 'page', 'exactmetrics_network', network_admin_url( 'admin.php' ) ) : add_query_arg( 'page', 'exactmetrics_settings', admin_url( 'admin.php' ) );
277
  $title = esc_html__( 'Please Setup Website Analytics to See Audience Insights', 'google-analytics-dashboard-for-wp' );
@@ -391,6 +397,7 @@ function exactmetrics_admin_setup_notices() {
391
  // 6. Authenticate, not manual
392
  $authed = ExactMetrics()->auth->is_authed() || ExactMetrics()->auth->is_network_authed();
393
  $url = is_network_admin() ? network_admin_url( 'admin.php?page=exactmetrics_network' ) : admin_url( 'admin.php?page=exactmetrics_settings' );
 
394
  // Translators: Placeholders add links to the settings panel.
395
  $manual_text = sprintf( esc_html__( 'Important: You are currently using manual UA code output. We highly recommend %1$sauthenticating with ExactMetrics%2$s so that you can access our new reporting area and take advantage of new ExactMetrics features.', 'google-analytics-dashboard-for-wp' ), '<a href="' . $url . '">', '</a>' );
396
  $migrated = exactmetrics_get_option( 'gadwp_migrated', 0 );
@@ -401,7 +408,7 @@ function exactmetrics_admin_setup_notices() {
401
  $manual_text = sprintf( $text, '<a href="' . $url . '">', '</a>', '<a href="' . exactmetrics_get_url( 'notice', 'manual-ua', 'https://www.exactmetrics.com/why-did-we-implement-the-new-google-analytics-authentication-flow-challenges-explained/' ) . '" target="_blank">', '</a>' );
402
  }
403
 
404
- if ( empty( $authed ) && ! isset( $notices['exactmetrics_auth_not_manual'] ) ) {
405
  echo '<div class="notice notice-info is-dismissible exactmetrics-notice" data-notice="exactmetrics_auth_not_manual">';
406
  echo '<p>';
407
  echo $manual_text;
28
 
29
  if ( $hook === 'exactmetrics_settings' ) {
30
  // If dashboards disabled, first settings page
31
+ add_menu_page( __( 'ExactMetrics', 'google-analytics-dashboard-for-wp' ), 'ExactMetrics' . ExactMetrics()->notifications->get_menu_count(), 'exactmetrics_save_settings', 'exactmetrics_settings', 'exactmetrics_settings_page', $menu_icon_inline, '100.00013467543' );
32
  $hook = 'exactmetrics_settings';
33
 
34
  add_submenu_page( $hook, __( 'ExactMetrics', 'google-analytics-dashboard-for-wp' ), __( 'Settings', 'google-analytics-dashboard-for-wp' ), 'exactmetrics_save_settings', 'exactmetrics_settings' );
35
  } else {
36
  // if dashboards enabled, first dashboard
37
+ add_menu_page( __( 'General:', 'google-analytics-dashboard-for-wp' ), 'ExactMetrics' . ExactMetrics()->notifications->get_menu_count(), 'exactmetrics_view_dashboard', 'exactmetrics_reports', 'exactmetrics_reports_page', $menu_icon_inline, '100.00013467543' );
38
 
39
  add_submenu_page( $hook, __( 'General Reports:', 'google-analytics-dashboard-for-wp' ), __( 'Reports', 'google-analytics-dashboard-for-wp' ), 'exactmetrics_view_dashboard', 'exactmetrics_reports', 'exactmetrics_reports_page' );
40
 
88
  $menu_icon_inline = exactmetrics_get_inline_menu_icon();
89
  $hook = 'exactmetrics_network';
90
  $submenu_base = add_query_arg( 'page', 'exactmetrics_network', network_admin_url( 'admin.php' ) );
91
+ add_menu_page( __( 'Network Settings:', 'google-analytics-dashboard-for-wp' ), 'ExactMetrics' . ExactMetrics()->notifications->get_menu_count(), 'exactmetrics_save_settings', 'exactmetrics_network', 'exactmetrics_network_page', $menu_icon_inline, '100.00013467543' );
92
 
93
  add_submenu_page( $hook, __( 'Network Settings:', 'google-analytics-dashboard-for-wp' ), __( 'Network Settings', 'google-analytics-dashboard-for-wp' ), 'exactmetrics_save_settings', 'exactmetrics_network', 'exactmetrics_network_page' );
94
 
179
  array_unshift( $links, $support );
180
  }
181
 
182
+ if ( is_network_admin() ) {
183
+ $settings_link = '<a href="' . esc_url( network_admin_url( 'admin.php?page=exactmetrics_network' ) ) . '">' . esc_html__( 'Network Settings', 'google-analytics-dashboard-for-wp' ) . '</a>';
184
+ } else {
185
+ $settings_link = '<a href="' . esc_url( admin_url( 'admin.php?page=exactmetrics_settings' ) ) . '">' . esc_html__( 'Settings', 'google-analytics-dashboard-for-wp' ) . '</a>';
186
+ }
187
+
188
  array_unshift( $links, $settings_link );
189
 
190
  return $links;
191
  }
192
  add_filter( 'plugin_action_links_' . plugin_basename( EXACTMETRICS_PLUGIN_FILE ), 'exactmetrics_add_action_links' );
193
+ add_filter( 'network_admin_plugin_action_links_' . plugin_basename( EXACTMETRICS_PLUGIN_FILE ), 'exactmetrics_add_action_links' );
194
 
195
 
196
 
277
 
278
 
279
  // 1. Google Analytics not authenticated
280
+ if ( ! is_network_admin() && ! exactmetrics_get_ua() && ! defined( 'EXACTMETRICS_DISABLE_TRACKING' ) ) {
281
 
282
  $submenu_base = is_network_admin() ? add_query_arg( 'page', 'exactmetrics_network', network_admin_url( 'admin.php' ) ) : add_query_arg( 'page', 'exactmetrics_settings', admin_url( 'admin.php' ) );
283
  $title = esc_html__( 'Please Setup Website Analytics to See Audience Insights', 'google-analytics-dashboard-for-wp' );
397
  // 6. Authenticate, not manual
398
  $authed = ExactMetrics()->auth->is_authed() || ExactMetrics()->auth->is_network_authed();
399
  $url = is_network_admin() ? network_admin_url( 'admin.php?page=exactmetrics_network' ) : admin_url( 'admin.php?page=exactmetrics_settings' );
400
+ $ua_code = exactmetrics_get_ua_to_output();
401
  // Translators: Placeholders add links to the settings panel.
402
  $manual_text = sprintf( esc_html__( 'Important: You are currently using manual UA code output. We highly recommend %1$sauthenticating with ExactMetrics%2$s so that you can access our new reporting area and take advantage of new ExactMetrics features.', 'google-analytics-dashboard-for-wp' ), '<a href="' . $url . '">', '</a>' );
403
  $migrated = exactmetrics_get_option( 'gadwp_migrated', 0 );
408
  $manual_text = sprintf( $text, '<a href="' . $url . '">', '</a>', '<a href="' . exactmetrics_get_url( 'notice', 'manual-ua', 'https://www.exactmetrics.com/why-did-we-implement-the-new-google-analytics-authentication-flow-challenges-explained/' ) . '" target="_blank">', '</a>' );
409
  }
410
 
411
+ if ( empty( $authed ) && ! isset( $notices['exactmetrics_auth_not_manual'] ) && ! empty( $ua_code ) ) {
412
  echo '<div class="notice notice-info is-dismissible exactmetrics-notice" data-notice="exactmetrics_auth_not_manual">';
413
  echo '<p>';
414
  echo $manual_text;
includes/admin/api-auth.php CHANGED
@@ -266,8 +266,8 @@ final class ExactMetrics_API_Auth {
266
  'ajaxurl' => admin_url( 'admin-ajax.php' ),
267
  'network' => is_network_admin() ? 'network' : 'site',
268
  'siteurl' => is_network_admin() ? network_admin_url() : site_url(),
269
- 'key' => ExactMetrics()->auth->get_key(),
270
- 'token' => ExactMetrics()->auth->get_token(),
271
  'return' => is_network_admin() ? network_admin_url( 'admin.php?page=exactmetrics_network' ) : admin_url( 'admin.php?page=exactmetrics_settings' ),
272
  'testurl' => 'https://' . exactmetrics_get_api_url() . 'test/',
273
  ), $this->get_route( 'https://' . exactmetrics_get_api_url() . 'auth/reauth/{type}' ) );
266
  'ajaxurl' => admin_url( 'admin-ajax.php' ),
267
  'network' => is_network_admin() ? 'network' : 'site',
268
  'siteurl' => is_network_admin() ? network_admin_url() : site_url(),
269
+ 'key' => is_network_admin() ? ExactMetrics()->auth->get_network_key() : ExactMetrics()->auth->get_key(),
270
+ 'token' => is_network_admin() ? ExactMetrics()->auth->get_network_token() : ExactMetrics()->auth->get_token(),
271
  'return' => is_network_admin() ? network_admin_url( 'admin.php?page=exactmetrics_network' ) : admin_url( 'admin.php?page=exactmetrics_settings' ),
272
  'testurl' => 'https://' . exactmetrics_get_api_url() . 'test/',
273
  ), $this->get_route( 'https://' . exactmetrics_get_api_url() . 'auth/reauth/{type}' ) );
includes/admin/common.php CHANGED
@@ -58,24 +58,20 @@ function exactmetrics_is_reports_page() {
58
  return false;
59
  }
60
 
61
- $settings_page = false;
62
  if ( ! empty( $admin_page_hooks['exactmetrics_reports'] ) && $current_screen->id === $admin_page_hooks['exactmetrics_reports'] ) {
63
- $settings_page = true;
64
  }
65
 
66
  if ( 'toplevel_page_exactmetrics_reports' === $current_screen->id ) {
67
- $settings_page = true;
68
  }
69
 
70
  if ( strpos( $current_screen->id, 'exactmetrics_reports' ) !== false ) {
71
- $settings_page = true;
72
- }
73
-
74
- if ( ! empty( $current_screen->base ) && strpos( $current_screen->base, 'exactmetrics_network' ) !== false ) {
75
- $settings_page = true;
76
  }
77
 
78
- return $settings_page;
79
  }
80
 
81
  /**
@@ -148,6 +144,7 @@ function exactmetrics_admin_scripts() {
148
 
149
  wp_register_script( 'exactmetrics-admin-common-script', plugins_url( 'assets/js/admin-common' . $suffix . '.js', EXACTMETRICS_PLUGIN_FILE ), array( 'jquery' ), exactmetrics_get_asset_version() );
150
  wp_enqueue_script( 'exactmetrics-admin-common-script' );
 
151
  wp_localize_script(
152
  'exactmetrics-admin-common-script',
153
  'exactmetrics_admin_common',
@@ -227,10 +224,11 @@ function exactmetrics_admin_scripts() {
227
  'shareasale_id' => exactmetrics_get_shareasale_id(),
228
  'shareasale_url' => exactmetrics_get_shareasale_url( exactmetrics_get_shareasale_id(), '' ),
229
  'addons_url' => is_multisite() ? network_admin_url( 'admin.php?page=exactmetrics_network#/addons' ) : admin_url( 'admin.php?page=exactmetrics_settings#/addons' ),
 
230
  'install_amp_url' => $install_amp_url,
231
  'install_fbia_url' => $install_fbia_url,
232
  'dimensions' => $prepared_dimensions,
233
- 'wizard_url' => admin_url( 'index.php?page=exactmetrics-onboarding' ),
234
  'install_plugins' => current_user_can( 'install_plugins' ),
235
  'unfiltered_html' => current_user_can( 'unfiltered_html' ),
236
  'activate_nonce' => wp_create_nonce( 'exactmetrics-activate' ),
@@ -249,10 +247,14 @@ function exactmetrics_admin_scripts() {
249
  ),
250
  'plugin_version' => EXACTMETRICS_VERSION,
251
  'is_admin' => true,
 
 
252
  'reports_url' => add_query_arg( 'page', 'exactmetrics_reports', admin_url( 'admin.php' ) ),
253
  'first_run_notice' => apply_filters( 'exactmetrics_settings_first_time_notice_hide', exactmetrics_get_option( 'exactmetrics_first_run_notice' ) ),
254
- 'getting_started_url' => is_multisite() ? network_admin_url( 'admin.php?page=exactmetrics_network#/about/getting-started' ) : admin_url( 'admin.php?page=exactmetrics_settings#/about/getting-started' ),
255
  'authed' => $is_authed,
 
 
256
  )
257
  );
258
 
@@ -281,19 +283,19 @@ function exactmetrics_admin_scripts() {
281
  'exactmetrics-vue-reports',
282
  'exactmetrics',
283
  array(
284
- 'ajax' => admin_url( 'admin-ajax.php' ),
285
- 'nonce' => wp_create_nonce( 'mi-admin-nonce' ),
286
- 'network' => is_network_admin(),
287
- 'translations' => wp_get_jed_locale_data( exactmetrics_is_pro_version() ? 'exactmetrics-premium' : 'google-analytics-dashboard-for-wp' ),
288
- 'assets' => plugins_url( $version_path . '/assets/vue', EXACTMETRICS_PLUGIN_FILE ),
289
- 'shareasale_id' => exactmetrics_get_shareasale_id(),
290
- 'shareasale_url' => exactmetrics_get_shareasale_url( exactmetrics_get_shareasale_id(), '' ),
291
- 'addons_url' => is_multisite() ? network_admin_url( 'admin.php?page=exactmetrics_network#/addons' ) : admin_url( 'admin.php?page=exactmetrics_settings#/addons' ),
292
- 'timezone' => date( 'e' ),
293
- 'authed' => $site_auth || $ms_auth,
294
- 'settings_url' => add_query_arg( 'page', 'exactmetrics_settings', admin_url( 'admin.php' ) ),
295
  // Used to add notices for future deprecations.
296
- 'versions' => array(
297
  'php_version' => phpversion(),
298
  'php_version_below_54' => apply_filters( 'exactmetrics_temporarily_hide_php_52_and_53_upgrade_warnings', version_compare( phpversion(), '5.4', '<' ) ),
299
  'php_version_below_56' => apply_filters( 'exactmetrics_temporarily_hide_php_54_and_55_upgrade_warnings', version_compare( phpversion(), '5.6', '<' ) ),
@@ -303,14 +305,16 @@ function exactmetrics_admin_scripts() {
303
  'wp_version_below_49' => version_compare( $wp_version, '4.9', '<' ),
304
  'wp_update_link' => exactmetrics_get_url( 'settings-notice', 'settings-page', 'https://www.exactmetrics.com/docs/update-wordpress/' ),
305
  ),
306
- 'plugin_version' => EXACTMETRICS_VERSION,
307
- 'is_admin' => true,
308
- 'wizard_url' => admin_url( 'index.php?page=exactmetrics-onboarding' ),
309
- 'install_nonce' => wp_create_nonce( 'exactmetrics-install' ),
310
- 'activate_nonce' => wp_create_nonce( 'exactmetrics-activate' ),
311
- 'deactivate_nonce'=> wp_create_nonce( 'exactmetrics-deactivate' ),
312
- 'update_settings' => current_user_can( 'exactmetrics_save_settings' ),
313
- 'migrated' => exactmetrics_get_option( 'gadwp_migrated', 0 ),
 
 
314
  )
315
  );
316
 
58
  return false;
59
  }
60
 
61
+ $reports_page = false;
62
  if ( ! empty( $admin_page_hooks['exactmetrics_reports'] ) && $current_screen->id === $admin_page_hooks['exactmetrics_reports'] ) {
63
+ $reports_page = true;
64
  }
65
 
66
  if ( 'toplevel_page_exactmetrics_reports' === $current_screen->id ) {
67
+ $reports_page = true;
68
  }
69
 
70
  if ( strpos( $current_screen->id, 'exactmetrics_reports' ) !== false ) {
71
+ $reports_page = true;
 
 
 
 
72
  }
73
 
74
+ return $reports_page;
75
  }
76
 
77
  /**
144
 
145
  wp_register_script( 'exactmetrics-admin-common-script', plugins_url( 'assets/js/admin-common' . $suffix . '.js', EXACTMETRICS_PLUGIN_FILE ), array( 'jquery' ), exactmetrics_get_asset_version() );
146
  wp_enqueue_script( 'exactmetrics-admin-common-script' );
147
+
148
  wp_localize_script(
149
  'exactmetrics-admin-common-script',
150
  'exactmetrics_admin_common',
224
  'shareasale_id' => exactmetrics_get_shareasale_id(),
225
  'shareasale_url' => exactmetrics_get_shareasale_url( exactmetrics_get_shareasale_id(), '' ),
226
  'addons_url' => is_multisite() ? network_admin_url( 'admin.php?page=exactmetrics_network#/addons' ) : admin_url( 'admin.php?page=exactmetrics_settings#/addons' ),
227
+ 'email_summary_url' => admin_url( 'admin.php?exactmetrics_email_preview&exactmetrics_email_template=summary' ),
228
  'install_amp_url' => $install_amp_url,
229
  'install_fbia_url' => $install_fbia_url,
230
  'dimensions' => $prepared_dimensions,
231
+ 'wizard_url' => is_network_admin() ? network_admin_url( 'index.php?page=exactmetrics-onboarding' ) : admin_url( 'index.php?page=exactmetrics-onboarding' ),
232
  'install_plugins' => current_user_can( 'install_plugins' ),
233
  'unfiltered_html' => current_user_can( 'unfiltered_html' ),
234
  'activate_nonce' => wp_create_nonce( 'exactmetrics-activate' ),
247
  ),
248
  'plugin_version' => EXACTMETRICS_VERSION,
249
  'is_admin' => true,
250
+ 'admin_email' => get_option( 'admin_email' ),
251
+ 'site_url' => get_site_url(),
252
  'reports_url' => add_query_arg( 'page', 'exactmetrics_reports', admin_url( 'admin.php' ) ),
253
  'first_run_notice' => apply_filters( 'exactmetrics_settings_first_time_notice_hide', exactmetrics_get_option( 'exactmetrics_first_run_notice' ) ),
254
+ 'getting_started_url' => is_network_admin() ? network_admin_url( 'admin.php?page=exactmetrics_network#/about' ) : admin_url( 'admin.php?page=exactmetrics_settings#/about/getting-started' ),
255
  'authed' => $is_authed,
256
+ 'new_pretty_link_url' => admin_url( 'post-new.php?post_type=pretty-link' ),
257
+ 'wpmailsmtp_admin_url' => admin_url( 'admin.php?page=wp-mail-smtp' ),
258
  )
259
  );
260
 
283
  'exactmetrics-vue-reports',
284
  'exactmetrics',
285
  array(
286
+ 'ajax' => admin_url( 'admin-ajax.php' ),
287
+ 'nonce' => wp_create_nonce( 'mi-admin-nonce' ),
288
+ 'network' => is_network_admin(),
289
+ 'translations' => wp_get_jed_locale_data( exactmetrics_is_pro_version() ? 'exactmetrics-premium' : 'google-analytics-dashboard-for-wp' ),
290
+ 'assets' => plugins_url( $version_path . '/assets/vue', EXACTMETRICS_PLUGIN_FILE ),
291
+ 'shareasale_id' => exactmetrics_get_shareasale_id(),
292
+ 'shareasale_url' => exactmetrics_get_shareasale_url( exactmetrics_get_shareasale_id(), '' ),
293
+ 'addons_url' => is_multisite() ? network_admin_url( 'admin.php?page=exactmetrics_network#/addons' ) : admin_url( 'admin.php?page=exactmetrics_settings#/addons' ),
294
+ 'timezone' => date( 'e' ),
295
+ 'authed' => $site_auth || $ms_auth,
296
+ 'settings_url' => add_query_arg( 'page', 'exactmetrics_settings', admin_url( 'admin.php' ) ),
297
  // Used to add notices for future deprecations.
298
+ 'versions' => array(
299
  'php_version' => phpversion(),
300
  'php_version_below_54' => apply_filters( 'exactmetrics_temporarily_hide_php_52_and_53_upgrade_warnings', version_compare( phpversion(), '5.4', '<' ) ),
301
  'php_version_below_56' => apply_filters( 'exactmetrics_temporarily_hide_php_54_and_55_upgrade_warnings', version_compare( phpversion(), '5.6', '<' ) ),
305
  'wp_version_below_49' => version_compare( $wp_version, '4.9', '<' ),
306
  'wp_update_link' => exactmetrics_get_url( 'settings-notice', 'settings-page', 'https://www.exactmetrics.com/docs/update-wordpress/' ),
307
  ),
308
+ 'plugin_version' => EXACTMETRICS_VERSION,
309
+ 'is_admin' => true,
310
+ 'admin_email' => get_option( 'admin_email' ),
311
+ 'site_url' => get_site_url(),
312
+ 'wizard_url' => is_network_admin() ? network_admin_url( 'index.php?page=exactmetrics-onboarding' ) : admin_url( 'index.php?page=exactmetrics-onboarding' ),
313
+ 'install_nonce' => wp_create_nonce( 'exactmetrics-install' ),
314
+ 'activate_nonce' => wp_create_nonce( 'exactmetrics-activate' ),
315
+ 'deactivate_nonce' => wp_create_nonce( 'exactmetrics-deactivate' ),
316
+ 'update_settings' => current_user_can( 'exactmetrics_save_settings' ),
317
+ 'migrated' => exactmetrics_get_option( 'gadwp_migrated', 0 ),
318
  )
319
  );
320
 
includes/admin/licensing/plugin-upgrader.php ADDED
@@ -0,0 +1,571 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /** WP_Upgrader class */
4
+ require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
5
+
6
+ /** Plugin_Upgrader class */
7
+ require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
8
+
9
+
10
+ /**
11
+ * In WP 5.3 a PHP 5.6 splat operator (...$args) was added to WP_Upgrader_Skin::feedback().
12
+ * We need to remove all calls to *Skin::feedback() method, as we can't override it in own Skins
13
+ * without breaking support for PHP 5.3-5.5.
14
+ *
15
+ * @internal Please do not use this class outside of core ExactMetrics development. May be removed at any time.
16
+ *
17
+ * @since 7.10.6
18
+ */
19
+ class ExactMetrics_Plugin_Upgrader extends Plugin_Upgrader {
20
+
21
+ /**
22
+ * Run an upgrade/installation.
23
+ *
24
+ * Attempt to download the package (if it is not a local file), unpack it, and
25
+ * install it in the destination folder.
26
+ *
27
+ * @since 1.5.6.1
28
+ *
29
+ * @param array $options {
30
+ * Array or string of arguments for upgrading/installing a package.
31
+ *
32
+ * @type string $package The full path or URI of the package to install.
33
+ * Default empty.
34
+ * @type string $destination The full path to the destination folder.
35
+ * Default empty.
36
+ * @type bool $clear_destination Whether to delete any files already in the
37
+ * destination folder. Default false.
38
+ * @type bool $clear_working Whether to delete the files form the working
39
+ * directory after copying to the destination.
40
+ * Default false.
41
+ * @type bool $abort_if_destination_exists Whether to abort the installation if the destination
42
+ * folder already exists. When true, `$clear_destination`
43
+ * should be false. Default true.
44
+ * @type bool $is_multi Whether this run is one of multiple upgrade/installation
45
+ * actions being performed in bulk. When true, the skin
46
+ * WP_Upgrader::header() and WP_Upgrader::footer()
47
+ * aren't called. Default false.
48
+ * @type array $hook_extra Extra arguments to pass to the filter hooks called by
49
+ * WP_Upgrader::run().
50
+ * }
51
+ * @return array|false|WP_error The result from self::install_package() on success, otherwise a WP_Error,
52
+ * or false if unable to connect to the filesystem.
53
+ */
54
+ public function run( $options ) {
55
+
56
+ $defaults = array(
57
+ 'package' => '', // Please always pass this.
58
+ 'destination' => '', // And this
59
+ 'clear_destination' => false,
60
+ 'abort_if_destination_exists' => true, // Abort if the Destination directory exists, Pass clear_destination as false please
61
+ 'clear_working' => true,
62
+ 'is_multi' => false,
63
+ 'hook_extra' => array(), // Pass any extra $hook_extra args here, this will be passed to any hooked filters.
64
+ );
65
+
66
+ $options = wp_parse_args( $options, $defaults );
67
+
68
+ /**
69
+ * Filter the package options before running an update.
70
+ *
71
+ * See also {@see 'upgrader_process_complete'}.
72
+ *
73
+ * @since 4.3.0
74
+ *
75
+ * @param array $options {
76
+ * Options used by the upgrader.
77
+ *
78
+ * @type string $package Package for update.
79
+ * @type string $destination Update location.
80
+ * @type bool $clear_destination Clear the destination resource.
81
+ * @type bool $clear_working Clear the working resource.
82
+ * @type bool $abort_if_destination_exists Abort if the Destination directory exists.
83
+ * @type bool $is_multi Whether the upgrader is running multiple times.
84
+ * @type array $hook_extra {
85
+ * Extra hook arguments.
86
+ *
87
+ * @type string $action Type of action. Default 'update'.
88
+ * @type string $type Type of update process. Accepts 'plugin', 'theme', or 'core'.
89
+ * @type bool $bulk Whether the update process is a bulk update. Default true.
90
+ * @type string $plugin Path to the plugin file relative to the plugins directory.
91
+ * @type string $theme The stylesheet or template name of the theme.
92
+ * @type string $language_update_type The language pack update type. Accepts 'plugin', 'theme',
93
+ * or 'core'.
94
+ * @type object $language_update The language pack update offer.
95
+ * }
96
+ * }
97
+ */
98
+ $options = apply_filters( 'upgrader_package_options', $options );
99
+
100
+ if ( ! $options['is_multi'] ) { // call $this->header separately if running multiple times
101
+ $this->skin->header();
102
+ }
103
+
104
+ // Connect to the Filesystem first.
105
+ $res = $this->fs_connect( array( WP_CONTENT_DIR, $options['destination'] ) );
106
+ // Mainly for non-connected filesystem.
107
+ if ( ! $res ) {
108
+ if ( ! $options['is_multi'] ) {
109
+ $this->skin->footer();
110
+ }
111
+ return false;
112
+ }
113
+
114
+ $this->skin->before();
115
+
116
+ if ( is_wp_error( $res ) ) {
117
+ $this->skin->error( $res );
118
+ $this->skin->after();
119
+ if ( ! $options['is_multi'] ) {
120
+ $this->skin->footer();
121
+ }
122
+ return $res;
123
+ }
124
+
125
+ /*
126
+ * Download the package (Note, This just returns the filename
127
+ * of the file if the package is a local file)
128
+ */
129
+ $download = $this->download_package( $options['package'], true );
130
+
131
+ // Allow for signature soft-fail.
132
+ // WARNING: This may be removed in the future.
133
+ if ( is_wp_error( $download ) && $download->get_error_data( 'softfail-filename' ) ) {
134
+
135
+ // Don't output the 'no signature could be found' failure message for now.
136
+ if ( 'signature_verification_no_signature' != $download->get_error_code() || WP_DEBUG ) {
137
+ // Outout the failure error as a normal feedback, and not as an error:
138
+ //$this->skin->feedback( $download->get_error_message() );
139
+
140
+ // Report this failure back to WordPress.org for debugging purposes.
141
+ wp_version_check(
142
+ array(
143
+ 'signature_failure_code' => $download->get_error_code(),
144
+ 'signature_failure_data' => $download->get_error_data(),
145
+ )
146
+ );
147
+ }
148
+
149
+ // Pretend this error didn't happen.
150
+ $download = $download->get_error_data( 'softfail-filename' );
151
+ }
152
+
153
+ if ( is_wp_error( $download ) ) {
154
+ $this->skin->error( $download );
155
+ $this->skin->after();
156
+ if ( ! $options['is_multi'] ) {
157
+ $this->skin->footer();
158
+ }
159
+ return $download;
160
+ }
161
+
162
+ $delete_package = ( $download != $options['package'] ); // Do not delete a "local" file
163
+
164
+ // Unzips the file into a temporary directory.
165
+ $working_dir = $this->unpack_package( $download, $delete_package );
166
+ if ( is_wp_error( $working_dir ) ) {
167
+ $this->skin->error( $working_dir );
168
+ $this->skin->after();
169
+ if ( ! $options['is_multi'] ) {
170
+ $this->skin->footer();
171
+ }
172
+ return $working_dir;
173
+ }
174
+
175
+ // With the given options, this installs it to the destination directory.
176
+ $result = $this->install_package(
177
+ array(
178
+ 'source' => $working_dir,
179
+ 'destination' => $options['destination'],
180
+ 'clear_destination' => $options['clear_destination'],
181
+ 'abort_if_destination_exists' => $options['abort_if_destination_exists'],
182
+ 'clear_working' => $options['clear_working'],
183
+ 'hook_extra' => $options['hook_extra'],
184
+ )
185
+ );
186
+
187
+ $this->skin->set_result( $result );
188
+ if ( is_wp_error( $result ) ) {
189
+ $this->skin->error( $result );
190
+ //$this->skin->feedback( 'process_failed' );
191
+ } else {
192
+ // Installation succeeded.
193
+ //$this->skin->feedback( 'process_success' );
194
+ }
195
+
196
+ $this->skin->after();
197
+
198
+ if ( ! $options['is_multi'] ) {
199
+
200
+ /**
201
+ * Fire when the upgrader process is complete.
202
+ *
203
+ * See also {@see 'upgrader_package_options'}.
204
+ *
205
+ * @since 3.6.0
206
+ * @since 3.7.0 Added to WP_Upgrader::run().
207
+ * @since 4.6.0 `$translations` was added as a possible argument to `$hook_extra`.
208
+ *
209
+ * @param WP_Upgrader $this WP_Upgrader instance. In other contexts, $this, might be a
210
+ * Theme_Upgrader, Plugin_Upgrader, Core_Upgrade, or Language_Pack_Upgrader instance.
211
+ * @param array $hook_extra {
212
+ * Array of bulk item update data.
213
+ *
214
+ * @type string $action Type of action. Default 'update'.
215
+ * @type string $type Type of update process. Accepts 'plugin', 'theme', 'translation', or 'core'.
216
+ * @type bool $bulk Whether the update process is a bulk update. Default true.
217
+ * @type array $plugins Array of the basename paths of the plugins' main files.
218
+ * @type array $themes The theme slugs.
219
+ * @type array $translations {
220
+ * Array of translations update data.
221
+ *
222
+ * @type string $language The locale the translation is for.
223
+ * @type string $type Type of translation. Accepts 'plugin', 'theme', or 'core'.
224
+ * @type string $slug Text domain the translation is for. The slug of a theme/plugin or
225
+ * 'default' for core translations.
226
+ * @type string $version The version of a theme, plugin, or core.
227
+ * }
228
+ * }
229
+ */
230
+ do_action( 'upgrader_process_complete', $this, $options['hook_extra'] );
231
+
232
+ $this->skin->footer();
233
+ }
234
+
235
+ return $result;
236
+ }
237
+
238
+ /**
239
+ * Toggle maintenance mode for the site.
240
+ *
241
+ * Create/delete the maintenance file to enable/disable maintenance mode.
242
+ *
243
+ * @since 2.8.0
244
+ *
245
+ * @global WP_Filesystem_Base $wp_filesystem Subclass
246
+ *
247
+ * @param bool $enable True to enable maintenance mode, false to disable.
248
+ */
249
+ public function maintenance_mode( $enable = false ) {
250
+ global $wp_filesystem;
251
+ $file = $wp_filesystem->abspath() . '.maintenance';
252
+ if ( $enable ) {
253
+ //$this->skin->feedback( 'maintenance_start' );
254
+ // Create maintenance file to signal that we are upgrading
255
+ $maintenance_string = '<?php $upgrading = ' . time() . '; ?>';
256
+ $wp_filesystem->delete( $file );
257
+ $wp_filesystem->put_contents( $file, $maintenance_string, FS_CHMOD_FILE );
258
+ } elseif ( ! $enable && $wp_filesystem->exists( $file ) ) {
259
+ //$this->skin->feedback( 'maintenance_end' );
260
+ $wp_filesystem->delete( $file );
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Download a package.
266
+ *
267
+ * @since 2.8.0
268
+ *
269
+ * @param string $package The URI of the package. If this is the full path to an
270
+ * existing local file, it will be returned untouched.
271
+ * @param bool $check_signatures Whether to validate file signatures. Default false.
272
+ * @return string|WP_Error The full path to the downloaded package file, or a WP_Error object.
273
+ */
274
+ public function download_package( $package, $check_signatures = false ) {
275
+
276
+ /**
277
+ * Filter whether to return the package.
278
+ *
279
+ * @since 3.7.0
280
+ *
281
+ * @param bool $reply Whether to bail without returning the package.
282
+ * Default false.
283
+ * @param string $package The package file name.
284
+ * @param WP_Upgrader $this The WP_Upgrader instance.
285
+ */
286
+ $reply = apply_filters( 'upgrader_pre_download', false, $package, $this );
287
+ if ( false !== $reply ) {
288
+ return $reply;
289
+ }
290
+
291
+ if ( ! preg_match( '!^(http|https|ftp)://!i', $package ) && file_exists( $package ) ) { //Local file or remote?
292
+ return $package; //must be a local file..
293
+ }
294
+
295
+ if ( empty( $package ) ) {
296
+ return new WP_Error( 'no_package', $this->strings['no_package'] );
297
+ }
298
+
299
+ //$this->skin->feedback( 'downloading_package', $package );
300
+
301
+ $download_file = download_url( $package, 300, $check_signatures );
302
+
303
+ if ( is_wp_error( $download_file ) && ! $download_file->get_error_data( 'softfail-filename' ) ) {
304
+ return new WP_Error( 'download_failed', $this->strings['download_failed'], $download_file->get_error_message() );
305
+ }
306
+
307
+ return $download_file;
308
+ }
309
+
310
+ /**
311
+ * Unpack a compressed package file.
312
+ *
313
+ * @since 2.8.0
314
+ *
315
+ * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
316
+ *
317
+ * @param string $package Full path to the package file.
318
+ * @param bool $delete_package Optional. Whether to delete the package file after attempting
319
+ * to unpack it. Default true.
320
+ * @return string|WP_Error The path to the unpacked contents, or a WP_Error on failure.
321
+ */
322
+ public function unpack_package( $package, $delete_package = true ) {
323
+ global $wp_filesystem;
324
+
325
+ //$this->skin->feedback( 'unpack_package' );
326
+
327
+ $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
328
+
329
+ //Clean up contents of upgrade directory beforehand.
330
+ $upgrade_files = $wp_filesystem->dirlist( $upgrade_folder );
331
+ if ( ! empty( $upgrade_files ) ) {
332
+ foreach ( $upgrade_files as $file ) {
333
+ $wp_filesystem->delete( $upgrade_folder . $file['name'], true );
334
+ }
335
+ }
336
+
337
+ // We need a working directory - Strip off any .tmp or .zip suffixes
338
+ $working_dir = $upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' );
339
+
340
+ // Clean up working directory
341
+ if ( $wp_filesystem->is_dir( $working_dir ) ) {
342
+ $wp_filesystem->delete( $working_dir, true );
343
+ }
344
+
345
+ // Unzip package to working directory
346
+ $result = unzip_file( $package, $working_dir );
347
+
348
+ // Once extracted, delete the package if required.
349
+ if ( $delete_package ) {
350
+ unlink( $package );
351
+ }
352
+
353
+ if ( is_wp_error( $result ) ) {
354
+ $wp_filesystem->delete( $working_dir, true );
355
+ if ( 'incompatible_archive' == $result->get_error_code() ) {
356
+ return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], $result->get_error_data() );
357
+ }
358
+ return $result;
359
+ }
360
+
361
+ return $working_dir;
362
+ }
363
+
364
+ /**
365
+ * Install a package.
366
+ *
367
+ * Copies the contents of a package form a source directory, and installs them in
368
+ * a destination directory. Optionally removes the source. It can also optionally
369
+ * clear out the destination folder if it already exists.
370
+ *
371
+ * @since 2.8.0
372
+ *
373
+ * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
374
+ * @global array $wp_theme_directories
375
+ *
376
+ * @param array|string $args {
377
+ * Optional. Array or string of arguments for installing a package. Default empty array.
378
+ *
379
+ * @type string $source Required path to the package source. Default empty.
380
+ * @type string $destination Required path to a folder to install the package in.
381
+ * Default empty.
382
+ * @type bool $clear_destination Whether to delete any files already in the destination
383
+ * folder. Default false.
384
+ * @type bool $clear_working Whether to delete the files form the working directory
385
+ * after copying to the destination. Default false.
386
+ * @type bool $abort_if_destination_exists Whether to abort the installation if
387
+ * the destination folder already exists. Default true.
388
+ * @type array $hook_extra Extra arguments to pass to the filter hooks called by
389
+ * WP_Upgrader::install_package(). Default empty array.
390
+ * }
391
+ *
392
+ * @return array|WP_Error The result (also stored in `WP_Upgrader::$result`), or a WP_Error on failure.
393
+ */
394
+ public function install_package( $args = array() ) {
395
+ global $wp_filesystem, $wp_theme_directories;
396
+
397
+ $defaults = array(
398
+ 'source' => '', // Please always pass this
399
+ 'destination' => '', // and this
400
+ 'clear_destination' => false,
401
+ 'clear_working' => false,
402
+ 'abort_if_destination_exists' => true,
403
+ 'hook_extra' => array(),
404
+ );
405
+
406
+ $args = wp_parse_args( $args, $defaults );
407
+
408
+ // These were previously extract()'d.
409
+ $source = $args['source'];
410
+ $destination = $args['destination'];
411
+ $clear_destination = $args['clear_destination'];
412
+
413
+ set_time_limit( 300 );
414
+
415
+ if ( empty( $source ) || empty( $destination ) ) {
416
+ return new WP_Error( 'bad_request', $this->strings['bad_request'] );
417
+ }
418
+ //$this->skin->feedback( 'installing_package' );
419
+
420
+ /**
421
+ * Filter the install response before the installation has started.
422
+ *
423
+ * Returning a truthy value, or one that could be evaluated as a WP_Error
424
+ * will effectively short-circuit the installation, returning that value
425
+ * instead.
426
+ *
427
+ * @since 2.8.0
428
+ *
429
+ * @param bool|WP_Error $response Response.
430
+ * @param array $hook_extra Extra arguments passed to hooked filters.
431
+ */
432
+ $res = apply_filters( 'upgrader_pre_install', true, $args['hook_extra'] );
433
+
434
+ if ( is_wp_error( $res ) ) {
435
+ return $res;
436
+ }
437
+
438
+ //Retain the Original source and destinations
439
+ $remote_source = $args['source'];
440
+ $local_destination = $destination;
441
+
442
+ $source_files = array_keys( $wp_filesystem->dirlist( $remote_source ) );
443
+ $remote_destination = $wp_filesystem->find_folder( $local_destination );
444
+
445
+ //Locate which directory to copy to the new folder, This is based on the actual folder holding the files.
446
+ if ( 1 == count( $source_files ) && $wp_filesystem->is_dir( trailingslashit( $args['source'] ) . $source_files[0] . '/' ) ) { //Only one folder? Then we want its contents.
447
+ $source = trailingslashit( $args['source'] ) . trailingslashit( $source_files[0] );
448
+ } elseif ( count( $source_files ) == 0 ) {
449
+ return new WP_Error( 'incompatible_archive_empty', $this->strings['incompatible_archive'], $this->strings['no_files'] ); // There are no files?
450
+ } else { // It's only a single file, the upgrader will use the folder name of this file as the destination folder. Folder name is based on zip filename.
451
+ $source = trailingslashit( $args['source'] );
452
+ }
453
+
454
+ /**
455
+ * Filter the source file location for the upgrade package.
456
+ *
457
+ * @since 2.8.0
458
+ * @since 4.4.0 The $hook_extra parameter became available.
459
+ *
460
+ * @param string $source File source location.
461
+ * @param string $remote_source Remote file source location.
462
+ * @param WP_Upgrader $this WP_Upgrader instance.
463
+ * @param array $hook_extra Extra arguments passed to hooked filters.
464
+ */
465
+ $source = apply_filters( 'upgrader_source_selection', $source, $remote_source, $this, $args['hook_extra'] );
466
+
467
+ if ( is_wp_error( $source ) ) {
468
+ return $source;
469
+ }
470
+
471
+ // Has the source location changed? If so, we need a new source_files list.
472
+ if ( $source !== $remote_source ) {
473
+ $source_files = array_keys( $wp_filesystem->dirlist( $source ) );
474
+ }
475
+
476
+ /*
477
+ * Protection against deleting files in any important base directories.
478
+ * Theme_Upgrader & Plugin_Upgrader also trigger this, as they pass the
479
+ * destination directory (WP_PLUGIN_DIR / wp-content/themes) intending
480
+ * to copy the directory into the directory, whilst they pass the source
481
+ * as the actual files to copy.
482
+ */
483
+ $protected_directories = array( ABSPATH, WP_CONTENT_DIR, WP_PLUGIN_DIR, WP_CONTENT_DIR . '/themes' );
484
+
485
+ if ( is_array( $wp_theme_directories ) ) {
486
+ $protected_directories = array_merge( $protected_directories, $wp_theme_directories );
487
+ }
488
+
489
+ if ( in_array( $destination, $protected_directories ) ) {
490
+ $remote_destination = trailingslashit( $remote_destination ) . trailingslashit( basename( $source ) );
491
+ $destination = trailingslashit( $destination ) . trailingslashit( basename( $source ) );
492
+ }
493
+
494
+ if ( $clear_destination ) {
495
+ // We're going to clear the destination if there's something there.
496
+ //$this->skin->feedback( 'remove_old' );
497
+
498
+ $removed = $this->clear_destination( $remote_destination );
499
+
500
+ /**
501
+ * Filter whether the upgrader cleared the destination.
502
+ *
503
+ * @since 2.8.0
504
+ *
505
+ * @param mixed $removed Whether the destination was cleared. true on success, WP_Error on failure
506
+ * @param string $local_destination The local package destination.
507
+ * @param string $remote_destination The remote package destination.
508
+ * @param array $hook_extra Extra arguments passed to hooked filters.
509
+ */
510
+ $removed = apply_filters( 'upgrader_clear_destination', $removed, $local_destination, $remote_destination, $args['hook_extra'] );
511
+
512
+ if ( is_wp_error( $removed ) ) {
513
+ return $removed;
514
+ }
515
+ } elseif ( $args['abort_if_destination_exists'] && $wp_filesystem->exists( $remote_destination ) ) {
516
+ //If we're not clearing the destination folder and something exists there already, Bail.
517
+ //But first check to see if there are actually any files in the folder.
518
+ $_files = $wp_filesystem->dirlist( $remote_destination );
519
+ if ( ! empty( $_files ) ) {
520
+ $wp_filesystem->delete( $remote_source, true ); //Clear out the source files.
521
+ return new WP_Error( 'folder_exists', $this->strings['folder_exists'], $remote_destination );
522
+ }
523
+ }
524
+
525
+ //Create destination if needed
526
+ if ( ! $wp_filesystem->exists( $remote_destination ) ) {
527
+ if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) ) {
528
+ return new WP_Error( 'mkdir_failed_destination', $this->strings['mkdir_failed'], $remote_destination );
529
+ }
530
+ }
531
+ // Copy new version of item into place.
532
+ $result = copy_dir( $source, $remote_destination );
533
+ if ( is_wp_error( $result ) ) {
534
+ if ( $args['clear_working'] ) {
535
+ $wp_filesystem->delete( $remote_source, true );
536
+ }
537
+ return $result;
538
+ }
539
+
540
+ //Clear the Working folder?
541
+ if ( $args['clear_working'] ) {
542
+ $wp_filesystem->delete( $remote_source, true );
543
+ }
544
+
545
+ $destination_name = basename( str_replace( $local_destination, '', $destination ) );
546
+ if ( '.' == $destination_name ) {
547
+ $destination_name = '';
548
+ }
549
+
550
+ $this->result = compact( 'source', 'source_files', 'destination', 'destination_name', 'local_destination', 'remote_destination', 'clear_destination' );
551
+
552
+ /**
553
+ * Filter the installation response after the installation has finished.
554
+ *
555
+ * @since 2.8.0
556
+ *
557
+ * @param bool $response Installation response.
558
+ * @param array $hook_extra Extra arguments passed to hooked filters.
559
+ * @param array $result Installation result data.
560
+ */
561
+ $res = apply_filters( 'upgrader_post_install', true, $args['hook_extra'], $this->result );
562
+
563
+ if ( is_wp_error( $res ) ) {
564
+ $this->result = $res;
565
+ return $res;
566
+ }
567
+
568
+ //Bombard the calling function will all the info which we've just used.
569
+ return $this->result;
570
+ }
571
+ }
includes/admin/notifications.php ADDED
@@ -0,0 +1,408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Notifications.
5
+ *
6
+ * @since 7.10.5
7
+ */
8
+ class ExactMetrics_Notifications {
9
+
10
+ /**
11
+ * Source of notifications content.
12
+ *
13
+ * @since {VERSION}
14
+ *
15
+ * @var string
16
+ */
17
+ const SOURCE_URL = 'https://plugin-cdn.exactmetrics.com/notifications.json';
18
+
19
+ /**
20
+ * Option value.
21
+ *
22
+ * @since {VERSION}
23
+ *
24
+ * @var bool|array
25
+ */
26
+ public $option = false;
27
+
28
+ /**
29
+ * The name of the option used to store the data.
30
+ *
31
+ * @var string
32
+ */
33
+ public $option_name = 'exactmetrics_notifications';
34
+
35
+ /**
36
+ * ExactMetrics_Notifications constructor.
37
+ */
38
+ public function __construct() {
39
+ $this->init();
40
+ }
41
+
42
+ /**
43
+ * Initialize class.
44
+ *
45
+ * @since {VERSION}
46
+ */
47
+ public function init() {
48
+
49
+ $this->hooks();
50
+ }
51
+
52
+ /**
53
+ * Register hooks.
54
+ *
55
+ * @since {VERSION}
56
+ */
57
+ public function hooks() {
58
+ add_action( 'wp_ajax_exactmetrics_notification_dismiss', array( $this, 'dismiss' ) );
59
+
60
+ add_action( 'wp_ajax_exactmetrics_vue_get_notifications', array( $this, 'ajax_get_notifications' ) );
61
+
62
+ add_action( 'exactmetrics_admin_notifications_update', array( $this, 'update' ) );
63
+
64
+ }
65
+
66
+ /**
67
+ * Check if user has access and is enabled.
68
+ *
69
+ * @return bool
70
+ * @since {VERSION}
71
+ *
72
+ */
73
+ public function has_access() {
74
+
75
+ $access = false;
76
+
77
+ if ( current_user_can( 'exactmetrics_view_dashboard' ) && ! exactmetrics_get_option( 'hide_am_notices', false ) ) {
78
+ $access = true;
79
+ }
80
+
81
+ return apply_filters( 'exactmetrics_admin_notifications_has_access', $access );
82
+ }
83
+
84
+ /**
85
+ * Get option value.
86
+ *
87
+ * @param bool $cache Reference property cache if available.
88
+ *
89
+ * @return array
90
+ * @since {VERSION}
91
+ *
92
+ */
93
+ public function get_option( $cache = true ) {
94
+
95
+ if ( $this->option && $cache ) {
96
+ return $this->option;
97
+ }
98
+
99
+ $option = get_option( $this->option_name, array() );
100
+
101
+ $this->option = array(
102
+ 'update' => ! empty( $option['update'] ) ? $option['update'] : 0,
103
+ 'events' => ! empty( $option['events'] ) ? $option['events'] : array(),
104
+ 'feed' => ! empty( $option['feed'] ) ? $option['feed'] : array(),
105
+ 'dismissed' => ! empty( $option['dismissed'] ) ? $option['dismissed'] : array(),
106
+ );
107
+
108
+ return $this->option;
109
+ }
110
+
111
+ /**
112
+ * Fetch notifications from feed.
113
+ *
114
+ * @return array
115
+ * @since {VERSION}
116
+ *
117
+ */
118
+ public function fetch_feed() {
119
+
120
+ $res = wp_remote_get( self::SOURCE_URL );
121
+
122
+ if ( is_wp_error( $res ) ) {
123
+ return array();
124
+ }
125
+
126
+ $body = wp_remote_retrieve_body( $res );
127
+
128
+ if ( empty( $body ) ) {
129
+ return array();
130
+ }
131
+
132
+ return $this->verify( json_decode( $body, true ) );
133
+ }
134
+
135
+ /**
136
+ * Verify notification data before it is saved.
137
+ *
138
+ * @param array $notifications Array of notifications items to verify.
139
+ *
140
+ * @return array
141
+ * @since {VERSION}
142
+ *
143
+ */
144
+ public function verify( $notifications ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
145
+
146
+ $data = array();
147
+
148
+ if ( ! is_array( $notifications ) || empty( $notifications ) ) {
149
+ return $data;
150
+ }
151
+
152
+ $option = $this->get_option();
153
+
154
+ foreach ( $notifications as $notification ) {
155
+
156
+ // The message and license should never be empty, if they are, ignore.
157
+ if ( empty( $notification['content'] ) || empty( $notification['type'] ) ) {
158
+ continue;
159
+ }
160
+
161
+ // Ignore if license type does not match.
162
+ if ( ! in_array( ExactMetrics()->license->get_license_type(), $notification['type'] ) ) {
163
+ continue;
164
+ }
165
+
166
+ // Ignore if expired.
167
+ if ( ! empty( $notification['end'] ) && time() > strtotime( $notification['end'] ) ) {
168
+ continue;
169
+ }
170
+
171
+ // Ignore if notification has already been dismissed.
172
+ if ( ! empty( $option['dismissed'] ) && in_array( $notification['id'], $option['dismissed'] ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
173
+ continue;
174
+ }
175
+
176
+ // Ignore if notification existed before installing ExactMetrics.
177
+ // Prevents bombarding the user with notifications after activation.
178
+ $over_time = get_option( 'exactmetrics_over_time', array() );
179
+
180
+ if (
181
+ ! empty( $over_time['installed_date'] ) &&
182
+ ! empty( $notification['start'] ) &&
183
+ $over_time['installed_date'] > strtotime( $notification['start'] )
184
+ ) {
185
+ continue;
186
+ }
187
+
188
+ $data[] = $notification;
189
+ }
190
+
191
+ return $data;
192
+ }
193
+
194
+ /**
195
+ * Verify saved notification data for active notifications.
196
+ *
197
+ * @param array $notifications Array of notifications items to verify.
198
+ *
199
+ * @return array
200
+ * @since {VERSION}
201
+ *
202
+ */
203
+ public function verify_active( $notifications ) {
204
+
205
+ if ( ! is_array( $notifications ) || empty( $notifications ) ) {
206
+ return array();
207
+ }
208
+
209
+ // Remove notifications that are not active.
210
+ foreach ( $notifications as $key => $notification ) {
211
+ if (
212
+ ( ! empty( $notification['start'] ) && time() < strtotime( $notification['start'] ) ) ||
213
+ ( ! empty( $notification['end'] ) && time() > strtotime( $notification['end'] ) )
214
+ ) {
215
+ unset( $notifications[ $key ] );
216
+ }
217
+ }
218
+
219
+ return $notifications;
220
+ }
221
+
222
+ /**
223
+ * Get notification data.
224
+ *
225
+ * @return array
226
+ * @since {VERSION}
227
+ *
228
+ */
229
+ public function get() {
230
+
231
+ if ( ! $this->has_access() ) {
232
+ return array();
233
+ }
234
+
235
+ $option = $this->get_option();
236
+
237
+ // Update notifications using async task.
238
+ if ( empty( $option['update'] ) || time() > $option['update'] + DAY_IN_SECONDS ) {
239
+ if ( false === wp_next_scheduled( 'exactmetrics_admin_notifications_update' ) ) {
240
+ wp_schedule_single_event( time(), 'exactmetrics_admin_notifications_update' );
241
+ }
242
+ }
243
+
244
+ $events = ! empty( $option['events'] ) ? $this->verify_active( $option['events'] ) : array();
245
+ $feed = ! empty( $option['feed'] ) ? $this->verify_active( $option['feed'] ) : array();
246
+
247
+ return array_merge( $events, $feed );
248
+ }
249
+
250
+ /**
251
+ * Get notification count.
252
+ *
253
+ * @return int
254
+ * @since {VERSION}
255
+ *
256
+ */
257
+ public function get_count() {
258
+
259
+ return count( $this->get() );
260
+ }
261
+
262
+ /**
263
+ * Add a manual notification event.
264
+ *
265
+ * @param array $notification Notification data.
266
+ *
267
+ * @since {VERSION}
268
+ *
269
+ */
270
+ public function add( $notification ) {
271
+
272
+ if ( empty( $notification['id'] ) ) {
273
+ return;
274
+ }
275
+
276
+ $option = $this->get_option();
277
+
278
+ if ( in_array( $notification['id'], $option['dismissed'] ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
279
+ return;
280
+ }
281
+
282
+ foreach ( $option['events'] as $item ) {
283
+ if ( $item['id'] === $notification['id'] ) {
284
+ return;
285
+ }
286
+ }
287
+
288
+ $notification = $this->verify( array( $notification ) );
289
+
290
+ update_option(
291
+ $this->option_name,
292
+ array(
293
+ 'update' => $option['update'],
294
+ 'feed' => $option['feed'],
295
+ 'events' => array_merge( $notification, $option['events'] ),
296
+ 'dismissed' => $option['dismissed'],
297
+ )
298
+ );
299
+ }
300
+
301
+ /**
302
+ * Update notification data from feed.
303
+ *
304
+ * @since {VERSION}
305
+ */
306
+ public function update() {
307
+
308
+ $feed = $this->fetch_feed();
309
+ $option = $this->get_option();
310
+
311
+ update_option(
312
+ $this->option_name,
313
+ array(
314
+ 'update' => time(),
315
+ 'feed' => $feed,
316
+ 'events' => $option['events'],
317
+ 'dismissed' => $option['dismissed'],
318
+ )
319
+ );
320
+ }
321
+
322
+ /**
323
+ * Dismiss notification via AJAX.
324
+ *
325
+ * @since {VERSION}
326
+ */
327
+ public function dismiss() {
328
+
329
+ // Run a security check.
330
+ check_ajax_referer( 'mi-admin-nonce', 'nonce' );
331
+
332
+ // Check for access and required param.
333
+ if ( ! $this->has_access() || empty( $_POST['id'] ) ) {
334
+ wp_send_json_error();
335
+ }
336
+
337
+ $id = sanitize_text_field( wp_unslash( $_POST['id'] ) );
338
+ $option = $this->get_option();
339
+ $type = is_numeric( $id ) ? 'feed' : 'events';
340
+
341
+ $option['dismissed'][] = $id;
342
+ $option['dismissed'] = array_unique( $option['dismissed'] );
343
+
344
+ // Remove notification.
345
+ if ( is_array( $option[ $type ] ) && ! empty( $option[ $type ] ) ) {
346
+ foreach ( $option[ $type ] as $key => $notification ) {
347
+ if ( $notification['id'] == $id ) { // phpcs:ignore WordPress.PHP.StrictComparisons
348
+ unset( $option[ $type ][ $key ] );
349
+ break;
350
+ }
351
+ }
352
+ }
353
+
354
+ update_option( $this->option_name, $option );
355
+
356
+ wp_send_json_success();
357
+ }
358
+
359
+ /**
360
+ * This generates the markup for the notifications indicator if needed.
361
+ *
362
+ * @return string
363
+ */
364
+ public function get_menu_count() {
365
+
366
+ if ( $this->get_count() > 0 ) {
367
+ return '<span class="exactmetrics-menu-notification-indicator"></span>';
368
+ }
369
+
370
+ return '';
371
+
372
+ }
373
+
374
+ /**
375
+ * Retrieve the notifications via an ajax call.
376
+ */
377
+ public function ajax_get_notifications() {
378
+
379
+ // Run a security check.
380
+ check_ajax_referer( 'mi-admin-nonce', 'nonce' );
381
+
382
+ $notifications_data = array(
383
+ 'notifications' => $this->get(),
384
+ 'view_url' => $this->get_view_url(),
385
+ );
386
+
387
+ wp_send_json_success( $notifications_data );
388
+ }
389
+
390
+ /**
391
+ * Get the URL for the page where users can see/read notifications.
392
+ *
393
+ * @return string
394
+ */
395
+ public function get_view_url() {
396
+
397
+ $disabled = exactmetrics_get_option( 'dashboards_disabled', false );
398
+
399
+ $url = add_query_arg( 'page', 'exactmetrics_reports', admin_url( 'admin.php' ) );
400
+
401
+ if ( false !== $disabled ) {
402
+ $url = is_multisite() ? network_admin_url( 'admin.php?page=exactmetrics_network' ) : admin_url( 'admin.php?page=exactmetrics_settings' );
403
+ }
404
+
405
+ return $url;
406
+
407
+ }
408
+ }
includes/admin/routes.php CHANGED
@@ -112,6 +112,37 @@ class ExactMetrics_Rest_Routes {
112
  $options['custom_code'] = stripslashes( $options['custom_code'] );
113
  }
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  wp_send_json( $options );
116
 
117
  }
@@ -132,8 +163,10 @@ class ExactMetrics_Rest_Routes {
132
  if ( isset( $_POST['value'] ) ) {
133
  $value = $this->handle_sanitization( $setting, $_POST['value'] );
134
  exactmetrics_update_option( $setting, $value );
 
135
  } else {
136
  exactmetrics_update_option( $setting, false );
 
137
  }
138
  }
139
 
@@ -286,7 +319,7 @@ class ExactMetrics_Rest_Routes {
286
  'basename' => 'optinmonster/optin-monster-wp-api.php',
287
  'slug' => 'optinmonster',
288
  );
289
- // OptinMonster.
290
  $parsed_addons['wp-mail-smtp'] = array(
291
  'active' => function_exists( 'wp_mail_smtp' ),
292
  'icon' => plugin_dir_url( EXACTMETRICS_PLUGIN_FILE ) . 'assets/images/plugin-smtp.png',
@@ -296,6 +329,16 @@ class ExactMetrics_Rest_Routes {
296
  'basename' => 'wp-mail-smtp/wp_mail_smtp.php',
297
  'slug' => 'wp-mail-smtp',
298
  );
 
 
 
 
 
 
 
 
 
 
299
  // SeedProd.
300
  $parsed_addons['coming-soon'] = array(
301
  'active' => function_exists( 'seed_csp4_activation' ),
@@ -683,14 +726,14 @@ class ExactMetrics_Rest_Routes {
683
  }
684
 
685
  // We do not need any extra credentials if we have gotten this far, so let's install the plugin.
686
- require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
687
  $base = ExactMetrics();
 
688
  require_once plugin_dir_path( $base->file ) . '/includes/admin/licensing/skin.php';
689
 
690
- // Prevent languange upgrade in ajax calls.
691
  remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
692
  // Create the plugin upgrader with our custom skin.
693
- $installer = new Plugin_Upgrader( new ExactMetrics_Skin() );
694
  $installer->install( $download_url );
695
 
696
  // Flush the cache and return the newly installed plugin basename.
112
  $options['custom_code'] = stripslashes( $options['custom_code'] );
113
  }
114
 
115
+ //add email summaries options
116
+ if ( exactmetrics_is_pro_version() ) {
117
+ $default_email = array(
118
+ 'email' => get_option( 'admin_email' ),
119
+ );
120
+
121
+ if ( ! isset( $options['email_summaries'] ) ) {
122
+ $options['email_summaries'] = 'on';
123
+ }
124
+
125
+ if ( ! isset( $options['summaries_email_addresses'] ) ) {
126
+ $options['summaries_email_addresses'] = array(
127
+ $default_email,
128
+ );
129
+ }
130
+
131
+ if ( ! isset( $options['summaries_html_template'] ) ) {
132
+ $options['summaries_html_template'] = 'yes';
133
+ }
134
+
135
+
136
+ if ( ! isset( $options['summaries_carbon_copy'] ) ) {
137
+ $options['summaries_carbon_copy'] = 'no';
138
+ }
139
+
140
+
141
+ if ( ! isset( $options['summaries_header_image'] ) ) {
142
+ $options['summaries_header_image'] = '';
143
+ }
144
+ }
145
+
146
  wp_send_json( $options );
147
 
148
  }
163
  if ( isset( $_POST['value'] ) ) {
164
  $value = $this->handle_sanitization( $setting, $_POST['value'] );
165
  exactmetrics_update_option( $setting, $value );
166
+ do_action( 'exactmetrics_after_update_settings', $setting, $value );
167
  } else {
168
  exactmetrics_update_option( $setting, false );
169
+ do_action( 'exactmetrics_after_update_settings', $setting, false );
170
  }
171
  }
172
 
319
  'basename' => 'optinmonster/optin-monster-wp-api.php',
320
  'slug' => 'optinmonster',
321
  );
322
+ // WP Mail Smtp.
323
  $parsed_addons['wp-mail-smtp'] = array(
324
  'active' => function_exists( 'wp_mail_smtp' ),
325
  'icon' => plugin_dir_url( EXACTMETRICS_PLUGIN_FILE ) . 'assets/images/plugin-smtp.png',
329
  'basename' => 'wp-mail-smtp/wp_mail_smtp.php',
330
  'slug' => 'wp-mail-smtp',
331
  );
332
+ // Pretty Links
333
+ $parsed_addons['pretty-link'] = array(
334
+ 'active' => class_exists( 'PrliBaseController' ),
335
+ 'icon' => '',
336
+ 'title' => 'Pretty Links',
337
+ 'excerpt' => __( 'Pretty Links helps you shrink, beautify, track, manage and share any URL on or off of your WordPress website. Create links that look how you want using your own domain name!', 'google-analytics-dashboard-for-wp' ),
338
+ 'installed' => array_key_exists( 'pretty-link/pretty-link.php', $installed_plugins ),
339
+ 'basename' => 'pretty-link/pretty-link.php',
340
+ 'slug' => 'pretty-link',
341
+ );
342
  // SeedProd.
343
  $parsed_addons['coming-soon'] = array(
344
  'active' => function_exists( 'seed_csp4_activation' ),
726
  }
727
 
728
  // We do not need any extra credentials if we have gotten this far, so let's install the plugin.
 
729
  $base = ExactMetrics();
730
+ require_once plugin_dir_path( $base->file ) . '/includes/admin/licensing/plugin-upgrader.php';
731
  require_once plugin_dir_path( $base->file ) . '/includes/admin/licensing/skin.php';
732
 
733
+ // Prevent language upgrade in ajax calls.
734
  remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
735
  // Create the plugin upgrader with our custom skin.
736
+ $installer = new ExactMetrics_Plugin_Upgrader( new ExactMetrics_Skin() );
737
  $installer->install( $download_url );
738
 
739
  // Flush the cache and return the newly installed plugin basename.
includes/em-install.php CHANGED
@@ -69,6 +69,10 @@ class ExactMetrics_Install {
69
 
70
  } else { // if existing install
71
 
 
 
 
 
72
  // Do not use. See exactmetrics_after_install_routine comment below.
73
  do_action( 'exactmetrics_after_existing_upgrade_routine', $version );
74
  $version = get_option( 'exactmetrics_current_version', $version );
@@ -399,6 +403,13 @@ class ExactMetrics_Install {
399
  }
400
 
401