settings = $settings; $this->api = $api; } public function register_menu(): void { $connected = $this->settings->get('connected') === '1'; $parent = $connected ? 'aiva-lite-overview' : 'aiva-lite-build'; add_menu_page(__('AI Integrations Chatbot', 'ai-integrations-chatbot'), __('AI Integrations Chatbot', 'ai-integrations-chatbot'), 'manage_options', $parent, array($this, $connected ? 'render_overview' : 'render_build'), 'dashicons-format-chat'); $pages = array( 'aiva-lite-overview' => array(__('Overview', 'ai-integrations-chatbot'), 'render_overview'), 'aiva-lite-settings' => array(__('Embed Settings', 'ai-integrations-chatbot'), 'render_settings'), 'aiva-lite-build' => array(__('Build My Chatbot', 'ai-integrations-chatbot'), 'render_build'), 'aiva-lite' => array(__('Connect Existing', 'ai-integrations-chatbot'), 'render_connect'), 'aiva-lite-upgrade' => array($this->settings->get('plan') === 'paid' ? __('Manage Subscription', 'ai-integrations-chatbot') : __('Upgrade', 'ai-integrations-chatbot'), 'render_upgrade'), ); foreach ($pages as $slug => $page) { add_submenu_page($parent, $page[0], $page[0], 'manage_options', $slug, array($this, $page[1])); } } public function enqueue_assets($hook): void { if (strpos((string) $hook, 'aiva-lite') === false) { return; } wp_enqueue_style('aiva-lite-admin', AIVA_LITE_PLUGIN_URL . 'assets/css/admin.css', array(), AIVA_LITE_VERSION); wp_enqueue_script('aiva-lite-admin', AIVA_LITE_PLUGIN_URL . 'assets/js/admin.js', array('jquery'), AIVA_LITE_VERSION, true); wp_localize_script('aiva-lite-admin', 'AivaLiteAdmin', array( 'ajaxUrl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('aiva_lite_admin'), 'poll' => (bool) $this->settings->get('pairing_id'), 'error' => __('AI Integrations could not complete this request. Please try again.', 'ai-integrations-chatbot'), 'pending' => __('Waiting for approval in AI Integrations. Keep this page open, or return when you finish.', 'ai-integrations-chatbot'), 'building' => __('Your setup is ready. Choose Continue setup in AI Integrations below, finish building your chatbot, then return here to connect it.', 'ai-integrations-chatbot'), )); } public function handle_actions(): void { if (!current_user_can('manage_options') || empty($_POST['aiva_lite_action'])) { return; } check_admin_referer('aiva_lite_action'); $action = sanitize_key(wp_unslash($_POST['aiva_lite_action'])); if (in_array($action, array('start_build', 'start_connect', 'connect'), true)) { if (empty($_POST['service_consent'])) { $this->notice(__('Please authorize the connection to AI Integrations.', 'ai-integrations-chatbot'), true); } if ($this->settings->get('connected') === '1' && empty($_POST['replace_connection'])) { $this->notice(__('Confirm that you want to replace this site’s assistant connection.', 'ai-integrations-chatbot'), true); } $this->settings->update(array('service_consent' => '1')); if ($action === 'connect') { $key = sanitize_text_field(wp_unslash($_POST['install_key'] ?? '')); $result = $this->api->connect($key); if (is_wp_error($result)) { $this->notice($result->get_error_message(), true); } if (!$this->settings->mark_connected_from_payload($result)) { $this->notice(__('Incomplete connection response. Please reconnect.', 'ai-integrations-chatbot'), true); } $this->notice(__('Your AI Integrations assistant is connected.', 'ai-integrations-chatbot')); } $mode = $action === 'start_build' ? 'build' : 'connect'; $result = $this->api->start_pairing($mode); if (is_wp_error($result)) { $this->notice($result->get_error_message(), true); } $url = $result['authorization_url'] ?? ''; $base = $this->settings->service_url('dashboard') . '/'; if (strpos($url, $base) !== 0 || empty($result['request_id']) || empty($result['pairing_secret'])) { $this->notice(__('Invalid authorization response. Please try again.', 'ai-integrations-chatbot'), true); } $this->settings->update(array('pairing_id' => $result['request_id'], 'pairing_secret' => $result['pairing_secret'], 'authorization_url' => $url, 'pairing_expires_at' => $result['expires_at'] ?? '')); $this->notice(__('Open AI Integrations below to sign in or create your free account. Return to this page after authorization to continue.', 'ai-integrations-chatbot'), false, $mode === 'build' ? 'aiva-lite-build' : 'aiva-lite'); } if ($action === 'save_settings') { $this->settings->update(array('embed_enabled' => !empty($_POST['embed_enabled']), 'auto_insert' => !empty($_POST['auto_insert']), 'position' => sanitize_key(wp_unslash($_POST['position'] ?? 'bottom-right')), 'accent_color' => sanitize_hex_color(wp_unslash($_POST['accent_color'] ?? '#f97316')))); $this->notice(__('Embed settings saved.', 'ai-integrations-chatbot')); } if ($action === 'disconnect') { $result = $this->api->disconnect(); // A failed revocation must remain retryable; do not discard its credential. if (is_wp_error($result)) { $this->notice($result->get_error_message(), true); } $this->settings->reset_connection(); $this->notice(__('Site disconnected. Your assistant and subscription are unchanged.', 'ai-integrations-chatbot')); } if ($action === 'reset_autobuild') { $this->settings->reset_pairing(); $this->notice(__('Pending connection cleared.', 'ai-integrations-chatbot')); } } private function notice(string $message, bool $error = false, string $page = ''): void { set_transient('aiva_lite_notice_' . get_current_user_id(), array('message' => $message, 'error' => $error), MINUTE_IN_SECONDS); wp_safe_redirect(admin_url('admin.php?page=' . ($page ?: ($this->settings->get('connected') === '1' ? 'aiva-lite-overview' : 'aiva-lite')))); exit; } private function render(string $template): void { if (!current_user_can('manage_options')) { return; } $settings = $this->settings; $summary = array(); if ($settings->get('connected') === '1' && $settings->get('service_consent') === '1') { $summary = $this->api->summary(); if (!is_wp_error($summary)) { $settings->apply_status($summary); } } $options = $settings->get_all(); $notice = get_transient('aiva_lite_notice_' . get_current_user_id()); delete_transient('aiva_lite_notice_' . get_current_user_id()); if ($notice) { echo '
' . esc_html($notice['message']) . '
' . esc_html($summary->get_error_message()) . ' ' . esc_html__('Use Connect Existing to refresh your authorization. Your embed settings are preserved.', 'ai-integrations-chatbot') . '