[ $this, 'sanitize_checkbox' ] ] ); register_setting( 'acosmaia_group', 'acosmaia_assistant_name', [ 'sanitize_callback' => 'sanitize_text_field' ] ); register_setting( 'acosmaia_group', 'acosmaia_welcome_message', [ 'sanitize_callback' => 'sanitize_textarea_field' ] ); register_setting( 'acosmaia_group', 'acosmaia_chat_position', [ 'sanitize_callback' => [ $this, 'sanitize_position' ] ] ); register_setting( 'acosmaia_group', 'acosmaia_chat_color', [ 'sanitize_callback' => [ $this, 'sanitize_hex' ] ] ); register_setting( 'acosmaia_group', 'acosmaia_bubble_icon', [ 'sanitize_callback' => [ $this, 'sanitize_bubble_icon' ] ] ); register_setting( 'acosmaia_group', 'acosmaia_default_theme', [ 'sanitize_callback' => [ $this, 'sanitize_theme' ] ] ); register_setting( 'acosmaia_group', 'acosmaia_api_provider', [ 'sanitize_callback' => [ $this, 'sanitize_api_provider' ] ] ); register_setting( 'acosmaia_group', 'acosmaia_openrouter_key', [ 'sanitize_callback' => 'sanitize_text_field' ] ); register_setting( 'acosmaia_group', 'acosmaia_openai_key', [ 'sanitize_callback' => 'sanitize_text_field' ] ); register_setting( 'acosmaia_group', 'acosmaia_openai_model', [ 'sanitize_callback' => 'sanitize_text_field' ] ); register_setting( 'acosmaia_group', 'acosmaia_gemini_key', [ 'sanitize_callback' => 'sanitize_text_field' ] ); register_setting( 'acosmaia_group', 'acosmaia_gemini_model', [ 'sanitize_callback' => 'sanitize_text_field' ] ); register_setting( 'acosmaia_group', 'acosmaia_ai_tool', [ 'sanitize_callback' => [ $this, 'sanitize_ai_tool' ] ] ); register_setting( 'acosmaia_group', 'acosmaia_model', [ 'sanitize_callback' => 'sanitize_text_field' ] ); register_setting( 'acosmaia_group', 'acosmaia_temperature', [ 'sanitize_callback' => [ $this, 'sanitize_temperature' ] ] ); register_setting( 'acosmaia_group', 'acosmaia_max_tokens', [ 'sanitize_callback' => 'absint' ] ); register_setting( 'acosmaia_group', 'acosmaia_timeout', [ 'sanitize_callback' => 'absint' ] ); register_setting( 'acosmaia_group', 'acosmaia_daily_limit', [ 'sanitize_callback' => 'absint' ] ); register_setting( 'acosmaia_group', 'acosmaia_monthly_limit', [ 'sanitize_callback' => 'absint' ] ); register_setting( 'acosmaia_group', 'acosmaia_max_products', [ 'sanitize_callback' => [ $this, 'sanitize_max_products' ] ] ); register_setting( 'acosmaia_group', 'acosmaia_enabled_pages', [ 'sanitize_callback' => [ $this, 'sanitize_enabled_pages' ] ] ); register_setting( 'acosmaia_group', 'acosmaia_restrict_product_only', [ 'sanitize_callback' => [ $this, 'sanitize_checkbox' ] ] ); register_setting( 'acosmaia_group', 'acosmaia_fallback_response', [ 'sanitize_callback' => 'sanitize_textarea_field' ] ); register_setting( 'acosmaia_group', 'acosmaia_knowledge_text', [ 'sanitize_callback' => 'sanitize_textarea_field' ] ); } public function enqueue_assets( $hook ) { if ( 'toplevel_page_ai-chat-assistance' !== $hook ) { return; } wp_enqueue_style( 'acosmaia-admin-style', ACOSMAIA_URL . 'assets/css/admin-style.css', [], ACOSMAIA_VERSION ); wp_enqueue_script( 'acosmaia-admin-script', ACOSMAIA_URL . 'assets/js/admin.js', [], ACOSMAIA_VERSION, true ); wp_localize_script( 'acosmaia-admin-script', 'acosmaiaAdmin', [ 'api_url' => rest_url( 'acosmaia/v1/admin/settings' ), 'nonce' => wp_create_nonce( 'wp_rest' ), ] ); } public function register_rest_routes() { register_rest_route( 'acosmaia/v1', '/admin/settings', [ [ 'methods' => WP_REST_Server::READABLE, 'callback' => [ $this, 'rest_get_settings' ], 'permission_callback' => function() { return current_user_can( 'manage_options' ); }, ], [ 'methods' => WP_REST_Server::EDITABLE, 'callback' => [ $this, 'rest_save_settings' ], 'permission_callback' => function() { return current_user_can( 'manage_options' ); }, ], ] ); } public function can_manage_settings( WP_REST_Request $request ) { unset( $request ); return is_user_logged_in() && current_user_can( 'manage_options' ); } public function rest_get_settings() { return new WP_REST_Response( [ 'options' => $this->get_all_options(), 'stats' => $this->get_usage_stats(), 'meta' => [ 'position_options' => [ [ 'value' => 'bottom-right', 'label' => __( 'Bottom right', 'aco-smart-ai-assistant' ) ], [ 'value' => 'bottom-left', 'label' => __( 'Bottom left', 'aco-smart-ai-assistant' ) ], ], 'theme_options' => [ [ 'value' => 'light', 'label' => __( 'Light', 'aco-smart-ai-assistant' ) ], [ 'value' => 'dark', 'label' => __( 'Dark', 'aco-smart-ai-assistant' ) ], ], 'bubble_icon_options' => [ [ 'value' => 'chat', 'label' => __( 'Chat', 'aco-smart-ai-assistant' ) ], [ 'value' => 'spark', 'label' => __( 'Spark', 'aco-smart-ai-assistant' ) ], [ 'value' => 'bolt', 'label' => __( 'Bolt', 'aco-smart-ai-assistant' ) ], ], 'model_options' => [ [ 'value' => 'mistralai/mistral-7b-instruct:free', 'label' => 'mistralai/mistral-7b-instruct:free' ], [ 'value' => 'google/gemma-2-9b-it:free', 'label' => 'google/gemma-2-9b-it:free' ], [ 'value' => 'meta-llama/llama-3.1-8b-instruct:free', 'label' => 'meta-llama/llama-3.1-8b-instruct:free' ], ], 'page_options' => $this->get_page_options(), 'tool_options' => [ [ 'value' => 'openrouter', 'label' => 'OpenRouter', 'key_label' => __( 'OpenRouter API key', 'aco-smart-ai-assistant' ), 'key_placeholder' => __( 'Paste your OpenRouter API key', 'aco-smart-ai-assistant' ), ], [ 'value' => 'openai', 'label' => 'OpenAI', 'key_label' => __( 'OpenAI API key', 'aco-smart-ai-assistant' ), 'key_placeholder' => __( 'Paste your OpenAI API key', 'aco-smart-ai-assistant' ), ], [ 'value' => 'gemini', 'label' => 'Google Gemini', 'key_label' => __( 'Google Gemini API key', 'aco-smart-ai-assistant' ), 'key_placeholder' => __( 'Paste your Google Gemini API key', 'aco-smart-ai-assistant' ), ], ], ], ] ); } public function rest_save_settings( WP_REST_Request $request ) { $settings = $request->get_param( 'settings' ); if ( ! is_array( $settings ) ) { return new WP_REST_Response( [ 'error' => 'Invalid settings payload.' ], 400 ); } foreach ( $this->option_defaults() as $option_key => $default ) { if ( ! array_key_exists( $option_key, $settings ) ) { continue; } $sanitized = $this->sanitize_option_value( $option_key, $settings[ $option_key ] ); update_option( $option_key, $sanitized ); } return new WP_REST_Response( [ 'success' => true, 'options' => $this->get_all_options(), 'stats' => $this->get_usage_stats(), ] ); } public function page() { echo '
'; } private function get_usage_stats() { return [ 'daily_tokens' => (int) get_option( 'acosmaia_usage_daily_' . current_time( 'Ymd' ), 0 ), 'monthly_tokens' => (int) get_option( 'acosmaia_usage_monthly_' . current_time( 'Ym' ), 0 ), 'total_chats' => (int) get_option( 'acosmaia_total_chats', 0 ), 'failed_queries' => (int) get_option( 'acosmaia_failed_queries', 0 ), ]; } private function option_defaults() { return [ 'acosmaia_enabled' => 'yes', 'acosmaia_assistant_name' => 'AI Assistant', 'acosmaia_welcome_message' => 'Hi! How can I help you today?', 'acosmaia_chat_position' => 'bottom-right', 'acosmaia_chat_color' => '#0073aa', 'acosmaia_bubble_icon' => 'chat', 'acosmaia_default_theme' => 'light', 'acosmaia_api_provider' => 'openrouter', 'acosmaia_openrouter_key' => '', 'acosmaia_openai_key' => '', 'acosmaia_openai_model' => 'gpt-3.5-turbo', 'acosmaia_gemini_key' => '', 'acosmaia_gemini_model' => 'gemini-2.0-flash', 'acosmaia_ai_tool' => 'openrouter', 'acosmaia_model' => 'mistralai/mistral-7b-instruct:free', 'acosmaia_temperature' => 0.5, 'acosmaia_max_tokens' => 600, 'acosmaia_timeout' => 25, 'acosmaia_daily_limit' => 0, 'acosmaia_monthly_limit' => 0, 'acosmaia_max_products' => 3, 'acosmaia_enabled_pages' => [], 'acosmaia_restrict_product_only' => 'no', 'acosmaia_fallback_response' => 'Sorry, I am unable to answer right now. Please contact support.', 'acosmaia_knowledge_text' => '', ]; } private function get_all_options() { $result = []; foreach ( $this->option_defaults() as $option_key => $default ) { $result[ $option_key ] = get_option( $option_key, $default ); } return $result; } private function sanitize_option_value( $option_key, $value ) { switch ( $option_key ) { case 'acosmaia_enabled': case 'acosmaia_restrict_product_only': return $this->sanitize_checkbox( $value ); case 'acosmaia_chat_position': return $this->sanitize_position( $value ); case 'acosmaia_default_theme': return $this->sanitize_theme( $value ); case 'acosmaia_bubble_icon': return $this->sanitize_bubble_icon( $value ); case 'acosmaia_api_provider': return $this->sanitize_api_provider( $value ); case 'acosmaia_ai_tool': return $this->sanitize_ai_tool( $value ); case 'acosmaia_chat_color': return $this->sanitize_hex( $value ); case 'acosmaia_temperature': return $this->sanitize_temperature( $value ); case 'acosmaia_max_tokens': case 'acosmaia_timeout': case 'acosmaia_daily_limit': case 'acosmaia_monthly_limit': return absint( $value ); case 'acosmaia_max_products': return $this->sanitize_max_products( $value ); case 'acosmaia_enabled_pages': return $this->sanitize_enabled_pages( $value ); case 'acosmaia_welcome_message': case 'acosmaia_fallback_response': case 'acosmaia_knowledge_text': return sanitize_textarea_field( (string) $value ); case 'acosmaia_assistant_name': case 'acosmaia_openrouter_key': case 'acosmaia_openai_key': case 'acosmaia_openai_model': case 'acosmaia_gemini_key': case 'acosmaia_gemini_model': case 'acosmaia_model': default: return sanitize_text_field( (string) $value ); } } public function sanitize_checkbox( $value ) { return $value === 'yes' ? 'yes' : 'no'; } public function sanitize_position( $value ) { return in_array( $value, [ 'bottom-right', 'bottom-left' ], true ) ? $value : 'bottom-right'; } public function sanitize_theme( $value ) { return in_array( $value, [ 'light', 'dark' ], true ) ? $value : 'light'; } public function sanitize_hex( $value ) { $sanitized = sanitize_hex_color( $value ); return $sanitized ? $sanitized : '#0073aa'; } public function sanitize_temperature( $value ) { $float = (float) $value; return max( 0, min( 2, $float ) ); } public function sanitize_max_products( $value ) { $count = absint( $value ); return max( 1, min( 20, $count ) ); } public function sanitize_enabled_pages( $value ) { if ( ! is_array( $value ) ) { return []; } $page_ids = []; foreach ( $value as $item ) { $id = absint( $item ); if ( $id > 0 ) { $page_ids[] = $id; } } $page_ids = array_values( array_unique( $page_ids ) ); return array_slice( $page_ids, 0, 100 ); } private function get_page_options() { $pages = get_pages( [ 'sort_column' => 'menu_order,post_title', 'post_status' => 'publish', ] ); if ( ! is_array( $pages ) || empty( $pages ) ) { return []; } $options = []; foreach ( $pages as $page ) { if ( ! $page instanceof WP_Post ) { continue; } $options[] = [ 'value' => (int) $page->ID, 'label' => sanitize_text_field( get_the_title( $page->ID ) ), 'url' => esc_url_raw( get_permalink( $page->ID ) ), ]; } return $options; } public function sanitize_ai_tool( $value ) { return in_array( $value, [ 'openrouter', 'openai', 'gemini' ], true ) ? $value : 'openrouter'; } public function sanitize_api_provider( $value ) { return in_array( $value, [ 'openrouter', 'openai', 'gemini' ], true ) ? $value : 'openrouter'; } public function sanitize_bubble_icon( $value ) { return in_array( $value, [ 'chat', 'spark', 'bolt' ], true ) ? $value : 'chat'; } } new ACOSMAIA_Admin_Settings();