prefix . $table; $table_exists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)); if (!$table_exists) { $missing_tables[] = $table; } } if (!empty($missing_tables)) { error_log('TWP Plugin: Missing database tables: ' . implode(', ', $missing_tables) . '. Creating them now.'); self::create_tables(); return false; // Tables were missing } // Check for and perform any needed migrations self::migrate_tables(); return true; // All tables exist } /** * Create plugin database tables */ private static function create_tables() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); // Phone schedules table $table_schedules = $wpdb->prefix . 'twp_phone_schedules'; $sql_schedules = "CREATE TABLE $table_schedules ( id int(11) NOT NULL AUTO_INCREMENT, phone_number varchar(20), schedule_name varchar(100) NOT NULL, days_of_week varchar(100) NOT NULL, start_time time NOT NULL, end_time time NOT NULL, workflow_id varchar(100), forward_number varchar(20), after_hours_action varchar(20) DEFAULT 'workflow', after_hours_workflow_id varchar(100), after_hours_forward_number varchar(20), holiday_dates text, is_active tinyint(1) DEFAULT 1, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY phone_number (phone_number) ) $charset_collate;"; // Call queues table $table_queues = $wpdb->prefix . 'twp_call_queues'; $sql_queues = "CREATE TABLE $table_queues ( id int(11) NOT NULL AUTO_INCREMENT, queue_name varchar(100) NOT NULL, notification_number varchar(20), agent_group_id int(11), max_size int(11) DEFAULT 10, wait_music_url varchar(255), tts_message text, timeout_seconds int(11) DEFAULT 300, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY agent_group_id (agent_group_id), KEY notification_number (notification_number) ) $charset_collate;"; // Queued calls table $table_queued_calls = $wpdb->prefix . 'twp_queued_calls'; $sql_queued_calls = "CREATE TABLE $table_queued_calls ( id int(11) NOT NULL AUTO_INCREMENT, queue_id int(11) NOT NULL, call_sid varchar(100) NOT NULL, from_number varchar(20) NOT NULL, to_number varchar(20) NOT NULL, position int(11) NOT NULL, status varchar(20) DEFAULT 'waiting', agent_phone varchar(20), agent_call_sid varchar(100), joined_at datetime DEFAULT CURRENT_TIMESTAMP, answered_at datetime, ended_at datetime, PRIMARY KEY (id), KEY queue_id (queue_id), KEY call_sid (call_sid), KEY status (status) ) $charset_collate;"; // Workflows table $table_workflows = $wpdb->prefix . 'twp_workflows'; $sql_workflows = "CREATE TABLE $table_workflows ( id int(11) NOT NULL AUTO_INCREMENT, workflow_name varchar(100) NOT NULL, phone_number varchar(20) NOT NULL, workflow_data longtext, is_active tinyint(1) DEFAULT 1, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY phone_number (phone_number) ) $charset_collate;"; // Call log table $table_call_log = $wpdb->prefix . 'twp_call_log'; $sql_call_log = "CREATE TABLE $table_call_log ( id int(11) NOT NULL AUTO_INCREMENT, call_sid varchar(100) NOT NULL, from_number varchar(20), to_number varchar(20), status varchar(20) NOT NULL, duration int(11) DEFAULT 0, workflow_id int(11), workflow_name varchar(100), queue_time int(11) DEFAULT 0, actions_taken text, call_data longtext, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY call_sid (call_sid), KEY from_number (from_number), KEY status (status) ) $charset_collate;"; // SMS log table $table_sms_log = $wpdb->prefix . 'twp_sms_log'; $sql_sms_log = "CREATE TABLE $table_sms_log ( id int(11) NOT NULL AUTO_INCREMENT, message_sid varchar(100) NOT NULL, from_number varchar(20) NOT NULL, to_number varchar(20) NOT NULL, body text, received_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY message_sid (message_sid) ) $charset_collate;"; // Voicemails table $table_voicemails = $wpdb->prefix . 'twp_voicemails'; $sql_voicemails = "CREATE TABLE $table_voicemails ( id int(11) NOT NULL AUTO_INCREMENT, workflow_id int(11), from_number varchar(20) NOT NULL, recording_url varchar(255), duration int(11) DEFAULT 0, transcription text, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY workflow_id (workflow_id) ) $charset_collate;"; // Agent groups table $table_agent_groups = $wpdb->prefix . 'twp_agent_groups'; $sql_agent_groups = "CREATE TABLE $table_agent_groups ( id int(11) NOT NULL AUTO_INCREMENT, group_name varchar(100) NOT NULL, description text, ring_strategy varchar(20) DEFAULT 'simultaneous', timeout_seconds int(11) DEFAULT 30, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY group_name (group_name) ) $charset_collate;"; // Group members table $table_group_members = $wpdb->prefix . 'twp_group_members'; $sql_group_members = "CREATE TABLE $table_group_members ( id int(11) NOT NULL AUTO_INCREMENT, group_id int(11) NOT NULL, user_id bigint(20) NOT NULL, priority int(11) DEFAULT 0, is_active tinyint(1) DEFAULT 1, added_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY group_id (group_id), KEY user_id (user_id), UNIQUE KEY group_user (group_id, user_id) ) $charset_collate;"; // Agent status table $table_agent_status = $wpdb->prefix . 'twp_agent_status'; $sql_agent_status = "CREATE TABLE $table_agent_status ( id int(11) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, status varchar(20) DEFAULT 'offline', current_call_sid varchar(100), last_activity datetime DEFAULT CURRENT_TIMESTAMP, available_for_queues tinyint(1) DEFAULT 1, PRIMARY KEY (id), UNIQUE KEY user_id (user_id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql_schedules); dbDelta($sql_queues); dbDelta($sql_queued_calls); dbDelta($sql_workflows); dbDelta($sql_call_log); dbDelta($sql_sms_log); dbDelta($sql_voicemails); // Callbacks table $table_callbacks = $wpdb->prefix . 'twp_callbacks'; $sql_callbacks = "CREATE TABLE $table_callbacks ( id int(11) NOT NULL AUTO_INCREMENT, phone_number varchar(20) NOT NULL, requested_at datetime DEFAULT CURRENT_TIMESTAMP, status varchar(20) DEFAULT 'pending', attempts int(11) DEFAULT 0, last_attempt datetime, completed_at datetime, queue_id int(11), original_call_sid varchar(100), callback_call_sid varchar(100), notes text, PRIMARY KEY (id), KEY phone_number (phone_number), KEY status (status), KEY queue_id (queue_id) ) $charset_collate;"; dbDelta($sql_schedules); dbDelta($sql_queues); dbDelta($sql_queued_calls); dbDelta($sql_workflows); dbDelta($sql_call_log); dbDelta($sql_sms_log); dbDelta($sql_voicemails); dbDelta($sql_agent_groups); dbDelta($sql_group_members); dbDelta($sql_agent_status); dbDelta($sql_callbacks); // Add missing columns for existing installations self::add_missing_columns(); } /** * Add missing columns for existing installations */ private static function add_missing_columns() { global $wpdb; $table_schedules = $wpdb->prefix . 'twp_phone_schedules'; // Check if holiday_dates column exists $column_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_schedules LIKE 'holiday_dates'"); if (empty($column_exists)) { $wpdb->query("ALTER TABLE $table_schedules ADD COLUMN holiday_dates text AFTER after_hours_forward_number"); } // Check if days_of_week column needs to be expanded $column_info = $wpdb->get_results("SHOW COLUMNS FROM $table_schedules LIKE 'days_of_week'"); if (!empty($column_info) && $column_info[0]->Type === 'varchar(20)') { $wpdb->query("ALTER TABLE $table_schedules MODIFY COLUMN days_of_week varchar(100) NOT NULL"); } // Add new columns to call queues table and migrate phone_number to notification_number $table_queues = $wpdb->prefix . 'twp_call_queues'; // Check if phone_number column exists and notification_number doesn't - need migration $phone_column_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'phone_number'"); $notification_column_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'notification_number'"); if (!empty($phone_column_exists) && empty($notification_column_exists)) { // Migrate phone_number to notification_number $wpdb->query("ALTER TABLE $table_queues CHANGE phone_number notification_number varchar(20)"); // Update the index name $wpdb->query("ALTER TABLE $table_queues DROP INDEX phone_number"); $wpdb->query("ALTER TABLE $table_queues ADD INDEX notification_number (notification_number)"); } elseif (empty($phone_column_exists) && empty($notification_column_exists)) { // Fresh installation - add notification_number column $wpdb->query("ALTER TABLE $table_queues ADD COLUMN notification_number varchar(20) AFTER queue_name"); $wpdb->query("ALTER TABLE $table_queues ADD INDEX notification_number (notification_number)"); } // Check if agent_group_id column exists in queues table $group_column_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'agent_group_id'"); if (empty($group_column_exists)) { $wpdb->query("ALTER TABLE $table_queues ADD COLUMN agent_group_id int(11) AFTER notification_number"); $wpdb->query("ALTER TABLE $table_queues ADD INDEX agent_group_id (agent_group_id)"); } // Add agent columns to queued_calls table if they don't exist $table_queued_calls = $wpdb->prefix . 'twp_queued_calls'; $agent_phone_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queued_calls LIKE 'agent_phone'"); if (empty($agent_phone_exists)) { $wpdb->query("ALTER TABLE $table_queued_calls ADD COLUMN agent_phone varchar(20) AFTER status"); } $agent_call_sid_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queued_calls LIKE 'agent_call_sid'"); if (empty($agent_call_sid_exists)) { $wpdb->query("ALTER TABLE $table_queued_calls ADD COLUMN agent_call_sid varchar(100) AFTER agent_phone"); } // Add status index if it doesn't exist $status_index_exists = $wpdb->get_results("SHOW INDEX FROM $table_queued_calls WHERE Key_name = 'status'"); if (empty($status_index_exists)) { $wpdb->query("ALTER TABLE $table_queued_calls ADD INDEX status (status)"); } } /** * Perform table migrations for existing installations */ private static function migrate_tables() { // Call the existing add_missing_columns function which now includes queue columns self::add_missing_columns(); } /** * Set default plugin options */ private static function set_default_options() { add_option('twp_twilio_account_sid', ''); add_option('twp_twilio_auth_token', ''); add_option('twp_elevenlabs_api_key', ''); add_option('twp_elevenlabs_voice_id', ''); add_option('twp_elevenlabs_model_id', 'eleven_multilingual_v2'); add_option('twp_default_queue_timeout', 300); add_option('twp_default_queue_size', 10); add_option('twp_urgent_keywords', 'urgent,emergency,important,asap,help'); add_option('twp_sms_notification_number', ''); add_option('twp_default_sms_number', ''); } /** * Create custom user roles for the plugin */ private static function create_user_roles() { // Remove role first if it exists to ensure clean setup remove_role('phone_agent'); // Add Phone Agent role with limited capabilities add_role('phone_agent', 'Phone Agent', array( // Basic WordPress capabilities 'read' => true, // Profile management 'edit_profile' => true, // Phone agent specific capabilities 'twp_access_voicemails' => true, 'twp_access_call_log' => true, 'twp_access_agent_queue' => true, 'twp_access_outbound_calls' => true, 'twp_access_sms_inbox' => true, 'twp_access_browser_phone' => true, )); } }