'installed', 'button_text' => esc_html__('Activate WooCommerce Now', 'ai-flash-tune'), 'action_url' => esc_url($activate_url), 'notice_text' => esc_html__('WooCommerce is installed but not currently active. Please activate it to enable this page.', 'ai-flash-tune') ]; } else { return [ 'status' => 'not_installed', 'button_text' => esc_html__('Install WooCommerce Now', 'ai-flash-tune'), 'action_url' => esc_url($aiflt_install_url), 'notice_text' => esc_html__('This page requires WooCommerce to be installed and active. Please install it to continue.', 'ai-flash-tune') ]; } } /** * Display a custom, well-designed admin notice if WooCommerce is not active. */ function aiflt_woocommerce_missing_notice() { $aiflt_install_url = admin_url('plugin-install.php?s=woocommerce&tab=search&type=term'); ?>
MODIFIED: Only add WooCommerce-dependent hooks if it's active if (aiflt_is_woocommerce_active()) { add_action('woocommerce_thankyou', array('AIFLT_Funnel_Analyzer_Logic', 'log_checkout_attempt'), 10, 1); // add_action('woocommerce_order_status_completed', array('AIFLT_Funnel_Analyzer_Logic', 'log_confirmed_sale'), 10, 1); add_action('wp_enqueue_scripts', 'aiflt_enqueue_frontend_scripts'); // ---> Add the server-side hook to reliably track all 'add to cart' actions. // 1. Hook for Item Addition (The original hook) add_action('woocommerce_add_to_cart', array('AIFLT_Funnel_Analyzer_Logic', 'log_add_to_cart_action'), 10, 6); // 2. Hook for Item Quantity Update (New hook for the same function) add_action('woocommerce_after_cart_item_quantity_update', array('AIFLT_Funnel_Analyzer_Logic', 'log_add_to_cart_action'), 10, 3); } // Add AJAX hooks (these are safe as their callbacks will also have checks) add_action('wp_ajax_aiflt_track_funnel_page', array('AIFLT_Funnel_Analyzer_Logic', 'track_funnel_page_callback')); add_action('wp_ajax_nopriv_aiflt_track_funnel_page', array('AIFLT_Funnel_Analyzer_Logic', 'track_funnel_page_callback')); add_action('wp_ajax_aiflt_save_page_speed', array('AIFLT_Funnel_Analyzer_Logic', 'save_page_speed_callback')); add_action('wp_ajax_nopriv_aiflt_save_page_speed', array('AIFLT_Funnel_Analyzer_Logic', 'save_page_speed_callback')); add_action('wp_ajax_aiflt_log_behavior', array('AIFLT_Funnel_Analyzer_Logic', 'log_behavior_callback')); add_action('wp_ajax_nopriv_aiflt_log_behavior', array('AIFLT_Funnel_Analyzer_Logic', 'log_behavior_callback')); add_action('wp_ajax_aiflt_track_simple_behavior', array('AIFLT_Funnel_Analyzer_Logic','ajax_track_simple_behavior')); add_action('wp_ajax_nopriv_aiflt_track_simple_behavior', array('AIFLT_Funnel_Analyzer_Logic','ajax_track_simple_behavior')); add_action('wp_ajax_aiflt_get_ai_analysis', array('AIFLT_Funnel_Analyzer_Logic', 'get_ai_analysis_callback')); add_action('wp_ajax_nopriv_aiflt_get_ai_analysis', array('AIFLT_Funnel_Analyzer_Logic', 'get_ai_analysis_callback')); add_action('wp_ajax_aiflt_get_funnel_data', array('AIFLT_Funnel_Analyzer_Logic', 'get_funnel_data_callback')); add_action('wp_ajax_aiflt_save_settings', array('AIFLT_Settings_Logic', 'save_settings_callback')); // --- NEW: Add AJAX action for capturing guest emails --- add_action('wp_ajax_nopriv_aiflt_capture_guest_email', array('AIFLT_Funnel_Analyzer_Logic', 'ajax_capture_guest_email')); add_action('wp_ajax_aiflt_capture_guest_email', array('AIFLT_Funnel_Analyzer_Logic', 'ajax_capture_guest_email')); add_action('wp_ajax_aiflt_export_privacy_data', array('AIFLT_Privacy_Logic', 'ajax_export_data')); add_action('wp_ajax_aiflt_get_segmented_funnel_data', ['AIFLT_Funnel_Analyzer_Logic', 'ajax_get_segmented_data']); } // ---> MODIFIED: Removed the gate. The plugin will now always initialize. add_action('plugins_loaded', 'aiflt_initialize_plugin'); function aiflt_activate_plugin() { // Set a transient flag for the welcome redirect. set_transient('aiflt_welcome_redirect', true, 30); // Schedule the daily cleanup event if it's not already scheduled. if (!wp_next_scheduled('aiflt_daily_cleanup_event')) { wp_schedule_event(time(), 'daily', 'aiflt_daily_cleanup_event'); } global $wpdb; $charset_collate = $wpdb->get_charset_collate(); // Create the funnel data table $aiflt_funnel_data_table = $wpdb->prefix . 'aiflt_funnel_data'; $sql_funnel_data = "CREATE TABLE $aiflt_funnel_data_table ( id bigint(20) NOT NULL AUTO_INCREMENT, session_id varchar(255) NOT NULL, user_id bigint(20) DEFAULT NULL, page_name varchar(50) NOT NULL, device_type varchar(20) NOT NULL, timestamp datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, cart_data longtext, page_speed float DEFAULT NULL, post_id bigint(20) DEFAULT NULL, order_id bigint(20) DEFAULT NULL, ip_address VARCHAR(45) NULL, PRIMARY KEY (id) ) $charset_collate;"; // Create the behavior data table $behavior_data_table = $wpdb->prefix . 'aiflt_behavior_data'; $sql_behavior_data = "CREATE TABLE $behavior_data_table ( id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, session_id VARCHAR(64) NOT NULL, user_id BIGINT(20) UNSIGNED NULL, product_id BIGINT(20) UNSIGNED DEFAULT 0, behavior_type VARCHAR(50) NOT NULL, behavior_value TEXT NULL, traffic_source VARCHAR(50) DEFAULT 'Unknown', user_agent VARCHAR(255) NULL, ip_address VARCHAR(45) NULL, timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY product_id (product_id), KEY behavior_type (behavior_type), KEY session_id (session_id) ) $charset_collate;"; add_option('aiflt_db_version', '1.0'); // Store activation timestamp if it doesn't exist if (false === get_option('aiflt_activation_time')) { add_option('aiflt_activation_time', time()); } require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql_funnel_data); dbDelta($sql_behavior_data); } function aiflt_deactivate_plugin() { // Clear the scheduled cron job on deactivation. $timestamp = wp_next_scheduled('aiflt_daily_cleanup_event'); if ($timestamp) { wp_unschedule_event($timestamp, 'aiflt_daily_cleanup_event'); } } function aiflt_welcome_redirect_handler() { // Check if our transient is set. if (get_transient('aiflt_welcome_redirect')) { // Delete the transient so this process only runs once. delete_transient('aiflt_welcome_redirect'); // Ensure the current user has permissions before redirecting. if (current_user_can('manage_options')) { // Perform a safe redirect to the main plugin dashboard. wp_safe_redirect(admin_url('admin.php?page=ai_flash_tune')); exit; } } } function aiflt_run_daily_cleanup_cron() { // --- REVISED: Read the correct individual database option --- $retention_days = get_option('aiflt_data_retention', 30); $retention_days = intval($retention_days); // A value of 0 means 'Forever', so we only run if it's a positive number. if ($retention_days > 0) { global $wpdb; $funnel_table = $wpdb->prefix . 'aiflt_funnel_data'; $behavior_table = $wpdb->prefix . 'aiflt_behavior_data'; // Calculate the cutoff date $cutoff_date = gmdate('Y-m-d H:i:s', strtotime("-$retention_days days")); // Delete old data from the funnel table $wpdb->query( $wpdb->prepare( "DELETE FROM {$funnel_table} WHERE timestamp < %s", $cutoff_date ) ); // Delete old data from the behavior table $wpdb->query( $wpdb->prepare( "DELETE FROM {$behavior_table} WHERE timestamp < %s", $cutoff_date ) ); } } /** * Register the core plugin settings and their sanitization callbacks. * Hooked to admin_init. */ function aiflt_register_core_settings() { // Register settings for the 'general' tab group // Each setting needs its own register_setting call. // The first argument is the 'option group' name used in settings_fields(). // The second argument is the actual 'option name' stored in wp_options. // The third argument is an array for arguments like sanitize_callback. register_setting('aiflt_settings_group_general', 'aiflt_ai_api_key', [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '' ]); register_setting('aiflt_settings_group_general', 'aiflt_ai_model', [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => 'gpt-4o-mini' ]); register_setting('aiflt_settings_group_general', 'aiflt_data_retention', [ 'type' => 'string', // Stored as string, but represents number or '0' 'sanitize_callback' => 'sanitize_text_field', 'default' => '30' ]); register_setting('aiflt_settings_group_general', 'aiflt_delete_data_on_uninstall', [ 'type' => 'integer', // Checkbox value is 1 or 0 'sanitize_callback' => 'absint', 'default' => 0 ]); register_setting('aiflt_settings_group_general', 'aiflt_anonymize_ip', [ 'type' => 'integer', 'sanitize_callback' => 'absint', 'default' => 0 ]); register_setting('aiflt_settings_group_general', 'aiflt_enable_tracking', [ 'type' => 'integer', 'sanitize_callback' => 'absint', 'default' => 1 ]); register_setting('aiflt_settings_group_general', 'aiflt_excluded_roles', [ 'type' => 'array', 'sanitize_callback' => 'aiflt_sanitize_roles_array', // Use your existing sanitize function 'default' => ['administrator'] ]); register_setting('aiflt_settings_group_general', 'aiflt_excluded_ips', [ 'type' => 'string', 'sanitize_callback' => 'aiflt_sanitize_ip_textarea', // Use your existing sanitize function 'default' => '' ]); // Hook for addons to register their settings (using their own option groups) do_action('aiflt_register_addon_settings'); } /** * Helper sanitize callback for roles array (already exists in ai-flash-tune.php) */ function aiflt_sanitize_roles_array($input) { $sanitized = []; if (is_array($input)) { foreach ($input as $role) { // Ensure only valid role keys are saved if (get_role($role)) { $sanitized[] = sanitize_key($role); } } } return $sanitized; } /** * Helper sanitize callback for IP textarea (already exists in ai-flash-tune.php) */ function aiflt_sanitize_ip_textarea($input) { $ips_array = explode("\n", trim($input)); $sanitized_ips = []; foreach ($ips_array as $ip) { $trimmed_ip = trim($ip); if (!empty($trimmed_ip)) { // Basic sanitization, could add IP validation if needed $sanitized_ips[] = sanitize_text_field($trimmed_ip); } } // Store as a single string separated by newlines return implode("\n", $sanitized_ips); } function aiflt_register_admin_menu() { add_menu_page( __('AI Flash Tune', 'ai-flash-tune'), __('AI Flash Tune', 'ai-flash-tune'), 'manage_options', 'ai_flash_tune', 'aiflt_render_dashboard_page', 'dashicons-chart-bar', // Using a standard dashicon instead of a separate image 25 ); add_submenu_page( 'ai_flash_tune', __('Funnel Analysis', 'ai-flash-tune'), __('Funnel Analysis', 'ai-flash-tune'), 'manage_options', 'funnelanalysis', 'aiflt_render_funnel_analysis_page' ); add_submenu_page( 'ai_flash_tune', __('Products', 'ai-flash-tune'), __('Products', 'ai-flash-tune'), 'manage_options', 'products', 'aiflt_render_products_page' ); add_submenu_page( 'ai_flash_tune_hide', __('Product Detail', 'ai-flash-tune'), __('Product Detail', 'ai-flash-tune'), 'manage_options', 'product-detail', 'aiflt_render_product_detail_page' ); add_submenu_page( 'ai_flash_tune', __('Abandoned Carts', 'ai-flash-tune'), __('Abandoned Carts', 'ai-flash-tune'), 'manage_options', 'abandonedcarts', 'aiflt_render_abandoned_carts_page' ); // This action hook allows addons to register their own submenu pages. do_action('aiflt_register_submenu_pages'); add_submenu_page( 'ai_flash_tune', __('Settings', 'ai-flash-tune'), __('Settings', 'ai-flash-tune'), 'manage_options', 'aiflt_settings', 'aiflt_render_settings_page' ); // ---> ADD THIS NEW SUBMENU PAGE add_submenu_page( 'ai_flash_tune', __('Privacy Tools', 'ai-flash-tune'), __('Privacy Tools', 'ai-flash-tune'), 'manage_options', 'privacy-tools', 'aiflt_render_privacy_tools_page' ); } /** * Handles the manual triggering of cron jobs from the System Info page. */ function aiflt_handle_manual_cron_trigger() { if (isset($_GET['trigger_cron']) && isset($_GET['_wpnonce'])) { if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'aiflt_trigger_cron')) { return; } $cron_type = sanitize_key($_GET['trigger_cron']); if ($cron_type === 'cleanup' && current_user_can('manage_options')) { // Run the cleanup function manually aiflt_run_daily_cleanup_cron(); // Add a success notice and redirect add_action('admin_notices', function() { echo '

' . esc_html__('The daily data cleanup job has been run successfully.', 'ai-flash-tune') . '

'; }); } // We can add more cron triggers here in the future } } // Callback functions to render the pages function aiflt_render_privacy_tools_page() { include(AIFLT_PLUGIN_PATH . 'includes/admin/privacy-tools.php'); } function aiflt_render_dashboard_page() { include(AIFLT_PLUGIN_PATH . 'includes/admin/dashboard.php'); } function aiflt_render_funnel_analysis_page() { include(AIFLT_PLUGIN_PATH . 'includes/admin/funnel-analysis.php'); } function aiflt_render_products_page() { include(AIFLT_PLUGIN_PATH . 'includes/admin/products.php'); } function aiflt_render_product_detail_page() { // CRITICAL FIX: Add explicit capability check here. if (!current_user_can('manage_options')) { wp_die(esc_html__('Sorry, you are not allowed to access this page 123.', 'ai-flash-tune')); } include(AIFLT_PLUGIN_PATH . 'includes/admin/product-detail.php'); } function aiflt_render_abandoned_carts_page() { include(AIFLT_PLUGIN_PATH . 'includes/admin/abandoned-carts.php'); } function aiflt_render_settings_page() { include(AIFLT_PLUGIN_PATH . 'includes/admin/settings.php'); } // Enqueue scripts and styles for the admin side add_action('admin_enqueue_scripts', 'aiflt_enqueue_admin_scripts'); function aiflt_enqueue_admin_scripts($hook) { // Get the current screen to check which page we are on $screen = get_current_screen(); $is_aiflt_page = false; // --- Define known addon slugs/page fragments --- // These should match the `$menu_slug` used in the add_submenu_page call for each addon $addon_slugs = [ 'aiftcr-email-log', 'aiftaa-analysis-dashboard', 'aiftss-suggestions-dashboard', 'aiftco-optimizer-dashboard', 'aiftpd-doctor-dashboard', 'product-detail', // Add slugs for other addons like copy-enhancer, segmentation, predictor, real-time-alerts if they have admin pages ]; // --- Determine if we are on ANY AIFLT admin page (Core or Addon) --- if ($screen) { $screen_id = $screen->id; $is_core_page = ( $screen_id === 'toplevel_page_ai_flash_tune' || strpos($screen_id, '_page_funnelanalysis') != 0 || strpos($screen_id, '_page_products') != 0 || strpos($screen_id, '_page_abandonedcarts') != 0 || strpos($screen_id, '_page_aiflt_settings') != 0 || strpos($screen_id, '_page_privacy-tools') != 0 || strpos($screen_id, 'ai_flash_tune_page_') === 0 || strpos($screen_id, 'ai-flash-tune_page_') === 0 ); $is_addon_page = false; foreach ($addon_slugs as $aiflt_slug) { // Check common addon patterns: admin_page_{slug} OR {parent_hook}_page_{slug} if ($screen_id === 'admin_page_' . $aiflt_slug || $screen_id === 'ai-flash-tune_page_' . $aiflt_slug) { $is_addon_page = true; break; } } $is_aiflt_page = $is_core_page || $is_addon_page; // error_log("AI Flash Tune Screen Check - ID: " . $screen_id . " | Is Core: " . ($is_core_page ? 'Yes' : 'No'). " | Is Addon: " . ($is_addon_page ? 'Yes' : 'No')); // Keep for debugging if needed } else { // Fallback check using $hook (less reliable) - Keep this broad $known_slug_fragments = ['ai_flash_tune', 'ai-flash-tune', 'aiflt_settings', 'funnelanalysis', 'products', 'product-detail', 'abandonedcarts', 'privacy-tools']; $known_slug_fragments = array_merge($known_slug_fragments, $addon_slugs); // Include addon slugs in fallback foreach ($known_slug_fragments as $fragment) { if (strpos($hook, $fragment) !== false) { $is_aiflt_page = true; break; } } // error_log("AI Flash Tune Hook Check - Hook: " . $hook . " | Is AIFLT Page: " . ($is_aiflt_page ? 'Yes' : 'No')); } // --- STEP 1: Enqueue basic styles on ALL identified AIFLT pages --- if ($is_aiflt_page) { wp_enqueue_style('ai-flash-tune-styles', AIFLT_PLUGIN_URL . 'includes/css/ai-flash-tune-styles.css', [], AIFLT_VERSION); wp_enqueue_style('aift-fontawesome', AIFLT_PLUGIN_URL . 'includes/css/all.min.css', [], '5.15.4'); // Keep handle simple for potential sharing } else { // If it's definitely not our page, bail early return; } // --- STEP 2: Check WC dependency for JS and specific assets --- if (!aiflt_is_woocommerce_active()) { // If WC is not active, we've already enqueued basic styles (if applicable), so just return. return; } // --- STEP 3: Enqueue JS and specific assets ONLY on specific pages AND if WC is active --- // Define the specific screen IDs that need JS, flatpickr, etc. // **CRITICAL:** Combine CORE and ADDON screen IDs correctly. $aiflt_pages_needing_js = [ // Core Pages 'toplevel_page_ai-flash-tune', 'toplevel_page_ai_flash_tune', 'ai-flash-tune_page_funnelanalysis', '_page_funnelanalysis', 'ai-flash-tune_page_products', '_page_products', 'ai-flash-tune_page_product-detail', 'admin_page_product-detail', '_product-detail', 'ai-flash-tune_page_abandonedcarts', '_page_abandonedcarts', 'ai-flash-tune_page_aiflt_settings', '_page_aiflt_settings', 'ai-flash-tune_page_privacy-tools', '_page_privacy-tools', // Addon Pages (Use the correct pattern identified via debugging, likely admin_page_{slug} or ai-flash-tune_page_{slug}) // Adjust these based on EXACT screen IDs found during debugging 'ai-flash-tune_page_aiftcr-email-log', // Example assuming it's under main menu 'admin_page_aiftcr-email-log', // Alternative pattern if registered differently 'ai-flash-tune_page_aiftaa-analysis-dashboard', // Example assuming it's under main menu 'admin_page_aiftaa-analysis-dashboard', // Alternative pattern 'ai-flash-tune_page_aiftss-suggestions-dashboard', // Example assuming it's under main menu 'admin_page_aiftss-suggestions-dashboard', // Alternative pattern 'ai-flash-tune_page_aiftco-optimizer-dashboard', // Example assuming it's under main menu 'admin_page_aiftco-optimizer-dashboard', // Alternative pattern 'ai-flash-tune_page_aiftpd-doctor-dashboard', // Example assuming it's under main menu // 'admin_page_aiftpd-doctor-dashboard', // Alternative pattern // Add ALL other addon screen IDs here ]; // Check if the current screen ID is in the list of pages needing JS if ($screen && ( strpos($screen->id, '_page_products') != 0 || strpos($screen->id, '_page_ai-flash-tune') != 0 || strpos($screen->id, '_page_ai_flash_tune') != 0 || strpos($screen->id, '_page_funnelanalysis') != 0 || strpos($screen->id, '_page_product-detail') != 0 || strpos($screen->id, '_page_abandonedcarts') != 0 || strpos($screen->id, '_page_aiflt_settings') != 0 || strpos($screen->id, '_page_privacy-tools') != 0 || strpos($screen->id, '_page_aiftcr-email-log') != 0 || strpos($screen->id, '_page_aiftaa-analysis-dashboard') != 0 || strpos($screen->id, '_page_aiftss-suggestions-dashboard') != 0 || strpos($screen->id, '_page_aiftco-optimizer-dashboard') != 0 || strpos($screen->id, '_page_aiftpd-doctor-dashboard') != 0 )) { // Enqueue Flatpickr for date range selection on relevant pages $flatpickr_pages = [ 'ai-flash-tune_page_products', // Use correct ID pattern 'ai-flash-tune_page_product-detail', // Use correct ID pattern 'admin_page_product-detail', // Use correct ID pattern 'ai-flash-tune_page_funnelanalysis', // Use correct ID pattern 'ai-flash-tune_page_abandonedcarts', // Use correct ID pattern 'ai-flash-tune_page_aiftcr-email-log', // Use correct ID pattern 'admin_page_aiftcr-email-log', // Use correct ID pattern ]; if (in_array($screen->id, $flatpickr_pages)) { wp_enqueue_script('aift-flatpickr-js', AIFLT_PLUGIN_URL .'includes/js/flatpickr.min.js', [], '4.6.13', true); wp_enqueue_style('aift-flatpickr-css', AIFLT_PLUGIN_URL .'includes/css/flatpickr.min.css', [], '4.6.13'); } // Enqueue the main jQuery script wp_enqueue_script('ai-flash-tune-main-js', AIFLT_PLUGIN_URL . 'includes/js/ai-flash-tune-main.js', ['jquery'], AIFLT_VERSION, true); // Prepare data to pass to JavaScript (wp_localize_script remains the same as previous step) $aiflt_start_date = isset($_GET['start_date']) ? sanitize_text_field(wp_unslash($_GET['start_date'])) : gmdate('Y-m-d', strtotime('-29 days')); $aiflt_end_date = isset($_GET['end_date']) ? sanitize_text_field($_GET['end_date']) : gmdate('Y-m-d'); $aiflt_current_device = isset($_GET['device']) ? sanitize_text_field($_GET['device']) : 'desktop'; $activation_time = get_option('aiflt_activation_time', time()); $min_date = gmdate('Y-m-d', $activation_time); // Pass PHP data to the JavaScript file (using aiflt_ajax_object and corrected nonce actions) wp_localize_script('ai-flash-tune-main-js', 'aiflt_ajax_object', [ // Use the corrected object name here 'ajax_url' => admin_url('admin-ajax.php'), // Ensure ALL these nonce actions match the check_ajax_referer() calls 'tracking_nonce' => wp_create_nonce('aiflt-tracking-nonce'), // For frontend 'ai_analysis_nonce' => wp_create_nonce('aiflt-ai-analysis-nonce'), // Core AI Ask 'settings_nonce' => wp_create_nonce('aiflt-save-settings-nonce'), // Core Settings Save 'get_funnel_nonce' => wp_create_nonce('aiflt-get-funnel-nonce'), // Core Get Funnel Data 'addon_management_nonce' => wp_create_nonce('aiflt-addon-management-nonce'), // Addon Install/Activate // Keep addon nonces specific for clarity, assuming checks use these specific actions 'aiftaa_nonce' => wp_create_nonce('aiftaa-generate-report-nonce'), // AI Analysis Addon 'smart_suggestions_nonce' => wp_create_nonce('aiftss-get-suggestion-nonce'), // Smart Suggestions Addon 'aiftco_nonce' => wp_create_nonce('aiftco-get-analysis-nonce'), // Checkout Optimizer Addon 'aiftap_nonce' => wp_create_nonce('aiftap-get-prediction-nonce'), // Abandonment Predictor Addon 'aiftpd_nonce' => wp_create_nonce('aiftpd-get-diagnosis-nonce'), // Product Doctor Addon 'aiftce_nonce' => wp_create_nonce('aiftce-get-copy-suggestion-nonce'), // Copy Enhancer Addon 'aiftfs_nonce' => wp_create_nonce('aiftfs-get-segmented-nonce'), // Funnel Segmentation Addon 'aiftcr_test_email_nonce' => wp_create_nonce('aiftcr-test-email-nonce'), // Cart Recovery Test Email 'privacy_nonce' => wp_create_nonce('aiflt_privacy_actions'), // <-- NEW NONCE // KEEP other localized variables 'current_device_type' => $aiflt_current_device, 'start_date' => $aiflt_start_date, 'end_date' => $aiflt_end_date, 'min_date_limit' => $min_date, // Pass the formatted date 'is_admin' => true, 'admin_base_url' => admin_url('admin.php'), 'i18n' => [ 'saving' => __('Saving...', 'ai-flash-tune'), 'saveSettings' => __('Save Settings', 'ai-flash-tune'), 'saveError' => __('Error: Could not save settings.', 'ai-flash-tune'), 'unknownError' => __('An unexpected error occurred. Please try again.', 'ai-flash-tune'), 'sending' => __('Sending...', 'ai-flash-tune'), // For test email // Dynamic Addon Action Verbs (for Addon Manager) 'installing' => __('Installing', 'ai-flash-tune'), 'activating' => __('Activating', 'ai-flash-tune'), 'deactivating' => __('Deactivating', 'ai-flash-tune'), // Diagnosis & Suggestions (AIFT, AIFTSS, AIFTPD) 'diagnosis' => __('Diagnosis', 'ai-flash-tune'), 'confidence' => __('Confidence Score', 'ai-flash-tune'), 'whySuggestion' => __('Why this suggestion?', 'ai-flash-tune'), 'recommendations' => __('Recommendations', 'ai-flash-tune'), 'aiAnalyzingSuggestions' => __('Our AI is analyzing your data to generate suggestions...', 'ai-flash-tune'), 'aiDiagnosingProduct' => __('AI is diagnosing the product...', 'ai-flash-tune'), 'aiGeneratingCopy' => __('Generating copy...', 'ai-flash-tune'), // AI Analysis & Checkout (AIFTAA, AIFTCO) 'generating' => __('Generating...', 'ai-flash-tune'), 'analyzing' => __('Analyzing...', 'ai-flash-tune'), 'aiAnalyzingData' => __('Our AI is analyzing your data...', 'ai-flash-tune'), 'aiAnalyzingCheckout' => __('Our AI is analyzing your checkout process...', 'ai-flash-tune'), // Abandonment Predictor (AIFTAP) 'predicting' => __('Predicting...', 'ai-flash-tune'), 'aiAnalyzingPrediction' => __('AI is analyzing your data...', 'ai-flash-tune'), // Funnel Messages 'loadingFunnel' => __('Loading Funnel Data...', 'ai-flash-tune'), 'noFunnelData' => __('No Funnel Data Found', 'ai-flash-tune'), 'noFunnelTraffic' => __('Your funnel visualization will appear here once your store has some visitor traffic.', 'ai-flash-tune'), 'noFunnelRange' => __('There is no visitor traffic data for the selected date range. Please try expanding your dates.', 'ai-flash-tune'), 'funnelError' => __('Error loading funnel data.', 'ai-flash-tune'), 'funnelNetworkError' => __('Error loading funnel data. Please check your network connection.', 'ai-flash-tune'), // Ask AI 'aiPromptEmpty' => __('Please enter a question for the AI.', 'ai-flash-tune'), 'aiThinking' => __('Thinking...', 'ai-flash-tune'), 'aiNetworkError' => __('Error: Could not retrieve AI response. Please check your network connection.', 'ai-flash-tune'), 'noSegmentData' => __('No data available for this segment in the selected date range.', 'ai-flash-tune'), 'segmentA' => __('Segment A', 'ai-flash-tune'), 'segmentB' => __('Segment B', 'ai-flash-tune'), 'getAiDiagnosis' => __('Get AI Diagnosis', 'ai-flash-tune'), 'landingPage' => __('Landing Page', 'ai-flash-tune'), 'productPage' => __('Product Page', 'ai-flash-tune'), 'addedToCart' => __('Added to Cart', 'ai-flash-tune'), 'checkoutPage' => __('Checkout Page', 'ai-flash-tune'), 'unknownError' => __('An unknown error occurred.', 'ai-flash-tune'), 'users' => __('Users', 'ai-flash-tune'), 'loadingSegmentedData...' => __('Loading segmented data...', 'ai-flash-tune'), 'dropOff' => __('Drop-Off', 'ai-flash-tune'), 'visitors' => __('Visitors', 'ai-flash-tune'), 'start' => __('Start', 'ai-flash-tune'), 'conversion' => __('Conversion', 'ai-flash-tune'), 'dropOffCartTooltip' => __('Percentage of users who left after adding to the Cart.', 'ai-flash-tune'), 'dropOffProductTooltip' => __('Percentage of users who left after showing Product Interest.', 'ai-flash-tune'), 'dropOffLandingTooltip' => __('Percentage of users who left after the Landing Page.', 'ai-flash-tune'), 'sales' => __('Sales', 'ai-flash-tune'), 'checkouts' => __('Checkouts', 'ai-flash-tune'), 'carts' => __('Carts', 'ai-flash-tune'), 'guestUsers' => __('Guest Users', 'ai-flash-tune'), 'registeredUsers' => __('Registered Users', 'ai-flash-tune'), 'desktop' => __('Desktop', 'ai-flash-tune'), 'mobile' => __('Mobile', 'ai-flash-tune'), 'purchaseComplete' => __('Purchase Complete', 'ai-flash-tune'), 'productInterest' => __('Product Interest', 'ai-flash-tune'), 'views' => __('Views', 'ai-flash-tune'), 'entries' => __('Entries', 'ai-flash-tune'), ], ]); } } // Enqueue scripts and styles for the front end add_action('wp_enqueue_scripts', 'aiflt_enqueue_frontend_scripts'); function aiflt_enqueue_frontend_scripts() { // --- REVISED: Load settings from their correct individual database options --- $settings = [ 'enable_tracking' => get_option('aiflt_enable_tracking', '1'), 'excluded_roles' => get_option('aiflt_excluded_roles', ['administrator']), 'excluded_ips' => get_option('aiflt_excluded_ips', ''), ]; // 1. Master switch check (This logic now works correctly) if (empty($settings['enable_tracking']) || $settings['enable_tracking'] !== '1') { return; } // 2. User role check if (is_user_logged_in()) { $user = wp_get_current_user(); $user_roles = (array) $user->roles; $excluded_roles = isset($settings['excluded_roles']) ? (array) $settings['excluded_roles'] : []; if (!empty(array_intersect($user_roles, $excluded_roles))) { return; // Exit if the user has an excluded role } } // 3. IP address check $user_ip = sanitize_text_field($_SERVER['REMOTE_ADDR']); $excluded_ips_raw = isset($settings['excluded_ips']) ? $settings['excluded_ips'] : ''; if (!empty($excluded_ips_raw)) { // Normalize line endings and create an array of IPs $excluded_ips = array_map('trim', explode("\n", str_replace("\r", "", $excluded_ips_raw))); if (in_array($user_ip, $excluded_ips)) { return; // Exit if the user's IP is in the exclusion list } } // If all checks pass, proceed to enqueue the script if (class_exists('WooCommerce')) { wp_enqueue_script('ai-flash-tune-frontend-js', AIFLT_PLUGIN_URL . 'includes/js/ai-flash-tune-main.js', array('jquery'), AIFLT_VERSION, true); // ---> Pass the consistent session ID to the JavaScript. wp_localize_script('ai-flash-tune-frontend-js', 'aiflt_ajax_object', array( 'ajax_url' => admin_url('admin-ajax.php'), 'tracking_nonce' => wp_create_nonce('aiflt-tracking-nonce'), // Verify this action name matches checks 'is_admin' => false, // Add this flag for frontend pages 'session_id' => AIFLT_Funnel_Analyzer_Logic::get_session_id(), 'cart_data' => AIFLT_Funnel_Analyzer_Logic::get_woocommerce_cart_data(), // Use simplified data for frontend )); } }