'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '', ) ); register_setting( 'aidev_chatbot', 'aidev_chatbot_api_url', array( 'type' => 'string', 'sanitize_callback' => 'esc_url_raw', 'default' => AIDEV_CHATBOT_DEFAULT_API_URL, ) ); } add_action( 'admin_init', 'aidev_chatbot_register_settings' ); /** * ── Key verification (2026-07-31) ─────────────────────────────────────── * Pings {api_url}/api/widget/config with the saved key, server-side, and * caches the verdict keyed to a hash of key+url — so it re-checks exactly * once after every settings change, never on normal page loads. * Identifies itself via User-Agent so Aidevelopia can see plugin installs. * * @return string|null 'ok' | 'bad' | 'unreachable' | null (no key saved) */ function aidev_chatbot_key_status() { $api_key = get_option( 'aidev_chatbot_api_key', '' ); if ( '' === $api_key ) { return null; } $api_url = get_option( 'aidev_chatbot_api_url', AIDEV_CHATBOT_DEFAULT_API_URL ); $sig = md5( $api_key . '|' . $api_url ); $cached = get_option( 'aidev_chatbot_key_check' ); if ( is_array( $cached ) && isset( $cached['sig'], $cached['status'] ) && $cached['sig'] === $sig ) { return $cached['status']; } $response = wp_remote_get( trailingslashit( $api_url ) . 'api/widget/config', array( 'timeout' => 6, 'headers' => array( 'X-Tenant-Api-Key' => $api_key, 'Accept' => 'application/json', ), 'user-agent' => 'aidevelopia-wordpress-plugin/' . AIDEV_CHATBOT_VERSION . '; ' . home_url(), ) ); if ( is_wp_error( $response ) ) { $status = 'unreachable'; } else { $status = 200 === wp_remote_retrieve_response_code( $response ) ? 'ok' : 'bad'; } update_option( 'aidev_chatbot_key_check', array( 'sig' => $sig, 'status' => $status ), false ); return $status; } /** * ── Settings page (Settings → Aidevelopia) ────────────────────────────── */ function aidev_chatbot_add_settings_page() { add_options_page( __( 'Aidevelopia Chatbot', 'aidevelopia-chatbot' ), __( 'Aidevelopia', 'aidevelopia-chatbot' ), 'manage_options', 'aidevelopia-chatbot', 'aidev_chatbot_render_settings_page' ); } add_action( 'admin_menu', 'aidev_chatbot_add_settings_page' ); function aidev_chatbot_render_settings_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } $api_key = get_option( 'aidev_chatbot_api_key', '' ); $api_url = get_option( 'aidev_chatbot_api_url', AIDEV_CHATBOT_DEFAULT_API_URL ); $status = aidev_chatbot_key_status(); // re-verifies only when key/url changed ?>
' . esc_html__( 'Settings', 'aidevelopia-chatbot' ) . ''; array_unshift( $links, $settings ); return $links; } add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'aidev_chatbot_action_links' ); /** * ── Front-end embed ───────────────────────────────────────────────────── * Enqueued (not echoed) so Plugin Check is happy; the widget loader reads * its config from data-* attributes, which core enqueues can't express — * the script_loader_tag filter below adds them to OUR tag only. * Nothing loads until an API key is saved. Never loads in wp-admin. */ function aidev_chatbot_enqueue_widget() { $api_key = get_option( 'aidev_chatbot_api_key', '' ); if ( '' === $api_key ) { return; } $api_url = get_option( 'aidev_chatbot_api_url', AIDEV_CHATBOT_DEFAULT_API_URL ); if ( '' === $api_url ) { $api_url = AIDEV_CHATBOT_DEFAULT_API_URL; } wp_enqueue_script( 'aidevelopia-chatbot', trailingslashit( $api_url ) . 'developia.js', array(), AIDEV_CHATBOT_VERSION, true // footer ); } add_action( 'wp_enqueue_scripts', 'aidev_chatbot_enqueue_widget' ); /** * Add the loader's data-* attributes to our script tag only. */ function aidev_chatbot_script_attributes( $tag, $handle ) { if ( 'aidevelopia-chatbot' !== $handle ) { return $tag; } $api_key = get_option( 'aidev_chatbot_api_key', '' ); $api_url = get_option( 'aidev_chatbot_api_url', AIDEV_CHATBOT_DEFAULT_API_URL ); return str_replace( ' src=', ' data-api-key="' . esc_attr( $api_key ) . '" data-api-url="' . esc_attr( untrailingslashit( $api_url ) ) . '" src=', $tag ); } add_filter( 'script_loader_tag', 'aidev_chatbot_script_attributes', 10, 2 );