prefix . 'twp_call_queues'; $queue = $wpdb->get_row($wpdb->prepare( "SELECT * FROM $queue_table WHERE id = %d", $queue_id )); } // Determine the prompt message $prompt_message = $custom_prompt; if (!$prompt_message && $queue && !empty($queue->voicemail_prompt)) { $prompt_message = $queue->voicemail_prompt; } if (!$prompt_message) { $prompt_message = "We're sorry, but all our agents are currently unavailable. Please leave a message after the tone, and we'll get back to you as soon as possible."; } // Generate TTS for the prompt require_once dirname(__FILE__) . '/class-twp-tts-helper.php'; $tts_result = TWP_TTS_Helper::text_to_speech($prompt_message); // Build TwiML response $response = new \Twilio\TwiML\VoiceResponse(); if ($tts_result['success'] && !empty($tts_result['file_url'])) { // Use generated TTS audio $response->play($tts_result['file_url']); } else { // Fallback to Twilio's Say $response->say($prompt_message, ['voice' => 'alice']); } // Record the voicemail $record_params = [ 'action' => home_url('/wp-json/twilio-webhook/v1/voicemail-complete'), 'recordingStatusCallback' => home_url('/wp-json/twilio-webhook/v1/voicemail-callback?' . http_build_query([ 'from' => $caller_number, 'queue_id' => $queue_id, 'source' => 'queue_timeout' ])), 'recordingStatusCallbackMethod' => 'POST', 'maxLength' => 300, // 5 minutes max 'playBeep' => true, 'finishOnKey' => '#', 'transcribe' => true, 'transcribeCallback' => home_url('/wp-json/twilio-webhook/v1/voicemail-transcription') ]; $response->record($record_params); // Thank you message after recording $response->say('Thank you for your message. Goodbye.', ['voice' => 'alice']); return $response; } /** * Save voicemail to database * * @param array $voicemail_data Voicemail data * @return int|false Voicemail ID or false on failure */ public static function save_voicemail($voicemail_data) { global $wpdb; $table_name = $wpdb->prefix . 'twp_voicemails'; $insert_data = array( 'call_sid' => sanitize_text_field($voicemail_data['call_sid']), 'from_number' => sanitize_text_field($voicemail_data['from_number']), 'to_number' => !empty($voicemail_data['to_number']) ? sanitize_text_field($voicemail_data['to_number']) : '', 'recording_url' => esc_url_raw($voicemail_data['recording_url']), 'recording_duration' => intval($voicemail_data['recording_duration']), 'workflow_id' => !empty($voicemail_data['workflow_id']) ? intval($voicemail_data['workflow_id']) : null, 'queue_id' => !empty($voicemail_data['queue_id']) ? intval($voicemail_data['queue_id']) : null, 'source' => !empty($voicemail_data['source']) ? sanitize_text_field($voicemail_data['source']) : 'workflow', 'status' => 'new', 'received_at' => current_time('mysql') ); $result = $wpdb->insert($table_name, $insert_data); if ($result) { $voicemail_id = $wpdb->insert_id; // Log the voicemail if (class_exists('TWP_Call_Logger')) { TWP_Call_Logger::log_action( $voicemail_data['call_sid'], 'Voicemail recorded from queue timeout (' . $voicemail_data['recording_duration'] . 's)' ); } return $voicemail_id; } return false; } /** * Update voicemail transcription * * @param int $voicemail_id Voicemail ID * @param string $transcription Transcription text * @param string $transcription_status Transcription status * @return bool Success */ public static function update_transcription($voicemail_id, $transcription, $transcription_status = 'completed') { global $wpdb; $table_name = $wpdb->prefix . 'twp_voicemails'; $result = $wpdb->update( $table_name, array( 'transcription' => sanitize_textarea_field($transcription), 'transcription_status' => $transcription_status ), array('id' => $voicemail_id), array('%s', '%s'), array('%d') ); // Check for urgent keywords in transcription if ($result && !empty($transcription)) { self::check_urgent_keywords($voicemail_id, $transcription); } return $result !== false; } /** * Check transcription for urgent keywords * * @param int $voicemail_id Voicemail ID * @param string $transcription Transcription text */ private static function check_urgent_keywords($voicemail_id, $transcription) { global $wpdb; // Get urgent keywords from settings $urgent_keywords = get_option('twp_urgent_voicemail_keywords', array('urgent', 'emergency', 'asap', 'critical')); if (is_string($urgent_keywords)) { $urgent_keywords = array_map('trim', explode(',', $urgent_keywords)); } // Check if transcription contains any urgent keywords $transcription_lower = strtolower($transcription); $found_keyword = null; foreach ($urgent_keywords as $keyword) { if (stripos($transcription_lower, strtolower(trim($keyword))) !== false) { $found_keyword = $keyword; break; } } if ($found_keyword) { // Mark voicemail as urgent $table_name = $wpdb->prefix . 'twp_voicemails'; $wpdb->update( $table_name, array('is_urgent' => 1), array('id' => $voicemail_id), array('%d'), array('%d') ); // Send urgent notification $voicemail = $wpdb->get_row($wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $voicemail_id )); if ($voicemail && class_exists('TWP_Notifications')) { TWP_Notifications::send_call_notification('urgent_voicemail', array( 'type' => 'urgent_voicemail', 'from_number' => $voicemail->from_number, 'keyword' => $found_keyword, 'transcription' => $transcription, 'voicemail_id' => $voicemail_id, 'admin_url' => admin_url('admin.php?page=twilio-wp-voicemails&voicemail_id=' . $voicemail_id) )); } error_log("TWP Voicemail: Urgent keyword '$found_keyword' detected in voicemail $voicemail_id"); } } /** * Get voicemail by ID * * @param int $voicemail_id Voicemail ID * @return object|null Voicemail object */ public static function get_voicemail($voicemail_id) { global $wpdb; $table_name = $wpdb->prefix . 'twp_voicemails'; return $wpdb->get_row($wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $voicemail_id )); } }