'Version')); $aieo_chat_ver = isset($aieo_chat_hdr['Version']) ? trim((string) $aieo_chat_hdr['Version']) : ''; unset($aieo_chat_hdr); } unset($aieo_chat_main); } define('AIEO_CHAT_VERSION', '' !== $aieo_chat_ver ? $aieo_chat_ver : '0'); unset($aieo_chat_ver); } defined('AIEO_CHAT_FILE') || define('AIEO_CHAT_FILE', __FILE__); defined('AIEO_CHAT_DIR') || define('AIEO_CHAT_DIR', plugin_dir_path(__FILE__)); defined('AIEO_CHAT_URI') || define('AIEO_CHAT_URI', plugin_dir_url(__FILE__)); class AI_eShop_Chat { private static $instance = null; public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } private function __construct() { $this->init_hooks(); if (get_option('aieo_chat_split_loader', 0)) { return; } if ($this->context_needs_engine()) { $this->load_dependencies(); } else { $this->load_frontend_only(); } } private function context_needs_engine() { if (is_admin() || (defined('DOING_CRON') && DOING_CRON) || (defined('DOING_AJAX') && DOING_AJAX) || (defined('WP_CLI') && WP_CLI)) { return true; } $uri = isset($_SERVER['REQUEST_URI']) ? (string) wp_unslash($_SERVER['REQUEST_URI']) : ''; return ($uri !== '' && strpos($uri, 'aieo-chat/') !== false); } private function load_frontend_only() { require_once AIEO_CHAT_DIR . 'includes/chat/class-shortcode-handler.php'; AI_eShop_Chat_Shortcode::get_instance(); } private function init_hooks() { register_activation_hook(AIEO_CHAT_FILE, array($this, 'activate')); register_deactivation_hook(AIEO_CHAT_FILE, array($this, 'deactivate')); add_action('admin_init', array($this, 'heal_auto_event_scheduling')); add_action('admin_enqueue_scripts', array($this, 'disable_emoji_images_on_plugin_pages'), 1); if (get_option('aieo_chat_split_loader', 0)) { $this->init_hooks_split(); return; } add_action('init', array($this, 'load_textdomain'), 0); add_action('admin_menu', array($this, 'add_admin_menu'), 60); add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets')); add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_assets')); add_action('wp_footer', array($this, 'render_floating_widget'), 999); add_action('wp_enqueue_scripts', array($this, 'enqueue_floating_widget_assets'), 20); add_action('wp_ajax_aieo_chat_save_content_selection', array($this, 'ajax_save_content_selection')); add_action('wp_ajax_aieo_chat_save_settings', array($this, 'ajax_save_settings')); add_action('admin_init', array($this, 'check_tables')); add_filter('cron_schedules', array($this, 'add_cron_schedules')); add_action('aieo_auto_analytics_event', array($this, 'run_auto_analytics')); add_action('aieo_auto_embeddings_event', array($this, 'run_auto_embeddings')); } private function init_hooks_split() { $context = class_exists('AIEO_Module_Manifest') ? AIEO_Module_Manifest::resolve_context() : 'other_frontend'; $loaders = array(); switch ($context) { case 'admin': case 'admin_ajax': $loaders[] = 'admin-loader.php'; break; case 'rest_api': $loaders[] = 'rest-loader.php'; break; case 'cron': $loaders[] = 'cron-loader.php'; break; default: $loaders[] = 'frontend-loader.php'; break; } foreach ($loaders as $loader) { $path = AIEO_CHAT_DIR . 'includes/chat/loaders/' . $loader; if (!file_exists($path)) { continue; } $register = include $path; if (is_callable($register)) { $register($this); } } } public function load_dependencies_public() { $this->load_dependencies(); } public function check_tables() { global $wpdb; $embeddings_table = $wpdb->prefix . 'aieo_chat_embeddings'; $history_table = $wpdb->prefix . 'aieo_chat_history'; $business_info_table = $wpdb->prefix . 'aieo_chat_business_info'; $embeddings_exists = $wpdb->get_var("SHOW TABLES LIKE '$embeddings_table'") === $embeddings_table; $history_exists = $wpdb->get_var("SHOW TABLES LIKE '$history_table'") === $history_table; $business_info_exists = $wpdb->get_var("SHOW TABLES LIKE '$business_info_table'") === $business_info_table; if (!$embeddings_exists || !$history_exists) { $this->load_dependencies(); AI_eShop_Chat_Database_Manager::get_instance()->create_tables(); } if (!$business_info_exists) { $this->load_dependencies(); AI_eShop_Chat_Business_Info_Manager::get_instance()->create_table(); } } private function load_dependencies() { require_once AIEO_CHAT_DIR . 'includes/chat/class-anthropic-api.php'; require_once AIEO_CHAT_DIR . 'includes/chat/class-openai-api.php'; require_once AIEO_CHAT_DIR . 'includes/chat/class-database-manager.php'; require_once AIEO_CHAT_DIR . 'includes/chat/class-product-vitals-helper.php'; require_once AIEO_CHAT_DIR . 'includes/chat/class-embedding-manager.php'; require_once AIEO_CHAT_DIR . 'includes/chat/class-chat-api.php'; require_once AIEO_CHAT_DIR . 'includes/chat/class-content-extractor.php'; require_once AIEO_CHAT_DIR . 'includes/chat/class-shortcode-handler.php'; require_once AIEO_CHAT_DIR . 'includes/chat/class-rest-api.php'; require_once AIEO_CHAT_DIR . 'includes/chat/class-model-registry.php'; require_once AIEO_CHAT_DIR . 'includes/chat/class-business-info-manager.php'; AI_eShop_Chat_Database_Manager::get_instance(); AI_eShop_Chat_Embedding_Manager::get_instance(); AI_eShop_Chat_API::get_instance(); AI_eShop_Chat_Shortcode::get_instance(); AI_eShop_Chat_REST_API::get_instance(); AI_eShop_Chat_Model_Registry::get_instance(); AI_eShop_Chat_Business_Info_Manager::get_instance(); } public function load_textdomain() { $domain = 'ai-eshop-optimizer'; $locale = determine_locale(); $mofile = WP_LANG_DIR . '/plugins/' . $domain . '-' . $locale . '.mo'; if (file_exists($mofile)) { load_textdomain($domain, $mofile); return; } $plugin_mofile = dirname(__FILE__) . '/languages/' . $domain . '-' . $locale . '.mo'; if (file_exists($plugin_mofile)) { load_textdomain($domain, $plugin_mofile); return; } load_plugin_textdomain( $domain, false, dirname(plugin_basename(__FILE__)) . '/languages' ); } public function add_admin_menu() { global $menu; $parent_exists = false; if (!empty($menu)) { foreach ($menu as $item) { if (isset($item[2]) && $item[2] === 'ai-eshop-optimizer') { $parent_exists = true; break; } } } if ($parent_exists) { add_submenu_page( 'ai-eshop-optimizer', __('AI Chat', 'ai-eshop-optimizer'), __('AI Chat', 'ai-eshop-optimizer'), 'manage_options', 'ai-eshop-chat', array($this, 'render_admin_page') ); } else { add_menu_page( __('AI Chat', 'ai-eshop-optimizer'), __('AI Chat', 'ai-eshop-optimizer'), 'manage_options', 'ai-eshop-chat', array($this, 'render_admin_page'), 'dashicons-format-chat', 58 ); } } public function render_admin_page() { if (class_exists('AIEO_Chrome') && AIEO_Chrome::on() && method_exists('\Rooster\Admin\Board', 'page')) { \Rooster\Admin\Board::page(static function () { require_once AIEO_CHAT_DIR . 'assets/pages/ai-eshop-chat.php'; }); return; } require_once AIEO_CHAT_DIR . 'assets/pages/ai-eshop-chat.php'; } public function enqueue_admin_assets($hook) { if ('ai-eshop-optimizer_page_ai-eshop-chat' !== $hook && (!isset($_GET['page']) || $_GET['page'] !== 'ai-eshop-chat')) { return; } $aieo_panel_css = AIEO_DIR . 'assets/css/aieo-admin-panel.css'; wp_enqueue_style( 'aieo-admin-panel', AIEO_URI . 'assets/css/aieo-admin-panel.css', array(), file_exists($aieo_panel_css) ? (string) filemtime($aieo_panel_css) : AIEO_VERSION ); wp_enqueue_style( 'aieo-chat-admin', AIEO_CHAT_URI . 'assets/css/chat-admin.css', array('aieo-admin-panel'), AIEO_CHAT_VERSION ); wp_enqueue_style('wp-color-picker'); wp_enqueue_script('wp-color-picker'); wp_enqueue_media(); } public function enqueue_frontend_assets() { $floating_enabled = get_option('aieo_chat_floating_enabled', '0') === '1'; $has_shortcode = $this->page_has_chat_shortcode(); if (!$floating_enabled && !$has_shortcode) { return; } wp_enqueue_style( 'aieo-chat-frontend', AIEO_CHAT_URI . 'assets/css/chat-frontend.css', array(), AIEO_CHAT_VERSION ); wp_enqueue_script( 'aieo-chat-frontend', AIEO_CHAT_URI . 'assets/js/chat-frontend.js', array('jquery'), AIEO_CHAT_VERSION, array('in_footer' => true, 'strategy' => 'defer') ); $current_category = ''; $current_blog_category = ''; $current_cpt_category = ''; if (class_exists('WooCommerce')) { if (is_product_category()) { $term = get_queried_object(); if ($term && !is_wp_error($term)) { $current_category = $this->get_top_category_for_term($term); } } elseif (is_product()) { global $post; if ($post) { $current_category = $this->get_top_category_for_product($post->ID); } } } if (is_category()) { $term = get_queried_object(); if ($term && !is_wp_error($term)) { $current_blog_category = $this->get_top_blog_category_for_term($term); } } elseif (is_single() && get_post_type() === 'post') { global $post; if ($post) { $current_blog_category = $this->get_top_blog_category_for_post($post->ID); } } $cpt_post_type = get_option('aieo_chat_cpt_post_type_slug', ''); $cpt_taxonomy = get_option('aieo_chat_cpt_taxonomy_slug', ''); if (!empty($cpt_post_type) && !empty($cpt_taxonomy)) { if (is_tax($cpt_taxonomy)) { $term = get_queried_object(); if ($term && !is_wp_error($term)) { $current_cpt_category = $this->get_top_cpt_category_for_term($term, $cpt_taxonomy); } } elseif (is_single() && get_post_type() === $cpt_post_type) { global $post; if ($post) { $current_cpt_category = $this->get_top_cpt_category_for_post($post->ID, $cpt_taxonomy); } } } wp_localize_script('aieo-chat-frontend', 'aieoChatConfig', array( 'restUrl' => rest_url('aieo-chat/v1/'), 'restNonce' => wp_create_nonce('wp_rest'), 'chatEnabled' => get_option('aieo_chat_enabled', '0'), 'floatingEnabled' => get_option('aieo_chat_floating_enabled', '0'), 'floatingPosition' => get_option('aieo_chat_floating_position', 'bottom-right'), 'botName' => get_option('aieo_chat_bot_name', __('AI Assistant by Oxford Metadata', 'ai-eshop-optimizer')), 'welcomeMessage' => get_option('aieo_chat_welcome_message', __('Hello! How can I help you find the perfect product today?', 'ai-eshop-optimizer')), 'inputPlaceholder' => get_option('aieo_chat_input_placeholder', __('Ask about anything...', 'ai-eshop-optimizer')), 'maxResults' => get_option('aieo_chat_max_results', 10), 'hideImages' => get_option('aieo_chat_hide_images', '0'), 'requireLogin' => get_option('aieo_chat_require_login', '0'), 'showTerms' => get_option('aieo_chat_show_terms', '0'), 'category_filter_enabled' => get_option('aieo_chat_category_filter_enabled', '0'), 'blog_category_filter_enabled' => get_option('aieo_chat_blog_category_filter_enabled', '0'), 'cpt_category_filter_enabled' => get_option('aieo_chat_cpt_category_filter_enabled', '0'), 'cpt_post_type_slug' => $cpt_post_type, 'cpt_taxonomy_slug' => $cpt_taxonomy, 'currentCategory' => $current_category, 'currentBlogCategory' => $current_blog_category, 'currentCptCategory' => $current_cpt_category, 'theme' => get_option('aieo_chat_theme', 'rounded'), 'i18n' => array( 'categoryPrompt' => __('Please select a product category to get started:', 'ai-eshop-optimizer'), 'selectedCategory' => __('Selected category', 'ai-eshop-optimizer'), 'categoryConfirm' => __('Great! I\'ll help you find products in the {category} category. What are you looking for?', 'ai-eshop-optimizer'), 'changeCategoryHint' => __('Type "menu" or "μενού" to change category', 'ai-eshop-optimizer'), 'categoryChangeHint' => __('Click a different category to change, or start chatting about {category} products', 'ai-eshop-optimizer'), 'categorySwitched' => __('Switched to {category} category. I\'ll help you find products in this category.', 'ai-eshop-optimizer'), 'allCategoriesSwitched' => __('Now searching across all categories. I\'ll help you find any product from our entire catalog.', 'ai-eshop-optimizer'), 'helpingWithAllCategories' => __('I\'ll help you find any product from our entire catalog. What are you looking for?', 'ai-eshop-optimizer'), 'menuReminder' => __('You can change categories anytime using the menu at the top of the chat.', 'ai-eshop-optimizer'), 'helpingWithCategory' => __('I\'ll help you find products in the {category} category. If you need something else, please select a different category.', 'ai-eshop-optimizer'), 'blogCategoryPrompt' => __('Please select a blog post category to get started:', 'ai-eshop-optimizer'), 'blogCategoryConfirm' => __('Great! I\'ll help you find blog posts in the {category} category. What are you looking for?', 'ai-eshop-optimizer'), 'blogCategorySwitched' => __('Switched to {category} category. I\'ll help you find blog posts in this category.', 'ai-eshop-optimizer'), 'helpingWithBlogCategory' => __('I\'ll help you find blog posts in the {category} category. If you need something else, please select a different category.', 'ai-eshop-optimizer'), 'cptCategoryPrompt' => __('Please select a category to get started:', 'ai-eshop-optimizer'), 'cptCategoryConfirm' => __('Great! I\'ll help you find content in the {category} category. What are you looking for?', 'ai-eshop-optimizer'), 'cptCategorySwitched' => __('Switched to {category} category. I\'ll help you find content in this category.', 'ai-eshop-optimizer'), 'helpingWithCptCategory' => __('I\'ll help you find content in the {category} category. If you need something else, please select a different category.', 'ai-eshop-optimizer'), 'feedbackPrompt' => __('Help me improve! Rate this answer:', 'ai-eshop-optimizer'), 'feedbackSaved' => __('Thanks for your feedback!', 'ai-eshop-optimizer'), 'feedbackError' => __('Could not save feedback', 'ai-eshop-optimizer') ) )); } public function enqueue_floating_widget_assets() { if (is_admin() || get_option('aieo_chat_floating_enabled', '0') !== '1') { return; } $dir = plugin_dir_path(__FILE__); $url = plugin_dir_url(__FILE__); $css = 'assets/css/aieo-chat-widget.css'; $js = 'assets/js/aieo-chat-widget.js'; if (file_exists($dir . $css)) { wp_enqueue_style('aieo-chat-widget', $url . $css, array(), (string) filemtime($dir . $css)); } if (file_exists($dir . $js)) { $deps = array('jquery'); if (wp_script_is('aieo-chat-frontend', 'registered') || wp_script_is('aieo-chat-frontend', 'enqueued')) { $deps[] = 'aieo-chat-frontend'; } wp_enqueue_script('aieo-chat-widget', $url . $js, $deps, (string) filemtime($dir . $js), array('in_footer' => true, 'strategy' => 'defer')); } } public function render_floating_widget() { $floating_enabled = get_option('aieo_chat_floating_enabled', '0'); if ($floating_enabled !== '1') { return; } if (is_admin()) { return; } $position = get_option('aieo_chat_floating_position', 'bottom-right'); $mobile_position = get_option('aieo_chat_floating_mobile_position', 'bottom-right'); $bot_name = get_option('aieo_chat_bot_name', 'AI Assistant by Oxford Metadata'); $custom_icon_id = intval(get_option('aieo_chat_floating_custom_icon', 0)); $welcome_bubble = get_option('aieo_chat_floating_welcome_bubble', 'Hi! How can I help you?'); $popup_width_raw = get_option('aieo_chat_floating_popup_width', '390'); $popup_height_raw = get_option('aieo_chat_floating_popup_height', '600'); $button_color = sanitize_hex_color(get_option('aieo_chat_floating_button_color', '#03163C')); $primary_color = sanitize_hex_color(get_option('aieo_chat_primary_color', '#47ACFE')); $aieo_fs = function ($opt, $def) { $v = trim((string) get_option($opt, '')); if ($v === '') { return $def; } return is_numeric($v) ? $v . 'px' : $v; }; $btn_fs_d = $aieo_fs('aieo_chat_btn_font_size_d', '13px'); $btn_fs_m = $aieo_fs('aieo_chat_btn_font_size_m', '12px'); $text_fs_d = $aieo_fs('aieo_chat_text_font_size_d', '15px'); $text_fs_m = $aieo_fs('aieo_chat_text_font_size_m', '14px'); $chat_theme = get_option('aieo_chat_theme', 'rounded'); if (empty($button_color)) { $button_color = '#03163C'; } if (empty($primary_color)) { $primary_color = '#47ACFE'; } $popup_width = $this->sanitize_dimension($popup_width_raw, '390px', 320, 800); $popup_height = $this->sanitize_dimension($popup_height_raw, '600px', 400, 900); $custom_icon_url = $custom_icon_id ? wp_get_attachment_image_url($custom_icon_id, 'thumbnail') : ''; $use_custom_icon = !empty($custom_icon_url); $primary_rgb = sscanf($primary_color, "#%02x%02x%02x"); $primary_color_light = sprintf('rgba(%d, %d, %d, 0.1)', $primary_rgb[0], $primary_rgb[1], $primary_rgb[2]); $button_rgb = sscanf($button_color, "#%02x%02x%02x"); $button_rgb_dark = array( max(0, $button_rgb[0] * 0.85), max(0, $button_rgb[1] * 0.85), max(0, $button_rgb[2] * 0.85) ); $button_color_dark = sprintf('#%02x%02x%02x', $button_rgb_dark[0], $button_rgb_dark[1], $button_rgb_dark[2]); $button_gradient = sprintf('linear-gradient(135deg, %s 0%%, %s 100%%)', $button_color, $button_color_dark); $button_shadow = sprintf('rgba(%d, %d, %d, 0.3)', $button_rgb[0], $button_rgb[1], $button_rgb[2]); ?>
0) { $number = max($min_px, min($max_px, $number)); return $number . 'px'; } return $default; } private function page_has_chat_shortcode() { global $post; if (!is_singular() || !$post) { return false; } if (has_shortcode($post->post_content, 'aieo_chat')) { return true; } if (has_block('core/shortcode', $post->post_content)) { if (strpos($post->post_content, '[aieo_chat') !== false) { return true; } } return false; } public function activate() { AI_eShop_Chat_Database_Manager::get_instance()->create_tables(); AI_eShop_Chat_Business_Info_Manager::get_instance()->create_table(); $this->set_default_options(); flush_rewrite_rules(); } public function deactivate() { flush_rewrite_rules(); } public function disable_emoji_images_on_plugin_pages() { remove_action('admin_print_scripts', 'print_emoji_detection_script'); remove_action('admin_print_styles', 'print_emoji_styles'); } private function set_default_options() { $defaults = array( 'aieo_chat_enabled' => '0', 'aieo_chat_bot_name' => 'AI Assistant by Oxford Metadata', 'aieo_chat_welcome_message' => 'Hello! How can I help you find the perfect product today?', 'aieo_chat_input_placeholder' => 'Ask about anything...', 'aieo_chat_model' => 'claude-sonnet-4-5', 'aieo_chat_max_tokens' => '2000', 'aieo_chat_temperature' => '0.5', 'aieo_chat_max_results' => '10', 'aieo_chat_rate_limit' => '1000', 'aieo_chat_product_threshold' => '50', 'aieo_chat_post_threshold' => '50', 'aieo_chat_card_min_score' => '55', 'aieo_chat_min_products' => '3', 'aieo_chat_max_products' => '10', 'aieo_chat_min_posts' => '2', 'aieo_chat_max_posts' => '5', 'aieo_chat_hide_images' => '0', 'aieo_chat_require_login' => '0', 'aieo_chat_history_enabled' => '1', 'aieo_chat_show_terms' => '0', 'aieo_chat_floating_enabled' => '0', 'aieo_chat_floating_position' => 'bottom-right', 'aieo_chat_floating_mobile_position' => 'bottom-right', 'aieo_chat_floating_popup_width' => '390px', 'aieo_chat_floating_popup_height' => '600px', 'aieo_chat_enabled_post_types' => array('product') ); foreach ($defaults as $key => $value) { if (get_option($key) === false) { add_option($key, $value, '', 'no'); } } } public function ajax_save_content_selection() { check_ajax_referer('aieo_chat_admin', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => __('Insufficient permissions', 'ai-eshop-optimizer')), 403); } $post_types = isset($_POST['post_types']) ? array_map('sanitize_text_field', (array) wp_unslash($_POST['post_types'])) : array(); $post_types = array_values(array_filter($post_types, 'strlen')); update_option('aieo_chat_enabled_post_types', $post_types); $taxonomies = isset($_POST['taxonomies']) ? array_map('sanitize_text_field', (array) wp_unslash($_POST['taxonomies'])) : array(); $taxonomies = array_values(array_filter($taxonomies, 'strlen')); update_option('aieo_chat_enabled_taxonomies', $taxonomies); wp_send_json_success(array( 'post_types_saved' => $post_types, 'taxonomies_saved' => $taxonomies )); } public function ajax_save_settings() { check_ajax_referer('aieo_chat_admin', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => __('Insufficient permissions', 'ai-eshop-optimizer')), 403); } $saved_settings = array(); if (isset($_POST['aieo_chat_deduplication_mode'])) { $dedup_mode = intval($_POST['aieo_chat_deduplication_mode']); update_option('aieo_chat_deduplication_mode', $dedup_mode); $saved_settings['deduplication_mode'] = $dedup_mode; } wp_send_json_success(array( 'message' => __('Settings saved successfully', 'ai-eshop-optimizer'), 'saved' => $saved_settings )); } public function add_cron_schedules($schedules) { if (!isset($schedules['weekly'])) { $schedules['weekly'] = array( 'interval' => 7 * DAY_IN_SECONDS, 'display' => __('Once Weekly', 'ai-eshop-optimizer') ); } if (!isset($schedules['monthly'])) { $schedules['monthly'] = array( 'interval' => 30 * DAY_IN_SECONDS, 'display' => __('Once Monthly', 'ai-eshop-optimizer') ); } return $schedules; } private function has_valid_pro_subscription() { if (get_option('aieo_user_membership') !== 'Pro') { return false; } $expiration_date = get_option('aieo_subscription_expiration', ''); if (!empty($expiration_date)) { $expiration_timestamp = strtotime($expiration_date); $current_timestamp = current_time('timestamp', true); if ($expiration_timestamp < $current_timestamp) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: Pro subscription expired on ' . $expiration_date . ' - disabling automation'); } update_option('aieo_auto_analytics_enabled', '0'); update_option('aieo_auto_embeddings_enabled', '0'); wp_clear_scheduled_hook('aieo_auto_analytics_event'); wp_clear_scheduled_hook('aieo_auto_embeddings_event'); return false; } } return true; } public function heal_auto_event_scheduling() { $this->maybe_rearm_auto_event( 'aieo_auto_analytics_enabled', 'aieo_auto_analytics_frequency', 'aieo_auto_analytics_time', 'aieo_auto_analytics_event' ); if (class_exists('AIEO_Chat_Indexing') && AIEO_Chat_Indexing::enabled()) { $this->maybe_rearm_auto_event( 'aieo_auto_embeddings_enabled', 'aieo_auto_embeddings_frequency', 'aieo_auto_embeddings_time', 'aieo_auto_embeddings_event' ); } } private function maybe_rearm_auto_event($enabled_opt, $freq_opt, $time_opt, $hook) { if ('1' !== (string) get_option($enabled_opt, '0')) { return; } if (wp_next_scheduled($hook)) { return; } $frequency = (string) get_option($freq_opt, 'weekly'); $recurrence = in_array($frequency, array('daily', 'weekly', 'monthly'), true) ? $frequency : 'weekly'; $time = (string) get_option($time_opt, '03:00'); $next_run = $this->calc_next_run_time($recurrence, $time); if ($next_run) { wp_schedule_event($next_run, $recurrence, $hook); if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: self-healed missing cron ' . $hook . ' for ' . gmdate('Y-m-d H:i:s', $next_run)); } } } private function calc_next_run_time($frequency, $time) { if (empty($time) || strpos($time, ':') === false) { return false; } list($hour, $minute) = array_pad(explode(':', $time), 2, '0'); $hour = (int) $hour; $minute = (int) $minute; $now = current_time('timestamp', true); $today = strtotime(gmdate('Y-m-d', $now) . ' ' . sprintf('%02d:%02d:00', $hour, $minute)); if ($today <= $now) { if ('daily' === $frequency) { return $today + DAY_IN_SECONDS; } if ('weekly' === $frequency) { return $today + (7 * DAY_IN_SECONDS); } return $today + (30 * DAY_IN_SECONDS); } return $today; } public function run_auto_analytics() { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: Running automated analytics update'); } if (!$this->has_valid_pro_subscription()) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: Skipping analytics automation - Valid Pro subscription required'); } return; } do_action('aieo_run_export_and_analysis'); if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: Completed automated analytics update'); } } public function run_auto_embeddings() { if (!class_exists('AIEO_Chat_Indexing') && file_exists(AIEO_CHAT_DIR . 'includes/chat/class-aieo-chat-indexing.php')) { require_once AIEO_CHAT_DIR . 'includes/chat/class-aieo-chat-indexing.php'; } if (class_exists('AIEO_Chat_Indexing') && !AIEO_Chat_Indexing::enabled()) { return; } if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: Running automated embeddings generation'); } if (!$this->has_valid_pro_subscription()) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: Skipping embeddings automation - Valid Pro subscription required'); } return; } $embedding_provider = get_option('aieo_embedding_provider', 'voyage'); $dedup_mode = get_option('aieo_chat_deduplication_mode', 1); $enabled_post_types = class_exists('AIEO_Content_Types') ? AIEO_Content_Types::chat_post_types() : get_option('aieo_chat_enabled_post_types', array('product')); if (empty($enabled_post_types)) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: No post types selected for embedding generation'); } return; } if ($embedding_provider === 'voyage') { $embedding_engine = get_option('aieo_chat_embedding_model', 'voyage-3'); } else { $embedding_engine = get_option('aieo_chat_openai_embedding_model', 'text-embedding-3-large'); } if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: Generating embeddings with engine: ' . $embedding_engine . ', dedup: ' . $dedup_mode); } if (!class_exists('AI_eShop_Chat_Embedding_Manager')) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: Embedding manager unavailable — auto-embeddings skipped'); } return; } $manager = AI_eShop_Chat_Embedding_Manager::get_instance(); $deduplicated = (int) $dedup_mode; $batch_size = 50; $time_budget = 120; $max_batches = 200; $start = time(); $processed = 0; foreach ($enabled_post_types as $post_type) { $batches_done = 0; do { $result = $manager->generate_all_embeddings($post_type, $batch_size, 0, $deduplicated, $embedding_engine); $did = isset($result['processed']) ? (int) $result['processed'] : 0; $remaining = isset($result['remaining']) ? (int) $result['remaining'] : 0; $processed += $did; $batches_done++; if ($did === 0) { break; } } while ($remaining > 0 && (time() - $start) < $time_budget && $batches_done < $max_batches); if ((time() - $start) >= $time_budget) { break; } } if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: Completed automated embeddings generation - processed ' . $processed . ' new items'); } } private function get_top_category_for_term($term) { if ($term->parent == 0) { return $term->name; } $ancestors = get_ancestors($term->term_id, 'product_cat'); if (empty($ancestors)) { return $term->name; } $top_term_id = end($ancestors); $top_term = get_term($top_term_id, 'product_cat'); return (!is_wp_error($top_term) && $top_term) ? $top_term->name : $term->name; } private function canonical_term($object_type, $object_id, $taxonomy) { if (!class_exists('AIEO_SEO_Store')) { return null; } $tid = (int) AIEO_SEO_Store::get_primary_term($object_type, (int) $object_id, $taxonomy); if ($tid <= 0) { return null; } $term = get_term($tid, $taxonomy); return ($term && !is_wp_error($term)) ? $term : null; } private function get_top_category_for_product($product_id) { $terms = wp_get_post_terms($product_id, 'product_cat', array('fields' => 'all')); if (empty($terms) || is_wp_error($terms)) { return ''; } $term = $this->canonical_term('product', $product_id, 'product_cat') ?: $terms[0]; if ($term->parent == 0) { return $term->name; } $ancestors = get_ancestors($term->term_id, 'product_cat'); if (empty($ancestors)) { return $term->name; } $top_term_id = end($ancestors); $top_term = get_term($top_term_id, 'product_cat'); return (!is_wp_error($top_term) && $top_term) ? $top_term->name : $term->name; } private function get_top_blog_category_for_term($term) { if ($term->parent == 0) { return $term->name; } $ancestors = get_ancestors($term->term_id, 'category'); if (empty($ancestors)) { return $term->name; } $top_term_id = end($ancestors); $top_term = get_term($top_term_id, 'category'); return (!is_wp_error($top_term) && $top_term) ? $top_term->name : $term->name; } private function get_top_blog_category_for_post($post_id) { $terms = wp_get_post_terms($post_id, 'category', array('fields' => 'all')); if (empty($terms) || is_wp_error($terms)) { return ''; } $term = $this->canonical_term('post', $post_id, 'category') ?: $terms[0]; if ($term->parent == 0) { return $term->name; } $ancestors = get_ancestors($term->term_id, 'category'); if (empty($ancestors)) { return $term->name; } $top_term_id = end($ancestors); $top_term = get_term($top_term_id, 'category'); return (!is_wp_error($top_term) && $top_term) ? $top_term->name : $term->name; } private function get_top_cpt_category_for_term($term, $taxonomy) { if ($term->parent == 0) { return $term->name; } $ancestors = get_ancestors($term->term_id, $taxonomy); if (empty($ancestors)) { return $term->name; } $top_term_id = end($ancestors); $top_term = get_term($top_term_id, $taxonomy); return (!is_wp_error($top_term) && $top_term) ? $top_term->name : $term->name; } private function get_top_cpt_category_for_post($post_id, $taxonomy) { $terms = wp_get_post_terms($post_id, $taxonomy, array('fields' => 'all')); if (empty($terms) || is_wp_error($terms)) { return ''; } $term = $this->canonical_term(get_post_type($post_id), $post_id, $taxonomy) ?: $terms[0]; if ($term->parent == 0) { return $term->name; } $ancestors = get_ancestors($term->term_id, $taxonomy); if (empty($ancestors)) { return $term->name; } $top_term_id = end($ancestors); $top_term = get_term($top_term_id, $taxonomy); return (!is_wp_error($top_term) && $top_term) ? $top_term->name : $term->name; } } function aieo_chat_init() { AI_eShop_Chat::get_instance(); } add_action('plugins_loaded', 'aieo_chat_init', 20);