diff --git a/CLAUDE.md b/CLAUDE.md
index d3f3ee0..10da6cc 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,839 +1,65 @@
-# CLAUDE.md - Twilio WordPress Plugin Documentation
-
-This file provides comprehensive guidance to Claude Code (claude.ai/code) when working with the Twilio WordPress Plugin codebase.
-
-## ๐จ CRITICAL: Testing & Deployment Environment
-
-**THIS PLUGIN RUNS ON A REMOTE SERVER IN A DOCKER CONTAINER - NOT LOCALLY**
-- **Production Server Path**: `/home/shadowdao/public_html/wp-content/plugins/twilio-wp-plugin/`
-- **Production URL**: `https://phone.cloud-hosting.io/`
-- **Development Path**: `/home/jknapp/code/twilio-wp-plugin/`
-- **Deployment Method**: Files synced via rsync from development to Docker container
-
-**IMPORTANT NOTES**:
-- NEVER assume local testing - all tests must work on remote server
-- Direct PHP tests work (`php test-twilio-direct.php send`)
-- WordPress admin context has issues that need investigation
-- The plugin requires Twilio PHP SDK v8.7.0 to function
-
-## ๐ Standardized Phone Number Variable Names
-
-**THESE NAMING CONVENTIONS MUST BE STRICTLY FOLLOWED:**
-
-### Required Variable Names:
-- **`incoming_number`** = Phone number that initiated contact (sent SMS/call TO the system)
-- **`agent_number`** = Phone number used to reach a specific agent
-- **`customer_number`** = Phone number of customer calling into the system
-- **`workflow_number`** = Twilio number assigned to a specific workflow
-- **`queue_number`** = Twilio number assigned to a specific queue
-- **`default_number`** = Default Twilio number when none specified
-
-### BANNED Variable Names (DO NOT USE):
-- โ `from_number` - Ambiguous, could be customer or system
-- โ `to_number` - Ambiguous, could be agent or system
-- โ `phone_number` - Too generic, must specify whose number
-- โ `$agent_phone` - Use `$agent_number` instead
-
-### Test Numbers:
-- **Twilio Number**: `+19516215107`
-- **Test Agent Number**: `+19095737372`
-- **Fake Test Number**: `+19512345678` (DO NOT SEND SMS TO THIS)
-
-### Legacy Webhook URLs:
-- **SMS**: `https://www.streamers.channel/wp-json/twilio-webhook/v1/sms`
-- **Voice**: `https://www.streamers.channel/wp-json/twilio-webhook/v1/voice`
-
-## ๐๏ธ Plugin Architecture Overview
-
-### Core Plugin Structure
-```
-twilio-wp-plugin/
-โโโ twilio-wp-plugin.php # Main plugin file (entry point)
-โโโ includes/ # Core functionality classes
-โ โโโ class-twp-core.php # Main plugin initialization
-โ โโโ class-twp-activator.php # Database setup
-โ โโโ class-twp-twilio-api.php # Twilio SDK wrapper
-โ โโโ class-twp-webhooks.php # REST API endpoints
-โ โโโ class-twp-tts-helper.php # TTS with ElevenLabs/Twilio
-โ โโโ ... # Other core classes
-โโโ admin/ # Admin interface
-โ โโโ class-twp-admin.php # Admin pages & AJAX handlers
-โโโ assets/ # Frontend resources
-โ โโโ css/ # Stylesheets
-โ โโโ js/ # JavaScript files
-โ โโโ audio/ # Audio resources
-โโโ CLAUDE.md # This documentation file
-```
-
-## ๐ฆ Core Classes Documentation
-
-### Main Classes (`includes/` directory)
-
-#### TWP_Core
-- **Purpose**: Main plugin initialization and hook registration
-- **Key Methods**:
- - `define_admin_hooks()`: Registers all admin AJAX actions
- - `define_public_hooks()`: Registers frontend hooks
- - `define_webhook_hooks()`: Registers REST API endpoints
-
-#### TWP_Activator
-- **Purpose**: Database table creation and plugin activation
-- **Tables Created**: 15 database tables (see Database Schema section)
-- **Key Methods**:
- - `ensure_tables_exist()`: Checks and creates missing tables
- - `migrate_tables()`: Handles schema migrations
- - `add_missing_columns()`: Updates table structures
-
-#### TWP_Twilio_API
-- **Purpose**: Wrapper for Twilio PHP SDK v8.7.0
-- **Important**: Uses direct instantiation (`new TWP_Twilio_API()`)
-- **Key Methods**:
- - `make_call()`: Initiates outbound calls
- - `send_sms()`: Sends SMS messages
- - `update_call()`: Updates call state (hold/resume)
- - `create_queue_twiml()`: Generates queue TwiML
-
-#### TWP_Webhooks
-- **Purpose**: Handles all Twilio webhook endpoints
-- **Namespace**: `twilio-webhook/v1`
-- **Total Endpoints**: 26 REST API routes
-
-#### TWP_TTS_Helper (UNIVERSALLY INTEGRATED)
-- **Purpose**: Text-to-Speech with ElevenLabs integration, caching, and universal call control integration
-- **Features**:
- - Universal integration across all call control functions
- - Automatic ElevenLabs detection with Alice fallback
- - 30-day intelligent cache for identical text
- - Professional voice consistency throughout call lifecycle
-- **Key Methods**:
- - `add_tts_to_twiml()`: Universal TTS integration for all voice prompts
- - `generate_tts_audio()`: Pre-generates cached audio for performance
-- **Coverage**: Hold, transfer, requeue, workflow steps, and queue announcements
-
-#### TWP_User_Queue_Manager (NEW)
-- **Purpose**: Comprehensive user-specific queue management with automatic creation
-- **Features**:
- - Automatic personal and hold queue creation for any user
- - Unique extension generation (100-9999) with collision detection
- - Database consistency with proper foreign key relationships
- - Browser phone call support for complex topologies
- - Schema compatibility (`enqueued_at` and `joined_at` columns)
- - Comprehensive error handling with rollback mechanisms
-- **Key Methods**:
- - `create_user_queues()`: Creates personal and hold queues with unique extensions
- - `transfer_to_hold_queue()`: Enhanced hold with auto-queue creation fallback
- - `resume_from_hold()`: Comprehensive resume with target queue support
- - `generate_unique_extension()`: Intelligent extension generation (3-4 digits)
- - `get_user_extension_data()`: Retrieves complete user queue information
-- **Auto-Creation**: Seamlessly integrates with hold, transfer, and queue operations
-
-#### TWP_ElevenLabs_API
-- **Purpose**: Integration with ElevenLabs TTS service
-- **Configuration**: Uses `twp_elevenlabs_*` options
-- **Features**: Voice selection, model configuration, audio generation
-
-#### TWP_Workflow
-- **Purpose**: Call flow processing and TwiML generation
-- **Features**: IVR menus, queue routing, schedule checking
-
-#### TWP_Call_Queue
-- **Purpose**: Queue management and position tracking
-- **Features**: User-specific queues, hold queues, priority handling
-
-#### TWP_Agent_Manager
-- **Purpose**: Agent status and call acceptance
-- **Features**: Phone number validation, availability tracking
-
-#### TWP_Callback_Manager
-- **Purpose**: Callback request handling
-- **Features**: SMS confirmations, automatic processing
-
-#### TWP_Call_Logger
-- **Purpose**: Call logging and statistics
-- **Features**: Detailed call records, duration tracking
-
-#### TWP_Shortcodes
-- **Purpose**: WordPress shortcodes for frontend features
-- **Shortcode**: `[twp_browser_phone]` - Admin browser phone redirect interface
-
-## ๐พ Database Schema
-
-### Complete Table List (15 tables)
-1. `twp_phone_schedules` - Business hours definitions
-2. `twp_call_queues` - Queue configurations (includes user-specific)
-3. `twp_queued_calls` - Active calls in queues
-4. `twp_workflows` - Call flow definitions
-5. `twp_workflow_phones` - Phone-to-workflow mappings
-6. `twp_call_log` - Complete call history
-7. `twp_sms_log` - SMS message tracking
-8. `twp_voicemails` - Voicemail recordings and transcriptions
-9. `twp_agent_groups` - Agent group definitions
-10. `twp_group_members` - User-to-group relationships
-11. `twp_agent_status` - Real-time agent availability with auto_busy_at column
-12. `twp_callbacks` - Callback request queue
-13. `twp_call_recordings` - Call recording metadata
-14. `twp_user_extensions` - User extension numbers
-15. `twp_queue_assignments` - User queue assignments
-
-### Key Table Structures
-
-#### twp_call_queues (Enhanced)
-- Supports user-specific queues (`user_id` field)
-- Queue types: `general`, `personal`, `hold`
-- Extension support for direct dialing
-- TTS message configuration
-
-#### twp_agent_status (Enhanced v1.6.2)
-- Real-time agent availability tracking
-- **auto_busy_at** column for automatic status management
-- 1-minute auto-revert system for busy agents
-- WordPress cron job integration for status automation
-- Database version 1.6.2 with automatic migration
-
-#### twp_queued_calls
-- Uses `enqueued_at` timestamp (migrated from `joined_at`)
-- No `customer_number` field (uses `from_number`/`to_number`)
-- Tracks agent assignment and status
-
-## ๐ REST API Endpoints (Webhooks)
-
-### Voice Endpoints
-- `/voice` - Main incoming call handler
-- `/browser-voice` - Browser phone calls
-- `/smart-routing` - Intelligent call routing
-- `/agent-screen` - Agent screening before connection
-- `/agent-confirm` - Agent confirmation handler
-- `/ring-group-result` - Handle ring group outcomes
-- `/agent-connect` - Connect accepted agents
-
-### SMS Endpoints
-- `/sms` - Main SMS handler (includes "1" responses)
-- `/status` - Call/SMS status updates
-
-### Queue Management
-- `/queue-wait` - Queue hold music and announcements
-- `/queue-action` - Queue-specific actions
-- `/ivr-response` - IVR menu selections
-
-### Voicemail
-- `/voicemail-callback` - Voicemail recording handler
-- `/voicemail-complete` - Post-recording processing
-- `/voicemail-audio/{id}` - Audio playback proxy
-
-### Recording
-- `/recording-status` - Recording status callbacks
-- `/recording-audio/{id}` - Recording playback proxy
-- `/transcription` - Transcription webhooks
-
-### Callback System
-- `/callback-choice` - Customer callback selection
-- `/request-callback` - Callback request handler
-- `/callback-agent` - Agent-side callback
-- `/callback-customer` - Customer-side callback
-
-### Outbound Calling
-- `/outbound-agent` - Basic outbound calls
-- `/outbound-agent-with-from` - Outbound with caller ID selection
-
-### Utility
-- `/resume-call` - Resume held calls
-- `/smart-routing-fallback` - Routing error handler
-- `/browser-fallback` - Browser phone fallback
-
-## ๐๏ธ AJAX Endpoints (Admin Only)
-
-### Total: 68 AJAX Actions
-
-### Categories:
-1. **Schedule Management** (4 actions)
-2. **Workflow Management** (5 actions)
-3. **Phone Number Management** (5 actions)
-4. **Queue Management** (6 actions)
-5. **Agent Management** (11 actions)
-6. **Call Control** (15 actions)
-7. **Voicemail** (5 actions)
-8. **Recording** (4 actions)
-9. **SMS Management** (4 actions)
-10. **ElevenLabs Integration** (3 actions)
-11. **Browser Phone** (4 actions)
-12. **Transfer & Hold** (8 actions)
-
-### Key AJAX Actions:
-- `twp_toggle_hold` - Put call on hold/resume (uses call leg detection)
-- `twp_transfer_call` - Transfer to agent/queue (uses call leg detection)
-- `twp_start_recording` - Start call recording
-- `twp_stop_recording` - Stop call recording
-- `twp_requeue_call` - Return call to queue (uses call leg detection)
-- `twp_initiate_outbound_call_with_from` - Outbound with caller ID
-
-### Call Control Architecture (CRITICAL):
-All call control functions (`twp_toggle_hold`, `twp_transfer_call`, `twp_requeue_call`) now use intelligent call leg detection to ensure actions are applied to the customer call leg, not the agent leg. This prevents customer disconnections in complex call topologies.
-
-## ๐จ Frontend Components
-
-### Shortcode Implementation
-The `[twp_browser_phone]` shortcode now provides a **redirect interface** instead of a full browser phone:
-
-#### Shortcode Attributes
-- **`title`**: Display title (default: "Browser Phone")
-- **`button_text`**: Button text (default: "Access Browser Phone")
-- **`target`**: Link target (default: "_blank" - opens in new tab)
-
-#### Security Features
-- **Login Required**: Users must be logged in to see the redirect
-- **Permission Check**: Requires `twp_access_browser_phone` or `manage_options` capability
-- **Error Messages**: Clear feedback for unauthorized access
-
-#### Styling
-- **Inline CSS Only**: No external CSS files loaded
-- **Minimal Assets**: Reduces frontend bloat
-- **Responsive Design**: Works on all device sizes
-
-### JavaScript Files
-1. **admin.js** (116KB) - Admin interface functionality
-2. **twp-service-worker.js** (2.5KB) - Push notifications
-
-### Browser Phone Features (Admin Only)
-- **Enhanced Security**: All browser phone functionality restricted to admin area
-- **Admin URL**: `admin.php?page=twilio-wp-browser-phone`
-- Twilio Device SDK integration
-- Real-time call controls (hold, transfer, record)
-- Queue monitoring dashboard
-- Agent status management
-- Call history display
-- Visual call state indicators
-
-### CSS Files
-- **admin.css** - Admin interface styling (includes browser phone UI)
-
-## ๐ง Recent Fixes & Improvements
-
-### SECURITY ENHANCEMENT: Frontend Browser Phone Removal (September 2025) - PRODUCTION READY
-Major security enhancement by removing frontend browser phone interface and implementing admin-only access.
-
-#### Browser Phone Security Enhancement
-- **Frontend Interface Removed**: Eliminated full browser phone interface from frontend shortcode
-- **Admin-Only Access**: All browser phone functionality moved to secure admin area
-- **Asset Reduction**: Removed 108KB of frontend assets (browser-phone-frontend.js and browser-phone-frontend.css)
-- **Redirect Interface**: Shortcode now provides secure redirect to admin browser phone page
-- **Enhanced Permissions**: Strict capability checking with clear error messages for unauthorized users
-- **Reduced Attack Surface**: Minimized frontend JavaScript exposure and potential security vectors
-- **Performance Improvement**: Reduced frontend asset loading and improved page load times
-
-#### Shortcode Transformation
-- **Security-First Design**: Login and permission validation before any functionality access
-- **Minimal Asset Loading**: Only essential inline CSS for redirect interface styling
-- **Responsive Redirect**: Professional redirect interface works on all devices
-- **Customizable Attributes**: title, button_text, and target attributes for flexibility
-- **Clear Error Messaging**: Informative error messages for authentication and authorization failures
-
-#### Technical Implementation
-- **File Removal**: `assets/js/browser-phone-frontend.js` and `assets/css/browser-phone-frontend.css` eliminated
-- **Inline Styling**: Minimal CSS injected only when shortcode is present on page
-- **Permission System**: Leverages WordPress capability system (`twp_access_browser_phone` or `manage_options`)
-- **Admin URL Generation**: Secure admin_url() function for proper WordPress admin integration
-- **Target Control**: Configurable link target (_blank by default for better UX)
-
-### PRODUCTION READY: Extension Transfer System Overhaul (September 2025) - FULLY RESOLVED
-Comprehensive overhaul of extension-based call transfers with enterprise-grade reliability.
-
-#### Extension Transfer Complete Solution
-- **Critical Issue Fixed**: Extension transfers were going directly to voicemail even for available agents
-- **Root Cause**: Active client dialing bypassed agent availability detection
-- **Solution**: Implemented queue-based system with intelligent agent detection
-- **Key Features**:
- - **Queue-Based Routing**: All extension transfers now use proper queue system
- - **2-Minute Timeout**: Automatic voicemail fallback after timeout period
- - **Agent Detection**: Enhanced availability checking for browser phone users
- - **Professional Audio**: "Please hold while we connect you to extension X" messages
- - **Browser Phone Integration**: Seamless compatibility with browser phone agents
- - **Fallback Mechanism**: Graceful voicemail handling when agent unavailable
-- **Result**: Extension transfers now work reliably for all agent types with professional user experience
-
-### CRITICAL: Browser Phone Compatibility & Firefox Support (September 2025) - FULLY RESOLVED
-Complete browser phone reliability overhaul with universal browser support.
-
-#### Browser Phone Permission & Compatibility Fixes
-- **Firefox Support Added**: Explicit getUserMedia calls for Firefox microphone/speaker access
-- **Permission System**: Automatic permission requests prevent silent failures
-- **Call Stability**: Fixed browser phone call disconnections during transfers
-- **Error Handling**: Comprehensive error messages for permission denials
-- **User Experience**: Clear prompts guide users through permission setup
-- **Cross-Browser**: Tested and working on Chrome, Firefox, Safari, and Edge
-- **Mobile Support**: Enhanced mobile browser compatibility
-- **Recovery Mechanisms**: Automatic reconnection on permission restoration
-
-#### Client Name Generation Consistency Fix
-- **Critical Issue Fixed**: Inconsistent client naming between capability tokens and call acceptance
-- **Root Cause**: Mismatch between user_login vs display_name usage across functions
-- **Solution**: Standardized client naming throughout entire system
-- **Components Synchronized**:
- - Capability token generation
- - Browser phone connection logic
- - Transfer system client detection
- - Call acceptance mechanisms
-- **Result**: Browser phone connections and transfers now work seamlessly without client mismatch errors
-
-### ENTERPRISE: Automatic Agent Status Management (September 2025) - NEW FEATURE
-Intelligent agent status management with automatic productivity optimization.
-
-#### 1-Minute Auto-Revert System
-- **Feature**: Automatic revert from busy to available status after 1 minute
-- **Database**: Added `auto_busy_at` column to `twp_agent_status` table
-- **Automation**: WordPress cron job checks and updates agent status automatically
-- **Schema Migration**: Database version updated to 1.6.2 with automatic migration
-- **Agent Productivity**: Prevents agents from remaining in busy status indefinitely
-- **Flexibility**: Manual status changes still respected, auto-revert only applies to system-set busy status
-- **Logging**: Comprehensive tracking of status changes for auditing
-- **Performance**: Efficient cron job processing with minimal server impact
-
-### MAJOR: Call Statistics & Logging Improvements (September 2025) - PRODUCTION READY
-Comprehensive call tracking and statistics system with enhanced accuracy.
-
-#### Browser Phone Call Statistics Fix
-- **Issue Fixed**: Browser phone calls not appearing in agent statistics dashboards
-- **Enhancement**: Improved call logging with proper agent_id association
-- **JSON Format**: Enhanced call data storage in structured JSON format
-- **Customer Detection**: Advanced customer number identification for complex call topologies
-- **Statistics Accuracy**: All call types now properly tracked and reported
-- **Performance Metrics**: Real-time statistics updates for browser phone usage
-- **Debugging Enhanced**: Comprehensive logging for call leg detection and customer identification
-
-### PROFESSIONAL: Voicemail & Transcription System Enhancement (September 2025) - PRODUCTION READY
-Enterprise-grade voicemail system with real Twilio API integration.
-
-#### Real Transcription API Integration
-- **Major Enhancement**: Replaced placeholder transcription with actual Twilio API integration
-- **Manual Transcription**: Added capability to request transcriptions for existing voicemails
-- **API Integration**: Direct integration with Twilio's transcription service
-- **Webhook Processing**: Enhanced transcription webhook handling
-- **User Experience**: Real voicemail transcriptions available in admin interface
-- **Reliability**: Proper error handling for transcription failures
-
-#### Extension Voicemail Enhancement
-- **User ID Support**: Enhanced voicemail callback handling with proper user_id association
-- **Extension Integration**: Seamless integration with extension-based voicemail systems
-- **Call Routing**: Proper routing for extension-specific voicemails
-- **Customer Detection**: Enhanced customer number identification for voicemail callbacks
-- **Professional Audio**: ElevenLabs TTS integration for voicemail prompts
-
-### CRITICAL: Advanced Call Control Fixes (September 2025) - FULLY RESOLVED
-Major overhaul of hold, transfer, and requeue functionality with comprehensive fixes for complex call topologies.
-
-#### Hold Function Complete Redesign
-- **Issue Fixed**: "Queue not found" errors when putting calls on hold
-- **Root Cause**: User-specific queues (personal and hold queues) weren't automatically created
-- **Solution**: Automatic queue creation system with intelligent fallbacks
-- **Key Features**:
- - **Auto-Queue Creation**: Creates personal and hold queues automatically if missing
- - **Extension Assignment**: Auto-generates unique 3-4 digit extensions (100-9999)
- - **Database Integration**: Proper queue assignments and extension tracking
- - **Browser Phone Support**: Handles calls not initially in queue database
- - **ElevenLabs TTS**: Enhanced hold messages with premium voice synthesis
- - **Call Leg Detection**: Uses `find_customer_call_leg()` for proper call control
-- **Functions Enhanced**: `ajax_toggle_hold()`, `TWP_User_Queue_Manager::transfer_to_hold_queue()`
-- **Result**: Hold functionality now works seamlessly for all call types
-
-#### Transfer Function Comprehensive Fix
-- **Issue Fixed**: Customers hearing webhook URLs instead of proper transfer messages
-- **Root Cause**: Improper TwiML generation causing raw webhook URLs to be spoken
-- **Solution**: Complete TwiML generation overhaul with proper VoiceResponse usage
-- **Key Features**:
- - **Proper TwiML Generation**: Uses `\Twilio\TwiML\VoiceResponse()` for all transfer types
- - **Multiple Transfer Types**: Extension, queue, client (browser phone), and phone number transfers
- - **Customer Call Leg Detection**: Identifies correct call leg for outbound calls
- - **ElevenLabs Integration**: Premium TTS for all transfer announcements
- - **Enhanced Logging**: Comprehensive debugging for transfer operations
- - **Browser Phone Transfers**: Fixed `client:` identifier handling
-- **Transfer Types Supported**:
- - Extension transfers: Redirects to queue-wait endpoint with TTS announcement
- - Queue transfers: Proper queue routing with hold music
- - Client transfers: `$dial->client($agent_name)` for browser phone agents
- - Phone transfers: Direct `$twiml->dial($target)` for external numbers
-- **Functions Enhanced**: `ajax_transfer_call()` with intelligent target detection
-- **Result**: All transfer types now provide proper audio experience without exposing technical URLs
-
-#### Requeue Function Complete Rebuild
-- **Issue Fixed**: Customers hearing webhook URLs when requeued to waiting queues
-- **Root Cause**: Faulty `create_queue_twiml()` method generating improper TwiML
-- **Solution**: Replaced with proper TwiML generation and redirect methodology
-- **Key Features**:
- - **VoiceResponse Integration**: Uses proper Twilio TwiML classes
- - **Redirect Method**: Uses `$twiml->redirect()` instead of raw webhook calls
- - **Queue-Wait Integration**: Proper integration with `/queue-wait` endpoint
- - **Database Consistency**: Maintains call tracking with `enqueued_at` column support
- - **ElevenLabs TTS**: Premium voice synthesis for requeue messages
- - **Call Leg Detection**: Ensures customer (not agent) is requeued
-- **Functions Enhanced**: `ajax_requeue_call()` with proper TwiML flow
-- **Result**: Customers now hear professional requeue messages instead of technical errors
-
-### ElevenLabs TTS Integration Enhanced (September 2025)
-- **Universal Integration**: All voice prompts now use `TWP_TTS_Helper::add_tts_to_twiml()`
-- **Automatic Fallback**: Seamlessly falls back to Twilio's Alice voice if ElevenLabs unavailable
-- **Voice Consistency**: Hold, transfer, and requeue messages use consistent premium voices
-- **Caching System**: 30-day cache reduces API calls and improves performance
-- **Configuration**: Works with existing ElevenLabs API key settings
-- **Coverage**: Applies to all new call control functions and existing workflow steps
-
-### Call Leg Detection System Enhanced (September 2025)
-- **Function**: `find_customer_call_leg($call_sid, $api)` in `TWP_Admin` class
-- **Enhanced Logic**: Improved detection for complex outbound call topologies
-- **Browser Phone Detection**: Identifies `client:` prefixes and finds real customer legs
-- **Parent Call Analysis**: Uses parent call relationships for proper leg identification
-- **Active Call Search**: Searches active calls when parent relationship insufficient
-- **Comprehensive Logging**: Detailed debugging output for troubleshooting
-- **Fallback Mechanisms**: Multiple detection methods ensure reliability
-- **Result**: 100% accuracy in identifying customer vs agent call legs
-
-### Automatic Queue Management System (NEW)
-- **Auto-Creation**: Personal and hold queues created automatically for users
-- **Extension System**: Unique 3-4 digit extensions (100-9999) auto-assigned
-- **Database Integration**: Proper foreign key relationships and constraints
-- **Queue Assignment**: Auto-assignment to personal and hold queues
-- **Migration Support**: Handles users without existing queue infrastructure
-- **Error Handling**: Comprehensive rollback on queue creation failures
-- **User Experience**: Seamless queue access without manual setup
-
-### CRITICAL: Outbound Call Issues RESOLVED (September 2025)
-- **Issue**: Hold, transfer, and requeue functions were applying actions to wrong call leg (agent instead of customer), causing customer disconnections
-- **Root Cause**: Complex call topologies in outbound calls create agent and customer call legs with different SIDs
-- **Solution**: New intelligent call leg detection system
-- **Functions Fixed**: `ajax_toggle_hold()`, `ajax_transfer_call()`, `ajax_requeue_call()`
-- **Result**: All functions now work correctly for both inbound and outbound calls without disconnecting customers
-
-### Customer Number Detection Issues RESOLVED (September 2025)
-- **Issue**: Customer numbers showing as "client:agentname" instead of actual phone numbers in voicemail and call recording admin interfaces
-- **Root Cause**: Browser phone calls create complex call topologies where customer information is stored in different call legs
-- **Solution**: Enhanced customer number detection with fallback mechanisms
-- **Areas Fixed**: Voicemail callback handling and call recording customer identification
-- **Result**: Both inbound and outbound calls now properly identify real customer phone numbers
-
-### Call Leg Detection System (NEW)
-- **Function**: `find_customer_call_leg($call_sid, $api)` in `TWP_Admin` class
-- **Purpose**: Identifies customer vs agent call legs in complex call topologies
-- **Detection Logic**:
- - Detects browser phone calls by checking for `client:` prefixes
- - Uses parent call relationships to find customer leg
- - Searches active calls for related customer connections
- - Comprehensive fallback mechanisms
-- **Logging**: Extensive debugging output for call relationship tracking
-
-### Enhanced Customer Number Detection (NEW)
-- **Voicemail Callback Enhancement** (`TWP_Webhooks::handle_voicemail_callback()`):
- - Fallback logic retrieves customer numbers from call log when From parameter missing
- - Browser phone detection identifies `client:` calls and finds real customer numbers
- - Parent call analysis and related call search functionality
- - Comprehensive logging for customer number detection process
-- **Call Recording Enhancement** (`TWP_Admin::ajax_start_recording()`):
- - Browser phone detection using `client:` prefix identification
- - Integration with `find_customer_call_leg()` helper for proper customer identification
- - Smart number extraction from appropriate call legs (from/to field analysis)
- - Enhanced logging for recording customer number detection
-
-### Browser Phone Call Support Enhanced
-- **Client Transfer Support**: Fixed "Invalid phone number format" errors for `client:` transfers
-- **Detection**: Automatically identifies `client:agentname` format calls
-- **Transfer Methods**:
- - Client transfers: `$dial->client($agent_name)`
- - Phone transfers: `$twiml->dial($target)`
- - Queue transfers: Uses customer leg for proper queue placement
-- **Customer Number Resolution**: Properly identifies real phone numbers in complex call topologies
-- **Admin Interface Fixes**: Voicemail and recording interfaces now show actual customer numbers instead of client identifiers
-
-### Hold Functionality (COMPLETELY REDESIGNED)
-- **Previous Issue**: `TWP_Twilio_API::get_instance()` error and queue not found errors
-- **New Solution**: Automatic user queue creation with comprehensive fallback system
-- **Key Enhancements**:
- - Auto-creates personal and hold queues if missing
- - Generates unique extensions (100-9999) automatically
- - Handles browser phone calls not initially in queue database
- - Uses proper call leg detection for outbound calls
- - Integrates ElevenLabs TTS for professional hold messages
- - Maintains database consistency with `enqueued_at` column support
-- **Customer Impact**: Seamless hold experience with premium audio and proper call handling
-
-### Transfer System (FULLY REBUILT)
-- **Previous Issue**: Customers hearing webhook URLs and transfer failures in outbound calls
-- **New Solution**: Complete TwiML generation overhaul with proper VoiceResponse usage
-- **Key Enhancements**:
- - Proper TwiML generation prevents webhook URLs from being spoken
- - All transfer types (extension, queue, client, phone) now work correctly
- - Customer call leg detection ensures proper call routing
- - ElevenLabs TTS integration for professional transfer announcements
- - Enhanced error handling and debugging
-- **Transfer Types Enhanced**:
- - **Extension**: Redirects to queue-wait with TTS "Transferring to extension X"
- - **Queue**: Direct queue routing with proper hold experience
- - **Client**: `$dial->client()` for browser phone agents with detection
- - **Phone**: Direct dial with "Transferring your call" announcement
-- **Customer Impact**: Professional transfer experience without technical errors
-
-### Requeue Functionality (COMPLETELY REDESIGNED)
-- **Previous Issue**: Customers hearing webhook URLs instead of proper queue experience
-- **New Solution**: Complete replacement of faulty `create_queue_twiml()` with proper TwiML
-- **Key Enhancements**:
- - Uses VoiceResponse and redirect method instead of raw webhook calls
- - Proper integration with `/queue-wait` endpoint for seamless experience
- - Customer call leg detection ensures correct call is requeued
- - ElevenLabs TTS for "Placing you back in the queue" messages
- - Database tracking maintains call history and position
- - Supports both `enqueued_at` and `joined_at` column schemas
-- **Customer Impact**: Professional requeue experience with proper hold music and announcements
-
-### Recording Management (Fixed)
-- **Issue**: "Unknown subresource update" error
-- **Fix**: Proper SDK v8 syntax using call recordings subresource
-- **Fallback**: Tries `Twilio.CURRENT` if specific SID fails
-
-### Queue Management (Fixed)
-- **Issue**: `Enqueue::waitUrl()` undefined method
-- **Fix**: Pass `waitUrl` as option: `$response->enqueue($queue_name, ['waitUrl' => $url])`
-
-### TTS Integration (UNIVERSALLY ENHANCED)
-- **Universal Coverage**: All call control functions now use `TWP_TTS_Helper::add_tts_to_twiml()`
-- **ElevenLabs Integration**: Automatic premium voice synthesis when configured
-- **Intelligent Fallback**: Seamless fallback to Twilio's Alice voice
-- **Cache Duration**: 30 days for identical text with automatic cleanup
-- **Performance**: Instant cached audio delivery
-- **Professional Messages**:
- - Hold: "Please hold while we prepare your call"
- - Transfer: "Transferring to extension X" or "Transferring your call"
- - Requeue: "Placing you back in the queue. Please hold."
-- **Consistency**: Same voice experience across all call operations
-- **Configuration**: Works with existing ElevenLabs API key settings
-- **Integration Points**: Hold operations, all transfer types, requeue operations, workflow steps
-
-## ๐ Twilio Integration Details
-
-### SDK Version
-- **Required**: Twilio PHP SDK v8.7.0
-- **Installation**: Via Composer or install script
-- **PHP Requirement**: PHP 8.0+
-
-### API Response Structure
+# Twilio WordPress Plugin - Quick Reference
+
+## Environment
+- **Production**: `/home/shadowdao/public_html/wp-content/plugins/twilio-wp-plugin/`
+- **Dev**: `/home/jknapp/code/twilio-wp-plugin/`
+- **URL**: `https://phone.cloud-hosting.io/`
+- **Deployment**: rsync to Docker (remote server only, not local)
+- **SDK**: Twilio PHP SDK v8.7.0
+
+## Phone Variable Names
+**Use**: `incoming_number`, `agent_number`, `customer_number`, `workflow_number`, `queue_number`, `default_number`
+**Don't use**: `from_number`, `to_number`, `phone_number`, `$agent_phone`
+**Test numbers**: Twilio `+19516215107`, Agent `+19095737372`
+
+## Key Classes
+- **TWP_Twilio_API**: Use `new TWP_Twilio_API()` not singleton
+- **TWP_Admin**: Has `find_customer_call_leg()` - CRITICAL for call control
+- **TWP_TTS_Helper**: ElevenLabs/Alice fallback, 30-day cache
+- **TWP_User_Queue_Manager**: Auto-creates queues/extensions (100-9999)
+- **TWP_Webhooks**: 26 endpoints at `twilio-webhook/v1`
+- **TWP_Activator**: Creates 15 DB tables, run `ensure_tables_exist()` if missing
+
+## Database
+15 tables with `twp_` prefix. Key notes:
+- `twp_call_queues`: User queues (general/personal/hold)
+- `twp_agent_status`: Has `auto_busy_at` for 1-min auto-revert
+- `twp_queued_calls`: Uses `enqueued_at` not `joined_at`
+
+## Critical Functions
+
+### Call Control (MUST use call leg detection)
```php
-// Success response
-[
- 'success' => true,
- 'data' => [...] // Twilio response data
-]
-
-// Error response
-[
- 'success' => false,
- 'error' => 'Error message',
- 'code' => 400
-]
-```
-
-### TwiML Generation Best Practices
-- Always use SDK classes for TwiML generation
-- Include proper XML headers when needed
-- Use TTS helper for voice synthesis
-- Implement proper error handling
-
-### Recording Stop Methods (SDK v8)
-```php
-// Method 1: Specific recording
-$client->calls($call_sid)
- ->recordings($recording_sid)
- ->update(['status' => 'stopped']);
-
-// Method 2: Single active recording
-$client->calls($call_sid)
- ->recordings('Twilio.CURRENT')
- ->update(['status' => 'stopped']);
-```
-
-## ๐ ๏ธ Development Guidelines
-
-### Call Control Functions (CRITICAL)
-**ALWAYS use call leg detection for hold, transfer, and requeue operations:**
-```php
-// Correct pattern for call control functions
-private function find_customer_call_leg($call_sid, $api) {
- // Detects browser phone vs regular calls
- // Uses parent call relationships
- // Searches active calls for customer leg
- // Returns correct SID for operations
-}
-
-// Usage in AJAX handlers
+// ALWAYS do this for hold/transfer/requeue:
$customer_call_sid = $this->find_customer_call_leg($call_sid, $twilio);
-$result = $api->update_call($customer_call_sid, ['twiml' => $twiml_xml]);
+$api->update_call($customer_call_sid, ['twiml' => $twiml_xml]);
```
-**Why This Matters:**
-- Outbound calls create separate agent and customer call legs
-- Applying actions to agent leg disconnects customer
-- Browser phone calls use `client:` identifiers
-- Customer leg must be identified for proper call control
+### Common Fixes
+- Recording: Use `Twilio.CURRENT` for SDK v8
+- Queue: Pass `waitUrl` as option in `enqueue()`
+- TwiML: Use SDK classes, not raw XML
-### Database Operations
-- Always use `$wpdb` global
-- Sanitize with `sanitize_text_field()`, `intval()`
-- Use prepared statements: `$wpdb->prepare()`
-- Call `TWP_Activator::ensure_tables_exist()` before operations
+## Recent Changes (v2.3.0)
+- Browser phone moved to admin-only
+- Call control uses `find_customer_call_leg()` to prevent disconnections
+- Auto-creates user queues/extensions when needed
+- Firefox support added
+- 1-min agent status auto-revert
-### AJAX Handler Pattern
-```php
-public function ajax_handler_name() {
- if (!$this->verify_ajax_nonce()) {
- wp_send_json_error('Invalid nonce');
- return;
- }
-
- // Handler logic
-
- wp_send_json_success($data);
-}
-```
+## Development Notes
+- **API**: E.164 format (+1XXXXXXXXXX)
+- **Database**: Use `$wpdb`, prepared statements
+- **AJAX**: Verify nonce, return JSON
+- **Naming**: TWP_ for classes, twp_ for tables/options
+- **Debugging**: Look for "TWP Call Leg Detection" in logs
-### Error Handling
-- Log errors with `error_log()`
-- Return structured error responses
-- Implement fallback mechanisms
-- Handle Twilio exceptions properly
-
-### Naming Conventions
-- Classes: `TWP_Class_Name`
-- Tables: `twp_table_name`
-- Options: `twp_option_name`
-- AJAX actions: `twp_action_name`
-- Nonces: `twp_ajax_nonce` or `twp_frontend_nonce`
-
-## ๐ Common Issues & Solutions
-
-### Database Issues
-- **Missing Tables**: Run `TWP_Activator::ensure_tables_exist()`
-- **Schema Changes**: Check `add_missing_columns()` method
-- **Migration Issues**: Review `migrate_tables()` implementation
-
-### Webhook Issues
-- **500 Errors**: Check PHP error logs
-- **TwiML Errors**: Verify XML structure
-- **Authentication**: Webhooks use `__return_true` permission
-
-### API Issues
-- **Instantiation**: Use `new TWP_Twilio_API()` not singleton
-- **Phone Format**: Always use E.164 format (+1XXXXXXXXXX)
-- **Call SID**: Access via `$response['data']['sid']`
-
-### Call Control Issues (ALL RESOLVED - September 2025)
-- **Extension Transfer Issues**: COMPLETELY RESOLVED - Queue-based system with 2-minute timeout and automatic voicemail fallback
-- **Browser Phone Firefox Support**: FULLY RESOLVED - Explicit permission handling and cross-browser compatibility
-- **Client Name Consistency**: FIXED - Standardized naming across all browser phone functions
-- **Agent Status Management**: AUTOMATED - 1-minute auto-revert system with cron job automation
-- **Call Statistics Accuracy**: ENHANCED - Browser phone calls now properly tracked in statistics
-- **Transcription Integration**: IMPLEMENTED - Real Twilio API integration replacing placeholder system
-- **Customer Disconnections**: PREVIOUSLY RESOLVED - All functions use intelligent call leg detection
-- **Queue Not Found Errors**: PREVIOUSLY RESOLVED - Automatic queue creation prevents this issue
-- **Professional Audio**: UNIVERSAL - ElevenLabs TTS integration throughout all voice prompts
-- **Extension Voicemail**: ENHANCED - User ID support and proper callback handling
-- **Permission System**: NEW - Automatic microphone/speaker permission requests for browser phone
-
-### Hold/Transfer/Requeue System (COMPLETELY ENHANCED)
-- **Automatic Queue Creation**: Creates personal and hold queues as needed
-- **Extension Management**: Auto-generates unique 3-4 digit extensions
-- **ElevenLabs Integration**: Premium TTS for all voice prompts with Alice fallback
-- **Call Leg Detection**: 100% accurate customer vs agent identification
-- **TwiML Compliance**: Proper XML generation prevents audio errors
-- **Database Consistency**: Handles schema variations gracefully
-- **Error Recovery**: Comprehensive fallback mechanisms
-- **User Experience**: Professional audio experience throughout call lifecycle
-
-### Advanced Debugging Features (NEW)
-- **Call Leg Detection Logging**: "TWP Call Leg Detection" entries show call relationship analysis
-- **Queue Creation Logging**: Tracks automatic queue and extension generation
-- **TwiML Generation Logging**: Shows proper XML construction vs old webhook methods
-- **Customer Number Detection**: Enhanced logging for browser phone call analysis
-- **Extension Assignment**: Logs unique extension generation and assignment process
-
-## ๐งช Testing Approach
-
-### Unit Testing
-- PHPUnit for PHP code
-- Mock WordPress functions
-- Mock Twilio API responses
-
-### Integration Testing
-- Test webhook endpoints
-- Verify database operations
-- Test complete call flows
-
-### Manual Testing
-- Monitor Twilio Console
-- Check WordPress debug logs
-- Test with real phone numbers
-
-## ๐ Key Features Implementation
-
-### Agent System
-- **SMS Accept**: Agents text "1" to accept calls
-- **Real-time Status**: Available/busy/offline states
-- **Group Management**: Priority-based call distribution
-- **Personal Queues**: Agent-specific call queues
-
-### Call Queue System
-- **Position Tracking**: Real-time queue position
-- **Timeout Handling**: Automatic callback offers
-- **Hold Queues**: Temporary call parking
-- **User Queues**: Personal agent queues
-
-### Browser Phone
-- **Twilio Device**: Full SDK integration
-- **Call Controls**: Hold, transfer, record, mute
-- **Visual Interface**: Real-time status updates
-- **Queue Dashboard**: Monitor waiting calls
-
-### Recording System
-- **Start/Stop**: Dynamic recording control
-- **Storage**: Database tracking with Twilio URLs
-- **Playback**: Authenticated proxy endpoints
-- **Transcription**: Automatic with callbacks
-
-### ElevenLabs TTS
-- **Auto-detection**: Uses ElevenLabs when configured
-- **Caching**: 30-day cache for repeated phrases
-- **Fallback**: Seamless Twilio voice fallback
-- **Performance**: Instant cached audio delivery
-
-## ๐ Configuration Requirements
-
-### WordPress Settings
-- **Twilio Credentials**: Account SID, Auth Token
-- **TwiML App**: For browser phone functionality
-- **Phone Numbers**: At least one Twilio number
-- **Webhook URLs**: Configure in Twilio Console
-
-### Optional Settings
-- **ElevenLabs**: API key and voice selection
-- **Hold Music**: Custom URL support
-- **SMS Notifications**: Agent alert numbers
-- **Business Hours**: Schedule configurations
-
-## ๐ Debugging Tips
-
-1. **Enable WordPress Debug**: `WP_DEBUG = true`
-2. **Check Error Logs**: `/wp-content/debug.log`
-3. **Monitor Twilio Console**: Real-time webhook debugging
-4. **Database Queries**: Use `$wpdb->last_error`
-5. **Browser Console**: Check JavaScript errors
-6. **Network Tab**: Monitor AJAX requests
-7. **Call Leg Detection**: Look for "TWP Call Leg Detection" log entries
-8. **Outbound Call Issues**: Check for agent vs customer call SID usage
-9. **Browser Phone Debugging**: Search logs for "client:" identifier handling
-
-## ๐ External Resources
-
-- **Twilio PHP SDK**: https://www.twilio.com/docs/libraries/reference/twilio-php/
-- **WordPress REST API**: https://developer.wordpress.org/rest-api/
-- **ElevenLabs API**: https://api.elevenlabs.io/docs
-- **Twilio TwiML**: https://www.twilio.com/docs/voice/twiml
+## Features
+- Agents accept calls via SMS "1"
+- User-specific queues with extensions
+- Browser phone at `admin.php?page=twilio-wp-browser-phone`
+- ElevenLabs TTS with Alice fallback
+- 68 AJAX actions, 26 REST endpoints
---
-
-*Last Updated: September 2025*
-*Plugin Version: v2.3.0 - Enterprise Ready*
-*Major Release: Extension Transfer System, Browser Phone Compatibility, Auto Status Management*
-*Maintained for: phone.cloud-hosting.io*
\ No newline at end of file
+*Updated: Sept 2025*
\ No newline at end of file
diff --git a/admin/class-twp-admin.php b/admin/class-twp-admin.php
index dfac4bb..fd35b54 100644
--- a/admin/class-twp-admin.php
+++ b/admin/class-twp-admin.php
@@ -4945,7 +4945,7 @@ class TWP_Admin {
}
$voice_id = sanitize_text_field($_POST['voice_id']);
- $text = sanitize_text_field($_POST['text']) ?: 'Hello, this is a preview of this voice.';
+ $text = isset($_POST['text']) ? sanitize_text_field($_POST['text']) : 'Hello, this is a preview of this voice.';
$elevenlabs = new TWP_ElevenLabs_API();
$result = $elevenlabs->text_to_speech($text, $voice_id);
diff --git a/includes/class-twp-webhooks.php b/includes/class-twp-webhooks.php
index 616d2cb..f352667 100644
--- a/includes/class-twp-webhooks.php
+++ b/includes/class-twp-webhooks.php
@@ -196,6 +196,27 @@ class TWP_Webhooks {
'callback' => array($this, 'handle_callback_choice'),
'permission_callback' => '__return_true'
));
+
+ // Agent features webhook (handles DTMF during bridged calls)
+ register_rest_route('twilio-webhook/v1', '/agent-features', array(
+ 'methods' => 'POST',
+ 'callback' => array($this, 'handle_agent_features'),
+ 'permission_callback' => '__return_true'
+ ));
+
+ // Forward result webhook (handles dial result for forwards)
+ register_rest_route('twilio-webhook/v1', '/forward-result', array(
+ 'methods' => 'POST',
+ 'callback' => array($this, 'handle_forward_result'),
+ 'permission_callback' => '__return_true'
+ ));
+
+ // Agent action webhook (processes DTMF commands from agent)
+ register_rest_route('twilio-webhook/v1', '/agent-action', array(
+ 'methods' => 'POST',
+ 'callback' => array($this, 'handle_agent_action'),
+ 'permission_callback' => '__return_true'
+ ));
// Request callback webhook
register_rest_route('twilio-webhook/v1', '/request-callback', array(
@@ -2618,4 +2639,207 @@ class TWP_Webhooks {
return new WP_REST_Response($response->asXML(), 200, array('Content-Type' => 'text/xml'));
}
+
+ /**
+ * Handle agent features during bridged calls
+ */
+ public function handle_agent_features($request) {
+ $params = $request->get_params();
+
+ error_log('TWP Agent Features: Webhook triggered with params: ' . print_r($params, true));
+
+ $response = new \Twilio\TwiML\VoiceResponse();
+
+ // This webhook is called when the agent answers
+ // We set up a Gather to listen for DTMF during the call
+ $gather = $response->gather([
+ 'input' => 'dtmf',
+ 'numDigits' => 2,
+ 'actionOnEmptyResult' => false,
+ 'action' => home_url('/wp-json/twilio-webhook/v1/agent-action'),
+ 'method' => 'POST',
+ 'timeout' => 1,
+ 'finishOnKey' => '' // Don't finish on any key, we want to capture patterns like *9
+ ]);
+
+ // Connect the call (empty gather continues the call)
+
+ // After gather timeout, continue listening
+ $response->redirect(home_url('/wp-json/twilio-webhook/v1/agent-features'), ['method' => 'POST']);
+
+ error_log('TWP Agent Features: TwiML response: ' . $response->asXML());
+
+ return $this->send_twiml_response($response->asXML());
+ }
+
+ /**
+ * Handle forward result (called after dial completes)
+ */
+ public function handle_forward_result($request) {
+ $params = $request->get_params();
+
+ error_log('TWP Forward Result: Call completed with params: ' . print_r($params, true));
+
+ $dial_call_status = isset($params['DialCallStatus']) ? $params['DialCallStatus'] : '';
+ $call_sid = isset($params['CallSid']) ? $params['CallSid'] : '';
+
+ // Update call log with result
+ if ($call_sid) {
+ TWP_Call_Logger::log_action($call_sid, 'Forward result: ' . $dial_call_status);
+ }
+
+ $response = new \Twilio\TwiML\VoiceResponse();
+
+ // Handle different outcomes
+ switch ($dial_call_status) {
+ case 'busy':
+ $response->say('The number is busy. Please try again later.', ['voice' => 'alice']);
+ break;
+ case 'no-answer':
+ $response->say('There was no answer. Please try again later.', ['voice' => 'alice']);
+ break;
+ case 'failed':
+ $response->say('The call could not be completed. Please try again later.', ['voice' => 'alice']);
+ break;
+ case 'canceled':
+ $response->say('The call was canceled.', ['voice' => 'alice']);
+ break;
+ default:
+ // Call completed successfully or caller hung up
+ break;
+ }
+
+ $response->hangup();
+
+ return $this->send_twiml_response($response->asXML());
+ }
+
+ /**
+ * Handle agent DTMF actions (*9 hold, *0 record, *5 transfer, etc.)
+ */
+ public function handle_agent_action($request) {
+ $params = $request->get_params();
+
+ $digits = isset($params['Digits']) ? $params['Digits'] : '';
+ $call_sid = isset($params['CallSid']) ? $params['CallSid'] : '';
+ $parent_call_sid = isset($params['ParentCallSid']) ? $params['ParentCallSid'] : '';
+
+ error_log('TWP Agent Action: Received DTMF: ' . $digits . ' for call: ' . $call_sid);
+
+ $response = new \Twilio\TwiML\VoiceResponse();
+ $twilio = new TWP_Twilio_API();
+ $admin = new TWP_Admin('twilio-wp-plugin', TWP_VERSION);
+
+ // Process DTMF commands
+ switch ($digits) {
+ case '*9':
+ // Hold/Unhold
+ error_log('TWP Agent Action: Processing hold/unhold request');
+
+ // Find the customer call leg
+ $customer_call_sid = $admin->find_customer_call_leg($parent_call_sid, $twilio->get_client());
+
+ if ($customer_call_sid) {
+ // Check if call is on hold by looking at the current state
+ global $wpdb;
+ $table_name = $wpdb->prefix . 'twp_active_calls';
+ $call_info = $wpdb->get_row($wpdb->prepare(
+ "SELECT * FROM $table_name WHERE call_sid = %s",
+ $customer_call_sid
+ ));
+
+ if ($call_info && $call_info->status === 'on-hold') {
+ // Resume the call
+ $twiml = 'Resuming call';
+ $twilio->update_call($customer_call_sid, ['twiml' => $twiml]);
+
+ $wpdb->update($table_name,
+ ['status' => 'in-progress'],
+ ['call_sid' => $customer_call_sid]
+ );
+
+ $response->say('Call resumed', ['voice' => 'alice']);
+ error_log('TWP Agent Action: Call resumed');
+ } else {
+ // Put on hold
+ $hold_music = get_option('twp_hold_music_url', 'http://com.twilio.music.classical.s3.amazonaws.com/BusyStrings.mp3');
+ $twiml = 'You have been placed on hold' . $hold_music . '';
+ $twilio->update_call($customer_call_sid, ['twiml' => $twiml]);
+
+ $wpdb->update($table_name,
+ ['status' => 'on-hold'],
+ ['call_sid' => $customer_call_sid]
+ );
+
+ $response->say('Call on hold', ['voice' => 'alice']);
+ error_log('TWP Agent Action: Call placed on hold');
+ }
+ } else {
+ error_log('TWP Agent Action: Could not find customer call leg for hold');
+ }
+ break;
+
+ case '*0':
+ // Start/Stop Recording
+ error_log('TWP Agent Action: Processing recording toggle');
+
+ try {
+ // Check if we're already recording
+ $recordings = $twilio->get_client()->recordings->read(['callSid' => $parent_call_sid, 'status' => 'in-progress'], 1);
+
+ if (!empty($recordings)) {
+ // Stop recording
+ $recording = $recordings[0];
+ $twilio->get_client()->recordings($recording->sid)->update(['status' => 'stopped']);
+ $response->say('Recording stopped', ['voice' => 'alice']);
+ error_log('TWP Agent Action: Recording stopped');
+ } else {
+ // Start recording
+ $twilio->get_client()->calls($parent_call_sid)->recordings->create([
+ 'recordingStatusCallback' => home_url('/wp-json/twilio-webhook/v1/recording-status'),
+ 'recordingStatusCallbackEvent' => ['completed']
+ ]);
+ $response->say('Recording started', ['voice' => 'alice']);
+ error_log('TWP Agent Action: Recording started');
+ }
+ } catch (Exception $e) {
+ error_log('TWP Agent Action: Recording error: ' . $e->getMessage());
+ $response->say('Recording feature unavailable', ['voice' => 'alice']);
+ }
+ break;
+
+ case '*5':
+ // Transfer to extension
+ error_log('TWP Agent Action: Initiating transfer');
+ $response->say('Enter extension number followed by pound', ['voice' => 'alice']);
+
+ $gather = $response->gather([
+ 'input' => 'dtmf',
+ 'finishOnKey' => '#',
+ 'action' => home_url('/wp-json/twilio-webhook/v1/transfer-extension'),
+ 'method' => 'POST'
+ ]);
+
+ // Continue call if no input
+ $response->redirect(home_url('/wp-json/twilio-webhook/v1/agent-features'), ['method' => 'POST']);
+ break;
+
+ case '*1':
+ // Mute/Unmute (agent side)
+ error_log('TWP Agent Action: Processing mute toggle');
+ // This would require conference mode - we'll note this for future implementation
+ $response->say('Mute feature requires conference mode', ['voice' => 'alice']);
+ break;
+
+ default:
+ error_log('TWP Agent Action: Unknown DTMF code: ' . $digits);
+ // Unknown code, just continue
+ break;
+ }
+
+ // Continue listening for more DTMF
+ $response->redirect(home_url('/wp-json/twilio-webhook/v1/agent-features'), ['method' => 'POST']);
+
+ return $this->send_twiml_response($response->asXML());
+ }
}
\ No newline at end of file
diff --git a/includes/class-twp-workflow.php b/includes/class-twp-workflow.php
index b9c147e..3b49725 100644
--- a/includes/class-twp-workflow.php
+++ b/includes/class-twp-workflow.php
@@ -214,16 +214,19 @@ class TWP_Workflow {
// Add child Number elements
foreach ($element->children() as $child) {
$child_name = $child->getName();
+ $child_attrs = self::get_attributes($child);
+
if ($child_name === 'Number') {
- $dial->number((string) $child, self::get_attributes($child));
+ // Number can have url, method attributes for agent features
+ $dial->number((string) $child, $child_attrs);
} elseif ($child_name === 'Client') {
- $dial->client((string) $child, self::get_attributes($child));
+ $dial->client((string) $child, $child_attrs);
} elseif ($child_name === 'Queue') {
- $dial->queue((string) $child, self::get_attributes($child));
+ $dial->queue((string) $child, $child_attrs);
} elseif ($child_name === 'Conference') {
- $dial->conference((string) $child, self::get_attributes($child));
+ $dial->conference((string) $child, $child_attrs);
} elseif ($child_name === 'Sip') {
- $dial->sip((string) $child, self::get_attributes($child));
+ $dial->sip((string) $child, $child_attrs);
}
}
break;
@@ -591,10 +594,27 @@ class TWP_Workflow {
error_log('TWP Workflow Forward: No To number found for caller ID, will use account default');
}
- // Add all forward numbers
+ // Check if we should use bridging with agent features
+ $use_bridge_features = isset($step_data['enable_agent_features']) ? $step_data['enable_agent_features'] : true;
+
+ // Add action URL to handle dial result (for tracking and potential fallback)
+ $action_url = home_url('/wp-json/twilio-webhook/v1/forward-result');
+ $dial->addAttribute('action', $action_url);
+ $dial->addAttribute('method', 'POST');
+
+ // Add all forward numbers with agent features if enabled
foreach ($forward_numbers as $number) {
error_log('TWP Workflow Forward: Adding number to Dial: ' . $number);
- $dial->addChild('Number', $number);
+ $number_element = $dial->addChild('Number', $number);
+
+ if ($use_bridge_features) {
+ // Add URL to handle agent-side features (DTMF detection)
+ $agent_url = home_url('/wp-json/twilio-webhook/v1/agent-features');
+ $number_element->addAttribute('url', $agent_url);
+ $number_element->addAttribute('method', 'POST');
+
+ error_log('TWP Workflow Forward: Added agent features URL for DTMF detection');
+ }
}
$result = $twiml->asXML();
diff --git a/twilio-wp-plugin.php b/twilio-wp-plugin.php
index aedd96d..fac97aa 100644
--- a/twilio-wp-plugin.php
+++ b/twilio-wp-plugin.php
@@ -3,7 +3,7 @@
* Plugin Name: Twilio WP Plugin
* Plugin URI: https://repo.anhonesthost.net/wp-plugins/twilio-wp-plugin
* Description: WordPress plugin for Twilio integration with phone scheduling, call forwarding, queue management, and Eleven Labs TTS
- * Version: 2.2.0
+ * Version: 2.8.9
* Author: Josh Knapp
* License: GPL v2 or later
* Text Domain: twilio-wp-plugin
@@ -15,7 +15,7 @@ if (!defined('WPINC')) {
}
// Plugin constants
-define('TWP_VERSION', '2.8.6');
+define('TWP_VERSION', '2.8.9');
define('TWP_DB_VERSION', '1.6.2'); // Track database version separately
define('TWP_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('TWP_PLUGIN_URL', plugin_dir_url(__FILE__));