'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');
?>
'free'|'pro'
*/
function aiflt_features() {
return (array) apply_filters('aiflt_features', [
'recovery_reminders' => 'free',
'recovery_coupons' => 'free',
]);
}
function aiflt_has_feature($feature) {
$tier = aiflt_features()[$feature] ?? 'free';
return $tier === 'free' || aiflt_is_pro_active();
}
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',
'aiflt_settings',
];
// Every other AI Flash Tune (and Pro) page slug starts with "aiflt-" or "aift".
$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',
'ai_flash_tune_page_',
'ai-flash-tune_page_',
'_page_aiflt',
'_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');
}
// Store activation timestamp if it doesn't exist
if (false === get_option('aiflt_activation_time')) {
add_option('aiflt_activation_time', time());
}
// One schema definition for fresh installs and upgrades.
require_once AIFLT_PLUGIN_PATH . 'includes/AIFLT_AI_Usage_Log.php';
require_once AIFLT_PLUGIN_PATH . 'includes/AIFLT_AI_Report_Log.php';
require_once AIFLT_PLUGIN_PATH . 'includes/AIFLT_World_Class_Tools.php';
require_once AIFLT_PLUGIN_PATH . 'includes/AIFLT-Updates.php';
aiflt_run_database_updates(get_option('aiflt_db_version', '0'));
update_option('aiflt_db_version', AIFLT_DB_VERSION);
update_option('aiflt_db_health_version', AIFLT_DB_VERSION);
AIFLT_World_Class_Tools::reschedule_weekly_email();
}
function aiflt_deactivate_plugin() {
wp_clear_scheduled_hook('aiflt_daily_cleanup_event');
wp_clear_scheduled_hook('aiflt_weekly_summary_email_event');
wp_clear_scheduled_hook('aiflt_recovery_tick');
wp_clear_scheduled_hook('aiflt_review_tick');
// Left by versions before 1.0.4, which ran the licence client in this plugin.
wp_clear_scheduled_hook('aiflt_weekly_license_check_event');
wp_clear_scheduled_hook('aiflt_twicedaily_addon_update_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
)
);
}
// Finished cart reminders (kept at least 90 days for the reports).
if (class_exists('AIFLT_Cart_Recovery')) {
AIFLT_Cart_Recovery::cleanup_old_rows();
}
}
/**
* 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' => 0
]);
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_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);
}
/**
* 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
}
}
// Enqueue scripts and styles for the admin side
function aiflt_enqueue_admin_scripts($hook) {
if (!aiflt_is_plugin_admin_page()) {
return;
}
// Every screen uses aiflt-admin.css and inline SVG icons (AIFLT_UI::icon()).
wp_enqueue_style('aiflt-admin', AIFLT_PLUGIN_URL . 'includes/css/aiflt-admin.css', [], AIFLT_VERSION);
if (!aiflt_is_woocommerce_active()) {
return;
}
// 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
// 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'),
// Section list shared by the PHP and JavaScript answer renderers.
'answerSections' => class_exists('AIFLT_UI') ? AIFLT_UI::answer_sections() : [],
'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
'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'),
'details' => __('Details', 'ai-flash-tune'),
'close' => __('Close', 'ai-flash-tune'),
'copied' => __('Copied', 'ai-flash-tune'),
'aiWorking' => __('Working on the answer…', 'ai-flash-tune'),
'aiNoAnswer' => __('No answer came back. Try another question.', 'ai-flash-tune'),
'aiError' => __('The answer could not be created:', 'ai-flash-tune'),
'ansSummary' => __('Summary', 'ai-flash-tune'),
'ansDetails' => __('Details', 'ai-flash-tune'),
'ansEvidence' => __('What the numbers show', 'ai-flash-tune'),
'ansCauses' => __('Likely causes to check', 'ai-flash-tune'),
'ansFixes' => __('Fixes, in order', 'ai-flash-tune'),
'ansChecks' => __('Next checks', 'ai-flash-tune'),
'ansNextSteps' => __('Next steps', 'ai-flash-tune'),
'ansNotYet' => __('Do not change yet', 'ai-flash-tune'),
'ansMore' => __('More details', 'ai-flash-tune'),
'ansConfidence' => __('Confidence:', 'ai-flash-tune'),
'ansReadiness' => __('Data:', 'ai-flash-tune'),
'ansImpact' => __('Impact:', 'ai-flash-tune'),
'ansEffort' => __('Effort:', 'ai-flash-tune'),
'ansRisk' => __('Risk:', '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 the storefront tracking script.
// The hook is registered only while WooCommerce is active in aiflt_initialize_plugin().
function aiflt_enqueue_frontend_scripts() {
if (!class_exists('AIFLT_Funnel_Analyzer_Logic') || !AIFLT_Funnel_Analyzer_Logic::is_tracking_enabled()) {
return;
}
// Excluded roles and IPs never load the script. (Consent is checked in the
// browser, and again on the server for every request.)
if (is_user_logged_in()) {
$excluded_roles = (array) get_option('aiflt_excluded_roles', ['administrator', 'shop_manager']);
if (array_intersect((array) wp_get_current_user()->roles, $excluded_roles)) {
return;
}
}
$user_ip = AIFLT_Funnel_Analyzer_Logic::client_ip();
$excluded_ips_raw = (string) get_option('aiflt_excluded_ips', '');
if ($user_ip !== '' && $excluded_ips_raw !== '') {
$excluded_ips = array_map('trim', explode("\n", str_replace("\r", '', $excluded_ips_raw)));
if (in_array($user_ip, $excluded_ips, true)) {
return;
}
}
wp_enqueue_script('ai-flash-tune-tracking', AIFLT_PLUGIN_URL . 'includes/js/ai-flash-tune-tracking.js', ['jquery'], AIFLT_VERSION, true);
// Nothing visitor-specific is printed into the page, so full-page caches
// can serve it to everyone. The session lives in a first-party cookie.
wp_localize_script('ai-flash-tune-tracking', 'aiflt_tracking', [
'ajax_url' => admin_url('admin-ajax.php'),
'tracking_nonce' => wp_create_nonce('aiflt-tracking-nonce'),
'require_consent' => (int) get_option('aiflt_require_consent', 0) === 1,
'capture_guest_email' => (bool) apply_filters('aiflt_capture_guest_email', true),
// Cart reminders: the short note under the checkout email field, with a "No thanks" link.
'reminder_notice' => class_exists('AIFLT_Cart_Recovery') && AIFLT_Cart_Recovery::is_enabled() && !empty(AIFLT_Cart_Recovery::settings()['notice'])
? AIFLT_Cart_Recovery::settings()['notice_text'] : '',
'reminder_decline' => __('No thanks', 'ai-flash-tune'),
'reminder_declined' => __('OK, we won\'t send reminders.', 'ai-flash-tune'),
'save_cart' => aiflt_save_cart_config(),
'cookie_path' => defined('COOKIEPATH') && COOKIEPATH ? COOKIEPATH : '/',
'cookie_lifetime' => (int) apply_filters('aiflt_session_cookie_lifetime', 30 * DAY_IN_SECONDS),
]);
}
/**
* Texts and switches for the "Save my cart" box and the exit popup, or false
* when neither is on. The same for every visitor, so pages stay cacheable.
*
* @return array|false
*/
function aiflt_save_cart_config() {
if (!class_exists('AIFLT_Cart_Recovery') || !AIFLT_Cart_Recovery::save_cart_enabled()) {
return false;
}
return [
'box' => AIFLT_Cart_Recovery::save_cart_enabled('box'),
'exit' => AIFLT_Cart_Recovery::save_cart_enabled('exit'),
'title' => __('Not ready to buy yet?', 'ai-flash-tune'),
'exit_title' => __('Before you go, save your cart?', 'ai-flash-tune'),
'text' => __('Get a link to this cart by email and pick it up later, on any device.', 'ai-flash-tune'),
'label' => __('Your email', 'ai-flash-tune'),
'button' => __('Email me my cart', 'ai-flash-tune'),
'note' => __('You may get a couple of reminders about this cart. Every email has an unsubscribe link.', 'ai-flash-tune'),
'done' => __('Sent. Check your inbox for the link to your cart.', 'ai-flash-tune'),
'error' => __('That didn\'t work. Please check the email address and try again.', 'ai-flash-tune'),
'close' => __('Close', 'ai-flash-tune'),
'no_thanks' => __('No thanks', 'ai-flash-tune'),
// Asked only when the popup is about to open: is there anything in the cart?
'cart_api' => esc_url_raw(rest_url('wc/store/v1/cart')),
];
}
/**
* Tell the WP Consent API that this plugin checks consent itself.
*/
add_filter('wp_consent_api_registered_' . plugin_basename(__FILE__), '__return_true');
/**
* Describe the tracking cookie to consent plugins that list cookies.
*/
function aiflt_register_consent_cookie_info() {
if (function_exists('wp_add_cookie_info')) {
wp_add_cookie_info(
'aiflt_session_id',
'AI Flash Tune',
'statistics',
__('30 days', 'ai-flash-tune'),
__('Groups page views, cart and checkout steps of one visit so the store owner can see where shoppers drop off.', 'ai-flash-tune'),
false,
false,
false
);
}
}
add_action('plugins_loaded', 'aiflt_register_consent_cookie_info', 20);