PluginProbe
Analytify – Google Analytics Dashboard For WordPress (GA4 analytics tracking) / 9.0.0
Analytify – Google Analytics Dashboard For WordPress (GA4 analytics tracking) v9.0.0
9.1.2 9.1.1 9.1.0 9.0.2 9.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.1.0 1.1.1 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 All 153 releases
wp-analytify / wp-analytify.php

wp-analytify.php in Analytify – Google Analytics Dashboard For WordPress (GA4 analytics tracking) 9.0.0, at wp-analytify.php

1,594 lines 51.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Plugin Name: Analytify Dashboard
4 * Plugin URI: https://analytify.io/?ref=27&utm_source=wp-org&utm_medium=plugin-header&utm_campaign=pro-upgrade&utm_content=plugin-uri
5 * Description: Analytify brings a brand new and modern feeling of Google Analytics superbly integrated within the WordPress.
6 * Version: 9.0.0
7 * Author: Analytify
8 * Author URI: https://analytify.io/?ref=27&utm_source=wp-org&utm_medium=plugin-header&utm_campaign=pro-upgrade&utm_content=author-uri
9 * License: GPLv3
10 * Text Domain: wp-analytify
11 * Requires at least: 4.0
12 * Tested up to: 7.0
13 * Domain Path: /languages
14 * GitHub Plugin URI: https://github.com/WPBrigade/wp-analytify
15 *
16 * @package WP_ANALYTIFY
17 */
18
19
20 // ========================================.
21 // TELEMETRY SDK INITIALIZATION START.
22 // ========================================.
23
24 if ( ! function_exists( 'wa_wpb78834179' ) ) {
25
26 /**
27 * Telemetry function.
28 *
29 * @return mixed
30 */
31 function wa_wpb78834179() {
32 global $wa_wpb78834179;
33
34 if ( ! isset( $wa_wpb78834179 ) ) {
35
36 require_once __DIR__ . '/lib/wpb-sdk/start.php';
37
38 $wa_wpb78834179 = wpb_dynamic_init(
39 array(
40 'id' => '7',
41 'slug' => 'wp-analytify',
42 'type' => 'plugin',
43 'public_key' => '1|4aOA8EuyIN4pi2miMvC23LLpnHbBZFNki9R9pVmwd673d3c8',
44 'secret_key' => 'sk_b36c525848fee035',
45 'is_premium' => false,
46 'has_addons' => false,
47 'has_paid_plans' => false,
48 'menu' => array(
49 'slug' => 'wp-analytify',
50 'account' => false,
51 'support' => false,
52 ),
53 'settings' => array(
54 'wp_analytify_modules' => '',
55 'wp-analytify-tracking' => '',
56 'wp-analytify-email' => '',
57 'wp-analytify-events-tracking' => '',
58 'wp-analytify-front' => '',
59 'wp-analytify-custom-dimensions' => '',
60 'wp-analytify-forms' => '',
61 'analytify_widget_date_differ' => '',
62 'wp-analytify-profile' => '',
63 'wp-analytify-admin' => '',
64 'wp-analytify-dashboard' => '',
65 'wp-analytify-advanced' => '',
66 'analytify_ua_code' => '',
67 'analytify_date_differ' => '',
68 'wp_analytify_review_dismiss_4_1_8' => '',
69 'wpanalytify_settings' => '',
70 'analytify_license_key' => '',
71 'analytify_license_status' => '',
72 'analytify_campaigns_license_status' => '',
73 'analytify_campaigns_license_key' => '',
74 'analytify_goals_license_status' => '',
75 'analytify_goals_license_key' => '',
76 'Analytify_Addon_Forms_license_status' => '',
77 'analytify_forms_license_key' => '',
78 'analytify_authors_license_status' => '',
79 'analytify_authors_license_key' => '',
80 'analytify_woo_license_status' => '',
81 'analytify_woo_license_key' => '',
82 'analytify_email_license_status' => '',
83 'analytify_email_license_key' => '',
84 'analytify-google-ads-tracking' => '',
85 '_analytify_optin' => '',
86 'analytify_cache_timeout' => '',
87 'analytify_csv_data' => '',
88 'analytify_active_date' => '',
89 'analytify_edd_license_status' => '',
90 'analytify_edd_license_key' => '',
91 '_transient_timeout_analytify_api_addons' => '',
92 '_transient_analytify_api_addons' => '',
93 'analytify_ga4_exceptions' => '',
94 'analytify-ga-properties-summery' => '',
95 'analytify_ga4-streams' => '',
96 'analytify_tracking_property_info' => '',
97 'analytify_reporting_property_info' => '',
98 'analytify_gtag_move_to_notice' => '',
99 'analytify_current_version' => '',
100 'analytify_logs_setup' => '',
101 'analytify_pro_default_settings' => '',
102 'analytify_pro_active_date' => '',
103 'analytify_pro_upgrade_routine' => '',
104 'analytify_pro_current_version' => '',
105 'WP_ANALYTIFY_PRO_PLUGIN_VERSION' => '',
106 'wp-analytify-license' => '',
107 'analytify_authentication_date' => '',
108 'WP_ANALYTIFY_PLUGIN_VERSION_OLD' => '',
109 'WP_ANALYTIFY_PRO_PLUGIN_VERSION_OLD' => '',
110 'analytify_default_settings' => '',
111 'analytify_free_upgrade_routine' => '',
112 'WP_ANALYTIFY_PLUGIN_VERSION' => '',
113 'wp_analytify_active_time' => '',
114 'wp-analytify-authentication' => '',
115 'wp-analytify-help' => '',
116 'WP_ANALYTIFY_NEW_LOGIN' => '',
117 'profiles_list_summary' => '',
118 'pa_google_token' => '',
119 'post_analytics_token' => '',
120 ),
121 )
122 );
123 }
124
125 return $wa_wpb78834179;
126 }
127
128
129 wa_wpb78834179();
130
131 do_action( 'wa_wpb78834179_loaded' );
132 }
133
134 // ========================================.
135 // TELEMETRY SDK INITIALIZATION END.
136 // ========================================.
137
138 if ( ! defined( 'ABSPATH' ) ) {
139 exit;
140 }
141
142
143
144
145 require_once __DIR__ . '/inc/analytify-constants.php';
146
147 if ( ! class_exists( 'Analytify_General' ) ) {
148 require_once 'analytify-general.php';
149 }
150
151
152
153 // ========================================.
154 // MAIN PLUGIN CLASS DEFINITION START.
155 // ========================================.
156
157 if ( ! class_exists( 'WP_Analytify' ) ) {
158 /**
159 * Main WP_Analytify class.
160 *
161 * @since 1.0.0
162 */
163 // phpcs:ignore Universal.Files.SeparateFunctionsFromOO.Mixed,Squiz.Commenting.ClassComment.Missing
164 class WP_Analytify extends Analytify_General {
165
166 /**
167 * Plugin instance.
168 *
169 * @var WP_Analytify $instance The one true WP_Analytify
170 * @since 1.2.2
171 */
172 private static $instance = null;
173
174 /**
175 * Token data.
176 *
177 * @var mixed
178 */
179 public $token = false;
180 /**
181 * Client instance.
182 *
183 * @var mixed
184 */
185 public $client = null;
186
187 /**
188 * Post stats disable flag.
189 *
190 * @var mixed
191 */
192 protected $disable_post_stats;
193
194 /**
195 * Settings data.
196 *
197 * @var mixed
198 */
199 public $settings;
200
201 /**
202 * Component loader instance
203 *
204 * @var Analytify_Loader
205 */
206 private $loader;
207
208 // ========================================.
209 // CONSTRUCTOR & CORE METHODS START.
210 // ========================================.
211
212 /**
213 * Constructor.
214 *
215 * @since 1.2.2
216 */
217 public function __construct() {
218 parent::__construct();
219 $this->setup_constants();
220 $this->includes();
221 $this->disable_post_stats = $this->settings->get_option( 'enable_back_end', 'wp-analytify-admin' );
222 $this->hooks();
223 }
224
225 /**
226 * Get active instance.
227 *
228 * @access public
229 * @since 1.2.2
230 * @return object self::$instance The one true WP_Analytify
231 */
232 public static function get_instance() {
233 if ( ! self::$instance ) {
234 self::$instance = new WP_Analytify();
235 }
236
237 return self::$instance;
238 }
239
240 /**
241 * Setup plugin constants
242 *
243 * @access private
244 * @since 1.2.2
245 * @return void
246 */
247 private function setup_constants() {
248
249 $upload_dir = wp_upload_dir( null, false );
250 }
251
252 /**
253 * Define constant if not already set
254 *
255 * @since 1.2.4
256 * @param string $name contanst name.
257 * @param string|bool $value constant value.
258 * @return void
259 */
260 private function define( $name, $value ) {
261 if ( ! defined( $name ) ) {
262 define( $name, $value );
263 }
264 }
265
266 /**
267 * What type of request is this?
268 *
269 * @since 1.2.4
270 * @param string $type ajax, frontend or admin.
271 * @return bool
272 */
273 private function is_request( $type ) {
274 switch ( $type ) {
275 case 'admin':
276 return is_admin();
277 case 'ajax':
278 return defined( 'DOING_AJAX' );
279 case 'cron':
280 return defined( 'DOING_CRON' );
281 case 'frontend':
282 return ( ! is_admin() || defined( 'DOING_AJAX' ) ) && ! defined( 'DOING_CRON' );
283 default:
284 return false;
285 }
286 }
287
288
289 /**
290 * Include necessary files
291 *
292 * @access private
293 * @since 1.2.2
294 * @return void
295 */
296 private function includes() {
297 $files = array(
298 WP_ANALYTIFY_LIB_PATH . 'logs/class-analytify-log-handler-interface.php',
299 WP_ANALYTIFY_LIB_PATH . 'logs/class-analytify-logger-interface.php',
300 WP_ANALYTIFY_LIB_PATH . 'logs/class-analytify-log-levels.php',
301 WP_ANALYTIFY_LIB_PATH . 'logs/class-analytify-logger.php',
302 WP_ANALYTIFY_LIB_PATH . 'logs/abstract-analytify-log-handler.php',
303 WP_ANALYTIFY_LIB_PATH . 'logs/class-analytify-log-handler-file.php',
304 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-logs.php',
305 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-sanitize.php',
306 WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytify-core-functions.php',
307 WP_ANALYTIFY_PLUGIN_DIR . '/inc/class-analytify-adminbar.php',
308 WP_ANALYTIFY_PLUGIN_DIR . '/classes/abstracts/analytify-report-abstract.php',
309 WP_ANALYTIFY_PLUGIN_DIR . '/classes/abstracts/analytify-host-analytics-abstract.php',
310 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-host-analytics.php',
311 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-report-core.php',
312 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-rest-api.php',
313 WP_ANALYTIFY_PLUGIN_DIR . '/inc/class-analytify-ajax.php',
314 WP_ANALYTIFY_PLUGIN_DIR . '/inc/class-analytify-post-columns.php',
315 WP_ANALYTIFY_PLUGIN_DIR . '/classes/class-wp-analytify-compatibility-upgrade.php',
316 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-dashboard-widget.php',
317 WP_ANALYTIFY_PLUGIN_DIR . '/classes/class-analytify-user-optout.php',
318 WP_ANALYTIFY_PLUGIN_DIR . '/classes/class-analytify-gdpr-compliance.php',
319 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-email.php',
320 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-settings.php',
321 );
322
323 foreach ( $files as $file ) {
324 if ( file_exists( $file ) ) {
325 include_once $file;
326 } else {
327
328 echo '<div class="notice notice-error"><p>' . esc_html__( 'A critical file is missing:', 'wp-analytify' ) . ' ' . esc_html( $file ) . '. ' . esc_html__( 'The Analytify plugin needs to be deactivated && re-installed.', 'wp-analytify' ) . '</p></div>';
329 return;
330 }
331 }
332
333 if ( file_exists( WP_ANALYTIFY_PLUGIN_DIR . '/inc/class-analytify-loader.php' ) ) {
334 require_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/class-analytify-loader.php';
335 if ( class_exists( 'Analytify_Loader' ) ) {
336 $this->loader = new Analytify_Loader( $this );
337 }
338 }
339 }
340
341 // ========================================.
342 // CONSTRUCTOR & CORE METHODS END.
343 // ========================================.
344
345 // ========================================.
346 // WordPress HOOKS & ACTIONS START.
347 // ========================================.
348
349 /**
350 * Run action && filter hooks
351 *
352 * @access private
353 * @since 1.2.2
354 * @return void
355 */
356 private function hooks() {
357
358 add_action( 'init', array( $this, 'load_textdomain' ) ); // Hook load_textdomain.
359 add_action( 'admin_init', array( $this, '_save_core_version' ) );
360 add_action( 'admin_init', array( $this, 'wpa_check_authentication' ) );
361 add_action( 'admin_init', array( $this, 'logout' ), 1 );
362 add_filter( 'removable_query_args', array( $this, 'Analytify_remove_query' ) );
363 add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
364
365 add_action( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 4 );
366 add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'wp_analytify_plugin_action_links' ), 10, 1 );
367 add_filter( 'network_admin_plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'wp_analytify_plugin_action_links' ), 10, 1 );
368
369 add_action( 'wp_head', array( $this, 'analytify_add_analytics_code' ) );
370 add_action( 'wp_head', array( $this, 'analytify_add_manual_analytics_code' ) );
371
372 add_filter( 'admin_footer_text', 'wpa_admin_rate_footer_text', 1 );
373 add_action( 'admin_footer', 'wpa_print_js', 25 );
374 add_action( 'admin_footer', array( $this, 'wp_analytify_maybe_render_sdk_optout_form' ), 5 );
375
376 add_action( 'admin_init', array( $this, 'redirect_optin' ) );
377
378 add_action( 'analytify_cleanup_logs', array( $this, 'analytify_cleanup_logs' ) );
379
380 add_action(
381 'init',
382 function () {
383 if ( WPANALYTIFY_Utils::get_option( 'locally_host_analytics', 'wp-analytify-advanced', false ) && ! wp_next_scheduled( 'analytify_analytics_lib_cron' ) ) {
384 wp_schedule_event( time(), 'daily', 'analytify_analytics_lib_cron' );
385 }
386 }
387 );
388
389 add_action(
390 'analytify_analytics_lib_cron',
391 function () {
392 if ( class_exists( 'Analytify_Host_Analytics' ) ) {
393 new Analytify_Host_Analytics( 'gtag', true );
394 }
395 }
396 );
397 }
398
399 // ========================================.
400 // WordPress HOOKS & ACTIONS END.
401 // ========================================.
402
403
404 // ========================================.
405 // ADMIN NOTICES & PROMOTIONS START.
406 // ========================================.
407
408
409
410 /**
411 * Redirect to Welcome page.
412 *
413 * @since 2.0.14
414 * @return void
415 */
416 public function redirect_optin() {
417 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading URL parameter for display purposes
418 $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
419
420 if ( $page && ( 'analytify-settings' === $page || 'analytify-dashboard' === $page || 'analytify-pmpro' === $page || 'analytify-learndash' === $page || 'analytify-lifterlms' === $page || 'analytify-woocommerce' === $page || 'analytify-addons' === $page ) ) {
421 if ( ! get_site_option( '_analytify_optin' ) ) {
422 wp_safe_redirect( admin_url( 'admin.php?page=analytify-optin' ) );
423 exit;
424 }
425 }
426 }
427
428
429 /**
430 * Internationalization.
431 *
432 * @access public
433 * @since 1.2.2
434 * @return void
435 */
436 public function load_textdomain() {
437 $plugin_dir = basename( __DIR__ );
438 load_plugin_textdomain( 'wp-analytify', false, $plugin_dir . '/languages/' );
439 }
440
441 /**
442 *
443 * Save Authentication code on return
444 * && nonce verification
445 *
446 * @return void
447 */
448 public function wpa_check_authentication() {
449
450 $state = isset( $_GET['state'] ) ? json_decode( urldecode( sanitize_text_field( wp_unslash( $_GET['state'] ) ) ), true ) : null;
451
452 if ( isset( $_GET['code'] ) && isset( $_GET['page'] ) && 'analytify-settings' === sanitize_text_field( wp_unslash( $_GET['page'] ) ) ) {
453 $get_nonce = isset( $_GET['nonce'] ) ? sanitize_text_field( wp_unslash( $_GET['nonce'] ) ) : null;
454 $nonce = isset( $state['nonce'] ) ? $state['nonce'] : $get_nonce;
455
456 if ( wp_verify_nonce( $nonce, 'analytify_analytics_login' ) ) {
457
458 $key_google_token = sanitize_text_field( wp_unslash( $_GET['code'] ) );
459 update_option( 'WP_ANALYTIFY_NEW_LOGIN', 'yes' );
460 self::pt_save_data( $key_google_token );
461 wp_safe_redirect( admin_url( 'admin.php?page=analytify-settings' ) . '#wp-analytify-profile' );
462 exit;
463
464 } else {
465 $plugin_page_url = admin_url( 'plugins.php' );
466 wp_die(
467 sprintf( // translators: Nonce verification failed.
468 esc_html__( 'Sorry, you are not allowed as nonce verification failed. %1$sClick here to return to the Dashboard%2$s.', 'wp-analytify' ),
469 '<a href="' . esc_url( $plugin_page_url ) . '">',
470 '</a>'
471 )
472 );
473 }
474 }
475 }
476
477 /**
478 * Save version number of the plugin && show a custom message for users
479 *
480 * @since 1.3
481 * @return void
482 */
483 public function _save_core_version() { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore -- Underscore prefix is intentional for internal method
484 if ( ANALYTIFY_VERSION !== get_option( 'WP_ANALYTIFY_PLUGIN_VERSION' ) ) {
485 update_option( 'WP_ANALYTIFY_PLUGIN_VERSION_OLD', get_option( 'WP_ANALYTIFY_PLUGIN_VERSION' ), true ); // saving old plugin version.
486 update_option( 'WP_ANALYTIFY_PLUGIN_VERSION', ANALYTIFY_VERSION );
487 }
488 }
489
490
491
492
493
494 // ========================================.
495 // GOOGLE ANALYTICS TRACKING CODE START.
496 // ========================================.
497
498 /**
499 * Add Google Analytics JS code
500 *
501 * @since 1.0.0
502 * @version 7.0.4
503 * @return bool|void Returns false if tracking is blocked/skipped, true if code is output, void otherwise.
504 */
505 public function analytify_add_analytics_code() {
506 if ( WPANALYTIFY_Utils::skip_page_tracking() ) {
507 return false;
508 }
509
510 // Check for GDPR compliance.
511 if ( Analytify_GDPR_Compliance::is_gdpr_compliance_blocking() ) {
512 return false;
513 }
514
515 if ( 'on' === $this->settings->get_option( 'install_ga_code', 'wp-analytify-profile', 'off' ) ) {
516 global $current_user;
517
518 $roles = $current_user->roles;
519
520 if ( isset( $roles[0] ) && in_array( $roles[0], $this->settings->get_option( 'exclude_users_tracking', 'wp-analytify-profile', array() ), true ) ) {
521 echo '<!-- This user is disabled from tracking by Analytify !-->';
522 return false;
523 } else {
524 if ( ! $this->settings->get_option( 'profile_for_posts', 'wp-analytify-profile' ) ) {
525 return false;
526 }
527
528 $ua_code = WP_ANALYTIFY_FUNCTIONS::get_UA_code();
529
530 // Validate UA code before outputting tracking code.
531 if ( empty( $ua_code ) ) {
532 // Add a comment in HTML for debugging.
533 echo '<!-- Analytify: No tracking code - check profile selection or OAuth connection -->';
534 return false;
535 }
536
537 if ( 'gtag' === WP_ANALYTIFY_TRACKING_MODE ) {
538 $ga_code = $this->output_gtag_code( $ua_code );
539 } else {
540 $ga_code = $this->output_ga_code( $ua_code );
541 }
542
543 echo apply_filters( 'analytify_ga_script', $ga_code ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JavaScript code needs to be output directly
544 return true;
545 }
546 }
547 }
548
549 /**
550 * Add Google Manual Analytics JS code
551 *
552 * @return void
553 */
554 public function analytify_add_manual_analytics_code() {
555 if ( get_option( 'pa_google_token' ) ) {
556 return;
557 }
558
559 $manual_ua_code = $this->settings->get_option( 'manual_ua_code', 'wp-analytify-authentication', false );
560
561 if ( ! $manual_ua_code ) {
562 return;
563 }
564
565 global $current_user;
566 $roles = $current_user->roles;
567
568 if ( in_array( 'administrator', $roles, true ) ) {
569 echo '<!-- This user is disabled from tracking by Analytify !-->';
570 } elseif ( apply_filters( 'analytify_manaul_ga_script', false ) ) {
571 echo apply_filters( 'analytify_ga_script', $this->output_ga_code( $manual_ua_code ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JavaScript code needs to be output directly
572 } else {
573 echo apply_filters( 'analytify_gtag_script', $this->output_gtag_code( $manual_ua_code ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JavaScript code needs to be output directly
574 }
575 }
576
577 /**
578 * Generate gtag code.
579 *
580 * @param string $ua_code Google Analytics UA code.
581 * @since 3.0
582 * @version 7.0.4
583 * @return $gtag_code
584 */
585 private function output_gtag_code( $ua_code ) {
586 ob_start();
587
588 $local_analytics_file = class_exists( 'Analytify_Host_Analytics' ) ? ( new Analytify_Host_Analytics( 'gtag', false ) )->local_analytics_file_url() : false;
589
590 if ( false !== apply_filters( 'analytify_tracking_code_comments', true ) ) {
591 printf( // translators: Tracking code comments.
592 esc_html__( '%2$s This code is added by Analytify (%1$s) %4$s %3$s', 'wp-analytify' ),
593 esc_html( ANALYTIFY_VERSION ),
594 '<!--',
595 '!-->',
596 'https://analytify.io/'
597 );
598 }
599
600 $allow_display_features = ( 'on' === $this->settings->get_option( 'demographic_interest_tracking', 'wp-analytify-advanced' ) ) ? 'true' : 'false';
601 $linker_cross_domain_tracking = ( 'on' === $this->settings->get_option( 'linker_cross_domain_tracking', 'wp-analytify-advanced' ) ) ? true : false;
602 $linked_domains = array();
603
604 if ( $linker_cross_domain_tracking ) {
605 $all_linked_domains = $this->settings->get_option( 'linked_domain', 'wp-analytify-advanced' );
606 $all_linked_domains = trim( $all_linked_domains ? $all_linked_domains : '' );
607
608 if ( ! empty( $all_linked_domains ) ) {
609 $all_linked_domains = str_replace( "'", '', $all_linked_domains );
610 $all_linked_domains = str_replace( '"', '', $all_linked_domains );
611
612 $all_linked_domains = preg_replace( '/\s+/', '', $all_linked_domains );
613
614 $list_linked_domains = explode( ',', $all_linked_domains );
615 $number_of_linked_domains = count( $list_linked_domains );
616
617 if ( $number_of_linked_domains > 0 ) {
618 $linked_domains = array_filter(
619 (array) $list_linked_domains,
620 function ( $value ) {
621 return strlen( $value ) > 0;
622 }
623 );
624 } else {
625 $linked_domains = (array) $all_linked_domains;
626 }
627 } else {
628 $linker_cross_domain_tracking = false;
629 }
630 }
631
632 $configuration = array(
633
634 'allow_display_features' => $allow_display_features,
635 );
636
637 if ( $linker_cross_domain_tracking ) {
638 $configuration['linker'] = array(
639 'domains' => $linked_domains,
640 );
641 }
642
643 $debug_mode = apply_filters( 'analytify_debug_mode', true );
644
645 if ( $debug_mode ) {
646 $configuration['debug_mode'] = true;
647 }
648
649 if ( 'on' === $this->settings->get_option( 'track_user_id', 'wp-analytify-advanced' ) && is_user_logged_in() ) {
650 $configuration['user_id'] = esc_html( (string) get_current_user_id() );
651 }
652
653 $configuration = apply_filters( 'analytify_gtag_configuration', $configuration );
654 $configuration_json = wp_json_encode( $configuration, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT );
655
656 // Build the script src URL correctly.
657 $script_src = $local_analytics_file ?? 'https://www.googletagmanager.com/gtag/js';
658 $script_src .= ( strpos( $script_src, '?' ) !== false ? '&' : '?' ) . 'id=' . esc_attr( $ua_code );
659
660 // Excluded query parameters: strip only these query keys from page_location (path and hash unchanged).
661 $exclude_params = 'on' === $this->settings->get_option( 'exclude_query_params', 'wp-analytify-advanced' );
662 $params_list = $this->settings->get_option( 'query_params_to_exclude', 'wp-analytify-advanced' );
663 $params_list = is_string( $params_list ) ? $params_list : '';
664
665 $js_location_logic = '';
666 if ( $exclude_params && '' !== $params_list ) {
667 $params_array = array_map( 'trim', explode( ',', $params_list ) );
668 $params_array = array_map( 'strtolower', $params_array );
669 $params_array = array_values( array_unique( array_filter( $params_array, 'strlen' ) ) );
670 $params_json = wp_json_encode( $params_array );
671
672 // Strip only query keys (case-insensitive); path and hash are not altered; no query string / repeated params are safe.
673 $js_location_logic = "
674 try {
675 var wa_loc = window.location.href;
676 var wa_url = new URL(wa_loc);
677 var wa_params = $params_json;
678 var keysToRemove = [];
679 wa_url.searchParams.forEach(function(val, key) {
680 if (wa_params.indexOf(key.toLowerCase()) !== -1) { keysToRemove.push(key); }
681 });
682 keysToRemove.forEach(function(k) { wa_url.searchParams.delete(k); });
683 configuration.page_location = wa_url.toString();
684 } catch (e) {}
685 ";
686 }
687
688 ?>
689
690 <?php // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Inline gtag script must be output directly in the page head. ?>
691 <script async src="<?php echo esc_url( $script_src ); ?>"></script>
692 <script>
693 window.dataLayer = window.dataLayer || [];
694 function gtag(){dataLayer.push(arguments);}
695 gtag('js', new Date());
696
697 const configuration = <?php echo $configuration_json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_json_encode() with JSON_HEX flags already escapes JSON safely for JavaScript context. ?>;
698 const gaID = '<?php echo esc_js( $ua_code ); ?>';
699
700 <?php do_action( 'analytify_tracking_code_before_pageview' ); ?>
701 <?php
702 if ( ! empty( $js_location_logic ) ) {
703 echo $js_location_logic; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JS logic constructed internally with safe JSON.
704 }
705 ?>
706
707 gtag('config', gaID, configuration);
708
709 <?php
710 if ( $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' ) ) {
711 $custom_js = $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' );
712
713 if ( ! empty( $custom_js ) ) {
714 echo wp_kses_post( $custom_js );
715 }
716 }
717
718 do_action( 'ga_ecommerce_js' );
719 do_action( 'analytify_tracking_code_after_pageview' );
720 ?>
721
722 </script>
723
724 <?php
725 if ( false !== apply_filters( 'analytify_tracking_code_comments', true ) ) {
726 printf( // translators: Tracking code comments.
727 esc_html__( '%2$s This code is added by Analytify (%1$s) %3$s', 'wp-analytify' ),
728 esc_html( ANALYTIFY_VERSION ),
729 '<!--',
730 '!-->'
731 );
732 }
733
734 $gtag_code = ob_get_contents();
735 ob_end_clean();
736 return $gtag_code ? $gtag_code : '';
737 }
738
739 /**
740 * Generate gtag code.
741 *
742 * @param string $ua_code Google Analytics UA code.
743 * @since 3.0
744 * @return string
745 */
746 public function output_ga_code( $ua_code ) {
747 ob_start();
748
749 $src = apply_filters( 'analytify_output_ga_js_src', '//www.google-analytics.com/analytics.js' );
750
751 if ( false !== apply_filters( 'analytify_tracking_code_comments', true ) ) {
752 printf( // translators: Tracking code comments.
753 esc_html__( '%2$s This code is added by Analytify (%1$s) %4$s %3$s', 'wp-analytify' ),
754 esc_html( ANALYTIFY_VERSION ),
755 '<!--',
756 '!-->',
757 'https://analytify.io/'
758 );
759 }
760 ?>
761
762 <script>
763 (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
764 (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
765 m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
766 })
767
768 (window,document,'script','<?php echo esc_url( $src ); ?>','ga');
769
770 <?php
771 if ( 'on' === $this->settings->get_option( 'linker_cross_domain_tracking', 'wp-analytify-advanced' ) ) {
772 echo " ga('create', '" . esc_js( $ua_code ) . "', 'auto', {'allowLinker': true});";
773 echo "ga('require', 'linker');";
774 } else {
775 echo " ga('create', '" . esc_js( $ua_code ) . "', 'auto');";
776 }
777
778 if ( 'on' === $this->settings->get_option( 'track_user_id', 'wp-analytify-advanced' ) && is_user_logged_in() ) {
779 echo "ga('set', 'userId', " . esc_html( (string) get_current_user_id() ) . ');';
780 }
781
782 if ( 'on' === $this->settings->get_option( 'demographic_interest_tracking', 'wp-analytify-advanced' ) ) {
783 echo "ga('require', 'displayfeatures');";
784 }
785
786 if ( $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' ) ) {
787
788 $custom_js = $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' );
789
790 if ( $custom_js && false !== $custom_js ) {
791 $custom_js = wp_kses(
792 $custom_js,
793 array(
794 'script' => array(),
795 'noscript' => array(),
796 'div' => array(
797 'id' => array(),
798 'class' => array(),
799 ),
800 'span' => array(
801 'id' => array(),
802 'class' => array(),
803 ),
804 )
805 );
806 echo '<script type="text/javascript">' . esc_js( wp_strip_all_tags( $custom_js ) ) . '</script>';
807 }
808 }
809
810 do_action( 'ga_ecommerce_js' );
811 do_action( 'analytify_tracking_code_before_pageview' );
812 echo "ga('send', 'pageview');";
813 ?>
814
815 </script>
816
817 <?php
818 if ( false !== apply_filters( 'analytify_tracking_code_comments', true ) ) {
819 printf( // translators: Tracking code comments.
820 esc_html__( '%2$s This code is added by Analytify (%1$s) %3$s', 'wp-analytify' ),
821 esc_html( ANALYTIFY_VERSION ),
822 '<!--',
823 '!-->'
824 );
825 }
826
827 $ga_code = ob_get_contents();
828 ob_end_clean();
829 return $ga_code ? $ga_code : '';
830 }
831
832 // ========================================.
833 // GOOGLE ANALYTICS TRACKING CODE END.
834 // ========================================.
835
836
837 /**
838 * Adds action links to the plugin on the Plugins screen (e.g. Opt In / Opt Out, Settings).
839 *
840 * @param array<int|string, string> $links Default action links.
841 * @return array<int|string, string>
842 */
843 public function wp_analytify_plugin_action_links( $links ) {
844 $settings_link = '';
845
846 $sdk_data = json_decode( get_option( 'wpb_sdk_wp-analytify' ), true );
847 $sdk_data = is_array( $sdk_data ) ? $sdk_data : array();
848 $communication = isset( $sdk_data['communication'] ) ? $sdk_data['communication'] : false;
849 $diagnostic_info = isset( $sdk_data['diagnostic_info'] ) ? $sdk_data['diagnostic_info'] : false;
850 $extensions = isset( $sdk_data['extensions'] ) ? $sdk_data['extensions'] : false;
851 $is_optin = 'yes' === get_site_option( '_analytify_optin', '' );
852 $all_options_false = ! $communication && ! $diagnostic_info && ! $extensions;
853
854 if ( $communication || $diagnostic_info || $extensions ) {
855 $settings_link .= sprintf(
856 /* translators: %1$s opening link tag, %2$s closing link tag */
857 esc_html__( '%1$s Opt Out %2$s | ', 'wp-analytify' ),
858 '<a class="opt-out" href="#">',
859 '</a>'
860 );
861 } elseif ( $is_optin && $all_options_false ) {
862 update_option(
863 'wpb_sdk_wp-analytify',
864 wp_json_encode(
865 array(
866 'communication' => '1',
867 'diagnostic_info' => '1',
868 'extensions' => '1',
869 'user_skip' => '0',
870 )
871 )
872 );
873 $settings_link .= sprintf(
874 /* translators: %1$s opening link tag, %2$s closing link tag */
875 esc_html__( '%1$s Opt Out %2$s | ', 'wp-analytify' ),
876 '<a class="opt-out" href="#">',
877 '</a>'
878 );
879 } else {
880 $settings_link .= sprintf(
881 /* translators: %1$s opening link tag, %2$s closing link tag */
882 esc_html__( '%1$s Opt In %2$s | ', 'wp-analytify' ),
883 '<a href="' . esc_url( admin_url( 'admin.php?page=analytify-optin' ) ) . '">',
884 '</a>'
885 );
886 }
887
888 if ( ! class_exists( 'WP_Analytify_Pro' ) ) {
889 $settings_link .= sprintf(
890 /* translators: %1$s opening link tag, %2$s closing link tag */
891 esc_html__( '%1$s Get Analytify Pro %2$s | ', 'wp-analytify' ),
892 '<a href="https://analytify.io/pricing/?utm_source=analytify-lite&utm_medium=plugin-action-link&utm_campaign=pro-upgrade&utm_content=Get+Analytify+Pro" target="_blank" rel="noopener noreferrer" style="color:#3db634;">',
893 '</a>'
894 );
895 }
896
897 $settings_link .= sprintf(
898 /* translators: %1$s opening link tag, %2$s closing link tag */
899 esc_html__( '%1$s Settings %2$s', 'wp-analytify' ),
900 '<a href="' . esc_url( admin_url( 'admin.php?page=analytify-settings' ) ) . '">',
901 '</a>'
902 );
903
904 array_unshift( $links, $settings_link );
905 return $links;
906 }
907
908 /**
909 * Plugin row meta links
910 *
911 * @since 1.1
912 * @version 5.0.5
913 * @param array $input already defined meta links.
914 * @param string $file plugin file path && name being processed.
915 * @param array $plugin_data relevent data about the currect plugin.
916 * @param string $status weather plugin is active or disabled.
917 * @return array $input
918 */
919 public function plugin_row_meta( $input, $file, $plugin_data, $status ) {
920
921 $analytify_plugins = array(
922 'wp-analytify/wp-analytify.php',
923 'analytify-analytics-dashboard-widget/wp-analytify-dashboard.php',
924 'wp-analytify-pro/wp-analytify-pro.php',
925 'wp-analytify-woocommerce/wp-analytify-woocommerce.php',
926 'wp-analytify-goals/wp-analytify-goals.php',
927 'wp-analytify-forms/wp-analytify-forms.php',
928 'wp-analytify-email/wp-analytify-email.php',
929 'wp-analytify-edd/wp-analytify-edd.php',
930 'wp-analytify-authors/wp-analytify-authors.php',
931 );
932
933 if ( ! in_array( $file, $analytify_plugins, true ) ) {
934 return $input;
935 }
936
937 if ( isset( $plugin_data['Author'] ) ) {
938
939 $input[1] = sprintf(
940 'By <a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
941 esc_url( $plugin_data['AuthorURI'] ),
942 esc_html( $plugin_data['Author'] )
943 );
944
945 }
946
947 if ( 'wp-analytify/wp-analytify.php' !== $file && 'analytify-analytics-dashboard-widget/wp-analytify-dashboard.php' !== $file && in_array( $file, $analytify_plugins, true ) ) {
948
949 $input[2] = sprintf(
950 '<a href="%s" target="_blank" rel="noopener noreferrer">Visit Plugin Site</a>',
951 esc_url( $plugin_data['PluginURI'] )
952 );
953 return $input;
954
955 }
956
957 $links = array(
958 sprintf( // translators: Premium features.
959 esc_html__( '%1$s Explore Premium Features %2$s', 'wp-analytify' ),
960 '<a target="_blank" href="https://analytify.io/add-ons/?ref=27&utm_source=analytify-pro&utm_medium=plugin-action-link&utm_campaign=pro-upgrade&utm_content=Explore+Premium+Features">',
961 '</a>'
962 ),
963 );
964
965 $input = array_merge( $input, $links );
966
967 return $input;
968 }
969
970 /**
971 * Output SDK opt-in/opt-out modal on the Plugins screen so the "Opt Out" action link opens the popup.
972 *
973 * @return void
974 */
975 public function wp_analytify_maybe_render_sdk_optout_form() {
976 if ( ! function_exists( 'get_current_screen' ) ) {
977 return;
978 }
979 $screen = get_current_screen();
980 if ( ! $screen || 'plugins' !== $screen->id ) {
981 return;
982 }
983 require_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytify-optout-form.php';
984 }
985
986 /**
987 * Display warning if profiles are not selected.
988 *
989 * @return void
990 */
991 public function pa_check_warnings() {
992 add_action( 'admin_footer', array( &$this, 'profile_warning' ) );
993 }
994
995
996 // Page routing function moved to Page_Management component.
997
998
999
1000
1001 // ========================================.
1002 // ADMIN ASSETS & STYLING START.
1003 // ========================================.
1004
1005 // Admin styles function moved to Scripts_Styles component.
1006
1007 // Functions moved to Scripts_Styles, Module_Manager && Promotions components.
1008
1009 // ========================================.
1010 // ANALYTICS DATA RETRIEVAL START.
1011 // ========================================.
1012
1013 // Analytics accounts function moved to Analytics_Accounts component.
1014
1015 // Analytics accounts summary function moved to Analytics_Accounts component.
1016
1017 /**
1018 * Get settings URL.
1019 *
1020 * @return string
1021 */
1022 public function pa_setting_url() {
1023 return admin_url( 'admin.php?page=analytify-settings' );
1024 }
1025
1026 /**
1027 * Save Google token data.
1028 *
1029 * @param mixed $key_google_token The Google token data.
1030 * @return bool|void
1031 */
1032 public function pt_save_data( $key_google_token ) {
1033 try {
1034 update_option( 'post_analytics_token', $key_google_token );
1035
1036 if ( $this->analytify_pa_connect_v2() ) {
1037 return true;
1038 }
1039 } catch ( Exception $e ) {
1040 echo esc_html( $e->getMessage() );
1041 }
1042 }
1043
1044 // Profile warning function moved to Promotions component.
1045
1046 // AJAX handler moved to Analytics_Reports component.
1047
1048 // Module state function moved to Module_Manager component.
1049
1050
1051
1052
1053 // ========================================.
1054 // ANALYTICS DATA RETRIEVAL END.
1055 // ========================================.
1056
1057 // Deprecated analytics function moved to Analytics_Reports component.
1058
1059
1060
1061
1062 // ========================================.
1063 // UTILITY & HELPER FUNCTIONS START.
1064 // ========================================.
1065
1066 // Utility functions moved to Utils component.
1067 // Backward compatibility wrappers.
1068 /**
1069 * Format numbers for display.
1070 *
1071 * @param mixed $num The number to format.
1072 * @return string
1073 */
1074 public function wpa_pretty_numbers( $num ) {
1075 return Analytify_Utils::wpa_pretty_numbers( $num );
1076 }
1077
1078 /**
1079 * Format number with proper formatting.
1080 *
1081 * @param mixed $num The number to format.
1082 * @return string
1083 */
1084 public function wpa_number_format( $num ) {
1085 return Analytify_Utils::wpa_number_format( $num );
1086 }
1087
1088 /**
1089 * Format time for display.
1090 *
1091 * @param mixed $time The time to format.
1092 * @return string
1093 */
1094 public function pa_pretty_time( $time ) {
1095 return Analytify_Utils::pa_pretty_time( $time );
1096 }
1097
1098 /**
1099 * Check user access level.
1100 *
1101 * @param mixed $access_level The required access level.
1102 * @return bool
1103 */
1104 public function pa_check_roles( $access_level ) {
1105 return Analytify_Utils::pa_check_roles( $access_level );
1106 }
1107
1108
1109 /**
1110 * Notice to switch gtag.js tracking mode.
1111 *
1112 * @return void
1113 */
1114 // Welcome message function moved to Promotions component.
1115
1116 // ========================================.
1117 // ADMIN MENU & PAGE ROUTING START.
1118 // ========================================.
1119
1120 /**
1121 * Create Analytics menu at the left side of dashboard
1122 *
1123 * @version 8.1.0
1124 * @return void
1125 */
1126 public function add_admin_menu() {
1127 $allowed_roles = $this->settings->get_option( 'show_analytics_roles_dashboard', 'wp-analytify-dashboard', array() );
1128 $allowed_roles[] = 'administrator';
1129
1130 $current_user = wp_get_current_user();
1131 $is_author_only = $current_user && in_array( 'author', $current_user->roles, true ) && ! in_array( 'administrator', $current_user->roles, true );
1132
1133 // Determine the capability to use for the dashboard.
1134 // If the user has an allowed role, we use 'read' to ensure they can see the menu,
1135 // since add_admin_menu already restricted registration to allowed roles.
1136 $dashboard_cap = 'manage_options';
1137 if ( array_intersect( $current_user->roles, $allowed_roles ) ) {
1138 $dashboard_cap = 'read';
1139 }
1140
1141 // Allow authors to see the menu (so they can access Authors dashboard submenu).
1142 // But restrict them from accessing main dashboard content.
1143 if ( $is_author_only ) {
1144 // Authors can see menu but will be restricted from main dashboard page.
1145 // They need edit_posts capability to see Authors dashboard.
1146 if ( ! current_user_can( 'edit_posts' ) ) {
1147 return;
1148 }
1149 } elseif ( ! $this->pa_check_roles( $allowed_roles ) ) {
1150 // For non-authors, check normal access.
1151 return;
1152 }
1153
1154 add_submenu_page( 'admin.php', __( 'Activate', 'wp-analytify' ), __( 'Activate', 'wp-analytify' ), 'manage_options', 'analytify-optin', array( $this, 'render_optin' ) );
1155
1156 add_menu_page(
1157 ANALYTIFY_NICK,
1158 'Analytify',
1159 $dashboard_cap,
1160 'analytify-dashboard',
1161 array(
1162 $this,
1163 'pa_page_file_path',
1164 ),
1165 'data:image/svg+xml;base64,' . base64_encode( // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Used for SVG data encoding
1166 '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
1167 width="18px" height="18px" viewBox="0 0 18 18" style="enable-background:new 0 0 18 18;" xml:space="preserve">
1168 <style type="text/css">
1169 .st0{fill-rule:evenodd;clip-rule:evenodd;fill:#23282D;}
1170 .st1{fill-rule:evenodd;clip-rule:evenodd;fill:#9EA3A8;}
1171 </style>
1172 <g>
1173 <path class="st0" d="M17.2,16c-0.4,0-0.8-0.3-0.8-0.8v-0.8V14c-1.6,2.4-4.3,4-7.5,4c-5,0-9-4-9-9s4-9,9-9c3.1,0,5.8,1.6,7.5,4V3.8
1174 v0l0,0c0-0.4,0.4-0.7,0.8-0.7S18,3.4,18,3.8l0,0v0V5v9.5v0.8C18,15.6,17.7,16,17.2,16z M9,1.5C4.9,1.5,1.5,4.9,1.5,9
1175 s3.4,7.5,7.5,7.5s7.5-3.4,7.5-7.5S13.1,1.5,9,1.5z"/>
1176 <g>
1177 <g>
1178 <path class="st1" d="M5.9,8.4c-0.5,0-0.9,0.4-0.9,0.9v2.9c0,0.5,0.4,0.9,0.9,0.9s0.9-0.4,0.9-0.9V9.3C6.7,8.8,6.3,8.4,5.9,8.4z
1179 M9,7C8.5,7,8.1,7.4,8.1,7.9v4.3C8.1,12.7,8.5,13,9,13s0.9-0.4,0.9-0.9V7.9C9.9,7.4,9.5,7,9,7z M12.1,4.9c-0.5,0-0.9,0.4-0.9,0.9
1180 v6.4c0,0.5,0.4,0.9,0.9,0.9s0.9-0.4,0.9-0.9V5.8C12.9,5.3,12.6,4.9,12.1,4.9z"/>
1181 </g>
1182 </g>
1183 </g>
1184 </svg>'
1185 ),
1186 2
1187 );
1188
1189 add_submenu_page(
1190 'analytify-dashboard',
1191 ANALYTIFY_NICK . esc_html__( ' Dashboards', 'wp-analytify' ),
1192 esc_html__( 'Dashboards', 'wp-analytify' ),
1193 $dashboard_cap,
1194 'analytify-dashboard',
1195 array(
1196 $this,
1197 'pa_page_file_path',
1198 ),
1199 10
1200 );
1201
1202 do_action( 'analytify_add_submenu' );
1203
1204 add_submenu_page(
1205 'analytify-dashboard',
1206 ANALYTIFY_NICK . esc_html__( ' Settings', 'wp-analytify' ),
1207 esc_html__( 'Settings', 'wp-analytify' ),
1208 'manage_options',
1209 'analytify-settings',
1210 array(
1211 $this,
1212 'pa_page_file_path',
1213 ),
1214 50
1215 );
1216
1217 add_submenu_page(
1218 'analytify-dashboard',
1219 ANALYTIFY_NICK . esc_html__( ' Help', 'wp-analytify' ),
1220 esc_html__( 'Help', 'wp-analytify' ),
1221 'manage_options',
1222 'analytify-settings#wp-analytify-help',
1223 array(
1224 $this,
1225 'pa_page_file_path',
1226 ),
1227 55
1228 );
1229
1230 // Add license submenu.
1231 if ( class_exists( 'WP_Analytify_Pro_Base' ) ) {
1232 add_submenu_page(
1233 'analytify-dashboard',
1234 ANALYTIFY_NICK . esc_html__( ' License', 'wp-analytify' ),
1235 esc_html__( 'License', 'wp-analytify' ),
1236 'manage_options',
1237 'analytify-settings#wp-analytify-license',
1238 array(
1239 $this,
1240 'pa_page_file_path',
1241 ),
1242 60
1243 );
1244 }
1245
1246 add_submenu_page(
1247 'analytify-dashboard',
1248 ANALYTIFY_NICK . esc_html__( ' list of all Add-ons', 'wp-analytify' ),
1249 esc_html__( 'Add-ons', 'wp-analytify' ),
1250 'manage_options',
1251 'analytify-addons',
1252 array(
1253 $this,
1254 'pa_page_file_path',
1255 ),
1256 65
1257 );
1258
1259 add_submenu_page(
1260 'analytify-dashboard',
1261 ANALYTIFY_NICK . esc_html__( ' FREE vs PRO', 'wp-analytify' ),
1262 esc_html__( 'FREE vs PRO', 'wp-analytify' ),
1263 'manage_options',
1264 'analytify-go-pro',
1265 array(
1266 $this,
1267 'pa_page_file_path',
1268 ),
1269 70
1270 );
1271
1272 // Promo page (will not appear in side menu).
1273 add_submenu_page( 'analytify-dashboard', esc_html__( 'Analytify Promo', 'wp-analytify' ), null, 'manage_options', 'analytify-promo', array( $this, 'addons_promo_screen' ) );
1274 }
1275
1276 /**
1277 * Get current screen details
1278 *
1279 * @return void
1280 */
1281 public function pa_page_file_path() {
1282 $screen = get_current_screen();
1283
1284 if ( strpos( $screen->base, 'analytify-settings' ) !== false ) {
1285 $version = defined( 'ANALYTIFY_PRO_VERSION' ) ? ANALYTIFY_PRO_VERSION : ANALYTIFY_VERSION;
1286
1287 echo '<div class="wrap"><h2 style="display: none;"></h2></div>
1288
1289 <div class="wpanalytify"><div class="wpb_plugin_wraper">
1290
1291 <div class="wpb_plugin_header_wraper">
1292 <div class="graph"></div>
1293
1294 <div class="wpb_plugin_header">
1295
1296 <div class="wpb_plugin_header_title"></div>
1297
1298 <div class="wpb_plugin_header_info">
1299 <a href="https://analytify.io/changelog/" target="_blank" class="btn">View Changelog</a>
1300 </div>
1301 <div class="wpb_plugin_header_logo">
1302 <img src="' . esc_url( plugins_url( 'assets/img/logo.svg', __FILE__ ) ) . '" alt="Analytify">
1303 </div>
1304 </div></div><div class="analytify-settings-body-container"><div class="wpb_plugin_body_wraper"><div class="wpb_plugin_body">';
1305 // Initialize settings before rendering.
1306 $this->settings->set_sections( $this->settings->get_settings_sections() );
1307 $this->settings->set_fields( $this->settings->get_settings_fields() );
1308 $this->settings->rendered_settings();
1309 $this->settings->show_tabs();
1310 echo '<div class="wpb_plugin_tabs_content">';
1311 $this->settings->show_forms();
1312 echo '</div>';
1313
1314 echo '</div></div></div></div>';
1315
1316 } elseif ( strpos( $screen->base, 'analytify-dashboard' ) !== false ) {
1317 // Restrict authors from accessing main dashboard - redirect to Authors dashboard.
1318 $current_user = wp_get_current_user();
1319 $is_author_only = $current_user && in_array( 'author', (array) $current_user->roles, true ) && ! in_array( 'administrator', (array) $current_user->roles, true );
1320
1321 if ( $is_author_only ) {
1322 // Redirect authors to their Authors dashboard.
1323 wp_safe_redirect( admin_url( 'admin.php?page=analytify-authors' ) );
1324 exit;
1325 }
1326
1327 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading URL parameter for display purposes
1328 if ( isset( $_GET['show'] ) ) {
1329 do_action( 'show_detail_dashboard_content' );
1330 } else {
1331 require_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytics-dashboard.php';
1332 }
1333 } elseif ( strpos( $screen->base, 'analytify-optin' ) !== false ) {
1334 require_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytify-optin-form.php';
1335 } elseif ( strpos( $screen->base, 'analytify-addons' ) !== false ) {
1336 require_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/page-addons.php';
1337 } elseif ( strpos( $screen->base, 'analytify-woocommerce' ) !== false ) {
1338 // WooCommerce page - this might not exist, let's check if file exists first.
1339 $woo_file = WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytify-woocommerce.php';
1340 if ( file_exists( $woo_file ) ) {
1341 require_once $woo_file;
1342 }
1343 } elseif ( strpos( $screen->base, 'analytify-logs' ) !== false ) {
1344 include_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/page-logs.php';
1345 } elseif ( strpos( $screen->base, 'analytify-go-pro' ) !== false ) {
1346 include_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytify-go-pro.php';
1347 } elseif ( isset( $_GET['show'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading URL parameter for display purposes
1348 do_action( 'show_detail_dashboard_content' );
1349 } else {
1350 // Dequeue event calendar js.
1351 wp_dequeue_script( 'tribe-common' );
1352 wp_dequeue_script( 'mcw-crypto-common' );
1353 include_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytics-dashboard.php';
1354 }
1355 }
1356
1357 // ========================================.
1358 // ADMIN MENU & PAGE ROUTING END.
1359 // ========================================.
1360
1361 /**
1362 * Render optin page
1363 *
1364 * @return void
1365 */
1366 public function render_optin() {
1367 require_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytify-optin-form.php';
1368 }
1369
1370 // Functions moved to Promotions && Analytics_Reports components.
1371
1372 /**
1373 * Process logout && clear stored options.
1374 *
1375 * @return void
1376 */
1377 public function logout() {
1378 if ( isset( $_POST['wp_analytify_log_out'] ) && isset( $_POST['analytify_analytics_logout_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['analytify_analytics_logout_nonce'] ) ), 'analytify_analytics_logout' ) ) {
1379 delete_option( 'pt_webprofile' );
1380 delete_option( 'pt_webprofile_dashboard' );
1381 delete_option( 'pt_webprofile_url' );
1382 delete_option( 'pa_google_token' );
1383 delete_option( 'post_analytics_token' );
1384 delete_option( 'hide_profiles' );
1385 delete_option( 'analytify-ga4-streams' );
1386 delete_option( 'analytify_tracking_property_info' );
1387 delete_option( 'analytify_reporting_property_info' );
1388 delete_option( 'analytify_ga4_exception' );
1389 delete_option( 'analytify_ga4_exceptions' );
1390 delete_option( 'profiles_list_summary' );
1391 delete_option( 'analytify_ga_properties_list' );
1392 delete_option( 'wp-analytify-mode' );
1393 delete_option( 'analytify-deprecated-auth' );
1394 delete_option( 'analytify-ga-properties-summery' );
1395 delete_option( 'analytify_profile_exception' );
1396 delete_option( 'profiles_list_summary_backup' );
1397 delete_transient( 'analytify_quota_exception' );
1398
1399 $_analytify_profile = get_option( 'wp-analytify-profile' );
1400 if ( $_analytify_profile ) {
1401 unset( $_analytify_profile['hide_profiles_list'], $_analytify_profile['profile_for_posts'], $_analytify_profile['profile_for_dashboard'] );
1402 update_option( 'wp-analytify-profile', $_analytify_profile );
1403 }
1404
1405 $update_message = sprintf( // translators: Login again notice.
1406 esc_html__( '%1$s %2$s %3$s Authentication Cleared login again. %4$s %5$s %6$s', 'wp-analytify' ),
1407 '<div id="setting-error-settings_updated" class="updated notice is-dismissible settings-error below-h2">',
1408 '<p>',
1409 '<strong>',
1410 '</strong>',
1411 '</p>',
1412 '</div>'
1413 );
1414 }
1415 }
1416
1417 /**
1418 * Used to add query args that need to be removed from url
1419 *
1420 * @since 5.0.6
1421 * @param mixed $args_array The arguments array to process.
1422 * @return array
1423 */
1424 public function Analytify_remove_query( $args_array ) {
1425 $analytify_args_to_remove = array( 'analytify-cache' );
1426 $args_array = array_merge( $args_array, $analytify_args_to_remove );
1427 return $args_array;
1428 }
1429
1430 /**
1431 * Trigger logging cleanup using the logging class.
1432 *
1433 * Uses guarded logger (null-safe) to avoid fatal if logger unavailable.
1434 *
1435 * @since 2.1.23
1436 * @version 9.0.0
1437 * @return void
1438 */
1439 public static function analytify_cleanup_logs() {
1440 $logger = function_exists( 'analytify_get_logger' ) ? analytify_get_logger() : null;
1441 if ( class_exists( 'QM' ) ) {
1442 QM::info( 'Analytify: Starting cleanup of expired logs.' );
1443 }
1444
1445 if ( $logger && is_callable( array( $logger, 'clear_expired_logs' ) ) ) {
1446 $logger->clear_expired_logs();
1447 if ( class_exists( 'QM' ) ) {
1448 QM::info( 'Analytify: Expired logs cleared successfully.' );
1449 }
1450 }
1451 }
1452
1453
1454
1455
1456 // ========================================.
1457 // PROFILE & SETTINGS MANAGEMENT START.
1458 // ========================================.
1459
1460 // Functions moved to Profile_Management && GA4_Property_Management components.
1461
1462 // ========================================.
1463 // PROFILE & SETTINGS MANAGEMENT END.
1464 // ========================================.
1465
1466 // Black Friday Deal Notice function moved to Promotions component.
1467
1468 // Function moved to Promotions component.
1469
1470 // Winter Sale promo function moved to Promotions component.
1471
1472 // Winter Sale dismiss notice function moved to Promotions component.
1473
1474 // Rating icon function moved to Promotions component.
1475
1476 // ========================================.
1477 // GDPR COMPLIANCE & META BOXES START.
1478 // ========================================.
1479
1480 // Functions add_exclusion_meta_box && print_exclusion_meta_box moved to GDPR_Compliance component.
1481
1482 // ========================================.
1483 // GDPR COMPLIANCE & META BOXES END.
1484 // ========================================.
1485
1486 /**
1487 * Init the compliance class.
1488 *
1489 * @return void
1490 */
1491 public function init_gdpr_compliance() {
1492 if ( class_exists( 'Class_Analytify_GDPR_Compliance' ) ) {
1493 new Class_Analytify_GDPR_Compliance();
1494 }
1495 }
1496
1497 /**
1498 * Get a component from the loader
1499 *
1500 * @param string $component_name The name of the component to get.
1501 * @return mixed|null The component instance or null if not found
1502 */
1503 public function get_component( $component_name ) {
1504 if ( $this->loader && method_exists( $this->loader, 'get_component' ) ) {
1505 return $this->loader->get_component( $component_name );
1506 }
1507 return null;
1508 }
1509
1510 /**
1511 * Check if a component is loaded
1512 *
1513 * @param string $component_name The name of the component to check.
1514 * @return bool True if component is loaded, false otherwise
1515 */
1516 public function has_component( $component_name ) {
1517 if ( $this->loader && method_exists( $this->loader, 'has_component' ) ) {
1518 return $this->loader->has_component( $component_name );
1519 }
1520 return false;
1521 }
1522
1523 // Welcome message function moved to Promotions component.
1524
1525 /**
1526 * Show promo screen for addons
1527 *
1528 * @return void
1529 */
1530 public function addons_promo_screen() {
1531 include WP_ANALYTIFY_PLUGIN_DIR . '/views/default/admin/addons-promo.php';
1532 }
1533 }
1534 } // End if class_exists check.
1535
1536 // ========================================.
1537 // MAIN PLUGIN CLASS DEFINITION END.
1538 // ========================================.
1539
1540 /**
1541 * Create instance of wp-analytify class.
1542 *
1543 * @return void
1544 */
1545 function analytify_free_instance() {
1546 $GLOBALS['WP_ANALYTIFY'] = WP_Analytify::get_instance();
1547 }
1548 add_action( 'plugins_loaded', 'analytify_free_instance', 10 );
1549
1550 // ========================================.
1551 // PLUGIN INSTANCE INITIALIZATION END.
1552 // ========================================.
1553
1554 /**
1555 * AJAX callback function for performing a factory reset of Analytify plugin settings
1556 *
1557 * This function handles the secure AJAX request to reset all Analytify settings
1558 * to their default values. It includes security checks, capability verification,
1559 * and proper error handling.
1560 *
1561 * @hook wp_ajax_analytify_factory_reset
1562 * @since 8.0.0
1563 * @return void Sends JSON response indicating success or failure
1564 */
1565 function analytify_factory_reset_callback() {
1566 // Verify the nonce for security - prevents CSRF attacks.
1567 check_ajax_referer( 'analytify_factory_reset_nonce', 'nonce' );
1568
1569 // Check if current user has administrative capabilities.
1570 if ( ! current_user_can( 'manage_options' ) ) {
1571 wp_send_json_error( 'Unauthorized' );
1572 }
1573
1574 // Load the factory reset class if not already available.
1575 if ( ! class_exists( 'Analytify_Factory_Reset' ) ) {
1576 require_once plugin_dir_path( __FILE__ ) . 'classes/analytify-factory-reset.php';
1577 }
1578
1579 // Initialize the reset class and execute the reset process.
1580 $reset = new Analytify_Factory_Reset();
1581 $reset->remove_settings();
1582
1583 // Send success response to the AJAX request.
1584 wp_send_json_success();
1585 }
1586
1587 /**
1588 * Hook the factory reset function to WordPress AJAX handlers
1589 *
1590 * This registers the function for both privileged (admin) and non-privileged users,
1591 * but the capability check inside the function will restrict access to admins only.
1592 */
1593 add_action( 'wp_ajax_analytify_factory_reset', 'analytify_factory_reset_callback' );
1594