version = AI_CHATBOT_VERSION; $this->loader = new Ai_Chatbot_Loader(); $this->set_locale(); $this->define_admin_hooks(); } // ----------------------------------------------------------------------- // Setup // ----------------------------------------------------------------------- private function set_locale() { $i18n = new Ai_Chatbot_i18n(); $this->loader->add_action( 'plugins_loaded', $i18n, 'load_plugin_textdomain' ); } private function define_admin_hooks() { $admin = new Ai_Chatbot_Admin( $this->version ); $this->loader->add_action( 'admin_enqueue_scripts', $admin, 'enqueue_styles' ); $this->loader->add_action( 'admin_enqueue_scripts', $admin, 'enqueue_scripts' ); $this->loader->add_action( 'admin_menu', $admin, 'register_menu' ); // AJAX handlers. $this->loader->add_action( 'wp_ajax_ai_chatbot_signup', $admin, 'ajax_signup' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_login', $admin, 'ajax_login' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_otp_init', $admin, 'ajax_otp_init' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_otp_verify', $admin, 'ajax_otp_verify' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_logout', $admin, 'ajax_logout' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_create_agent', $admin, 'ajax_create_agent' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_update_agent', $admin, 'ajax_update_agent' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_delete_agent', $admin, 'ajax_delete_agent' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_get_stats', $admin, 'ajax_get_stats' ); // Phase 2 – Agent Management. $this->loader->add_action( 'wp_ajax_ai_chatbot_get_appearance', $admin, 'ajax_get_appearance' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_update_appearance', $admin, 'ajax_update_appearance' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_get_ai_settings', $admin, 'ajax_get_ai_settings' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_update_ai_settings', $admin, 'ajax_update_ai_settings' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_get_kb', $admin, 'ajax_get_kb' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_link_content', $admin, 'ajax_link_content' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_delink_content', $admin, 'ajax_delink_content' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_toggle_frontend_embed', $admin, 'ajax_toggle_frontend_embed' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_get_site_content', $admin, 'ajax_get_site_content' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_link_wp_post', $admin, 'ajax_link_wp_post' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_get_inbox_sessions', $admin, 'ajax_get_inbox_sessions' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_get_inbox_chats', $admin, 'ajax_get_inbox_chats' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_get_account_limits', $admin, 'ajax_get_account_limits' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_crawl_website', $admin, 'ajax_crawl_website' ); // Auto-refresh KB when a linked post/product is saved. // Priority 99 ensures WooCommerce has finished saving product meta (priority 34) // before we read price, SKU, and other product-specific fields. $this->loader->add_action( 'save_post', $admin, 'on_post_saved', 99, 3 ); // Widget Tabs (Tab Integrations). $this->loader->add_action( 'wp_ajax_ai_chatbot_get_widget_tabs', $admin, 'ajax_get_widget_tabs' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_save_widget_tabs', $admin, 'ajax_save_widget_tabs' ); // WooCommerce Integration. $this->loader->add_action( 'wp_ajax_ai_chatbot_get_woocommerce_status', $admin, 'ajax_get_woocommerce_status' ); $this->loader->add_action( 'wp_ajax_ai_chatbot_toggle_woocommerce', $admin, 'ajax_toggle_woocommerce' ); } private function define_public_hooks() { // Inject the embed script into the frontend footer when an agent is enabled. $this->loader->add_action( 'wp_footer', $this, 'inject_frontend_embed' ); // Enqueue the WooCommerce cart bridge when an embed is active and WC is installed. $this->loader->add_action( 'wp_enqueue_scripts', $this, 'enqueue_public_scripts' ); } /** * Enqueue the WooCommerce postMessage cart bridge on the frontend. * * The bridge runs on the WordPress parent page (same origin as WooCommerce) * and forwards cart API calls from the cross-origin chatbot iframe, supplying * the WC Store API nonce and session cookies that are inaccessible from inside * the iframe. * * Only loaded when: * - An agent embed is configured (chatbot_id present in option). * - WooCommerce is active. */ public function enqueue_public_scripts() { $embed = get_option( PLUGIN_SLUG . '_frontend_embed' ); if ( empty( $embed['chatbot_id'] ) || ! class_exists( 'WooCommerce' ) ) { return; } wp_enqueue_script( 'ai-chatbot-cart-bridge', AI_CHATBOT_URL . 'assets/ai-chatbot-cart-bridge.js', array(), // no dependencies AI_CHATBOT_VERSION, true // load in footer ); wp_localize_script( 'ai-chatbot-cart-bridge', 'aiChatbotWooBridge', array( 'storeApiUrl' => esc_url( get_rest_url( null, 'wc/store/v1' ) ), 'nonce' => wp_create_nonce( 'wc_store_api' ), 'iframeOrigin' => rtrim( PLUGIN_PLAYGROUND_BASE_URL, '/' ), ) ); } /** * Output the chatbot embed script in the site footer when an agent is enabled. * Runs on wp_footer – no admin check needed; wp_footer only fires on the frontend. */ public function inject_frontend_embed() { $embed = get_option( PLUGIN_SLUG . '_frontend_embed' ); if ( empty( $embed['chatbot_id'] ) || empty( $embed['project_id'] ) ) { return; } $base = rtrim( PLUGIN_PLAYGROUND_BASE_URL, '/' ); $pid = esc_js( $embed['project_id'] ); $cid = esc_js( $embed['chatbot_id'] ); ?> define_public_hooks(); $this->loader->run(); } }