PluginProbe
Analytify – Google Analytics Dashboard For WordPress (GA4 analytics tracking) / 9.1.1
Analytify – Google Analytics Dashboard For WordPress (GA4 analytics tracking) v9.1.1
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.1.1, at wp-analytify.php

1,937 lines 63.9 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.1.1
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 if ( ! defined( 'ABSPATH' ) ) {
19 exit;
20 }
21
22 if ( ! function_exists( 'wa_wpb78834179' ) ) {
23 /**
24 * Create a helper function for easy SDK access.
25 *
26 * @return mixed
27 */
28 function wa_wpb78834179() {
29 global $wa_wpb78834179;
30
31 if ( ! isset( $wa_wpb78834179 ) || ! is_array( $wa_wpb78834179 ) ) {
32 require_once __DIR__ . '/lib/wpb-sdk/start.php';
33
34 /**
35 * Initialize WPB SDK.
36 *
37 * @phpstan-ignore-next-line
38 */
39 $wa_wpb78834179 = wpb_sdk_dynamic_init(
40 array(
41 'id' => '7',
42 'slug' => 'wp-analytify',
43 'type' => 'plugin',
44 'plugin_file' => __FILE__,
45 'sdk_views_dir' => __DIR__ . '/lib/wpb-sdk/views',
46 'public_key' => '1|4aOA8EuyIN4pi2miMvC23LLpnHbBZFNki9R9pVmwd673d3c8',
47 'secret_key' => 'sk_b36c525848fee035',
48 'is_premium' => false,
49 'has_addons' => false,
50 'has_paid_plans' => false,
51 'optin_user_meta' => array(
52 'token' => '_analytify_verification_token',
53 'email_verified' => '_analytify_email_verified',
54 ),
55 'lifecycle' => array(
56 'class' => 'Analytify_Plugin_Lifecycle',
57 'bootstrap_files' => array(
58 'inc/analytify-constants.php',
59 'inc/plugin-lifecycle.php',
60 ),
61 'uninstall_requires' => 'classes/analytify-utils.php',
62 'constructor_args' => array( null ),
63 ),
64 'telemetry' => array(
65 'user_info_format' => 'laravel',
66 'optout_submit_key' => 'analytify-submit-optout',
67 ),
68 'optin' => array(
69 'option_name' => '_analytify_optin',
70 'verify_query_arg' => 'wp-analytify_optin_verify',
71 'settings_page' => 'analytify-settings',
72 'optin_page' => 'analytify-optin',
73 'use_site_option' => true,
74 'guard_pages' => array(
75 'analytify-settings',
76 'analytify-dashboard',
77 'analytify-pmpro',
78 'analytify-learndash',
79 'analytify-lifterlms',
80 'analytify-woocommerce',
81 'analytify-addons',
82 ),
83 ),
84 'menu' => array(
85 'slug' => 'wp-analytify',
86 'account' => false,
87 'support' => false,
88 ),
89 'settings' => array(
90 'wp_analytify_modules' => '',
91 'wp-analytify-tracking' => '',
92 'wp-analytify-email' => '',
93 'wp-analytify-events-tracking' => '',
94 'wp-analytify-front' => '',
95 'wp-analytify-custom-dimensions' => '',
96 'wp-analytify-forms' => '',
97 'analytify_widget_date_differ' => '',
98 'wp-analytify-profile' => '',
99 'wp-analytify-admin' => '',
100 'wp-analytify-dashboard' => '',
101 'wp-analytify-advanced' => '',
102 'analytify_ua_code' => '',
103 'analytify_date_differ' => '',
104 'wp_analytify_review_dismiss' => '',
105 'analytify_date_start' => '',
106 'analytify_date_end' => '',
107 'wp_analytify_review_dismiss_4_1_8' => '',
108 'wpanalytify_settings' => '',
109 'analytify_license_key' => '',
110 'analytify_license_status' => '',
111 'analytify_campaigns_license_status' => '',
112 'analytify_campaigns_license_key' => '',
113 'analytify_goals_license_status' => '',
114 'analytify_goals_license_key' => '',
115 'Analytify_Addon_Forms_license_status' => '',
116 'analytify_forms_license_key' => '',
117 'analytify_authors_license_status' => '',
118 'analytify_authors_license_key' => '',
119 'analytify_woo_license_status' => '',
120 'analytify_woo_license_key' => '',
121 'analytify_email_license_status' => '',
122 'analytify_email_license_key' => '',
123 'analytify-google-ads-tracking' => '',
124 '_analytify_optin' => '',
125 'analytify_cache_timeout' => '',
126 'analytify_csv_data' => '',
127 'analytify_active_date' => '',
128 'analytify_edd_license_status' => '',
129 'analytify_edd_license_key' => '',
130 '_transient_timeout_analytify_api_addons' => '',
131 '_transient_analytify_api_addons' => '',
132 'analytify_ga4_exceptions' => '',
133 'analytify-ga-properties-summery' => '',
134 'analytify_ga4-streams' => '',
135 'analytify_tracking_property_info' => '',
136 'analytify_reporting_property_info' => '',
137 'analytify_gtag_move_to_notice' => '',
138 'analytify_current_version' => '',
139 'analytify_logs_setup' => '',
140 'analytify_pro_default_settings' => '',
141 'analytify_pro_active_date' => '',
142 'analytify_pro_upgrade_routine' => '',
143 'analytify_pro_current_version' => '',
144 'WP_ANALYTIFY_PRO_PLUGIN_VERSION' => '',
145 'wp-analytify-license' => '',
146 'analytify_authentication_date' => '',
147 'WP_ANALYTIFY_PLUGIN_VERSION_OLD' => '',
148 'WP_ANALYTIFY_PRO_PLUGIN_VERSION_OLD' => '',
149 'analytify_default_settings' => '',
150 'analytify_free_upgrade_routine' => '',
151 'WP_ANALYTIFY_PLUGIN_VERSION' => '',
152 'wp_analytify_active_time' => '',
153 'wp-analytify-authentication' => '',
154 'wp-analytify-help' => '',
155 'WP_ANALYTIFY_NEW_LOGIN' => '',
156 'profiles_list_summary' => '',
157 'pa_google_token' => '',
158 'post_analytics_token' => '',
159 ),
160 )
161 );
162 }
163
164 return $wa_wpb78834179;
165 }
166
167 wa_wpb78834179();
168 do_action( 'wa_wpb78834179_loaded' );
169 }
170
171 require_once __DIR__ . '/inc/analytify-constants.php';
172
173 if ( ! class_exists( 'Analytify_General' ) ) {
174 require_once 'analytify-general.php';
175 }
176
177 if ( ! class_exists( 'WP_Analytify' ) ) {
178 /**
179 * Main WP_Analytify class.
180 *
181 * @since 1.0.0
182 */
183 // phpcs:ignore Universal.Files.SeparateFunctionsFromOO.Mixed,Squiz.Commenting.ClassComment.Missing
184 class WP_Analytify extends Analytify_General {
185
186 /**
187 * Plugin instance.
188 *
189 * @var WP_Analytify $instance The one true WP_Analytify
190 * @since 1.2.2
191 */
192 private static $instance = null;
193
194 /**
195 * Token data.
196 *
197 * @var mixed
198 */
199 public $token = false;
200 /**
201 * Client instance.
202 *
203 * @var mixed
204 */
205 public $client = null;
206
207 /**
208 * Post stats disable flag.
209 *
210 * @var mixed
211 */
212 protected $disable_post_stats;
213
214 /**
215 * Settings data.
216 *
217 * @var mixed
218 */
219 public $settings;
220
221 /**
222 * Component loader instance
223 *
224 * @var Analytify_Loader
225 */
226 private $loader;
227
228 /**
229 * Measurement ID for gtag when consent-deferred (any CMP that opts in via filters).
230 *
231 * @var string|null
232 */
233 private $consent_deferred_gtag_ua_code = null;
234
235 /**
236 * Whether the wp_footer handler for consent-deferred gtag was registered.
237 *
238 * @var bool
239 */
240 private $consent_deferred_gtag_hooked = false;
241
242 /**
243 * Filter applied to deferred gtag markup ({@see 'analytify_ga_script'} or {@see 'analytify_gtag_script'}).
244 *
245 * @var string
246 */
247 private $consent_deferred_gtag_filter = 'analytify_ga_script';
248
249 /**
250 * When true, {@see self::output_gtag_code()} emits immediate async gtag only (for footer base64 payload).
251 *
252 * @var bool
253 */
254 private $output_gtag_for_footer_payload = false;
255
256 // ========================================.
257 // CONSTRUCTOR & CORE METHODS START.
258 // ========================================.
259
260 /**
261 * Constructor.
262 *
263 * @since 1.2.2
264 */
265 public function __construct() {
266 parent::__construct();
267 $this->setup_constants();
268 $this->includes();
269 $this->disable_post_stats = $this->settings->get_option( 'enable_back_end', 'wp-analytify-admin' );
270 $this->hooks();
271 }
272
273 /**
274 * Get active instance.
275 *
276 * @access public
277 * @since 1.2.2
278 * @return object self::$instance The one true WP_Analytify
279 */
280 public static function get_instance() {
281 if ( ! self::$instance ) {
282 self::$instance = new WP_Analytify();
283 }
284
285 return self::$instance;
286 }
287
288 /**
289 * Setup plugin constants
290 *
291 * @access private
292 * @since 1.2.2
293 * @return void
294 */
295 private function setup_constants() {
296
297 $upload_dir = wp_upload_dir( null, false );
298 }
299
300 /**
301 * Define constant if not already set
302 *
303 * @since 1.2.4
304 * @param string $name contanst name.
305 * @param string|bool $value constant value.
306 * @return void
307 */
308 private function define( $name, $value ) {
309 if ( ! defined( $name ) ) {
310 define( $name, $value );
311 }
312 }
313
314 /**
315 * What type of request is this?
316 *
317 * @since 1.2.4
318 * @param string $type ajax, frontend or admin.
319 * @return bool
320 */
321 private function is_request( $type ) {
322 switch ( $type ) {
323 case 'admin':
324 return is_admin();
325 case 'ajax':
326 return defined( 'DOING_AJAX' );
327 case 'cron':
328 return defined( 'DOING_CRON' );
329 case 'frontend':
330 return ( ! is_admin() || defined( 'DOING_AJAX' ) ) && ! defined( 'DOING_CRON' );
331 default:
332 return false;
333 }
334 }
335
336
337 /**
338 * Include necessary files
339 *
340 * @access private
341 * @since 1.2.2
342 * @return void
343 */
344 private function includes() {
345 $files = array(
346 WP_ANALYTIFY_LIB_PATH . 'logs/class-analytify-log-handler-interface.php',
347 WP_ANALYTIFY_LIB_PATH . 'logs/class-analytify-logger-interface.php',
348 WP_ANALYTIFY_LIB_PATH . 'logs/class-analytify-log-levels.php',
349 WP_ANALYTIFY_LIB_PATH . 'logs/class-analytify-logger.php',
350 WP_ANALYTIFY_LIB_PATH . 'logs/abstract-analytify-log-handler.php',
351 WP_ANALYTIFY_LIB_PATH . 'logs/class-analytify-log-handler-file.php',
352 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-logs.php',
353 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-sanitize.php',
354 WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytify-core-functions.php',
355 WP_ANALYTIFY_PLUGIN_DIR . '/inc/class-analytify-adminbar.php',
356 WP_ANALYTIFY_PLUGIN_DIR . '/classes/abstracts/analytify-report-abstract.php',
357 WP_ANALYTIFY_PLUGIN_DIR . '/classes/abstracts/analytify-host-analytics-abstract.php',
358 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-host-analytics.php',
359 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-report-core.php',
360 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-rest-api.php',
361 WP_ANALYTIFY_PLUGIN_DIR . '/inc/class-analytify-ajax.php',
362 WP_ANALYTIFY_PLUGIN_DIR . '/inc/class-analytify-post-columns.php',
363 WP_ANALYTIFY_PLUGIN_DIR . '/classes/class-wp-analytify-compatibility-upgrade.php',
364 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-dashboard-widget.php',
365 WP_ANALYTIFY_PLUGIN_DIR . '/classes/class-analytify-user-optout.php',
366 WP_ANALYTIFY_PLUGIN_DIR . '/classes/class-analytify-gdpr-compliance.php',
367 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-email.php',
368 WP_ANALYTIFY_PLUGIN_DIR . '/classes/analytify-settings.php',
369 );
370
371 foreach ( $files as $file ) {
372 if ( file_exists( $file ) ) {
373 include_once $file;
374 } else {
375
376 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>';
377 return;
378 }
379 }
380
381 if ( file_exists( WP_ANALYTIFY_PLUGIN_DIR . '/inc/class-analytify-loader.php' ) ) {
382 require_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/class-analytify-loader.php';
383 if ( class_exists( 'Analytify_Loader' ) ) {
384 $this->loader = new Analytify_Loader( $this );
385 }
386 }
387 }
388
389 // ========================================.
390 // CONSTRUCTOR & CORE METHODS END.
391 // ========================================.
392
393 // ========================================.
394 // WordPress HOOKS & ACTIONS START.
395 // ========================================.
396
397 /**
398 * Run action && filter hooks
399 *
400 * @access private
401 * @since 1.2.2
402 * @return void
403 */
404 private function hooks() {
405
406 add_action( 'init', array( $this, 'load_textdomain' ) ); // Hook load_textdomain.
407 add_action( 'admin_init', array( $this, '_save_core_version' ) );
408 add_action( 'admin_init', array( $this, 'wpa_check_authentication' ) );
409 add_action( 'admin_init', array( $this, 'logout' ), 1 );
410 add_filter( 'removable_query_args', array( $this, 'Analytify_remove_query' ) );
411 add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
412
413 add_action( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 4 );
414 add_filter( 'wpb_sdk_plugin_action_links', array( $this, 'wp_analytify_plugin_action_links' ), 10, 3 );
415
416 add_action( 'wp_head', array( $this, 'analytify_add_analytics_code' ) );
417 add_action( 'wp_head', array( $this, 'analytify_add_manual_analytics_code' ) );
418
419 add_filter( 'admin_footer_text', 'wpa_admin_rate_footer_text', 1 );
420 add_action( 'admin_footer', 'wpa_print_js', 25 );
421
422 add_action( 'admin_init', array( $this, 'redirect_optin' ) );
423 add_action( 'admin_init', array( $this, 'block_subscriber_analytify_access' ) );
424
425 add_action( 'analytify_cleanup_logs', array( $this, 'analytify_cleanup_logs' ) );
426 add_action(
427 'init',
428 function () {
429 if ( WPANALYTIFY_Utils::get_option( 'locally_host_analytics', 'wp-analytify-advanced', false ) && ! wp_next_scheduled( 'analytify_analytics_lib_cron' ) ) {
430 wp_schedule_event( time(), 'daily', 'analytify_analytics_lib_cron' );
431 }
432 }
433 );
434
435 add_action(
436 'analytify_analytics_lib_cron',
437 function () {
438 if ( class_exists( 'Analytify_Host_Analytics' ) ) {
439 new Analytify_Host_Analytics( 'gtag', true );
440 }
441 }
442 );
443 }
444
445 /**
446 * Redirect to Welcome page.
447 *
448 * @since 2.0.14
449 * @return void
450 */
451 public function redirect_optin() {
452 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading URL parameter for display purposes
453 $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
454
455 if ( $page && ( 'analytify-settings' === $page || 'analytify-dashboard' === $page || 'analytify-pmpro' === $page || 'analytify-learndash' === $page || 'analytify-lifterlms' === $page || 'analytify-woocommerce' === $page || 'analytify-addons' === $page ) ) {
456 if ( ! get_site_option( '_analytify_optin' ) ) {
457 wp_safe_redirect( admin_url( 'admin.php?page=analytify-optin' ) );
458 exit;
459 }
460 }
461 }
462
463
464 /**
465 * Internationalization.
466 *
467 * @access public
468 * @since 1.2.2
469 * @return void
470 */
471 public function load_textdomain() {
472 $plugin_dir = basename( __DIR__ );
473 load_plugin_textdomain( 'wp-analytify', false, $plugin_dir . '/languages/' );
474 }
475
476 /**
477 *
478 * Save Authentication code on return
479 * && nonce verification
480 *
481 * @return void
482 */
483 public function wpa_check_authentication() {
484
485 $state = isset( $_GET['state'] ) ? json_decode( urldecode( sanitize_text_field( wp_unslash( $_GET['state'] ) ) ), true ) : null;
486
487 if ( isset( $_GET['code'] ) && isset( $_GET['page'] ) && 'analytify-settings' === sanitize_text_field( wp_unslash( $_GET['page'] ) ) ) {
488 $get_nonce = isset( $_GET['nonce'] ) ? sanitize_text_field( wp_unslash( $_GET['nonce'] ) ) : null;
489 $nonce = isset( $state['nonce'] ) ? $state['nonce'] : $get_nonce;
490
491 if ( wp_verify_nonce( $nonce, 'analytify_analytics_login' ) ) {
492
493 $key_google_token = sanitize_text_field( wp_unslash( $_GET['code'] ) );
494 update_option( 'WP_ANALYTIFY_NEW_LOGIN', 'yes' );
495 delete_transient( 'analytify_google_userinfo_probe_skip' );
496 self::pt_save_data( $key_google_token );
497 wp_safe_redirect( admin_url( 'admin.php?page=analytify-settings' ) . '#wp-analytify-profile' );
498 exit;
499
500 } else {
501 $plugin_page_url = admin_url( 'plugins.php' );
502 wp_die(
503 sprintf( // translators: Nonce verification failed.
504 esc_html__( 'Sorry, you are not allowed as nonce verification failed. %1$sClick here to return to the Dashboard%2$s.', 'wp-analytify' ),
505 '<a href="' . esc_url( $plugin_page_url ) . '">',
506 '</a>'
507 )
508 );
509 }
510 }
511 }
512
513 /**
514 * Save version number of the plugin && show a custom message for users
515 *
516 * @since 1.3
517 * @return void
518 */
519 public function _save_core_version() { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore -- Underscore prefix is intentional for internal method
520 if ( ANALYTIFY_VERSION !== get_option( 'WP_ANALYTIFY_PLUGIN_VERSION' ) ) {
521 update_option( 'WP_ANALYTIFY_PLUGIN_VERSION_OLD', get_option( 'WP_ANALYTIFY_PLUGIN_VERSION' ), true ); // saving old plugin version.
522 update_option( 'WP_ANALYTIFY_PLUGIN_VERSION', ANALYTIFY_VERSION );
523 }
524 }
525
526
527
528
529
530 // ========================================.
531 // GOOGLE ANALYTICS TRACKING CODE START.
532 // ========================================.
533
534 /**
535 * Add Google Analytics JS code
536 *
537 * @since 1.0.0
538 * @version 7.0.4
539 * @return bool|void Returns false if tracking is blocked/skipped, true if code is output, void otherwise.
540 */
541 public function analytify_add_analytics_code() {
542 if ( WPANALYTIFY_Utils::skip_page_tracking() ) {
543 return false;
544 }
545
546 // Check for GDPR compliance.
547 if ( Analytify_GDPR_Compliance::is_gdpr_compliance_blocking() ) {
548 return false;
549 }
550
551 if ( 'on' === $this->settings->get_option( 'install_ga_code', 'wp-analytify-profile', 'off' ) ) {
552 global $current_user;
553
554 $roles = $current_user->roles;
555
556 if ( isset( $roles[0] ) && in_array( $roles[0], $this->settings->get_option( 'exclude_users_tracking', 'wp-analytify-profile', array() ), true ) ) {
557 echo '<!-- This user is disabled from tracking by Analytify !-->';
558 return false;
559 } else {
560 if ( ! $this->settings->get_option( 'profile_for_posts', 'wp-analytify-profile' ) ) {
561 return false;
562 }
563
564 $ua_code = WP_ANALYTIFY_FUNCTIONS::get_UA_code();
565
566 // Validate UA code before outputting tracking code.
567 if ( empty( $ua_code ) ) {
568 // Add a comment in HTML for debugging.
569 echo '<!-- Analytify: No tracking code - check profile selection or OAuth connection -->';
570 return false;
571 }
572
573 if ( 'gtag' === WP_ANALYTIFY_TRACKING_MODE && $this->maybe_schedule_consent_deferred_gtag( $ua_code, 'analytify_ga_script' ) ) {
574 return false;
575 }
576
577 if ( 'gtag' === WP_ANALYTIFY_TRACKING_MODE ) {
578 $ga_code = $this->output_gtag_code( $ua_code );
579 } else {
580 $ga_code = $this->output_ga_code( $ua_code );
581 }
582
583 echo apply_filters( 'analytify_ga_script', $ga_code ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JavaScript code needs to be output directly
584 return true;
585 }
586 }
587 }
588
589 /**
590 * Add Google Manual Analytics JS code
591 *
592 * @return void
593 */
594 public function analytify_add_manual_analytics_code() {
595 if ( get_option( 'pa_google_token' ) ) {
596 return;
597 }
598
599 $manual_ua_code = $this->settings->get_option( 'manual_ua_code', 'wp-analytify-authentication', false );
600
601 if ( ! $manual_ua_code ) {
602 return;
603 }
604
605 if ( class_exists( 'WPANALYTIFY_Utils' ) && WPANALYTIFY_Utils::skip_page_tracking() ) {
606 return;
607 }
608
609 if ( Analytify_GDPR_Compliance::is_gdpr_compliance_blocking() ) {
610 return;
611 }
612
613 global $current_user;
614 $roles = $current_user->roles;
615
616 if ( in_array( 'administrator', $roles, true ) ) {
617 echo '<!-- This user is disabled from tracking by Analytify !-->';
618 } elseif ( apply_filters( 'analytify_manaul_ga_script', false ) ) {
619 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
620 } elseif ( $this->maybe_schedule_consent_deferred_gtag( $manual_ua_code, 'analytify_gtag_script' ) ) {
621 return;
622 } else {
623 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
624 }
625 }
626
627 /**
628 * Schedule gtag for wp_footer when consent-deferred mode is on (any compatible cookie plugin).
629 *
630 * @since 9.0.0
631 * @param string $ua_code Measurement ID (or legacy property id).
632 * @param string $result_filter Filter name for the deferred markup.
633 * @return bool True when deferred (no head output).
634 */
635 private function maybe_schedule_consent_deferred_gtag( $ua_code, $result_filter = 'analytify_ga_script' ) {
636
637 if ( ! class_exists( 'Class_Analytify_GDPR_Compliance' ) ) {
638 return false;
639 }
640
641 if ( ! Class_Analytify_GDPR_Compliance::is_consent_deferred_gtag_enabled() ) {
642 return false;
643 }
644
645 if ( ! defined( 'WP_ANALYTIFY_TRACKING_MODE' ) || 'gtag' !== WP_ANALYTIFY_TRACKING_MODE ) {
646 return false;
647 }
648
649 $ua_code = is_string( $ua_code ) ? trim( $ua_code ) : '';
650 if ( '' === $ua_code ) {
651 return false;
652 }
653
654 $allowed_filters = array( 'analytify_ga_script', 'analytify_gtag_script' );
655 if ( ! in_array( $result_filter, $allowed_filters, true ) ) {
656 $result_filter = 'analytify_ga_script';
657 }
658
659 if ( $this->consent_deferred_gtag_hooked ) {
660 return true;
661 }
662
663 $this->consent_deferred_gtag_filter = $result_filter;
664 $this->consent_deferred_gtag_ua_code = $ua_code;
665 $this->consent_deferred_gtag_hooked = true;
666 add_action( 'wp_footer', array( $this, 'analytify_print_consent_deferred_gtag' ), 1 );
667
668 return true;
669 }
670
671 /**
672 * Print base64 gtag payload and loader for consent-deferred integrations.
673 *
674 * Listens to DOM events from {@see Class_Analytify_GDPR_Compliance::get_consent_ready_dom_events()}
675 * and exposes {@see Class_Analytify_GDPR_Compliance::get_consent_deferred_js_loader_name()} on window.
676 *
677 * @since 9.0.0
678 * @return void
679 */
680 public function analytify_print_consent_deferred_gtag() {
681
682 if ( null === $this->consent_deferred_gtag_ua_code ) {
683 return;
684 }
685
686 if ( class_exists( 'WPANALYTIFY_Utils' ) && WPANALYTIFY_Utils::skip_page_tracking() ) {
687 return;
688 }
689
690 if ( Analytify_GDPR_Compliance::is_gdpr_compliance_blocking() ) {
691 return;
692 }
693
694 global $current_user;
695 $roles = $current_user->roles;
696
697 if ( isset( $roles[0] ) && in_array( $roles[0], $this->settings->get_option( 'exclude_users_tracking', 'wp-analytify-profile', array() ), true ) ) {
698 return;
699 }
700
701 $ua = $this->consent_deferred_gtag_ua_code;
702
703 $this->output_gtag_for_footer_payload = true;
704 $markup = $this->output_gtag_code( $ua );
705 $this->output_gtag_for_footer_payload = false;
706 if ( '' === $markup ) {
707 return;
708 }
709
710 $markup = apply_filters( $this->consent_deferred_gtag_filter, $markup ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core plugin filter.
711
712 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Deferred gtag payload for atob(); not obfuscation.
713 $b64 = base64_encode( $markup );
714
715 $dom_events = class_exists( 'Class_Analytify_GDPR_Compliance' )
716 ? Class_Analytify_GDPR_Compliance::get_consent_ready_dom_events()
717 : array( 'analytifyConsentGranted' );
718
719 $js_global = class_exists( 'Class_Analytify_GDPR_Compliance' )
720 ? Class_Analytify_GDPR_Compliance::get_consent_deferred_js_loader_name()
721 : 'analytifyLoadGtagAfterConsent';
722
723 ?>
724 <script type="text/plain" id="analytify-consent-deferred-gtag-b64" style="display:none;"><?php echo esc_html( $b64 ); ?></script>
725 <script>
726 (function () {
727 var events = <?php echo wp_json_encode( $dom_events ); ?>;
728 var globalName = <?php echo wp_json_encode( $js_global ); ?>;
729 function analytifyConsentDeferredInjectGtag() {
730 if (window.__analytifyConsentDeferredGtagDone) {
731 return;
732 }
733 var el = document.getElementById('analytify-consent-deferred-gtag-b64');
734 if (!el || !el.textContent) {
735 return;
736 }
737 var html;
738 try {
739 html = atob(el.textContent.replace(/\s/g, ''));
740 } catch (e) {
741 return;
742 }
743 window.__analytifyConsentDeferredGtagDone = true;
744 var doc = new DOMParser().parseFromString(html, 'text/html');
745 var nodes = doc.querySelectorAll('script');
746 for (var i = 0; i < nodes.length; i++) {
747 var oldScript = nodes[i];
748 var s = document.createElement('script');
749 if (oldScript.src) {
750 s.src = oldScript.src;
751 s.async = true;
752 } else {
753 s.textContent = oldScript.textContent;
754 }
755 document.head.appendChild(s);
756 }
757 }
758 if (events && events.length) {
759 for (var j = 0; j < events.length; j++) {
760 document.addEventListener(events[j], analytifyConsentDeferredInjectGtag, false);
761 }
762 }
763 if (globalName && typeof globalName === 'string' && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(globalName)) {
764 window[globalName] = analytifyConsentDeferredInjectGtag;
765 }
766 })();
767 </script>
768 <?php
769 }
770
771 /**
772 * Back-compat alias for {@see self::analytify_print_consent_deferred_gtag()}.
773 *
774 * @since 9.0.0
775 * @return void
776 */
777 public function analytify_print_ccv_deferred_gtag() {
778
779 $this->analytify_print_consent_deferred_gtag();
780 }
781
782 /**
783 * Generate gtag code.
784 *
785 * @param string $ua_code Google Analytics UA code.
786 * @since 3.0
787 * @version 9.1.0
788 * @return $gtag_code
789 */
790 private function output_gtag_code( $ua_code ) {
791 ob_start();
792
793 $local_analytics_file = class_exists( 'Analytify_Host_Analytics' ) ? ( new Analytify_Host_Analytics( 'gtag', false ) )->local_analytics_file_url() : false;
794
795 if ( false !== apply_filters( 'analytify_tracking_code_comments', true ) ) {
796 printf( // translators: Tracking code comments.
797 esc_html__( '%2$s This code is added by Analytify (%1$s) %4$s %3$s', 'wp-analytify' ),
798 esc_html( ANALYTIFY_VERSION ),
799 '<!--',
800 '!-->',
801 'https://analytify.io/'
802 );
803 }
804
805 $allow_display_features = ( 'on' === $this->settings->get_option( 'demographic_interest_tracking', 'wp-analytify-advanced' ) ) ? 'true' : 'false';
806 $linker_cross_domain_tracking = ( 'on' === $this->settings->get_option( 'linker_cross_domain_tracking', 'wp-analytify-advanced' ) ) ? true : false;
807 $linked_domains = array();
808
809 if ( $linker_cross_domain_tracking ) {
810 $all_linked_domains = $this->settings->get_option( 'linked_domain', 'wp-analytify-advanced' );
811 $all_linked_domains = trim( $all_linked_domains ? $all_linked_domains : '' );
812
813 if ( ! empty( $all_linked_domains ) ) {
814 $all_linked_domains = str_replace( "'", '', $all_linked_domains );
815 $all_linked_domains = str_replace( '"', '', $all_linked_domains );
816
817 $all_linked_domains = preg_replace( '/\s+/', '', $all_linked_domains );
818
819 $list_linked_domains = explode( ',', $all_linked_domains );
820 $number_of_linked_domains = count( $list_linked_domains );
821
822 if ( $number_of_linked_domains > 0 ) {
823 $linked_domains = array_filter(
824 (array) $list_linked_domains,
825 function ( $value ) {
826 return strlen( $value ) > 0;
827 }
828 );
829 } else {
830 $linked_domains = (array) $all_linked_domains;
831 }
832 } else {
833 $linker_cross_domain_tracking = false;
834 }
835 }
836
837 $configuration = array(
838
839 'allow_display_features' => $allow_display_features,
840 );
841
842 if ( $linker_cross_domain_tracking ) {
843 $configuration['linker'] = array(
844 'domains' => $linked_domains,
845 );
846 }
847
848 $debug_mode = apply_filters( 'analytify_debug_mode', true );
849
850 if ( $debug_mode ) {
851 $configuration['debug_mode'] = true;
852 }
853
854 if ( 'on' === $this->settings->get_option( 'track_user_id', 'wp-analytify-advanced' ) && is_user_logged_in() ) {
855 $configuration['user_id'] = esc_html( (string) get_current_user_id() );
856 }
857
858 $configuration = apply_filters( 'analytify_gtag_configuration', $configuration );
859 $configuration_json = wp_json_encode( $configuration, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT );
860
861 // Build the script src URL correctly.
862 $script_src = $local_analytics_file ?? 'https://www.googletagmanager.com/gtag/js';
863 $script_src .= ( strpos( $script_src, '?' ) !== false ? '&' : '?' ) . 'id=' . esc_attr( $ua_code );
864
865 // Excluded query parameters: strip only these query keys from page_location (path and hash unchanged).
866 $exclude_params = 'on' === $this->settings->get_option( 'exclude_query_params', 'wp-analytify-advanced' );
867 $params_list = $this->settings->get_option( 'query_params_to_exclude', 'wp-analytify-advanced' );
868 $params_list = is_string( $params_list ) ? $params_list : '';
869
870 $js_location_logic = '';
871 if ( $exclude_params && '' !== $params_list ) {
872 $params_array = analytify_query_params_to_exclude_keys_array( $params_list );
873 if ( ! empty( $params_array ) ) {
874 $params_json = wp_json_encode( $params_array );
875
876 // Strip only query keys (case-insensitive); path and hash are not altered; no query string / repeated params are safe.
877 $js_location_logic = "
878 try {
879 var wa_loc = window.location.href;
880 var wa_url = new URL(wa_loc);
881 var wa_params = $params_json;
882 var keysToRemove = [];
883 wa_url.searchParams.forEach(function(val, key) {
884 if (wa_params.indexOf(key.toLowerCase()) !== -1) { keysToRemove.push(key); }
885 });
886 keysToRemove.forEach(function(k) { wa_url.searchParams.delete(k); });
887 configuration.page_location = wa_url.toString();
888 } catch (e) {}
889 ";
890 }
891 }
892
893 $gdpr_class = 'Class_Analytify_GDPR_Compliance';
894 $has_gdpr_class = class_exists( $gdpr_class );
895 $consent_params = $has_gdpr_class ? Class_Analytify_GDPR_Compliance::get_gtag_consent_default_params() : array();
896 $has_consent_line = $has_gdpr_class
897 && Class_Analytify_GDPR_Compliance::should_output_gtag_consent_defaults()
898 && ! empty( $consent_params );
899 $use_defer_gtag = $has_gdpr_class
900 && Class_Analytify_GDPR_Compliance::is_consent_deferred_gtag_enabled()
901 && ! $this->output_gtag_for_footer_payload;
902 $defer_events = $has_gdpr_class ? Class_Analytify_GDPR_Compliance::get_consent_ready_dom_events() : array();
903 if ( $use_defer_gtag && empty( $defer_events ) ) {
904 $use_defer_gtag = false;
905 }
906 $split_gtag_markup = $has_consent_line || $use_defer_gtag;
907 $defer_pageview_cmp = $has_gdpr_class
908 && ! $use_defer_gtag
909 && Class_Analytify_GDPR_Compliance::should_defer_gtag_pageview_until_cmp_consent();
910 $consent_json = wp_json_encode(
911 $consent_params,
912 JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT
913 );
914 $defer_events_json = wp_json_encode( array_values( $defer_events ) );
915 $script_src_json = wp_json_encode( $script_src );
916 $loader_name = $use_defer_gtag ? Class_Analytify_GDPR_Compliance::get_consent_deferred_js_loader_name() : '';
917 ?>
918
919 <?php if ( $split_gtag_markup ) : ?>
920 <script>
921 window.dataLayer = window.dataLayer || [];
922 function gtag(){dataLayer.push(arguments);}
923 <?php if ( $has_consent_line ) : ?>
924 gtag('consent', 'default', <?php echo $consent_json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON from sanitized consent params. ?>);
925 <?php endif; ?>
926 </script>
927 <?php endif; ?>
928
929 <?php if ( ! $use_defer_gtag ) : ?>
930 <?php // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Inline gtag script must be output directly in the page head. ?>
931 <script async src="<?php echo esc_url( $script_src ); ?>"></script>
932 <?php endif; ?>
933
934 <script>
935 <?php if ( ! $split_gtag_markup ) : ?>
936 window.dataLayer = window.dataLayer || [];
937 function gtag(){dataLayer.push(arguments);}
938 <?php endif; ?>
939 <?php if ( ! $use_defer_gtag ) : ?>
940 gtag('js', new Date());
941 <?php endif; ?>
942
943 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. ?>;
944 const gaID = '<?php echo esc_js( $ua_code ); ?>';
945
946 <?php if ( $use_defer_gtag ) : ?>
947 (function() {
948 var gtagSrc = <?php echo $script_src_json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_json_encode() on URL. ?>;
949 var consentEvents = <?php echo $defer_events_json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_json_encode() on validated event names. ?>;
950 var injectFired = false;
951 function analytifyInjectGtagAfterConsent() {
952 if (injectFired) {
953 return;
954 }
955 injectFired = true;
956 var s = document.createElement('script');
957 s.async = true;
958 s.src = gtagSrc;
959 s.onload = function() {
960 gtag('js', new Date());
961 <?php do_action( 'analytify_tracking_code_before_pageview' ); ?>
962 <?php
963 if ( ! empty( $js_location_logic ) ) {
964 echo $js_location_logic; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JS logic constructed internally with safe JSON.
965 }
966 ?>
967 gtag('config', gaID, configuration);
968 <?php
969 if ( $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' ) ) {
970 $custom_js = $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' );
971 if ( ! empty( $custom_js ) ) {
972 echo wp_kses_post( $custom_js );
973 }
974 }
975 do_action( 'ga_ecommerce_js' );
976 do_action( 'analytify_tracking_code_after_pageview' );
977 ?>
978 };
979 document.head.appendChild(s);
980 }
981 if (consentEvents.length) {
982 consentEvents.forEach(function(evName) {
983 document.addEventListener(evName, analytifyInjectGtagAfterConsent);
984 });
985 }
986 <?php if ( '' !== $loader_name ) : ?>
987 window['<?php echo esc_js( $loader_name ); ?>'] = analytifyInjectGtagAfterConsent;
988 <?php endif; ?>
989 })();
990 <?php else : ?>
991 <?php if ( $defer_pageview_cmp ) : ?>
992 (function() {
993 var fired = false;
994 function firePageview() {
995 if (fired) { return; }
996 fired = true;
997 <?php do_action( 'analytify_tracking_code_before_pageview' ); ?>
998 <?php
999 if ( ! empty( $js_location_logic ) ) {
1000 echo $js_location_logic; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JS logic constructed internally with safe JSON.
1001 }
1002 ?>
1003 gtag('config', gaID, configuration);
1004 <?php
1005 if ( $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' ) ) {
1006 $custom_js = $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' );
1007 if ( ! empty( $custom_js ) ) {
1008 echo wp_kses_post( $custom_js );
1009 }
1010 }
1011 do_action( 'ga_ecommerce_js' );
1012 do_action( 'analytify_tracking_code_after_pageview' );
1013 ?>
1014 }
1015 function onAnalyticsGranted() {
1016 gtag('consent', 'update', {
1017 analytics_storage: 'granted',
1018 personalization_storage: 'granted'
1019 });
1020 firePageview();
1021 }
1022 document.addEventListener('cookieyes_consent_update', function(evt) {
1023 var accepted = evt.detail && evt.detail.accepted;
1024 if (accepted && -1 !== accepted.indexOf('analytics')) {
1025 onAnalyticsGranted();
1026 }
1027 });
1028 document.addEventListener('cookieyes_banner_load', function() {
1029 if ('function' === typeof window.getCkyConsent && getCkyConsent().categories.analytics) {
1030 onAnalyticsGranted();
1031 }
1032 });
1033 document.addEventListener('cookielawinfo-consent', onAnalyticsGranted);
1034 })();
1035 <?php else : ?>
1036 <?php do_action( 'analytify_tracking_code_before_pageview' ); ?>
1037 <?php
1038 if ( ! empty( $js_location_logic ) ) {
1039 echo $js_location_logic; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JS logic constructed internally with safe JSON.
1040 }
1041 ?>
1042
1043 gtag('config', gaID, configuration);
1044
1045 <?php
1046 if ( $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' ) ) {
1047 $custom_js = $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' );
1048
1049 if ( ! empty( $custom_js ) ) {
1050 echo wp_kses_post( $custom_js );
1051 }
1052 }
1053
1054 do_action( 'ga_ecommerce_js' );
1055 do_action( 'analytify_tracking_code_after_pageview' );
1056 ?>
1057 <?php endif; ?>
1058 <?php endif; ?>
1059
1060 </script>
1061
1062 <?php
1063 if ( false !== apply_filters( 'analytify_tracking_code_comments', true ) ) {
1064 printf( // translators: Tracking code comments.
1065 esc_html__( '%2$s This code is added by Analytify (%1$s) %3$s', 'wp-analytify' ),
1066 esc_html( ANALYTIFY_VERSION ),
1067 '<!--',
1068 '!-->'
1069 );
1070 }
1071
1072 $gtag_code = ob_get_contents();
1073 ob_end_clean();
1074 return $gtag_code ? $gtag_code : '';
1075 }
1076
1077 /**
1078 * Generate gtag code.
1079 *
1080 * @param string $ua_code Google Analytics UA code.
1081 * @since 3.0
1082 * @return string
1083 */
1084 public function output_ga_code( $ua_code ) {
1085 ob_start();
1086
1087 $src = apply_filters( 'analytify_output_ga_js_src', '//www.google-analytics.com/analytics.js' );
1088
1089 if ( false !== apply_filters( 'analytify_tracking_code_comments', true ) ) {
1090 printf( // translators: Tracking code comments.
1091 esc_html__( '%2$s This code is added by Analytify (%1$s) %4$s %3$s', 'wp-analytify' ),
1092 esc_html( ANALYTIFY_VERSION ),
1093 '<!--',
1094 '!-->',
1095 'https://analytify.io/'
1096 );
1097 }
1098 ?>
1099
1100 <script>
1101 (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
1102 (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
1103 m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
1104 })
1105
1106 (window,document,'script','<?php echo esc_url( $src ); ?>','ga');
1107
1108 <?php
1109 if ( 'on' === $this->settings->get_option( 'linker_cross_domain_tracking', 'wp-analytify-advanced' ) ) {
1110 echo " ga('create', '" . esc_js( $ua_code ) . "', 'auto', {'allowLinker': true});";
1111 echo "ga('require', 'linker');";
1112 } else {
1113 echo " ga('create', '" . esc_js( $ua_code ) . "', 'auto');";
1114 }
1115
1116 if ( 'on' === $this->settings->get_option( 'track_user_id', 'wp-analytify-advanced' ) && is_user_logged_in() ) {
1117 echo "ga('set', 'userId', " . esc_html( (string) get_current_user_id() ) . ');';
1118 }
1119
1120 if ( 'on' === $this->settings->get_option( 'demographic_interest_tracking', 'wp-analytify-advanced' ) ) {
1121 echo "ga('require', 'displayfeatures');";
1122 }
1123
1124 if ( $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' ) ) {
1125
1126 $custom_js = $this->settings->get_option( 'custom_js_code', 'wp-analytify-advanced' );
1127
1128 if ( $custom_js && false !== $custom_js ) {
1129 $custom_js = wp_kses(
1130 $custom_js,
1131 array(
1132 'script' => array(),
1133 'noscript' => array(),
1134 'div' => array(
1135 'id' => array(),
1136 'class' => array(),
1137 ),
1138 'span' => array(
1139 'id' => array(),
1140 'class' => array(),
1141 ),
1142 )
1143 );
1144 echo '<script type="text/javascript">' . esc_js( wp_strip_all_tags( $custom_js ) ) . '</script>';
1145 }
1146 }
1147
1148 do_action( 'ga_ecommerce_js' );
1149 do_action( 'analytify_tracking_code_before_pageview' );
1150 echo "ga('send', 'pageview');";
1151 ?>
1152
1153 </script>
1154
1155 <?php
1156 if ( false !== apply_filters( 'analytify_tracking_code_comments', true ) ) {
1157 printf( // translators: Tracking code comments.
1158 esc_html__( '%2$s This code is added by Analytify (%1$s) %3$s', 'wp-analytify' ),
1159 esc_html( ANALYTIFY_VERSION ),
1160 '<!--',
1161 '!-->'
1162 );
1163 }
1164
1165 $ga_code = ob_get_contents();
1166 ob_end_clean();
1167 return $ga_code ? $ga_code : '';
1168 }
1169
1170 // ========================================.
1171 // GOOGLE ANALYTICS TRACKING CODE END.
1172 // ========================================.
1173
1174
1175 /**
1176 * Adds Analytify-specific action links on the Plugins screen (Settings, Pro notices).
1177 *
1178 * Opt In / Opt Out are registered by the bundled WPB SDK only.
1179 *
1180 * @param array<int|string, string> $links Plugin row action links.
1181 * @param string $slug Product slug from the SDK.
1182 * @param array<string, mixed> $module Module definition from the SDK.
1183 * @return array<int|string, string>
1184 */
1185 public function wp_analytify_plugin_action_links( $links, $slug = '', $module = array() ) {
1186 if ( '' !== $slug && 'wp-analytify' !== $slug ) {
1187 return $links;
1188 }
1189 $settings_link = '';
1190 if ( class_exists( 'WP_Analytify_Pro' ) ) {
1191 // Remove deactivate link if Pro is active, and add a message that it's required by Pro.
1192 $settings_link .= sprintf(
1193 /* translators: %1$s: opening span tag, %2$s: closing span tag. */
1194 esc_html__( '%1$s Required by Analytify Pro %2$s | ', 'wp-analytify' ),
1195 '<span style="color:#32373c">',
1196 '</span>'
1197 );
1198 unset( $links['deactivate'] );
1199 } elseif ( class_exists( 'Analytify_Dashboard_Addon' ) ) {
1200 // Remove deactivate link if Widget is active, and add a message that it's required by Widget.
1201 $settings_link .= sprintf(
1202 /* translators: %1$s: opening span tag, %2$s: closing span tag. */
1203 esc_html__( '%1$s Required by Analytify Dashboard Widget %2$s | ', 'wp-analytify' ),
1204 '<span style="color:#32373c">',
1205 '</span>'
1206 );
1207 unset( $links['deactivate'] );
1208 }
1209
1210 if ( ! class_exists( 'WP_Analytify_Pro' ) ) {
1211 $settings_link .= sprintf(
1212 /* translators: %1$s opening link tag, %2$s closing link tag */
1213 esc_html__( '%1$s Get Analytify Pro %2$s | ', 'wp-analytify' ),
1214 '<a href="' . esc_url( '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;">',
1215 '</a>'
1216 );
1217 }
1218
1219 $settings_link .= sprintf(
1220 /* translators: %1$s opening link tag, %2$s closing link tag */
1221 esc_html__( '%1$s Settings %2$s', 'wp-analytify' ),
1222 '<a href="' . esc_url( admin_url( 'admin.php?page=analytify-settings' ) ) . '">',
1223 '</a>'
1224 );
1225
1226 array_unshift( $links, $settings_link );
1227 return $links;
1228 }
1229
1230 /**
1231 * Plugin row meta links
1232 *
1233 * @since 1.1
1234 * @version 5.0.5
1235 * @param array $input already defined meta links.
1236 * @param string $file plugin file path && name being processed.
1237 * @param array $plugin_data relevent data about the currect plugin.
1238 * @param string $status weather plugin is active or disabled.
1239 * @return array $input
1240 */
1241 public function plugin_row_meta( $input, $file, $plugin_data, $status ) {
1242
1243 $analytify_plugins = array(
1244 'wp-analytify/wp-analytify.php',
1245 'analytify-analytics-dashboard-widget/wp-analytify-dashboard.php',
1246 'wp-analytify-pro/wp-analytify-pro.php',
1247 'wp-analytify-woocommerce/wp-analytify-woocommerce.php',
1248 'wp-analytify-goals/wp-analytify-goals.php',
1249 'wp-analytify-forms/wp-analytify-forms.php',
1250 'wp-analytify-email/wp-analytify-email.php',
1251 'wp-analytify-edd/wp-analytify-edd.php',
1252 'wp-analytify-authors/wp-analytify-authors.php',
1253 );
1254
1255 if ( ! in_array( $file, $analytify_plugins, true ) ) {
1256 return $input;
1257 }
1258
1259 if ( isset( $plugin_data['Author'] ) ) {
1260
1261 $input[1] = sprintf(
1262 'By <a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
1263 esc_url( $plugin_data['AuthorURI'] ),
1264 esc_html( $plugin_data['Author'] )
1265 );
1266
1267 }
1268
1269 if ( 'wp-analytify/wp-analytify.php' !== $file && 'analytify-analytics-dashboard-widget/wp-analytify-dashboard.php' !== $file && in_array( $file, $analytify_plugins, true ) ) {
1270
1271 $input[2] = sprintf(
1272 '<a href="%s" target="_blank" rel="noopener noreferrer">Visit Plugin Site</a>',
1273 esc_url( $plugin_data['PluginURI'] )
1274 );
1275 return $input;
1276
1277 }
1278
1279 $links = array(
1280 sprintf( // translators: Premium features.
1281 esc_html__( '%1$s Explore Premium Features %2$s', 'wp-analytify' ),
1282 '<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">',
1283 '</a>'
1284 ),
1285 );
1286
1287 $input = array_merge( $input, $links );
1288
1289 return $input;
1290 }
1291
1292 /**
1293 * Display warning if profiles are not selected.
1294 *
1295 * @return void
1296 */
1297 public function pa_check_warnings() {
1298 add_action( 'admin_footer', array( &$this, 'profile_warning' ) );
1299 }
1300
1301
1302 // Page routing function moved to Page_Management component.
1303
1304
1305
1306
1307 // ========================================.
1308 // ADMIN ASSETS & STYLING START.
1309 // ========================================.
1310
1311 // Admin styles function moved to Scripts_Styles component.
1312
1313 // Functions moved to Scripts_Styles, Module_Manager && Promotions components.
1314
1315 // ========================================.
1316 // ANALYTICS DATA RETRIEVAL START.
1317 // ========================================.
1318
1319 // Analytics accounts function moved to Analytics_Accounts component.
1320
1321 // Analytics accounts summary function moved to Analytics_Accounts component.
1322
1323 /**
1324 * Get settings URL.
1325 *
1326 * @return string
1327 */
1328 public function pa_setting_url() {
1329 return admin_url( 'admin.php?page=analytify-settings' );
1330 }
1331
1332 /**
1333 * Save Google token data.
1334 *
1335 * @param mixed $key_google_token The Google token data.
1336 * @return bool|void
1337 */
1338 public function pt_save_data( $key_google_token ) {
1339 try {
1340 update_option( 'post_analytics_token', $key_google_token );
1341
1342 if ( $this->analytify_pa_connect_v2() ) {
1343 return true;
1344 }
1345 } catch ( Exception $e ) {
1346 echo esc_html( $e->getMessage() );
1347 }
1348 }
1349
1350 // Profile warning function moved to Promotions component.
1351
1352 // AJAX handler moved to Analytics_Reports component.
1353
1354 // Module state function moved to Module_Manager component.
1355
1356
1357
1358
1359 // ========================================.
1360 // ANALYTICS DATA RETRIEVAL END.
1361 // ========================================.
1362
1363 // Deprecated analytics function moved to Analytics_Reports component.
1364
1365
1366
1367
1368 // ========================================.
1369 // UTILITY & HELPER FUNCTIONS START.
1370 // ========================================.
1371
1372 // Utility functions moved to Utils component.
1373 // Backward compatibility wrappers.
1374 /**
1375 * Format numbers for display.
1376 *
1377 * @param mixed $num The number to format.
1378 * @return string
1379 */
1380 public function wpa_pretty_numbers( $num ) {
1381 return Analytify_Utils::wpa_pretty_numbers( $num );
1382 }
1383
1384 /**
1385 * Format number with proper formatting.
1386 *
1387 * @param mixed $num The number to format.
1388 * @return string
1389 */
1390 public function wpa_number_format( $num ) {
1391 return Analytify_Utils::wpa_number_format( $num );
1392 }
1393
1394 /**
1395 * Format time for display.
1396 *
1397 * @param mixed $time The time to format.
1398 * @return string
1399 */
1400 public function pa_pretty_time( $time ) {
1401 return Analytify_Utils::pa_pretty_time( $time );
1402 }
1403
1404 /**
1405 * Check user access level.
1406 *
1407 * @param mixed $access_level The required access level.
1408 * @return bool
1409 */
1410 public function pa_check_roles( $access_level ) {
1411 return Analytify_Utils::pa_check_roles( $access_level );
1412 }
1413
1414
1415 /**
1416 * Notice to switch gtag.js tracking mode.
1417 *
1418 * @return void
1419 */
1420 // Welcome message function moved to Promotions component.
1421
1422 // ========================================.
1423 // ADMIN MENU & PAGE ROUTING START.
1424 // ========================================.
1425
1426 /**
1427 * Create Analytics menu at the left side of dashboard
1428 *
1429 * @version 9.1.0
1430 * @return void
1431 */
1432 public function add_admin_menu() {
1433 $current_user = wp_get_current_user();
1434
1435 if ( Analytify_Utils::is_subscriber_blocked_from_analytify() ) {
1436 return;
1437 }
1438
1439 $allowed_roles = $this->settings->get_option( 'show_analytics_roles_dashboard', 'wp-analytify-dashboard', array() );
1440 $allowed_roles[] = 'administrator';
1441
1442 $is_author_only = $current_user && in_array( 'author', $current_user->roles, true ) && ! in_array( 'administrator', $current_user->roles, true );
1443
1444 // Determine the capability to use for the dashboard.
1445 // If the user has an allowed role, we use 'read' to ensure they can see the menu,
1446 // since add_admin_menu already restricted registration to allowed roles.
1447 $dashboard_cap = 'manage_options';
1448 if ( array_intersect( $current_user->roles, $allowed_roles ) ) {
1449 $dashboard_cap = 'read';
1450 }
1451
1452 // Allow authors to see the menu (so they can access Authors dashboard submenu).
1453 // But restrict them from accessing main dashboard content.
1454 if ( $is_author_only ) {
1455 // Authors can see menu but will be restricted from main dashboard page.
1456 // They need edit_posts capability to see Authors dashboard.
1457 if ( ! current_user_can( 'edit_posts' ) ) {
1458 return;
1459 }
1460 } elseif ( ! $this->pa_check_roles( $allowed_roles ) ) {
1461 // For non-authors, check normal access.
1462 return;
1463 }
1464
1465 add_submenu_page( 'admin.php', __( 'Activate', 'wp-analytify' ), __( 'Activate', 'wp-analytify' ), 'manage_options', 'analytify-optin', array( $this, 'render_optin' ) );
1466
1467 add_menu_page(
1468 ANALYTIFY_NICK,
1469 'Analytify',
1470 $dashboard_cap,
1471 'analytify-dashboard',
1472 array(
1473 $this,
1474 'pa_page_file_path',
1475 ),
1476 'data:image/svg+xml;base64,' . base64_encode( // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Used for SVG data encoding
1477 '<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"
1478 width="18px" height="18px" viewBox="0 0 18 18" style="enable-background:new 0 0 18 18;" xml:space="preserve">
1479 <style type="text/css">
1480 .st0{fill-rule:evenodd;clip-rule:evenodd;fill:#23282D;}
1481 .st1{fill-rule:evenodd;clip-rule:evenodd;fill:#9EA3A8;}
1482 </style>
1483 <g>
1484 <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
1485 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
1486 s3.4,7.5,7.5,7.5s7.5-3.4,7.5-7.5S13.1,1.5,9,1.5z"/>
1487 <g>
1488 <g>
1489 <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
1490 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
1491 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"/>
1492 </g>
1493 </g>
1494 </g>
1495 </svg>'
1496 ),
1497 2
1498 );
1499
1500 add_submenu_page(
1501 'analytify-dashboard',
1502 ANALYTIFY_NICK . esc_html__( ' Dashboards', 'wp-analytify' ),
1503 esc_html__( 'Dashboards', 'wp-analytify' ),
1504 $dashboard_cap,
1505 'analytify-dashboard',
1506 array(
1507 $this,
1508 'pa_page_file_path',
1509 ),
1510 10
1511 );
1512
1513 do_action( 'analytify_add_submenu' );
1514
1515 add_submenu_page(
1516 'analytify-dashboard',
1517 ANALYTIFY_NICK . esc_html__( ' Settings', 'wp-analytify' ),
1518 esc_html__( 'Settings', 'wp-analytify' ),
1519 'manage_options',
1520 'analytify-settings',
1521 array(
1522 $this,
1523 'pa_page_file_path',
1524 ),
1525 50
1526 );
1527
1528 add_submenu_page(
1529 'analytify-dashboard',
1530 ANALYTIFY_NICK . esc_html__( ' Help', 'wp-analytify' ),
1531 esc_html__( 'Help', 'wp-analytify' ),
1532 'manage_options',
1533 'analytify-settings#wp-analytify-help',
1534 array(
1535 $this,
1536 'pa_page_file_path',
1537 ),
1538 55
1539 );
1540
1541 // Add license submenu.
1542 if ( class_exists( 'WP_Analytify_Pro_Base' ) ) {
1543 add_submenu_page(
1544 'analytify-dashboard',
1545 ANALYTIFY_NICK . esc_html__( ' License', 'wp-analytify' ),
1546 esc_html__( 'License', 'wp-analytify' ),
1547 'manage_options',
1548 'analytify-settings#wp-analytify-license',
1549 array(
1550 $this,
1551 'pa_page_file_path',
1552 ),
1553 60
1554 );
1555 }
1556
1557 add_submenu_page(
1558 'analytify-dashboard',
1559 ANALYTIFY_NICK . esc_html__( ' list of all Add-ons', 'wp-analytify' ),
1560 esc_html__( 'Add-ons', 'wp-analytify' ),
1561 'manage_options',
1562 'analytify-addons',
1563 array(
1564 $this,
1565 'pa_page_file_path',
1566 ),
1567 65
1568 );
1569
1570 add_submenu_page(
1571 'analytify-dashboard',
1572 ANALYTIFY_NICK . esc_html__( ' FREE vs PRO', 'wp-analytify' ),
1573 esc_html__( 'FREE vs PRO', 'wp-analytify' ),
1574 'manage_options',
1575 'analytify-go-pro',
1576 array(
1577 $this,
1578 'pa_page_file_path',
1579 ),
1580 70
1581 );
1582
1583 // Promo page (will not appear in side menu).
1584 add_submenu_page( 'analytify-dashboard', esc_html__( 'Analytify Promo', 'wp-analytify' ), null, 'manage_options', 'analytify-promo', array( $this, 'addons_promo_screen' ) );
1585 }
1586
1587 /**
1588 * Redirect subscribers away from Analytify admin screens.
1589 *
1590 * @since 9.1.0
1591 * @version 9.1.0
1592 * @return void
1593 */
1594 public function block_subscriber_analytify_access() {
1595 if ( ! Analytify_Utils::is_subscriber_blocked_from_analytify() ) {
1596 return;
1597 }
1598
1599 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Admin screen routing only.
1600 $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
1601
1602 if ( $page && 0 === strpos( $page, 'analytify' ) ) {
1603 wp_safe_redirect( admin_url() );
1604 exit;
1605 }
1606 }
1607
1608 /**
1609 * Get current screen details
1610 *
1611 * @version 9.1.0
1612 * @return void
1613 */
1614 public function pa_page_file_path() {
1615 $allowed_roles = $this->settings->get_option( 'show_analytics_roles_dashboard', 'wp-analytify-dashboard', array() );
1616 $allowed_roles[] = 'administrator';
1617
1618 if ( ! $this->pa_check_roles( $allowed_roles ) ) {
1619 wp_safe_redirect( admin_url() );
1620 exit;
1621 }
1622
1623 $screen = get_current_screen();
1624
1625 if ( strpos( $screen->base, 'analytify-settings' ) !== false ) {
1626 $version = defined( 'ANALYTIFY_PRO_VERSION' ) ? ANALYTIFY_PRO_VERSION : ANALYTIFY_VERSION;
1627
1628 echo '<div class="wrap"><h2 style="display: none;"></h2></div>
1629
1630 <div class="wpanalytify"><div class="wpb_plugin_wraper">
1631
1632 <div class="wpb_plugin_header_wraper">
1633 <div class="graph"></div>
1634
1635 <div class="wpb_plugin_header">
1636
1637 <div class="wpb_plugin_header_title"></div>
1638
1639 <div class="wpb_plugin_header_info">
1640 <a href="https://analytify.io/changelog/" target="_blank" class="btn">View Changelog</a>
1641 </div>
1642 <div class="wpb_plugin_header_logo">
1643 <img src="' . esc_url( plugins_url( 'assets/img/logo.svg', __FILE__ ) ) . '" alt="Analytify">
1644 </div>
1645 </div></div><div class="analytify-settings-body-container"><div class="wpb_plugin_body_wraper"><div class="wpb_plugin_body">';
1646 // Initialize settings before rendering.
1647 $this->settings->set_sections( $this->settings->get_settings_sections() );
1648 $this->settings->set_fields( $this->settings->get_settings_fields() );
1649 $this->settings->rendered_settings();
1650 $this->settings->show_tabs();
1651 echo '<div class="wpb_plugin_tabs_content">';
1652 $this->settings->show_forms();
1653 echo '</div>';
1654
1655 echo '</div></div></div></div>';
1656
1657 } elseif ( strpos( $screen->base, 'analytify-dashboard' ) !== false ) {
1658 // Restrict authors from accessing main dashboard - redirect to Authors dashboard.
1659 $current_user = wp_get_current_user();
1660 $is_author_only = $current_user && in_array( 'author', (array) $current_user->roles, true ) && ! in_array( 'administrator', (array) $current_user->roles, true );
1661
1662 if ( $is_author_only ) {
1663 // Redirect authors to their Authors dashboard.
1664 wp_safe_redirect( admin_url( 'admin.php?page=analytify-authors' ) );
1665 exit;
1666 }
1667
1668 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading URL parameter for display purposes
1669 if ( isset( $_GET['show'] ) ) {
1670 do_action( 'show_detail_dashboard_content' );
1671 } else {
1672 require_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytics-dashboard.php';
1673 }
1674 } elseif ( strpos( $screen->base, 'analytify-optin' ) !== false ) {
1675 require_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytify-optin-form.php';
1676 } elseif ( strpos( $screen->base, 'analytify-addons' ) !== false ) {
1677 require_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/page-addons.php';
1678 } elseif ( strpos( $screen->base, 'analytify-woocommerce' ) !== false ) {
1679 // WooCommerce page - this might not exist, let's check if file exists first.
1680 $woo_file = WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytify-woocommerce.php';
1681 if ( file_exists( $woo_file ) ) {
1682 require_once $woo_file;
1683 }
1684 } elseif ( strpos( $screen->base, 'analytify-logs' ) !== false ) {
1685 include_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/page-logs.php';
1686 } elseif ( strpos( $screen->base, 'analytify-go-pro' ) !== false ) {
1687 include_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytify-go-pro.php';
1688 } elseif ( isset( $_GET['show'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading URL parameter for display purposes
1689 do_action( 'show_detail_dashboard_content' );
1690 } else {
1691 // Dequeue event calendar js.
1692 wp_dequeue_script( 'tribe-common' );
1693 wp_dequeue_script( 'mcw-crypto-common' );
1694 include_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytics-dashboard.php';
1695 }
1696 }
1697
1698 // ========================================.
1699 // ADMIN MENU & PAGE ROUTING END.
1700 // ========================================.
1701
1702 /**
1703 * Render optin page
1704 *
1705 * @return void
1706 */
1707 public function render_optin() {
1708 require_once WP_ANALYTIFY_PLUGIN_DIR . '/inc/analytify-optin-form.php';
1709 }
1710
1711 // Functions moved to Promotions && Analytics_Reports components.
1712
1713 /**
1714 * Process logout && clear stored options.
1715 *
1716 * @return void
1717 */
1718 public function logout() {
1719 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' ) ) {
1720 delete_option( 'pt_webprofile' );
1721 delete_option( 'pt_webprofile_dashboard' );
1722 delete_option( 'pt_webprofile_url' );
1723 delete_option( 'pa_google_token' );
1724 $this->analytify_auth_settings_clear_google_oauth_email();
1725 delete_option( 'post_analytics_token' );
1726 delete_option( 'hide_profiles' );
1727 delete_option( 'analytify-ga4-streams' );
1728 delete_option( 'analytify_tracking_property_info' );
1729 delete_option( 'analytify_reporting_property_info' );
1730 delete_option( 'analytify_ga4_exception' );
1731 delete_option( 'analytify_ga4_exceptions' );
1732 delete_option( 'profiles_list_summary' );
1733 delete_option( 'analytify_ga_properties_list' );
1734 delete_option( 'wp-analytify-mode' );
1735 delete_option( 'analytify-deprecated-auth' );
1736 delete_option( 'analytify-ga-properties-summery' );
1737 delete_option( 'analytify_profile_exception' );
1738 delete_option( 'profiles_list_summary_backup' );
1739 delete_transient( 'analytify_quota_exception' );
1740 delete_transient( 'analytify_google_userinfo_probe_skip' );
1741
1742 $_analytify_profile = get_option( 'wp-analytify-profile' );
1743 if ( $_analytify_profile ) {
1744 unset( $_analytify_profile['hide_profiles_list'], $_analytify_profile['profile_for_posts'], $_analytify_profile['profile_for_dashboard'] );
1745 update_option( 'wp-analytify-profile', $_analytify_profile );
1746 }
1747
1748 $update_message = sprintf( // translators: Login again notice.
1749 esc_html__( '%1$s %2$s %3$s Authentication Cleared login again. %4$s %5$s %6$s', 'wp-analytify' ),
1750 '<div id="setting-error-settings_updated" class="updated notice is-dismissible settings-error below-h2">',
1751 '<p>',
1752 '<strong>',
1753 '</strong>',
1754 '</p>',
1755 '</div>'
1756 );
1757 }
1758 }
1759
1760 /**
1761 * Used to add query args that need to be removed from url
1762 *
1763 * @since 5.0.6
1764 * @param mixed $args_array The arguments array to process.
1765 * @return array
1766 */
1767 public function Analytify_remove_query( $args_array ) {
1768 $analytify_args_to_remove = array( 'analytify-cache' );
1769 $args_array = array_merge( $args_array, $analytify_args_to_remove );
1770 return $args_array;
1771 }
1772
1773 /**
1774 * Trigger logging cleanup using the logging class.
1775 *
1776 * Uses guarded logger (null-safe) to avoid fatal if logger unavailable.
1777 *
1778 * @since 2.1.23
1779 * @version 1
1780 * @return void
1781 */
1782 public static function analytify_cleanup_logs() {
1783 $logger = function_exists( 'analytify_get_logger' ) ? analytify_get_logger() : null;
1784 if ( class_exists( 'QM' ) ) {
1785 QM::info( 'Analytify: Starting cleanup of expired logs.' );
1786 }
1787
1788 if ( $logger && is_callable( array( $logger, 'clear_expired_logs' ) ) ) {
1789 $logger->clear_expired_logs();
1790 if ( class_exists( 'QM' ) ) {
1791 QM::info( 'Analytify: Expired logs cleared successfully.' );
1792 }
1793 }
1794 }
1795
1796
1797
1798
1799 // ========================================.
1800 // PROFILE & SETTINGS MANAGEMENT START.
1801 // ========================================.
1802
1803 // Functions moved to Profile_Management && GA4_Property_Management components.
1804
1805 // ========================================.
1806 // PROFILE & SETTINGS MANAGEMENT END.
1807 // ========================================.
1808
1809 // Black Friday Deal Notice function moved to Promotions component.
1810
1811 // Function moved to Promotions component.
1812
1813 // Winter Sale promo function moved to Promotions component.
1814
1815 // Winter Sale dismiss notice function moved to Promotions component.
1816
1817 // Rating icon function moved to Promotions component.
1818
1819 // ========================================.
1820 // GDPR COMPLIANCE & META BOXES START.
1821 // ========================================.
1822
1823 // Functions add_exclusion_meta_box && print_exclusion_meta_box moved to GDPR_Compliance component.
1824
1825 // ========================================.
1826 // GDPR COMPLIANCE & META BOXES END.
1827 // ========================================.
1828
1829 /**
1830 * Init the compliance class.
1831 *
1832 * @return void
1833 */
1834 public function init_gdpr_compliance() {
1835 if ( class_exists( 'Class_Analytify_GDPR_Compliance' ) ) {
1836 new Class_Analytify_GDPR_Compliance();
1837 }
1838 }
1839
1840 /**
1841 * Get a component from the loader
1842 *
1843 * @param string $component_name The name of the component to get.
1844 * @return mixed|null The component instance or null if not found
1845 */
1846 public function get_component( $component_name ) {
1847 if ( $this->loader && method_exists( $this->loader, 'get_component' ) ) {
1848 return $this->loader->get_component( $component_name );
1849 }
1850 return null;
1851 }
1852
1853 /**
1854 * Check if a component is loaded
1855 *
1856 * @param string $component_name The name of the component to check.
1857 * @return bool True if component is loaded, false otherwise
1858 */
1859 public function has_component( $component_name ) {
1860 if ( $this->loader && method_exists( $this->loader, 'has_component' ) ) {
1861 return $this->loader->has_component( $component_name );
1862 }
1863 return false;
1864 }
1865
1866 // Welcome message function moved to Promotions component.
1867
1868 /**
1869 * Show promo screen for addons
1870 *
1871 * @return void
1872 */
1873 public function addons_promo_screen() {
1874 include WP_ANALYTIFY_PLUGIN_DIR . '/views/default/admin/addons-promo.php';
1875 }
1876 }
1877 } // End if class_exists check.
1878
1879 // ========================================.
1880 // MAIN PLUGIN CLASS DEFINITION END.
1881 // ========================================.
1882
1883 /**
1884 * Create instance of wp-analytify class.
1885 *
1886 * @return void
1887 */
1888 function analytify_free_instance() {
1889 $GLOBALS['WP_ANALYTIFY'] = WP_Analytify::get_instance();
1890 }
1891 add_action( 'plugins_loaded', 'analytify_free_instance', 10 );
1892
1893 // ========================================.
1894 // PLUGIN INSTANCE INITIALIZATION END.
1895 // ========================================.
1896
1897 /**
1898 * AJAX callback function for performing a factory reset of Analytify plugin settings
1899 *
1900 * This function handles the secure AJAX request to reset all Analytify settings
1901 * to their default values. It includes security checks, capability verification,
1902 * and proper error handling.
1903 *
1904 * @hook wp_ajax_analytify_factory_reset
1905 * @since 8.0.0
1906 * @return void Sends JSON response indicating success or failure
1907 */
1908 function analytify_factory_reset_callback() {
1909 // Verify the nonce for security - prevents CSRF attacks.
1910 check_ajax_referer( 'analytify_factory_reset_nonce', 'nonce' );
1911
1912 // Check if current user has administrative capabilities.
1913 if ( ! current_user_can( 'manage_options' ) ) {
1914 wp_send_json_error( 'Unauthorized' );
1915 }
1916
1917 // Load the factory reset class if not already available.
1918 if ( ! class_exists( 'Analytify_Factory_Reset' ) ) {
1919 require_once plugin_dir_path( __FILE__ ) . 'classes/analytify-factory-reset.php';
1920 }
1921
1922 // Initialize the reset class and execute the reset process.
1923 $reset = new Analytify_Factory_Reset();
1924 $reset->remove_settings();
1925
1926 // Send success response to the AJAX request.
1927 wp_send_json_success();
1928 }
1929
1930 /**
1931 * Hook the factory reset function to WordPress AJAX handlers
1932 *
1933 * This registers the function for both privileged (admin) and non-privileged users,
1934 * but the capability check inside the function will restrict access to admins only.
1935 */
1936 add_action( 'wp_ajax_analytify_factory_reset', 'analytify_factory_reset_callback' );
1937