'array', 'sanitize_callback' => array( self::class, 'sanitize_settings' ), 'default' => self::default_settings(), ) ); add_settings_section( 'ai_receptionist_connection', esc_html__( 'Widget connection', 'aireceptionist-so' ), array( self::class, 'render_connection_section' ), self::PAGE_SLUG ); add_settings_field( 'ai_receptionist_office_id', esc_html__( 'Office ID', 'aireceptionist-so' ), array( self::class, 'render_office_id_field' ), self::PAGE_SLUG, 'ai_receptionist_connection' ); add_settings_field( 'ai_receptionist_enabled', esc_html__( 'Widget', 'aireceptionist-so' ), array( self::class, 'render_enabled_field' ), self::PAGE_SLUG, 'ai_receptionist_connection' ); add_settings_field( 'ai_receptionist_display_scope', esc_html__( 'Display on', 'aireceptionist-so' ), array( self::class, 'render_display_scope_field' ), self::PAGE_SLUG, 'ai_receptionist_connection' ); } /** * Adds the plugin settings page under Settings. * * @return void */ public static function add_settings_page() { add_options_page( esc_html__( 'AI Receptionist', 'aireceptionist-so' ), esc_html__( 'AI Receptionist', 'aireceptionist-so' ), 'manage_options', self::PAGE_SLUG, array( self::class, 'render_settings_page' ) ); } /** * Adds a direct settings link on the Plugins page. * * @param string[] $links Existing action links. * @return string[] */ public static function add_settings_link( $links ) { $settings_link = sprintf( '%2$s', esc_url( self::settings_page_url() ), esc_html__( 'Settings', 'aireceptionist-so' ) ); array_unshift( $links, $settings_link ); return $links; } /** * Describes the settings section. * * @return void */ public static function render_connection_section() { echo '
' . esc_html__( 'Connect this site to an AI Receptionist office, then choose where the widget appears.', 'aireceptionist-so' ) . '
'; } /** * Renders the Office ID field. * * @return void */ public static function render_office_id_field() { $settings = self::get_settings(); printf( '', esc_attr( self::OPTION_NAME ), esc_attr( $settings['office_id'] ) ); printf( '%1$s %3$s
', esc_html__( 'Copy the Office ID from your AI Receptionist settings.', 'aireceptionist-so' ), esc_url( self::DASHBOARD_URL ), esc_html__( 'Open dashboard', 'aireceptionist-so' ) ); } /** * Renders the enabled field and its consent disclosure. * * @return void */ public static function render_enabled_field() { $settings = self::get_settings(); ?>$office_id, 'enabled' => $enabled, 'display_scope' => $display_scope, ); } /** * Checks the saved Office ID against the hosted service. * * @return void */ public static function handle_connection_check() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have permission to check this connection.', 'aireceptionist-so' ) ); } check_admin_referer( 'ai_receptionist_check_connection' ); $settings = self::get_settings(); $office_id = $settings['office_id']; if ( '' === $office_id ) { self::save_connection_status( 'error', '', '' ); self::redirect_to_settings(); } $request_url = add_query_arg( 'officeId', $office_id, self::STATUS_URL ); $response = wp_safe_remote_get( esc_url_raw( $request_url ), array( 'limit_response_size' => 32768, 'redirection' => 0, 'timeout' => 10, ) ); if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { self::save_connection_status( 'error', $office_id, '' ); self::redirect_to_settings(); } $data = json_decode( wp_remote_retrieve_body( $response ), true ); if ( ! is_array( $data ) || ! isset( $data['connected'] ) || ! is_bool( $data['connected'] ) ) { self::save_connection_status( 'error', $office_id, '' ); self::redirect_to_settings(); } if ( ! $data['connected'] ) { self::save_connection_status( 'not_connected', $office_id, '' ); self::redirect_to_settings(); } $office_name = isset( $data['officeName'] ) && is_string( $data['officeName'] ) ? self::sanitize_office_name( $data['officeName'] ) : ''; self::save_connection_status( 'connected', $office_id, $office_name ); self::redirect_to_settings(); } /** * Enqueues the hosted widget when its saved settings allow it. * * @return void */ public static function enqueue_widget() { $settings = self::get_settings(); if ( ! $settings['enabled'] || '' === $settings['office_id'] ) { return; } if ( ! self::should_display( $settings['display_scope'] ) ) { return; } wp_enqueue_script( self::SCRIPT_HANDLE, self::SCRIPT_URL, array(), AI_RECEPTIONIST_VERSION, array( 'in_footer' => true, 'strategy' => 'async', ) ); } /** * Adds the Office ID and source label to the widget script tag. * * @param string $tag Generated script tag. * @param string $handle Registered script handle. * @param string $src Generated script source. * @return string */ public static function add_widget_script_attributes( $tag, $handle, $src ) { if ( self::SCRIPT_HANDLE !== $handle ) { return $tag; } $settings = self::get_settings(); if ( ! $settings['enabled'] || '' === $settings['office_id'] ) { return $tag; } return wp_get_script_tag( array( 'id' => 'ai-receptionist-widget-js', 'src' => esc_url_raw( $src ), 'async' => true, 'data-office' => $settings['office_id'], 'data-source' => 'wordpress', ) ); } /** * Shows the most recent result for the current Office ID. * * @return void */ private static function render_connection_status() { $status = get_option( self::STATUS_OPTION_NAME, array() ); $settings = self::get_settings(); if ( ! is_array( $status ) || ( $status['office_id'] ?? '' ) !== $settings['office_id'] ) { return; } $state = isset( $status['state'] ) && is_string( $status['state'] ) ? $status['state'] : ''; if ( 'connected' === $state ) { $office_name = isset( $status['office_name'] ) && is_string( $status['office_name'] ) ? self::sanitize_office_name( $status['office_name'] ) : ''; $message = '' !== $office_name ? sprintf( /* translators: %s: office name returned by AI Receptionist. */ esc_html__( 'Connected to %s.', 'aireceptionist-so' ), $office_name ) : esc_html__( 'Connection confirmed.', 'aireceptionist-so' ); echo '
' . esc_html( $message ) . '
' . esc_html__( 'No AI Receptionist office was found for this Office ID.', 'aireceptionist-so' ) . '
' . esc_html__( 'The connection could not be checked. Confirm the Office ID and try again.', 'aireceptionist-so' ) . '