'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => false, ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_delete_data_on_uninstall', [ 'type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => false, ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_prompt_response_style', [ 'sanitize_callback' => 'salyut_agents_sanitize_text_field_b64', 'default' => 'You are having a conversation, not giving a presentation. Respond to what the person just said in one sentence. Then either ask one question if it genuinely moves the conversation forward, or stop — do not default to a question if the visitor has expressed a clear need, pain point, or readiness to move forward; address it directly instead. Never volunteer multiple points unprompted. Never invent or assume features, facts, or capabilities that are not explicitly stated in your instructions. If you do not know the answer to a question, say so honestly and direct the visitor to the appropriate contact or resource.', ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_default_model_resolved', [ 'type' => 'string', 'sanitize_callback' => 'salyut_agents_sanitize_default_model_override', 'default' => '', ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_chat_disclaimer', [ 'type' => 'string', 'sanitize_callback' => 'salyut_agents_sanitize_html_field', 'default' => salyut_agents_get_default_disclaimer(), ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_field_name', [ 'sanitize_callback' => 'salyut_agents_sanitize_field_state', 'default' => 'optional', ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_field_email', [ 'sanitize_callback' => 'salyut_agents_sanitize_field_state', 'default' => 'optional', ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_field_telephone', [ 'sanitize_callback' => 'salyut_agents_sanitize_field_state', 'default' => 'off', ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_newsletter_optin_enabled', [ 'type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => false, ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_newsletter_optin_label', [ 'type' => 'string', 'sanitize_callback' => 'salyut_agents_sanitize_html_field', 'default' => __( 'Opt in to our newsletter', 'salyut-agents' ), ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_support_email', [ 'sanitize_callback' => 'sanitize_email', 'default' => '', ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_email_notifications', [ 'type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => false, ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_notification_email', [ 'sanitize_callback' => 'sanitize_email', 'default' => '', ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_contact_url', [ 'sanitize_callback' => 'esc_url_raw', 'default' => '', ] ); // --------------------------------------------------------------------------- // WIDGET BEHAVIOUR SETTINGS // --------------------------------------------------------------------------- register_setting( 'salyut_agents_general_group', 'salyut_agents_start_minimized', [ 'type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => false, ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_open_delay', [ 'type' => 'integer', 'sanitize_callback' => 'absint', 'default' => 0, ] ); register_setting( 'salyut_agents_general_group', 'salyut_agents_scroll_threshold', [ 'type' => 'integer', 'sanitize_callback' => 'absint', 'default' => 0, ] ); // --------------------------------------------------------------------------- // VISITOR IP DETECTION SETTINGS // --------------------------------------------------------------------------- // NOTE: these live in salyut_agents_security_group (not salyut_agents_general_group) so // they render + save under the Security tab. Keeping them in the general group // while rendering them on a separate tab would let each tab's save null out the // other tab's options (options.php processes every option in the submitted group). register_setting( 'salyut_agents_security_group', 'salyut_agents_ip_source', [ 'type' => 'string', 'sanitize_callback' => 'salyut_agents_sanitize_ip_source', 'default' => 'direct', ] ); register_setting( 'salyut_agents_security_group', 'salyut_agents_ip_custom_header', [ 'type' => 'string', 'sanitize_callback' => 'salyut_agents_sanitize_ip_custom_header', 'default' => '', ] ); // --------------------------------------------------------------------------- // BOT PROTECTION (TURNSTILE) SETTINGS // --------------------------------------------------------------------------- register_setting( 'salyut_agents_security_group', 'salyut_agents_turnstile_enabled', [ 'type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => false, ] ); register_setting( 'salyut_agents_security_group', 'salyut_agents_turnstile_site_key', [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '', ] ); // Secret key: server-side only. Never localized to JS or returned in any REST // response — read exclusively during siteverify in salyut_agents_session(). register_setting( 'salyut_agents_security_group', 'salyut_agents_turnstile_secret_key', [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '', ] ); // --------------------------------------------------------------------------- // DESIGN TAB SETTINGS // --------------------------------------------------------------------------- register_setting( 'salyut_agents_design_group', 'salyut_agents_primary_color', [ 'type' => 'string', 'sanitize_callback' => 'sanitize_hex_color', 'default' => '', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_accent_color', [ 'type' => 'string', 'sanitize_callback' => 'sanitize_hex_color', 'default' => '', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_header_text_color', [ 'sanitize_callback' => 'sanitize_hex_color', 'default' => '', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_dept_color', [ 'sanitize_callback' => 'sanitize_hex_color', 'default' => '#888888', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_bot_bubble_bg', [ 'sanitize_callback' => 'sanitize_hex_color', 'default' => '', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_bot_bubble_text', [ 'sanitize_callback' => 'sanitize_hex_color', 'default' => '', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_user_bubble_bg', [ 'sanitize_callback' => 'sanitize_hex_color', 'default' => '', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_user_bubble_text', [ 'sanitize_callback' => 'sanitize_hex_color', 'default' => '', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_minimize_btn_color', [ 'sanitize_callback' => 'sanitize_hex_color', 'default' => '', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_switch_btn_color', [ 'sanitize_callback' => 'sanitize_hex_color', 'default' => '', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_switch_agent_btn_bg', [ 'sanitize_callback' => 'sanitize_hex_color', 'default' => '', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_switch_agent_btn_text', [ 'sanitize_callback' => 'sanitize_hex_color', 'default' => '', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_border_radius', [ 'sanitize_callback' => 'absint', 'default' => 16, ] ); // Widget height — same two-option "mode + companion value" shape as // salyut_agents_ip_source/salyut_agents_ip_custom_header above: a mode // selector (default/custom) plus the pixel value that only applies // when custom is chosen. The pixel value is independently re-clamped // on RENDER too (includes/widget.php), not just here on save — a row // edited directly in the database (migration, direct SQL, a future // import tool) must never be able to push the rendered widget outside // [400, 900]px either. register_setting( 'salyut_agents_design_group', 'salyut_agents_widget_height_mode', [ 'type' => 'string', 'sanitize_callback' => 'salyut_agents_sanitize_widget_height_mode', 'default' => 'default', ] ); register_setting( 'salyut_agents_design_group', 'salyut_agents_widget_height_px', [ 'type' => 'integer', 'sanitize_callback' => 'salyut_agents_sanitize_widget_height_px', 'default' => SALYUT_AGENTS_WIDGET_HEIGHT_DEFAULT_PX, ] ); add_settings_section( 'salyut_agents_general_section', '', 'salyut_agents_general_section_notice_render', 'salyut-agents-chatbot-general' ); add_settings_section( 'salyut_agents_leadcap_section', __( 'Lead Capture', 'salyut-agents' ), 'salyut_agents_section_head_render', 'salyut-agents-chatbot-general' ); add_settings_section( 'salyut_agents_notify_section', __( 'Notifications', 'salyut-agents' ), 'salyut_agents_section_head_render', 'salyut-agents-chatbot-general' ); add_settings_section( 'salyut_agents_behaviour_section',__( 'Widget Behaviour', 'salyut-agents' ), 'salyut_agents_section_head_render', 'salyut-agents-chatbot-general' ); add_settings_section( 'salyut_agents_data_section', __( 'Data', 'salyut-agents' ), 'salyut_agents_section_head_render', 'salyut-agents-chatbot-general' ); add_settings_section( 'salyut_agents_design_section', '', '__return_false', 'salyut-agents-chatbot-design' ); // Security tab. The overview section is read-only (no fields) and registered first // so it renders above the configurable IP-detection and Turnstile sections. add_settings_section( 'salyut_agents_security_overview_section', __( 'Security Overview', 'salyut-agents' ), 'salyut_agents_security_overview_render', 'salyut-agents-chatbot-security' ); add_settings_section( 'salyut_agents_security_section', __( 'Visitor IP Detection', 'salyut-agents' ), 'salyut_agents_section_head_render', 'salyut-agents-chatbot-security' ); add_settings_section( 'salyut_agents_turnstile_section', __( 'Bot Protection (Turnstile)', 'salyut-agents' ), 'salyut_agents_section_head_render', 'salyut-agents-chatbot-security' ); function salyut_agents_section_head_render( $args ) { $blurbs = [ 'salyut_agents_leadcap_section' => __( 'What visitors are asked before a chat begins.', 'salyut-agents' ), 'salyut_agents_notify_section' => __( 'Where new-lead alerts are sent.', 'salyut-agents' ), 'salyut_agents_behaviour_section' => __( 'How and when the widget appears on the page.', 'salyut-agents' ), 'salyut_agents_data_section' => __( 'What happens to your stored data if the plugin is deleted.', 'salyut-agents' ), 'salyut_agents_security_section' => __( 'How the plugin determines each visitor\'s real IP address for rate limiting.', 'salyut-agents' ), 'salyut_agents_turnstile_section' => __( 'Optional Cloudflare Turnstile challenge on new chat sessions — the strongest bot gate. Off by default.', 'salyut-agents' ), ]; $id = $args['id'] ?? ''; if ( ! empty( $blurbs[ $id ] ) ) { echo '
' . esc_html( $blurbs[ $id ] ) . '
'; } } // General /* translators: %s: product display name */ add_settings_field( 'salyut_agents_master_enabled', sprintf( __( '%s Status', 'salyut-agents' ), salyut_agents_display_name() ), 'salyut_agents_master_enabled_render', 'salyut-agents-chatbot-general', 'salyut_agents_general_section' ); add_settings_field( 'salyut_agents_prompt_response_style', __( 'Response Style', 'salyut-agents' ), 'salyut_agents_prompt_response_style_render', 'salyut-agents-chatbot-general', 'salyut_agents_general_section' ); add_settings_field( 'salyut_agents_default_model_resolved', __( 'Default Model', 'salyut-agents' ), 'salyut_agents_default_model_resolved_render', 'salyut-agents-chatbot-general', 'salyut_agents_general_section' ); add_settings_field( 'salyut_agents_chat_disclaimer', __( 'Chatbot Disclaimer', 'salyut-agents' ), 'salyut_agents_chat_disclaimer_render', 'salyut-agents-chatbot-general', 'salyut_agents_general_section' ); add_settings_field( 'salyut_agents_field_name', __( 'Name Field', 'salyut-agents' ), 'salyut_agents_field_name_render', 'salyut-agents-chatbot-general', 'salyut_agents_leadcap_section' ); add_settings_field( 'salyut_agents_field_email', __( 'Email Field', 'salyut-agents' ), 'salyut_agents_field_email_render', 'salyut-agents-chatbot-general', 'salyut_agents_leadcap_section' ); add_settings_field( 'salyut_agents_field_telephone', __( 'Telephone Field', 'salyut-agents' ), 'salyut_agents_field_telephone_render', 'salyut-agents-chatbot-general', 'salyut_agents_leadcap_section' ); add_settings_field( 'salyut_agents_newsletter_optin_enabled', __( 'Newsletter Opt-in', 'salyut-agents' ), 'salyut_agents_newsletter_optin_enabled_render', 'salyut-agents-chatbot-general', 'salyut_agents_leadcap_section' ); add_settings_field( 'salyut_agents_newsletter_optin_label', __( 'Newsletter Opt-in Label', 'salyut-agents' ), 'salyut_agents_newsletter_optin_label_render', 'salyut-agents-chatbot-general', 'salyut_agents_leadcap_section' ); add_settings_field( 'salyut_agents_support_email', __( 'Support Email', 'salyut-agents' ), 'salyut_agents_support_email_render', 'salyut-agents-chatbot-general', 'salyut_agents_notify_section' ); add_settings_field( 'salyut_agents_email_notifications', __( 'Lead Email Notifications', 'salyut-agents' ), 'salyut_agents_email_notifications_render', 'salyut-agents-chatbot-general', 'salyut_agents_notify_section' ); add_settings_field( 'salyut_agents_notification_email', __( 'Notification Email', 'salyut-agents' ), 'salyut_agents_notification_email_render', 'salyut-agents-chatbot-general', 'salyut_agents_notify_section' ); add_settings_field( 'salyut_agents_contact_url', __( 'Contact Page URL', 'salyut-agents' ), 'salyut_agents_contact_url_render', 'salyut-agents-chatbot-general', 'salyut_agents_notify_section' ); // Widget behaviour add_settings_field( 'salyut_agents_start_minimized', __( 'Start Minimised', 'salyut-agents' ), 'salyut_agents_start_minimized_render', 'salyut-agents-chatbot-general', 'salyut_agents_behaviour_section' ); add_settings_field( 'salyut_agents_open_delay', __( 'Auto-open Delay', 'salyut-agents' ), 'salyut_agents_open_delay_render', 'salyut-agents-chatbot-general', 'salyut_agents_behaviour_section' ); add_settings_field( 'salyut_agents_scroll_threshold', __( 'Auto-open on Scroll', 'salyut-agents' ), 'salyut_agents_scroll_threshold_render', 'salyut-agents-chatbot-general', 'salyut_agents_behaviour_section' ); // Data add_settings_field( 'salyut_agents_delete_data_on_uninstall', __( 'On Deletion', 'salyut-agents' ), 'salyut_agents_delete_data_on_uninstall_render', 'salyut-agents-chatbot-general', 'salyut_agents_data_section' ); // Visitor IP detection (Security tab) add_settings_field( 'salyut_agents_ip_source', __( 'CDN / Proxy', 'salyut-agents' ), 'salyut_agents_ip_source_render', 'salyut-agents-chatbot-security', 'salyut_agents_security_section' ); // Bot protection (Turnstile) (Security tab) add_settings_field( 'salyut_agents_turnstile_enabled', __( 'Enable Turnstile', 'salyut-agents' ), 'salyut_agents_turnstile_enabled_render', 'salyut-agents-chatbot-security', 'salyut_agents_turnstile_section' ); add_settings_field( 'salyut_agents_turnstile_site_key', __( 'Site Key', 'salyut-agents' ), 'salyut_agents_turnstile_site_key_render', 'salyut-agents-chatbot-security', 'salyut_agents_turnstile_section' ); add_settings_field( 'salyut_agents_turnstile_secret_key', __( 'Secret Key', 'salyut-agents' ), 'salyut_agents_turnstile_secret_key_render', 'salyut-agents-chatbot-security', 'salyut_agents_turnstile_section' ); // Design Tab add_settings_field( 'salyut_agents_primary_color', __( 'Primary Colour', 'salyut-agents' ), 'salyut_agents_primary_color_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_accent_color', __( 'Accent Colour', 'salyut-agents' ), 'salyut_agents_accent_color_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_header_text_color', __( 'Header Text Colour', 'salyut-agents' ), 'salyut_agents_header_text_color_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_dept_color', __( 'Department Text Colour', 'salyut-agents' ), 'salyut_agents_dept_color_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_minimize_btn_color', __( 'Minimize Icon', 'salyut-agents' ), 'salyut_agents_minimize_btn_color_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_switch_btn_color', __( 'Minimize Button Color', 'salyut-agents' ), 'salyut_agents_switch_btn_color_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_switch_agent_btn_bg', __( 'Switch Agent Button BG', 'salyut-agents' ), 'salyut_agents_switch_agent_btn_bg_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_switch_agent_btn_text', __( 'Switch Agent Button Text', 'salyut-agents' ), 'salyut_agents_switch_agent_btn_text_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_bot_bubble_bg', __( 'Bot Bubble Background', 'salyut-agents' ), 'salyut_agents_bot_bubble_bg_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_bot_bubble_text', __( 'Bot Bubble Text', 'salyut-agents' ), 'salyut_agents_bot_bubble_text_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_user_bubble_bg', __( 'User Bubble Background', 'salyut-agents' ), 'salyut_agents_user_bubble_bg_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_user_bubble_text', __( 'User Bubble Text', 'salyut-agents' ), 'salyut_agents_user_bubble_text_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_border_radius', __( 'Widget Corner Radius', 'salyut-agents' ), 'salyut_agents_border_radius_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); add_settings_field( 'salyut_agents_widget_height', __( 'Chat Widget Height', 'salyut-agents' ), 'salyut_agents_widget_height_render', 'salyut-agents-chatbot-design', 'salyut_agents_design_section' ); } add_action( 'admin_init', 'salyut_agents_register_settings' ); // --------------------------------------------------------------------------- // Admin notices // --------------------------------------------------------------------------- /** * Whether an AI provider is connected and usable for text generation. * * Replaces the old "is the OpenAI API key set" check. Credentials now live in * Settings > Connectors (WP core), so we ask the AI Client directly rather than * reading a stored key. * * @return bool */ function salyut_agents_ai_is_available(): bool { if ( ! function_exists( 'wp_ai_client_prompt' ) ) { return false; } return (bool) wp_ai_client_prompt( 'test' )->is_supported_for_text_generation(); } add_action( 'admin_notices', 'salyut_agents_configuration_notices', 25 ); function salyut_agents_configuration_notices(): void { if ( ! current_user_can( 'manage_options' ) ) { return; } $screen = get_current_screen(); if ( ! $screen ) { return; } $master_enabled = (bool) get_option( 'salyut_agents_master_enabled', false ); $ai_available = salyut_agents_ai_is_available(); $settings_url = admin_url( 'edit.php?post_type=salyut_lead&page=salyut-agents-settings' ); $connectors_url = admin_url( 'options-connectors.php' ); $display_name = salyut_agents_display_name(); $is_salyut_agents_page = ( $screen->post_type === 'salyut_lead' || $screen->post_type === 'salyut_agent' || strpos( $screen->id, 'salyut' ) !== false ); // Show globally when the chatbot is on but something is broken $is_broken = $master_enabled && ! $ai_available; if ( ! $is_salyut_agents_page && ! $is_broken ) { return; } $notices = []; if ( ! $ai_available ) { $notices[] = [ 'type' => 'error', 'message' => sprintf( /* translators: 1: product display name, 2: Connectors settings URL */ __( '%1$s: No AI provider connected. The chatbot will not work until you connect a provider in Settings › Connectors.', 'salyut-agents' ), $display_name, esc_url( $connectors_url ) ), ]; } if ( $is_salyut_agents_page && ! $master_enabled ) { $notices[] = [ 'type' => 'warning', 'message' => sprintf( /* translators: 1: product display name, 2: settings page URL, 3: product display name */ __( '%1$s is currently disabled and will not appear anywhere on your website. Enable %3$s', 'salyut-agents' ), $display_name, esc_url( $settings_url ), $display_name ), ]; } if ( $is_salyut_agents_page && $master_enabled && ! salyut_agents_has_active_prompt() ) { $agents_url = admin_url( 'edit.php?post_type=salyut_agent' ); $notices[] = [ 'type' => 'warning', 'message' => sprintf( /* translators: 1: product display name, 2: agents page URL */ __( '%1$s: The chatbot is enabled but has no agents configured. Add an agent.', 'salyut-agents' ), $display_name, esc_url( $agents_url ) ), ]; } if ( $is_salyut_agents_page && get_option( 'salyut_agents_field_name', 'optional' ) === 'off' && get_option( 'salyut_agents_field_email', 'optional' ) === 'off' && get_option( 'salyut_agents_field_telephone', 'off' ) === 'off' ) { $notices[] = [ 'type' => 'warning', 'message' => __( 'No lead capture fields selected. The chatbot will start immediately without collecting information upfront.', 'salyut-agents' ), ]; } if ( $is_salyut_agents_page && ! get_option( 'salyut_agents_default_agent_id', 0 ) ) { $agents_url = admin_url( 'edit.php?post_type=salyut_agent' ); $notices[] = [ 'type' => 'warning', 'message' => sprintf( /* translators: 1: product display name, 2: agents page URL */ __( '%1$s: No default agent assigned. The chatbot will not appear on any page that does not have a specific agent assigned. Assign a default agent.', 'salyut-agents' ), $display_name, esc_url( $agents_url ) ), ]; } foreach ( $notices as $notice ) { printf( '%s
%s
', esc_html( sprintf( /* translators: %s: product display name */ __( '%s: the agents below are not answering until this is fixed.', 'salyut-agents' ), $display_name ) ) ); echo '
%2$s Terms of Service.', 'salyut-agents' ), [ 'a' => [ 'href' => [], 'target' => [], 'rel' => [] ] ] ), 'https://salyutplugins.com/terms-of-service', esc_html( $name ) ); ?>
Terms and Conditions.', 'salyut-agents' ); } function salyut_agents_chat_disclaimer_render() { $raw = get_option( 'salyut_agents_chat_disclaimer', salyut_agents_get_default_disclaimer() ); $decoded = base64_decode( $raw, true ); $content = ( $decoded !== false && base64_encode( $decoded ) === $raw ) ? $decoded : $raw; ?> 'salyut_agents_chat_disclaimer', 'textarea_rows' => 5, 'media_buttons' => false, 'teeny' => true, 'quicktags' => true, ] ); } function salyut_agents_field_name_render() { $value = get_option( 'salyut_agents_field_name', 'optional' ); ?> 'salyut_agents_newsletter_optin_label', 'textarea_rows' => 3, 'media_buttons' => false, 'teeny' => true, 'quicktags' => true, ] ); } function salyut_agents_support_email_render() { $email = get_option( 'salyut_agents_support_email', '' ); ?>
Start Minimised is on. Set to 0 to disable.', 'salyut-agents' ), [ 'strong' => [] ] ); ?>
seconds 0 ) : ?>Widget will expand second after page load.
Start Minimised is on. Set to 0 to disable.', 'salyut-agents' ), [ 'strong' => [] ] ); ?>
px 0 ) : ?>Widget will expand after px of scroll.
Security warning: a chosen header is only trustworthy if your origin server is locked down to accept traffic only from your CDN. Otherwise an attacker can bypass the CDN, connect to your origin directly, and forge that header to spoof any IP they like.', 'salyut-agents' ), [ 'strong' => [], 'em' => [] ] ); ?>
Cloudflare Turnstile dashboard.', 'salyut-agents' ), [ 'strong' => [] ] ); ?>
Managed (recommended) or Invisible — not Non-Interactive, which clutters the chat. Add your site\'s domain to the widget\'s allowed hostnames, then copy the Site Key and Secret Key below. See the security documentation for full setup steps.', 'salyut-agents' ), esc_url( $doc_url ) ), [ 'strong' => [], 'a' => [ 'href' => [], 'target' => [], 'rel' => [] ], ] ); ?>
' . esc_html__( 'Text colour in the chat header.', 'salyut-agents' ) . ''; echo ''; } function salyut_agents_dept_color_render() { $color = get_option( 'salyut_agents_dept_color', '#888888' ); echo '' . esc_html__( 'Colour of the agent department label shown in the chat header.', 'salyut-agents' ) . '
'; echo ''; } function salyut_agents_bot_bubble_bg_render() { $color = get_option( 'salyut_agents_bot_bubble_bg', '' ); echo '' . esc_html__( 'Background colour of bot chat bubbles.', 'salyut-agents' ) . '
'; echo ''; } function salyut_agents_bot_bubble_text_render() { $color = get_option( 'salyut_agents_bot_bubble_text', '' ); echo '' . esc_html__( 'Text colour of bot chat bubbles.', 'salyut-agents' ) . '
'; echo ''; } function salyut_agents_user_bubble_bg_render() { $color = get_option( 'salyut_agents_user_bubble_bg', '' ); echo '' . esc_html__( 'Background colour of user chat bubbles.', 'salyut-agents' ) . '
'; echo ''; } function salyut_agents_user_bubble_text_render() { $color = get_option( 'salyut_agents_user_bubble_text', '' ); echo '' . esc_html__( 'Text colour of user chat bubbles.', 'salyut-agents' ) . '
'; echo ''; } function salyut_agents_minimize_btn_color_render() { $color = get_option( 'salyut_agents_minimize_btn_color', '' ); echo '' . esc_html__( 'Colour of the − (minus) icon in the chat header that minimises the widget.', 'salyut-agents' ) . '
'; echo ''; } function salyut_agents_switch_btn_color_render() { $color = get_option( 'salyut_agents_switch_btn_color', '' ); echo '' . esc_html__( 'Background colour of the floating button that reopens the chat widget when it is minimised.', 'salyut-agents' ) . '
'; echo ''; } function salyut_agents_switch_agent_btn_bg_render() { $color = get_option( 'salyut_agents_switch_agent_btn_bg', '' ); echo '' . esc_html__( 'Background colour of the "Yes, switch agents" button in the agent handoff prompt.', 'salyut-agents' ) . '
'; echo ''; } function salyut_agents_switch_agent_btn_text_render() { $color = get_option( 'salyut_agents_switch_agent_btn_text', '' ); echo '' . esc_html__( 'Text colour of the "Yes, switch agents" button in the agent handoff prompt.', 'salyut-agents' ) . '
'; echo ''; } function salyut_agents_border_radius_render() { $value = get_option( 'salyut_agents_border_radius', 16 ); ?> px
post_type === 'salyut_lead' && $screen->base === 'post' ) { return 'edit.php?post_type=salyut_lead'; } return $parent_file; } function salyut_agents_fix_submenu_highlight( $submenu_file ) { $screen = get_current_screen(); if ( ! $screen ) return $submenu_file; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- reading the request only to detect the current admin screen for menu highlighting; nothing is processed. $is_leads_list = $screen->base === 'edit' && $screen->post_type === 'salyut_lead' && empty( $_GET['page'] ); $is_leads_post = $screen->base === 'post' && $screen->post_type === 'salyut_lead'; if ( $is_leads_list || $is_leads_post ) { return 'edit.php?post_type=salyut_lead&view=list'; } return $submenu_file; } // --------------------------------------------------------------------------- // Settings page renderer // --------------------------------------------------------------------------- function salyut_agents_render_settings_page() { if ( ! current_user_can( 'manage_options' ) ) return; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- reading the request only to pick which settings tab to render; the form itself is protected by the Settings API nonce on save. $current_tab = sanitize_text_field( wp_unslash( $_GET['tab'] ?? 'general' ) ); $base_url = admin_url( 'edit.php?post_type=salyut_lead&page=salyut-agents-settings' ); ?>