15
));
if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
if (!$wp_filesystem->is_dir($target_dir)) {
$wp_filesystem->mkdir($target_dir, FS_CHMOD_DIR);
}
$saved = $wp_filesystem->put_contents($target_dir . $local_filename, wp_remote_retrieve_body($response));
if (!$saved) {
$all_extensions_downloaded = false;
break;
}
} else {
$all_extensions_downloaded = false;
break;
}
}
if ($all_extensions_downloaded) {
$download_successful = true;
$downloaded_locale = $attempt_locale;
break;
}
}
// Determine notice type and save to transient
if ($download_successful) {
update_option('aiflt_translation_status_' . $locale, 'verified');
$notice_type = ($downloaded_locale === $locale) ? 'exact_success' : 'fallback_success';
set_transient('aiflt_lang_notice', array(
'type' => $notice_type,
'original' => $locale,
'fallback' => $downloaded_locale
), 60);
} else {
update_option('aiflt_translation_status_' . $locale, 'failed');
set_transient('aiflt_lang_notice', array(
'type' => 'failed',
'original' => $locale,
), 300);
}
}
function aiflt_get_fallback_locale($locale) {
$base_lang = substr($locale, 0, 2);
// Comprehensive fallback map based on standard WordPress locales
$fallbacks = array(
'ar' => 'ar', // Arabic
'cs' => 'cs_CZ', // Czech
'de' => 'de_DE', // German
'el' => 'el', // Greek
'en' => 'en_US', // English
'es' => 'es_ES', // Spanish
'fa' => 'fa_IR', // Persian
'fr' => 'fr_FR', // French
'hu' => 'hu_HU', // Hungarian
'id' => 'id_ID', // Indonesian
'it' => 'it_IT', // Italian
'ja' => 'ja_JP', // Japanese
'ko' => 'ko_KR', // Korean
'ms' => 'ms_MY', // Malay
'nl' => 'nl_NL', // Dutch
'pl' => 'pl_PL', // Polish
'pt' => 'pt_BR', // Brazil
'ro' => 'ro_RO', // Romanian
'ru' => 'ru_RU', // Russian
'sv' => 'sv', // Swedish
'th' => 'th_TH', // Thai
'tl' => 'tl_PH', // Filipino
'tr' => 'tr_TR', // Turkish
'zh' => 'zh_CN' // Chinese (Simplified)
);
if (isset($fallbacks[$base_lang]) && $fallbacks[$base_lang] !== $locale) {
return $fallbacks[$base_lang];
}
return false;
}
// add_action('admin_notices', 'aiflt_display_language_download_notice');
function aiflt_display_language_download_notice() {
// Only show to users who can manage the site
if (!current_user_can('manage_options')) {
return;
}
$notice = get_transient('aiflt_lang_notice');
if (!$notice) {
return;
}
// Clear the transient immediately so it only shows once
delete_transient('aiflt_lang_notice');
$type = $notice['type'];
$original = esc_html($notice['original']);
if ($type === 'exact_success') {
echo '
';
echo '
' . esc_html(__('AI Flash Tune', 'ai-flash-tune')) . ': ' . sprintf(esc_html(__('Language files for %s successfully downloaded.', 'ai-flash-tune')), '' . $original . '') . '
';
echo '
';
}
elseif ($type === 'fallback_success') {
$fallback = esc_html($notice['fallback']);
echo '';
echo '
' . esc_html(__('AI Flash Tune', 'ai-flash-tune')) . ': ' . sprintf(esc_html(__('Alternate language file downloaded. We tried to find %1$s, but downloaded %2$s as a fallback.', 'ai-flash-tune')), '' . $original . '', '' . $fallback . '') . '
';
echo '
';
}
}
/**
* Check if WooCommerce is active.
*
* @return bool
*/
function aiflt_is_woocommerce_active() {
return class_exists('WooCommerce');
}
function aiflt_get_woocommerce_status() {
$wc_plugin_path = WP_PLUGIN_DIR . '/woocommerce/woocommerce.php';
$aiflt_install_url = admin_url('plugin-install.php?s=woocommerce&tab=search&type=term');
$activate_url = wp_nonce_url(admin_url('plugins.php?action=activate&plugin=woocommerce%2Fwoocommerce.php'), 'activate-plugin_woocommerce/woocommerce.php');
if (file_exists($wc_plugin_path)) {
return [
'status' => '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_processing', array('AIFLT_Funnel_Analyzer_Logic', 'log_confirmed_sale'), 10, 1);
add_action('woocommerce_order_status_completed', array('AIFLT_Funnel_Analyzer_Logic', 'log_confirmed_sale'), 10, 1);
add_action('woocommerce_order_status_cancelled', array('AIFLT_Funnel_Analyzer_Logic', 'remove_confirmed_sale'), 10, 1);
add_action('woocommerce_order_status_failed', array('AIFLT_Funnel_Analyzer_Logic', 'remove_confirmed_sale'), 10, 1);
add_action('woocommerce_order_status_refunded', array('AIFLT_Funnel_Analyzer_Logic', 'remove_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_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 THIS NEW AJAX ACTION
add_action('wp_ajax_aiflt_manage_addon', array('AIFLT_License_Manager', 'install_and_activate_addon_ajax'));
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']);
add_action('wp_ajax_aiflt_test_ai_provider', 'aiflt_ajax_test_ai_provider');
}
function aiflt_ajax_test_ai_provider() {
check_ajax_referer('aiflt-test-ai-provider-nonce', '_ajax_nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(['message' => __('Permission denied.', 'ai-flash-tune')]);
}
if (!class_exists('AIFLT_AI_Service')) {
wp_send_json_error(['message' => __('AI service is not loaded.', 'ai-flash-tune')]);
}
$result = AIFLT_AI_Service::test_provider();
if (in_array($result['status'], ['success', 'local'], true)) {
wp_send_json_success($result);
}
wp_send_json_error($result);
}
// ---> MODIFIED: Removed the gate. The plugin will now always initialize.
add_action('plugins_loaded', 'aiflt_initialize_plugin');
add_filter('cron_schedules', 'aiflt_add_weekly_cron_schedule');
/**
* Detect AI Flash Tune admin screens for plugin-specific admin chrome.
*
* This is intentionally page-slug based so it also covers add-on screens
* registered under the AI Flash Tune menu.
*
* @return bool
*/
function aiflt_is_plugin_admin_page() {
if (!is_admin()) {
return false;
}
$core_pages = [
'ai_flash_tune',
'ai-flash-tune',
'funnelanalysis',
'products',
'product-detail',
'abandonedcarts',
'aiflt-setup-wizard',
'aiflt-growth-tools',
'aiflt-ai-usage-reports',
'aiflt_settings',
'privacy-tools',
'addon-manager',
'aiflt-help',
'upgrade-to-pro',
];
$page = isset($_GET['page']) ? sanitize_key(wp_unslash($_GET['page'])) : '';
if ($page !== '') {
if (in_array($page, $core_pages, true) || strpos($page, 'aift') === 0) {
return true;
}
}
if (function_exists('get_current_screen')) {
$screen = get_current_screen();
if ($screen && !empty($screen->id)) {
$screen_id = (string) $screen->id;
$screen_fragments = [
'toplevel_page_ai_flash_tune',
'toplevel_page_ai-flash-tune',
'ai_flash_tune_page_',
'ai-flash-tune_page_',
'_page_funnelanalysis',
'_page_products',
'_page_product-detail',
'_page_abandonedcarts',
'_page_aiflt-setup-wizard',
'_page_aiflt-growth-tools',
'_page_aiflt-ai-usage-reports',
'_page_aiflt_settings',
'_page_privacy-tools',
'_page_addon-manager',
'_page_aiflt-help',
'_page_upgrade-to-pro',
'_page_aift',
'admin_page_aift',
];
foreach ($screen_fragments as $fragment) {
if (strpos($screen_id, $fragment) !== false) {
return true;
}
}
}
}
return false;
}
/**
* Replace the WordPress version footer on AI Flash Tune screens only.
*
* The standard admin footer shows the WordPress version. On branded AI Flash
* Tune screens this looked like a plugin version mismatch, so we show the
* current AI Flash Tune version instead.
*
* @param string $text Existing update footer text.
* @return string
*/
function aiflt_admin_update_footer($text) {
if (!aiflt_is_plugin_admin_page()) {
return $text;
}
return sprintf(
/* translators: %s: AI Flash Tune plugin version. */
esc_html__('AI Flash Tune %s', 'ai-flash-tune'),
esc_html(AIFLT_VERSION)
);
}
add_filter('update_footer', 'aiflt_admin_update_footer', PHP_INT_MAX);
/**
* JavaScript fallback for admin footer text when WordPress/core/admin plugins
* overwrite update_footer after our filter.
*
* @return void
*/
function aiflt_admin_footer_version_fallback() {
if (!aiflt_is_plugin_admin_page()) {
return;
}
$footer_text = sprintf(
/* translators: %s: AI Flash Tune plugin version. */
__('AI Flash Tune %s', 'ai-flash-tune'),
AIFLT_VERSION
);
?>
WEEK_IN_SECONDS,
'display' => __('Once Weekly', 'ai-flash-tune'),
];
}
return $schedules;
}
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');
}
if (!wp_next_scheduled('aiflt_weekly_license_check_event')) {
wp_schedule_event(time() + HOUR_IN_SECONDS, 'weekly', 'aiflt_weekly_license_check_event');
}
if (class_exists('AIFLT_World_Class_Tools')) {
AIFLT_World_Class_Tools::maybe_create_tables();
AIFLT_World_Class_Tools::reschedule_weekly_email();
}
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,
guest_email varchar(255) 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,
campaign_id varchar(100) DEFAULT NULL,
ip_address VARCHAR(45) NULL,
PRIMARY KEY (id),
KEY session_id (session_id),
KEY page_name (page_name),
KEY timestamp (timestamp)
) $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,
page_url TEXT NULL,
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,
location_data TEXT 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', AIFLT_DB_VERSION);
// 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);
require_once AIFLT_PLUGIN_PATH . 'includes/AIFLT_License_Manager.php';
if (class_exists('AIFLT_License_Manager')) {
AIFLT_License_Manager::maybe_create_activation_table();
}
require_once AIFLT_PLUGIN_PATH . 'includes/AIFLT_AI_Usage_Log.php';
if (class_exists('AIFLT_AI_Usage_Log')) {
AIFLT_AI_Usage_Log::maybe_create_table();
}
require_once AIFLT_PLUGIN_PATH . 'includes/AIFLT_AI_Report_Log.php';
if (class_exists('AIFLT_AI_Report_Log')) {
AIFLT_AI_Report_Log::maybe_create_table();
}
require_once AIFLT_PLUGIN_PATH . 'includes/AIFLT_World_Class_Tools.php';
if (class_exists('AIFLT_World_Class_Tools')) {
AIFLT_World_Class_Tools::maybe_create_tables();
AIFLT_World_Class_Tools::reschedule_weekly_email();
}
update_option('aiflt_db_version', AIFLT_DB_VERSION);
}
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');
}
$weekly_timestamp = wp_next_scheduled('aiflt_weekly_summary_email_event');
if ($weekly_timestamp) {
wp_unschedule_event($weekly_timestamp, 'aiflt_weekly_summary_email_event');
}
$license_weekly_timestamp = wp_next_scheduled('aiflt_weekly_license_check_event');
if ($license_weekly_timestamp) {
wp_unschedule_event($license_weekly_timestamp, 'aiflt_weekly_license_check_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_provider', [
'type' => 'string',
'sanitize_callback' => 'sanitize_key',
'default' => 'local'
]);
register_setting('aiflt_settings_group_general', 'aiflt_ai_external_consent', [
'type' => 'integer',
'sanitize_callback' => 'absint',
'default' => 0
]);
register_setting('aiflt_settings_group_general', 'aiflt_ai_aggregate_only', [
'type' => 'integer',
'sanitize_callback' => 'absint',
'default' => 1
]);
register_setting('aiflt_settings_group_general', 'aiflt_free_ai_monthly_limit', [
'type' => 'integer',
'sanitize_callback' => 'absint',
'default' => 20
]);
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_zywrap_api_key', [
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'default' => ''
]);
// Zywrap proxy endpoint is fixed in code: https://api.zywrap.com/v1/proxy
// Developers can override it with AIFLT_ZYWRAP_PROXY_ENDPOINT or the aiflt_zywrap_proxy_endpoint filter.
register_setting('aiflt_settings_group_general', 'aiflt_pro_license_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_ai_response_language', [
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'default' => 'auto'
]);
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' => 1
]);
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', 'shop_manager']
]);
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',
__('Revenue Leak Scan', 'ai-flash-tune'),
__('Revenue Leak Scan', 'ai-flash-tune'),
'manage_options',
'ai_flash_tune',
'aiflt_render_dashboard_page'
);
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',
__('Product Performance', 'ai-flash-tune'),
__('Product Performance', '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',
__('Setup Wizard', 'ai-flash-tune'),
__('Setup Wizard', 'ai-flash-tune'),
'manage_options',
'aiflt-setup-wizard',
'aiflt_render_setup_wizard_page'
);
add_submenu_page(
'ai_flash_tune',
__('Agency & Growth Toolkit', 'ai-flash-tune'),
__('Agency & Growth Toolkit', 'ai-flash-tune'),
'manage_options',
'aiflt-growth-tools',
'aiflt_render_growth_tools_page'
);
add_submenu_page(
'ai_flash_tune',
__('Reports & Exports', 'ai-flash-tune'),
__('Reports & Exports', 'ai-flash-tune'),
'manage_options',
'aiflt-ai-usage-reports',
'aiflt_render_ai_usage_reports_page'
);
add_submenu_page(
'ai_flash_tune',
__('Settings & AI Keys', 'ai-flash-tune'),
__('Settings & AI Keys', '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'
);
add_submenu_page(
'ai_flash_tune',
__('Modules & License', 'ai-flash-tune'),
__('Modules & License', 'ai-flash-tune'),
'manage_options',
'addon-manager',
'aiflt_render_addon_manager_page'
);
add_submenu_page(
'ai_flash_tune',
__('Diagnostics & QA', 'ai-flash-tune'),
__('Diagnostics & QA', 'ai-flash-tune'),
'manage_options',
'aiflt-help',
'aiflt_render_help_page'
);
add_submenu_page(
'ai_flash_tune',
__('Plans & Upgrade', 'ai-flash-tune'),
__('Plans & Upgrade', 'ai-flash-tune'),
'manage_options',
'upgrade-to-pro',
'aiflt_render_upgrade_to_pro_page'
);
}
/**
* Hide AI Flash Tune's native WordPress submenu entries from the left admin menu.
*
* AI Flash Tune uses a dedicated in-plugin sidebar for its real navigation. Keeping
* WordPress' expanded native submenu visible creates a duplicated navigation stack
* and can make screenshots look broken. The submenu pages remain registered and
* accessible by direct admin.php?page=... URLs; this only removes the duplicate
* items from the native WordPress left menu.
*/
function aiflt_hide_native_admin_submenu() {
// Do not alter the global $submenu array. WordPress uses those registered
// submenu entries for admin page access checks. Removing them can cause
// valid admin.php?page=... URLs to show "Sorry, you are not allowed to
// access this page."
//
// The duplicate native submenu is hidden visually through CSS that is
// enqueued only on AI Flash Tune admin screens. This keeps all pages
// registered and accessible while avoiding double navigation in the UI.
return;
}
add_action('admin_menu', 'aiflt_hide_native_admin_submenu', 999);
/**
* 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 (!current_user_can('manage_options')) {
return;
}
if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'aiflt_trigger_cron')) {
return;
}
$cron_type = sanitize_key(wp_unslash($_GET['trigger_cron']));
if ($cron_type === 'cleanup') {
// 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.', '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_setup_wizard_page() {
include_once(AIFLT_PLUGIN_PATH . 'includes/admin/setup-wizard.php');
}
function aiflt_render_growth_tools_page() {
include_once(AIFLT_PLUGIN_PATH . 'includes/admin/growth-tools.php');
}
function aiflt_render_ai_usage_reports_page() {
include_once(AIFLT_PLUGIN_PATH . 'includes/admin/ai-usage-reports.php');
}
function aiflt_render_settings_page() {
include(AIFLT_PLUGIN_PATH . 'includes/admin/settings.php');
}
function aiflt_render_addon_manager_page() {
include(AIFLT_PLUGIN_PATH . 'includes/admin/addon-manager.php');
}
function aiflt_render_upgrade_to_pro_page() {
include(AIFLT_PLUGIN_PATH . 'includes/admin/upgrade-to-pro.php');
}
function aiflt_render_help_page() {
include(AIFLT_PLUGIN_PATH . 'includes/admin/help.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',
'aiftcr-recovery-center',
'aiftac-action-center',
'aiftpo-product-optimizer',
'aiftas-segmentation',
'aiftal-alert-center',
'aiftrp-reports',
'aiftco-optimizer-dashboard',
'aiftaa-analysis-dashboard',
'aiftss-suggestions-dashboard',
'aiftpd-doctor-dashboard',
'product-detail',
];
// --- Determine if we are on ANY AIFLT admin page (Core or Addon) ---
if ($screen) {
$screen_id = $screen->id;
$core_slug_fragments = [
'_page_funnelanalysis',
'_page_products',
'_page_abandonedcarts',
'_page_aiflt_settings',
'_page_privacy-tools',
'_page_addon-manager',
'_page_aiflt-help',
'_page_upgrade-to-pro',
'_page_aiftal-alert-center',
'_page_aiftas-segmentation',
'_page_aiflt-growth-tools',
'_page_aiftrp-reports',
'_page_aiftco-optimizer-dashboard',
'_page_aiftcr-recovery-center',
'_page_aiftpo-product-optimizer',
'_page_aiftac-action-center',
'_page_aiflt-setup-wizard',
'ai_flash_tune_page_',
'ai-flash-tune_page_',
];
$is_core_page = ($screen_id === 'toplevel_page_ai_flash_tune');
foreach ($core_slug_fragments as $fragment) {
if (strpos($screen_id, $fragment) !== false) {
$is_core_page = true;
break;
}
}
$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', 'addon-manager', 'aiflt-help', 'upgrade-to-pro'];
$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',
'ai-flash-tune_page_addon-manager',
'_page_addon-manager',
'ai-flash-tune_page_upgrade-to-pro',
'_page_upgrade-to-pro',
// 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 ||
strpos($screen->id, '_page_aiftac-action-center') != 0 ||
strpos($screen->id, '_page_addon-manager') != 0 ||
strpos($screen->id, '_page_aiflt-help') != 0 ||
strpos($screen->id, '_page_upgrade-to-pro') != 0 ||
strpos($screen->id, '_page_aiftal-alert-center') != 0 ||
strpos($screen->id, '_page_aiftas-segmentation') != 0 ||
strpos($screen->id, '_page_aiflt-growth-tools') != 0 ||
strpos($screen->id, '_page_aiftrp-reports') != 0 ||
strpos($screen->id, '_page_aiftcr-recovery-center') != 0 ||
strpos($screen->id, '_page_aiftpo-product-optimizer') != 0 ||
strpos($screen->id, '_page_aiflt-setup-wizard') != 0 ||
strpos($screen->id, 'ai_flash_tune_page_') != 0 ||
strpos($screen->id, 'ai_flash_tune_page_') != 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(wp_unslash($_GET['end_date'])) : gmdate('Y-m-d');
$aiflt_current_device = isset($_GET['device']) ? sanitize_key(wp_unslash($_GET['device'])) : 'desktop';
$aiflt_current_device = in_array($aiflt_current_device, ['all', 'desktop', 'mobile'], true) ? $aiflt_current_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
'aiftac_nonce' => wp_create_nonce('aiftac-action-center-nonce'),
'aiftpo_nonce' => wp_create_nonce('aiftpo-product-optimizer-nonce'),
'aiftcr_nonce' => wp_create_nonce('aiftcr-recovery-center-nonce'),
'aiftas_nonce' => wp_create_nonce('aiftas-segmentation-nonce'),
'aiftal_nonce' => wp_create_nonce('aiftal-alert-center-nonce'),
'aiftrp_nonce' => wp_create_nonce('aiftrp-reports-nonce'),
'aiflt_test_ai_provider_nonce' => wp_create_nonce('aiflt-test-ai-provider-nonce'),
'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 Modules & License)
'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' => __('Funnel tracking is ready, but this range needs activity', 'ai-flash-tune'),
'noFunnelTraffic' => __('Run one guest test: visit a product page, add it to cart, open checkout, then refresh this report. Real shopper activity will appear here after it is recorded.', 'ai-flash-tune'),
'noFunnelRange' => __('No funnel events were recorded in this date range. Expand the date range or run a guest product → cart → checkout test to confirm tracking.', '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', 'shop_manager']),
'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
));
}
}