prefix; add_option('aieo_site_prefix', $prefix_name, '', 'no'); } // Always ensure correct table names (fix old installations with wrong suffix) $correct_orders_table = $wpdb->prefix . 'aieo_temp_orders'; // Use update_option instead of add_option to ensure immediate availability update_option('aieo_site_orders_table', $correct_orders_table, 'no'); $correct_store_orders_table = $wpdb->prefix . 'aieo_temp_store_orders'; update_option('aieo_store_orders_table', $correct_store_orders_table, 'no'); update_option('aieo_offline_orders', $correct_store_orders_table, 'no'); $correct_products_table = $wpdb->prefix . 'aieo_temp_product_catalogue'; update_option('aieo_site_products_table', $correct_products_table, 'no'); if (get_option('aieo_core_attribute_brands') === false) { // Set the value for 'aieo_core_attribute_brands' option $default_attribute_for_brand = 'product_brand'; add_option('aieo_core_attribute_brands', $default_attribute_for_brand, '', 'no'); } if (get_option('aieo_core_attribute_size') === false) { // Set the value for 'aieo_core_attribute_size' option $default_attribute_for_size = 'pa_size,pa_noumero,pa_megethos'; add_option('aieo_core_attribute_size', $default_attribute_for_size, '', 'no'); } if (get_option('aieo_core_attribute_color') === false) { // Set the value for 'aieo_core_attribute_color' option $default_attribute_for_color = 'pa_color,pa_colour'; add_option('aieo_core_attribute_color', $default_attribute_for_color, '', 'no'); } if (get_option('aieo_season_days_past') === false) { // Set the value for 'aieo_season_days_past' option $default_season_days_past = '15'; add_option('aieo_season_days_past', $default_season_days_past, '', 'no'); } if (get_option('aieo_analytics_eponymous_id_field') === false) { // Set the value for 'aieo_analytics_eponymous_id_field' option $default_analytics_eponymous_id_field = 'EponymousId'; add_option('aieo_analytics_eponymous_id_field', $default_analytics_eponymous_id_field, '', 'no'); } if (get_option('aieo_season_days_after') === false) { // Set the value for 'aieo_season_days_after' option $default_season_days_after = '60'; add_option('aieo_season_days_after', $default_season_days_after, '', 'no'); } // Use update_option instead of add_option to ensure immediate availability $table_name = $wpdb->prefix . 'aieo_core_product_attributes'; update_option('aieo_core_product_attributes_table', $table_name, 'no'); $table_name = $wpdb->prefix . 'aieo_core_product_category_hierarchy'; update_option('aieo_core_product_category_hierarchy_table', $table_name, 'no'); $table_name = $wpdb->prefix . 'aieo_core_product_vitals'; update_option('aieo_core_product_vitals_table', $table_name, 'no'); $table_name = $wpdb->prefix . 'aieo_core_variation_vitals'; update_option('aieo_core_variation_vitals_table', $table_name, 'no'); $table_name = $wpdb->prefix . 'aieo_core_reciprocal_products'; update_option('aieo_core_reciprocal_products_table', $table_name, 'no'); if (get_option('aieo_erp_store_products_table') === false) { // Set the value for 'aieo_erp_store_products_table' option $table_name = $wpdb->prefix . 'aieo_erp_store_products'; add_option('aieo_erp_store_products_table', $table_name, '', 'no'); } if (get_option('aieo_erp_store_orders_table') === false) { // Set the value for 'aieo_erp_store_orders_table' option $table_name = $wpdb->prefix . 'aieo_erp_store_orders'; add_option('aieo_erp_store_orders_table', $table_name, '', 'no'); } if (get_option('aieo_erp_store_customers_table') === false) { // Set the value for 'aieo_erp_store_customers_table' option $table_name = $wpdb->prefix . 'aieo_erp_store_customers'; add_option('aieo_erp_store_customers_table', $table_name, '', 'no'); } if (get_option('aieo_google_user_journey_table') === false) { // Set the value for 'aieo_google_user_journey_table' option $table_name = $wpdb->prefix . 'aieo_google_user_journey'; add_option('aieo_google_user_journey_table', $table_name, '', 'no'); } if (get_option('aieo_order_id') === false) { add_option('aieo_order_id', '1', '', 'no'); } if (get_option('aieo_max_records') === false) { add_option('aieo_max_records', '1000', '', 'no'); } if (get_option('aieo_batch_size') === false) { add_option('aieo_batch_size', '100', '', 'no'); } if (get_option('aieo_batch_sleep') === false) { add_option('aieo_batch_sleep', '0', '', 'no'); } if (get_option('aieo_include_text') === false) { add_option('aieo_include_text', '1', '', 'no'); } if (get_option('aieo_include_attributes') === false) { add_option('aieo_include_attributes', '1', '', 'no'); } // Export checkbox options - default to '0' (unchecked) so user chooses what to run if (get_option('aieo_create_attributes') === false) { add_option('aieo_create_attributes', '0', '', 'no'); } if (get_option('aieo_create_catalogue') === false) { add_option('aieo_create_catalogue', '0', '', 'no'); } if (get_option('aieo_create_orders') === false) { add_option('aieo_create_orders', '0', '', 'no'); } if (get_option('aieo_erp_consolidation') === false) { add_option('aieo_erp_consolidation', '0', '', 'no'); } if (get_option('aieo_erp_merge_orders') === false) { add_option('aieo_erp_merge_orders', '0', '', 'no'); } if (get_option('aieo_include_unsold') === false) { add_option('aieo_include_unsold', '0', '', 'no'); } if (get_option('aieo_include_aggregate_stats') === false) { add_option('aieo_include_aggregate_stats', '0', '', 'no'); } if (get_option('aieo_include_aggregate_cust_std_stats') === false) { add_option('aieo_include_aggregate_cust_std_stats', '0', '', 'no'); } if (get_option('aieo_include_aggregate_cust_adv_stats') === false) { add_option('aieo_include_aggregate_cust_adv_stats', '0', '', 'no'); } if (get_option('aieo_create_uuids') === false) { add_option('aieo_create_uuids', '0', '', 'no'); } if (get_option('aieo_create_export') === false) { add_option('aieo_create_export', '0', '', 'no'); } if (get_option('aieo_include_full_text') === false) { add_option('aieo_include_full_text', '0', '', 'no'); } if (get_option('aieo_include_price') === false) { add_option('aieo_include_price', '1', '', 'no'); } if (get_option('aieo_variations_choice') === false) { add_option('aieo_variations_choice', '1', '', 'no'); } if (get_option('aieo_include_eponymous') === false) { add_option('aieo_include_eponymous', '1', '', 'no'); } if (get_option('aieo_include_reciprocity') === false) { add_option('aieo_include_reciprocity', '0', '', 'no'); } if (get_option('aieo_include_seasonality') === false) { add_option('aieo_include_seasonality', '0', '', 'no'); } if (get_option('aieo_include_restricted_seasonality') === false) { add_option('aieo_include_restricted_seasonality', '0', '', 'no'); } if (get_option('aieo_instore_anonymous') === false) { add_option('aieo_instore_anonymous', '0', '', 'no'); } if (get_option('aieo_activate_utm_stats') === false) { add_option('aieo_activate_utm_stats', '0', '', 'no'); } if (get_option('aieo_google_ga4') === false) { add_option('aieo_google_ga4', '0', '', 'no'); } if (get_option('aieo_display_upsells') === false) { add_option('aieo_display_upsells', '0', '', 'no'); } if (get_option('aieo_display_cross_sells') === false) { add_option('aieo_display_cross_sells', '0', '', 'no'); } if (get_option('aieo_display_related') === false) { add_option('aieo_display_related', '0', '', 'no'); } if (get_option('aieo_display_recently_viewed_products') === false) { add_option('aieo_display_recently_viewed_products', '0', '', 'no'); } if (get_option('aieo_season_days_past') === false) { add_option('aieo_season_days_past', '15', '', 'no'); } if (get_option('aieo_season_days_after') === false) { add_option('aieo_season_days_after', '60', '', 'no'); } // Record initial activation date (only set once, never updated) if (get_option('aieo_initial_activation_date') === false) { add_option('aieo_initial_activation_date', current_time('mysql'), '', 'no'); } } register_activation_hook(__FILE__, 'aieo_set_default_options'); // Inside your plugin's main file or in a file that gets loaded during plugin activation // Register a hook to execute your table creation function during plugin activation register_activation_hook(__FILE__, 'aieo_create_temp_tables_activation_hook'); // Define the activation hook function function aieo_create_temp_tables_activation_hook() { global $wpdb; // Enable error reporting for debugging $wpdb->show_errors(); error_log('AIEO: Starting table creation activation hook'); // Load WordPress database manipulation functions require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); // CRITICAL FIX: Set options for backward compatibility with stored procedures // that still read these options aieo_set_default_options(); error_log('AIEO: Options set'); // CRITICAL FIX: Call table creation functions WITHOUT parameters // Table names are now constructed internally like chat tables (using $wpdb->prefix directly) // This eliminates dependency on options and prevents race conditions error_log('AIEO: Creating temp_orders table'); aieo_create_temp_orders_table(); error_log('AIEO: Creating temp_store_orders table'); aieo_create_temp_store_orders_table(); error_log('AIEO: Creating temp_products table'); aieo_create_temp_products_table(); error_log('AIEO: Creating core_product_attributes table'); aieo_create_core_product_attributes_table(); error_log('AIEO: Creating core_product_category_hierarchy table'); aieo_create_core_product_category_hierarchy_table(); error_log('AIEO: Creating core_product_vitals table'); aieo_create_core_product_vitals_table(); error_log('AIEO: Creating core_variation_vitals table'); aieo_create_core_variation_vitals_table(); error_log('AIEO: Creating core_reciprocal_products table'); aieo_create_core_reciprocal_products_table(); // Create AI Chat tables error_log('AIEO: Creating chat_embeddings table'); aieo_create_chat_embeddings_table(); error_log('AIEO: Creating chat_history table'); aieo_create_chat_history_table(); // Create Session Tracker table error_log('AIEO: Creating sessions table'); aieo_create_sessions_table(); error_log('AIEO: Table creation activation hook completed'); } function aieo_create_stored_procedures() { global $wpdb; // CRITICAL FIX: Ensure options are set BEFORE trying to read them // This fixes the race condition where stored procedures weren't created on first activation aieo_set_default_options(); $sp_prefix = get_option('aieo_site_prefix'); $sp_orders_table = get_option('aieo_site_orders_table'); $sp_store_orders_table = get_option('aieo_store_orders_table'); $sp_products_table = get_option('aieo_site_products_table'); $sp_core_product_attributes_table_name = get_option('aieo_core_product_attributes_table'); $sp_core_product_category_hierarchy_table_name = get_option('aieo_core_product_category_hierarchy_table'); $sp_core_product_vitals_table_name = get_option('aieo_core_product_vitals_table'); $sp_core_variation_vitals_table_name = get_option('aieo_core_variation_vitals_table'); $sp_erp_store_products_table_name = get_option('aieo_erp_store_products_table'); $sp_erp_store_orders_table_name = get_option('aieo_erp_store_orders_table'); $sp_erp_store_customers_table_name = get_option('aieo_erp_store_customers_table'); $sp_google_user_journey_table_name = get_option('aieo_google_user_journey_table'); $domain_name = get_site_url(); // CRITICAL FIX: Drop all procedures BEFORE creating them // This prevents "PROCEDURE already exists" errors during activation // Suppress errors during drop (procedures might not exist on first activation) $wpdb->hide_errors(); $wpdb->suppress_errors(true); @aieo_drop_sp_AIEO_InsertCoreProductAttributes($sp_prefix); @aieo_drop_sp_AIEO_InsertProductCategoryHierarchy($sp_prefix); @aieo_drop_sp_AIEO_InsertProductVitals($sp_prefix); @aieo_drop_sp_AIEO_InsertVariationVitals($sp_prefix); @aieo_drop_sp_AIEO_CombineVariationVitalsInProductVitals($sp_prefix); @aieo_drop_sp_AIEO_UpdateOrdersWithUnsold($sp_prefix); @aieo_drop_sp_AIEO_FindDifferences($sp_prefix); @aieo_drop_sp_AIEO_Create_Product_Catalogue_HPOS($sp_prefix); @aieo_drop_sp_AIEO_Export_Orders_HPOS($sp_prefix); @aieo_drop_sp_AIEO_Export_Store_Orders($sp_prefix); @aieo_drop_sp_AIEO_Merge_Store_Orders($sp_prefix); @aieo_drop_sp_AIEO_Export_Orders_non_HPOS($sp_prefix); @aieo_drop_sp_AIEO_RenameTable($sp_prefix); @aieo_drop_sp_AIEO_UpdateContentWordCount($sp_prefix); @aieo_drop_sp_AIEO_UpdateContentOutgoingLinks($sp_prefix); @aieo_drop_sp_AIEO_UpdateContentIntroPlain($sp_prefix); @aieo_drop_sp_AIEO_UpdateProductCentricStats($sp_prefix); @aieo_drop_sp_AIEO_UpdateCustomerCentricStdStats($sp_prefix); @aieo_drop_sp_AIEO_UpdateCustomerCentricAdvStats($sp_prefix); @aieo_drop_sp_AIEO_GenerateGraphDBUUIDs($sp_prefix); @aieo_drop_sp_AIEO_GenerateGraphDBUUIDFreqs($sp_prefix); // Drop MySQL functions @aieo_drop_function_AIEO_StripHTML(); @aieo_drop_function_AIEO_CountWords(); @aieo_drop_function_AIEO_CountLinks(); // Drop legacy procedures that are no longer created but may exist from older versions @aieo_drop_sp_AIEO_Include_Products_Without_Sales(); @$wpdb->query("DROP PROCEDURE IF EXISTS UpdateShortDescriptionForProduct"); // Re-enable error reporting for CREATE statements $wpdb->show_errors(); $wpdb->suppress_errors(false); // Create optimized v2 procedures aieo_create_sp_AIEO_InsertCoreProductAttributes($sp_prefix, $sp_core_product_attributes_table_name); aieo_create_sp_AIEO_InsertProductCategoryHierarchy($sp_prefix, $sp_core_product_category_hierarchy_table_name); aieo_create_sp_AIEO_InsertProductVitals($sp_prefix, $sp_core_product_vitals_table_name, $domain_name); aieo_create_sp_AIEO_InsertVariationVitals($sp_prefix, $sp_core_variation_vitals_table_name); aieo_create_sp_AIEO_CombineVariationVitalsInProductVitals($sp_prefix, $sp_core_product_vitals_table_name, $domain_name); aieo_create_sp_AIEO_UpdateOrdersWithUnsold($sp_prefix, $sp_orders_table, $sp_products_table); aieo_create_sp_AIEO_FindDifferences($sp_prefix); aieo_create_sp_AIEO_Create_Product_Catalogue_HPOS($sp_prefix, $sp_products_table); aieo_create_sp_AIEO_Export_Orders_HPOS($sp_prefix, $sp_orders_table); aieo_create_sp_AIEO_Export_Store_Orders($sp_prefix, $sp_store_orders_table, $sp_erp_store_products_table_name, $sp_erp_store_orders_table_name, $sp_erp_store_customers_table_name); aieo_create_sp_AIEO_Merge_Store_Orders($sp_prefix); aieo_create_sp_AIEO_Export_Orders_non_HPOS($sp_prefix, $sp_orders_table); // UNUSED - Never called in current codebase aieo_create_sp_AIEO_RenameTable($sp_prefix); aieo_create_sp_AIEO_UpdateContentWordCount($sp_prefix); aieo_create_sp_AIEO_UpdateContentOutgoingLinks($sp_prefix); aieo_create_sp_AIEO_UpdateContentIntroPlain($sp_prefix); aieo_create_sp_UpdateProductCentricStats($sp_prefix); aieo_create_sp_AIEO_UpdateCustomerCentricStdStats_Smart($sp_prefix, $sp_orders_table); aieo_create_sp_AIEO_UpdateCustomerCentricAdvStats($sp_prefix, $sp_orders_table); aieo_create_sp_AIEO_GenerateGraphDBUUIDs($sp_prefix); aieo_create_sp_AIEO_GenerateGraphDBUUIDFreqs($sp_prefix); // UNUSED - Never called in current codebase // aieo_create_sp_AIEO_Orchestrate_all_non_HPOS_SPs($sp_prefix); aieo_create_function_AIEO_StripHTML(); aieo_create_function_AIEO_CountWords(); aieo_create_function_AIEO_CountLinks(); } function aieo_drop_stored_procedures() { global $wpdb; // Set aggressive timeouts set_time_limit(120); @ini_set('max_execution_time', 120); @ini_set('mysql.connect_timeout', 10); // Suppress errors during cleanup $wpdb->hide_errors(); $wpdb->suppress_errors(true); $sp_prefix = get_option('aieo_site_prefix'); $sp_temp_orders_table_name = get_option('aieo_site_orders_table'); $sp_temp_store_orders_table_name = get_option('aieo_offline_orders'); $sp_temp_products_table_name = get_option('aieo_site_products_table'); $sp_core_product_attributes_table_name = get_option('aieo_core_product_attributes_table'); $sp_core_product_category_hierarchy_table_name = get_option('aieo_core_product_category_hierarchy_table'); $sp_core_product_vitals_table_name = get_option('aieo_core_product_vitals_table'); $sp_core_variation_vitals_table_name = get_option('aieo_core_variation_vitals_table'); $sp_core_reciprocal_products_table_name = get_option('aieo_core_reciprocal_products_table'); @aieo_drop_sp_AIEO_InsertCoreProductAttributes($sp_prefix); @aieo_drop_sp_AIEO_InsertProductCategoryHierarchy($sp_prefix); @aieo_drop_sp_AIEO_InsertProductVitals($sp_prefix); @aieo_drop_sp_AIEO_InsertVariationVitals($sp_prefix); @aieo_drop_sp_AIEO_CombineVariationVitalsInProductVitals($sp_prefix); @aieo_drop_sp_AIEO_UpdateOrdersWithUnsold($sp_prefix); @aieo_drop_sp_AIEO_FindDifferences($sp_prefix); @aieo_drop_sp_AIEO_Create_Product_Catalogue_HPOS($sp_prefix); @aieo_drop_sp_AIEO_Export_Orders_HPOS($sp_prefix); @aieo_drop_sp_AIEO_Export_Store_Orders($sp_prefix); @aieo_drop_sp_AIEO_Export_Orders_non_HPOS($sp_prefix); @aieo_drop_sp_AIEO_Merge_Store_Orders($sp_prefix); // UNUSED - Never called in current codebase // @aieo_drop_sp_AIEO_StripHTMLAndReplicateContentIntro($sp_prefix); @aieo_drop_sp_AIEO_RenameTable($sp_prefix); @aieo_drop_sp_AIEO_UpdateContentWordCount($sp_prefix); @aieo_drop_sp_AIEO_UpdateContentOutgoingLinks($sp_prefix); @aieo_drop_sp_AIEO_UpdateContentIntroPlain($sp_prefix); @aieo_drop_sp_AIEO_UpdateProductCentricStats($sp_prefix); // V1 statistics procedures - DEPRECATED - No longer created // @aieo_drop_sp_AIEO_UpdateCustomerCentricAdvStats($sp_prefix); @aieo_drop_sp_AIEO_UpdateCustomerCentricAdvStats($sp_prefix); @aieo_drop_sp_AIEO_GenerateGraphDBUUIDs($sp_prefix); @aieo_drop_sp_AIEO_GenerateGraphDBUUIDFreqs($sp_prefix); // @aieo_drop_sp_AIEO_Orchestrate_all_non_HPOS_SPs($sp_prefix); // @aieo_drop_sp_AIEO_UpdateCustomerCentricStdStats($sp_prefix); @aieo_drop_sp_AIEO_UpdateCustomerCentricStdStats_v2($sp_prefix); @aieo_drop_sp_AIEO_UpdateCustomerCentricStdStats($sp_prefix); // Drop legacy procedures that are no longer created but may exist from older versions @aieo_drop_sp_AIEO_Include_Products_Without_Sales(); @$wpdb->query("DROP PROCEDURE IF EXISTS UpdateShortDescriptionForProduct"); // Drop functions SECOND (they don't depend on tables) @aieo_drop_function_AIEO_StripHTML(); @aieo_drop_function_AIEO_CountWords(); @aieo_drop_function_AIEO_CountLinks(); // Drop tables LAST (after nothing references them) @aieo_drop_core_product_attributes_table($sp_core_product_attributes_table_name); @aieo_drop_core_product_category_hierarchy_table($sp_core_product_category_hierarchy_table_name); @aieo_drop_core_product_vitals_table($sp_core_product_vitals_table_name); @aieo_drop_core_variation_vitals_table($sp_core_variation_vitals_table_name); @aieo_drop_core_reciprocal_products_table($sp_core_reciprocal_products_table_name); @aieo_drop_temp_orders_table($sp_temp_orders_table_name); @aieo_drop_temp_store_orders_table($sp_temp_store_orders_table_name); @aieo_drop_temp_products_table($sp_temp_products_table_name); // IMPORTANT: Do NOT drop AI Chat tables - this data is valuable and must be preserved // @aieo_drop_chat_embeddings_table(); // @aieo_drop_chat_history_table(); // IMPORTANT: Do NOT drop Session Tracker table - this analytics data is valuable // @aieo_drop_sessions_table(); // Re-enable errors $wpdb->show_errors(); $wpdb->suppress_errors(false); } register_deactivation_hook(__FILE__, 'aieo_drop_stored_procedures'); register_activation_hook(__FILE__, 'aieo_create_stored_procedures'); function aieo_check_for_plugin_update() { $stored_version = get_option('aieo_version', false); if ($stored_version === false) { update_option('aieo_version', AIEO_VERSION); return; } if (version_compare(AIEO_VERSION, $stored_version, '>')) { // Drop and Create Stored Procedures aieo_drop_stored_procedures(); // Ensure tables are recreated during upgrades (drop routine removes them) aieo_create_temp_tables_activation_hook(); aieo_create_stored_procedures(); // Ensure initial activation date is set for existing installations upgrading to 3.3.0+ if (get_option('aieo_initial_activation_date') === false) { add_option('aieo_initial_activation_date', current_time('mysql'), '', 'no'); } // Then update the version value in the database update_option('aieo_version', AIEO_VERSION); } } add_action('plugins_loaded', 'aieo_check_for_plugin_update'); // Note: load_plugin_textdomain() is no longer needed for WordPress.org hosted plugins. // WordPress automatically loads translations from translate.wordpress.org when available. // The /languages/ directory is kept for local .po/.mo file overrides if needed. function aieo_initialize_aieo_recommendations() { new aieo_display_recommendations(); } add_action('plugins_loaded', 'aieo_initialize_aieo_recommendations'); /** * AJAX handler to dismiss rotating banner */ function aieo_dismiss_banner_ajax_handler() { // Verify nonce check_ajax_referer('aieo_dismiss_banner', 'nonce'); // Get current user ID $user_id = get_current_user_id(); if (!$user_id) { wp_send_json_error('User not logged in'); return; } // Save dismissal preference update_user_meta($user_id, 'aieo_banner_dismissed', '1'); wp_send_json_success('Banner dismissed'); } add_action('wp_ajax_aieo_dismiss_banner', 'aieo_dismiss_banner_ajax_handler');