'GPT-4o (Default)', 'gpt-4-turbo' => 'GPT-4 Turbo (Default)', ]; /** * Constructor. * * Hooks into WordPress to register the settings page. */ public function __construct() { add_action( 'admin_menu', array( $this, 'add_settings_page' ) ); add_action( 'admin_init', array( $this, 'register_settings' ) ); // Clear models cache when API key changes. add_action( 'update_option_' . $this->option_name, array( $this, 'clear_models_cache' ), 10, 0 ); // AJAX handler for refreshing models. add_action( 'wp_ajax_aichatbotbuilder_refresh_models', array( $this, 'handle_ajax_refresh_models' ) ); // Enqueue scripts for settings page. add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_settings_scripts' ) ); } /** * Adds the settings page to the admin menu. * * @return void */ public function add_settings_page(): void { add_menu_page( esc_html__( 'AI Chatbot Builder Settings', 'ai-chatbot-builder' ), esc_html__( 'AI Chatbot', 'ai-chatbot-builder' ), 'manage_options', $this->settings_page_slug, array( $this, 'render_settings_page' ), 'dashicons-format-chat', 80 ); add_submenu_page( $this->settings_page_slug, esc_html__( 'Settings', 'ai-chatbot-builder' ), esc_html__( 'Settings', 'ai-chatbot-builder' ), 'manage_options', $this->settings_page_slug, array( $this, 'render_settings_page' ) ); } /** * Registers the plugin settings, sections, and fields. * * @return void */ public function register_settings(): void { register_setting( $this->option_group, $this->option_name, array( $this, 'sanitize_options' ) ); add_settings_section( 'aichatbotbuilder_openai_section', esc_html__( 'OpenAI API Settings', 'ai-chatbot-builder' ), array( $this, 'render_openai_section' ), $this->settings_page_slug ); add_settings_field( 'openai_api_key', esc_html__( 'OpenAI API Key', 'ai-chatbot-builder' ), array( $this, 'render_api_key_field' ), $this->settings_page_slug, 'aichatbotbuilder_openai_section' ); add_settings_field( 'openai_model', esc_html__( 'OpenAI Model', 'ai-chatbot-builder' ), array( $this, 'render_model_field' ), $this->settings_page_slug, 'aichatbotbuilder_openai_section' ); // Add Usage Quota Settings section and field add_settings_section( 'aichatbotbuilder_quota_section', esc_html__( 'Usage Quota Settings', 'ai-chatbot-builder' ), array( $this, 'render_quota_section' ), $this->settings_page_slug ); add_settings_field( 'daily_token_limit', esc_html__( 'Daily Token Limit', 'ai-chatbot-builder' ), array( $this, 'render_quota_field' ), $this->settings_page_slug, 'aichatbotbuilder_quota_section' ); // Add Usage Statistics section (read-only) add_settings_section( 'aichatbotbuilder_quota_stats_section', esc_html__( 'Usage Statistics', 'ai-chatbot-builder' ), array( $this, 'render_quota_stats_section' ), $this->settings_page_slug ); } /** * Sanitizes the plugin options before saving. * * @param array $input The input options. * @return array Sanitized options. */ public function sanitize_options( array $input ): array { // Nonce verification for settings form. $nonce = isset( $_POST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ) : ''; if ( ! $nonce || ! wp_verify_nonce( $nonce, $this->option_group . '-options' ) ) { wp_die( esc_html__( 'Security check failed. Please try again.', 'ai-chatbot-builder' ) ); } $sanitized_input = array(); $options = get_option( $this->option_name ); // Sanitize API Key. $new_api_key = isset( $input['openai_api_key'] ) ? sanitize_text_field( $input['openai_api_key'] ) : null; $old_api_key = $options['openai_api_key'] ?? null; if ( $new_api_key !== null ) { $sanitized_input['openai_api_key'] = $new_api_key; if ( $new_api_key !== $old_api_key ) { $this->clear_models_cache(); } } elseif ( $old_api_key !== null ) { $sanitized_input['openai_api_key'] = $old_api_key; } // Fetch available models for validation. $current_key = $sanitized_input['openai_api_key'] ?? null; $available_models = $this->get_available_models( $current_key ); // Sanitize OpenAI Model. if ( isset( $input['openai_model'] ) && array_key_exists( $input['openai_model'], $available_models ) ) { $sanitized_input['openai_model'] = $input['openai_model']; } else { $old_model = $options['openai_model'] ?? self::DEFAULT_MODEL; if ( array_key_exists( $old_model, $available_models ) ) { $sanitized_input['openai_model'] = $old_model; } else { $sanitized_input['openai_model'] = self::DEFAULT_MODEL; if ( ! empty( $available_models ) && ! array_key_exists( self::DEFAULT_MODEL, $available_models ) ) { if ( function_exists( 'array_key_first' ) ) { $sanitized_input['openai_model'] = array_key_first( $available_models ); } else { reset( $available_models ); $sanitized_input['openai_model'] = key( $available_models ); } } } } // Sanitize Daily Token Limit. if ( isset( $input['daily_token_limit'] ) ) { $daily_limit = intval( $input['daily_token_limit'] ); } else { $daily_limit = self::DEFAULT_DAILY_TOKEN_LIMIT; } $sanitized_input['daily_token_limit'] = max( 0, $daily_limit ); return $sanitized_input; } /** * Renders the description for the OpenAI API Settings section. * * @return void */ public function render_openai_section(): void { echo '
' . esc_html__( 'Enter your OpenAI API key and select the model for AI features.', 'ai-chatbot-builder' ) . '
'; } /** * Renders the OpenAI API Key input field. * * @return void */ public function render_api_key_field(): void { $options = get_option( $this->option_name ); $api_key = $options['openai_api_key'] ?? ''; ?>', '' ); esc_html_e( ' Saving the key will attempt to fetch the available models.', 'ai-chatbot-builder' ); ?>
default_models ) : ?>
'', 'count' => 0 ) ); $today = current_time( 'Y-m-d' ); $used = ( isset( $usage_data['date'] ) && $usage_data['date'] === $today ) ? intval( $usage_data['count'] ) : 0; $opts = get_option( $this->option_name ); $limit = isset( $opts['daily_token_limit'] ) ? intval( $opts['daily_token_limit'] ) : self::DEFAULT_DAILY_TOKEN_LIMIT; if ( $limit > 0 ) { $limit_display = number_format_i18n( $limit ); $remaining = max( 0, $limit - $used ); $remaining_display = number_format_i18n( $remaining ); } else { $limit_display = esc_html__( 'Unlimited', 'ai-chatbot-builder' ); $remaining_display = esc_html__( 'Unlimited', 'ai-chatbot-builder' ); } echo '
'; printf( /* translators: %1$s is tokens used today, %2$s is daily token limit, %3$s is tokens remaining. */ esc_html__( 'Tokens used today: %1$s / %2$s (Remaining: %3$s)', 'ai-chatbot-builder' ), esc_html( number_format_i18n( $used ) ), esc_html( $limit_display ), esc_html( $remaining_display ) ); echo '
'; } /** * Renders the settings page HTML. * * @return void */ public function render_settings_page(): void { ?>