*/ function aimaxchat_default_options() { return array( 'enabled' => false, 'botId' => '', 'publicToken' => '', 'apiUrl' => '', 'widgetCdnUrl' => '', ); } /** * Fetch plugin options with defaults. * * @return array */ function aimaxchat_get_options() { $options = get_option( AIMAXCHAT_OPTION_NAME, array() ); if ( ! is_array( $options ) ) { $options = array(); } return wp_parse_args( $options, aimaxchat_default_options() ); } /** * Check whether the given value is UUID-like. * * @param string $value Value to validate. * @return bool */ function aimaxchat_is_uuid_like( $value ) { return 1 === preg_match( '/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i', $value ); } /** * Validate public token. * * @param string $value Token value. * @return bool */ function aimaxchat_is_valid_public_token( $value ) { return 1 === preg_match( '/^[A-Za-z0-9_-]{16,255}$/', $value ); } /** * Sanitize plugin options. * * @param mixed $input Raw form input. * @return array */ function aimaxchat_sanitize_options( $input ) { $defaults = aimaxchat_default_options(); $input = is_array( $input ) ? $input : array(); $output = $defaults; $output['enabled'] = ! empty( $input['enabled'] ); $bot_id = trim( (string) ( $input['botId'] ?? '' ) ); if ( '' !== $bot_id && ! aimaxchat_is_uuid_like( $bot_id ) ) { add_settings_error( AIMAXCHAT_OPTION_NAME, 'aimaxchat_bot_id', 'Bot ID должен быть корректным UUID.' ); } else { $output['botId'] = $bot_id; } $public_token = trim( (string) ( $input['publicToken'] ?? '' ) ); if ( '' !== $public_token && ! aimaxchat_is_valid_public_token( $public_token ) ) { add_settings_error( AIMAXCHAT_OPTION_NAME, 'aimaxchat_public_token', 'Public Token содержит недопустимые символы или длину.' ); } else { $output['publicToken'] = $public_token; } $api_url = trim( (string) ( $input['apiUrl'] ?? '' ) ); if ( '' !== $api_url ) { $api_url = esc_url_raw( $api_url ); if ( ! wp_http_validate_url( $api_url ) || ! preg_match( '#^https?://#i', $api_url ) ) { add_settings_error( AIMAXCHAT_OPTION_NAME, 'aimaxchat_api_url', 'API URL должен быть корректным http/https адресом.' ); } else { $output['apiUrl'] = untrailingslashit( $api_url ); } } $widget_cdn_url = trim( (string) ( $input['widgetCdnUrl'] ?? '' ) ); if ( '' !== $widget_cdn_url ) { $widget_cdn_url = esc_url_raw( $widget_cdn_url ); if ( ! wp_http_validate_url( $widget_cdn_url ) || ! preg_match( '#^https?://#i', $widget_cdn_url ) ) { add_settings_error( AIMAXCHAT_OPTION_NAME, 'aimaxchat_widget_cdn_url', 'Widget CDN URL должен быть корректным http/https адресом.' ); } else { $output['widgetCdnUrl'] = $widget_cdn_url; } } return $output; } /** * Register plugin settings. * * @return void */ function aimaxchat_register_settings() { register_setting( AIMAXCHAT_SETTINGS_GROUP, AIMAXCHAT_OPTION_NAME, array( 'type' => 'array', 'sanitize_callback' => 'aimaxchat_sanitize_options', 'default' => aimaxchat_default_options(), ) ); add_settings_section( 'aimaxchat_main_section', 'AiMaxChat', 'aimaxchat_render_settings_intro', AIMAXCHAT_SETTINGS_PAGE ); add_settings_field( 'aimaxchat_enabled', 'Включить виджет', 'aimaxchat_render_checkbox_field', AIMAXCHAT_SETTINGS_PAGE, 'aimaxchat_main_section', array( 'id' => 'enabled', 'label' => 'Подключать виджет на публичных страницах WordPress.', 'description' => 'После сохранения проверьте публичную страницу сайта, а не только админку.', ) ); add_settings_field( 'aimaxchat_bot_id', 'Bot ID', 'aimaxchat_render_text_field', AIMAXCHAT_SETTINGS_PAGE, 'aimaxchat_main_section', array( 'id' => 'botId', 'placeholder' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 'description' => 'UUID бота из AiMaxChat.', ) ); add_settings_field( 'aimaxchat_public_token', 'Public Token', 'aimaxchat_render_text_field', AIMAXCHAT_SETTINGS_PAGE, 'aimaxchat_main_section', array( 'id' => 'publicToken', 'placeholder' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'description' => 'Публичный токен бота из AiMaxChat.', ) ); add_settings_field( 'aimaxchat_api_url', 'API URL', 'aimaxchat_render_text_field', AIMAXCHAT_SETTINGS_PAGE, 'aimaxchat_main_section', array( 'id' => 'apiUrl', 'placeholder' => 'https://api.aimaxchat.ru', 'description' => 'Публичный backend API URL без закрывающего слеша.', ) ); add_settings_field( 'aimaxchat_widget_cdn_url', 'Widget CDN URL', 'aimaxchat_render_text_field', AIMAXCHAT_SETTINGS_PAGE, 'aimaxchat_main_section', array( 'id' => 'widgetCdnUrl', 'placeholder' => 'https://cdn.aimaxchat.ru/widget/latest/widget.js', 'description' => 'Публичный CDN URL на widget.js.', ) ); } add_action( 'admin_init', 'aimaxchat_register_settings' ); /** * Add plugin settings page. * * @return void */ function aimaxchat_add_settings_page() { add_options_page( 'AiMaxChat', 'AiMaxChat', 'manage_options', AIMAXCHAT_SETTINGS_PAGE, 'aimaxchat_render_settings_page' ); } add_action( 'admin_menu', 'aimaxchat_add_settings_page' ); /** * Render intro text. * * @return void */ function aimaxchat_render_settings_intro() { echo '

Скопируйте параметры из личного кабинета AiMaxChat. Внешний вид и сценарии остаются в AiMaxChat и не требуют переустановки плагина.

'; } /** * Render a checkbox field. * * @param array $args Field arguments. * @return void */ function aimaxchat_render_checkbox_field( $args ) { $options = aimaxchat_get_options(); $id = $args['id']; $checked = ! empty( $options[ $id ] ); ?>

$args Field arguments. * @return void */ function aimaxchat_render_text_field( $args ) { $options = aimaxchat_get_options(); $id = $args['id']; $value = isset( $options[ $id ] ) ? (string) $options[ $id ] : ''; $placeholder = $args['placeholder'] ?? ''; ?>

AiMaxChat

(string) $options['botId'], 'publicToken' => (string) $options['publicToken'], 'apiUrl' => (string) $options['apiUrl'], ); $json = wp_json_encode( $payload, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ); if ( ! $json ) { return; } $inline_script = 'if (window.AiMaxChat && typeof window.AiMaxChat.init === "function") { window.AiMaxChat.init(' . $json . '); }'; wp_add_inline_script( AIMAXCHAT_SCRIPT_HANDLE, $inline_script, 'after' ); } add_action( 'wp_enqueue_scripts', 'aimaxchat_enqueue_widget' );