'success', 'full_name' => $account['full_name'], 'role' => $account['role'], 'can_manage' => current_user_can(RAPIDCHAT_CAP_MANAGE), 'can_assign' => rapidchat_user_can('rapidchat_assign'), )); } add_action('wp_ajax_rapidchat_admin_conversations_user', 'rapidchat_admin_conversations_user'); function rapidchat_admin_conversations_user() { global $wpdb; $account = rapidchat_require_operator(); $wpdb->update( $wpdb->rapidchat_accounts, array('status' => 'Waiting', 'last_seen' => current_time('mysql')), array('id' => (int) $account['id']), array('%s', '%s'), array('%d') ); $filter = isset($_POST['filter']) ? sanitize_text_field(wp_unslash($_POST['filter'])) : 'all'; echo rapidchat_kses(rapidchat_render_admin_conversations($account, $filter)); wp_die(); } /** Fill team_name / team_colour on conversation rows (arrays or objects) from the rapidchat_team_labels filter. */ function rapidchat_add_team_labels($rows) { $team_ids = array(); foreach ($rows as $row) { $team_ids[] = (int) (is_object($row) ? $row->team_id : $row['team_id']); } $team_ids = array_values(array_filter(array_unique($team_ids))); $labels = $team_ids ? (array) apply_filters('rapidchat_team_labels', array(), $team_ids) : array(); foreach ($rows as $key => $row) { $team_id = (int) (is_object($row) ? $row->team_id : $row['team_id']); $name = isset($labels[$team_id]['name']) ? (string) $labels[$team_id]['name'] : ''; $colour = isset($labels[$team_id]['colour']) ? (string) $labels[$team_id]['colour'] : ''; if (is_object($row)) { $row->team_name = $name; $row->team_colour = $colour; } else { $rows[$key]['team_name'] = $name; $rows[$key]['team_colour'] = $colour; } } return $rows; } /** One row per conversation, filtered and ordered in the database. */ function rapidchat_admin_conversations($operator_id, $limit = RAPIDCHAT_LIST_LIMIT, $filter = 'all') { global $wpdb; $visibility = rapidchat_operator_visibility($operator_id); $filters = array( 'all' => array('', array()), 'closed' => array(" AND c.state = 'closed'", array()), 'mine' => array(" AND c.state = 'open' AND EXISTS (SELECT 1 FROM %i cp_mine WHERE cp_mine.conversation_id = c.id AND cp_mine.operator_id = %d AND cp_mine.is_available IN (0, 3))", array($wpdb->rapidchat_participants, (int) $operator_id)), 'queued' => array(" AND c.state = 'open' AND NOT EXISTS (SELECT 1 FROM %i cp_claimed WHERE cp_claimed.conversation_id = c.id AND cp_claimed.is_available = 0)", array($wpdb->rapidchat_participants)), 'unread' => array(' AND (SELECT COUNT(*) FROM %i um WHERE um.conversation_id = c.id AND um.is_read = 0 AND um.account_id = c.account_sender_id) > 0', array($wpdb->rapidchat_messages)), ); list($filter_sql, $filter_args) = isset($filters[$filter]) ? $filters[$filter] : $filters['all']; // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- $visibility['sql'] and $filter_sql are literal SQL with placeholders only; every value is bound by prepare(). $rows = $wpdb->get_results( $wpdb->prepare( "SELECT c.id, c.account_sender_id, c.account_receiver_id, c.submit_date, c.last_activity, c.state, c.team_id, c.custom_fields, c.rating, c.feedback, c.closed_at, a.full_name AS sender_name, a.country AS sender_country, a2.full_name AS receiver_name, a2.country AS receiver_country, lm.msg AS msg, lm.submit_date AS msg_date, lm.msg_type AS msg_type, CASE WHEN EXISTS (SELECT 1 FROM %i cp_mine WHERE cp_mine.conversation_id = c.id AND cp_mine.operator_id = %d AND cp_mine.is_available = 0) THEN 0 WHEN EXISTS (SELECT 1 FROM %i cp_join WHERE cp_join.conversation_id = c.id AND cp_join.operator_id = %d AND cp_join.is_available = 3) THEN 3 WHEN EXISTS (SELECT 1 FROM %i cp_other WHERE cp_other.conversation_id = c.id AND cp_other.is_available = 0) THEN 2 ELSE 1 END AS is_available, (SELECT COUNT(*) FROM %i um WHERE um.conversation_id = c.id AND um.is_read = 0 AND um.account_id = c.account_sender_id) AS unread_count, (SELECT a3.full_name FROM %i cp3 JOIN %i a3 ON a3.id = cp3.operator_id WHERE cp3.conversation_id = c.id AND cp3.is_available = 0 LIMIT 1) AS assigned_name, (SELECT cp4.operator_id FROM %i cp4 WHERE cp4.conversation_id = c.id AND cp4.is_available = 0 LIMIT 1) AS assigned_id FROM %i c JOIN %i a ON a.id = c.account_sender_id JOIN %i a2 ON a2.id = c.account_receiver_id LEFT JOIN %i lm ON lm.id = (SELECT MAX(m2.id) FROM %i m2 WHERE m2.conversation_id = c.id) WHERE 1=1" . $visibility['sql'] . $filter_sql . ' ORDER BY COALESCE(c.last_activity, c.submit_date) DESC LIMIT %d', array_merge( array( $wpdb->rapidchat_participants, (int) $operator_id, $wpdb->rapidchat_participants, (int) $operator_id, $wpdb->rapidchat_participants, $wpdb->rapidchat_messages, $wpdb->rapidchat_participants, $wpdb->rapidchat_accounts, $wpdb->rapidchat_participants, $wpdb->rapidchat_conversations, $wpdb->rapidchat_accounts, $wpdb->rapidchat_accounts, $wpdb->rapidchat_messages, $wpdb->rapidchat_messages, ), $visibility['args'], $filter_args, array((int) $limit) ) ), ARRAY_A ); // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared return rapidchat_add_team_labels((array) $rows); } function rapidchat_render_admin_conversations(array $account, $filter = 'all') { $operator_id = (int) $account['id']; $conversations = rapidchat_admin_conversations($operator_id, RAPIDCHAT_LIST_LIMIT, $filter); $can_queue = rapidchat_user_can('rapidchat_reply'); $can_assign = rapidchat_user_can('rapidchat_assign'); $output = '
'; $output .= '
'; if (empty($conversations)) { $empty_label = __('No conversations found.', 'rapidchat'); if ($filter === 'unread') { $empty_label = __('No unread conversations.', 'rapidchat'); } elseif ($filter === 'mine') { $empty_label = __('No active conversations assigned to you.', 'rapidchat'); } elseif ($filter === 'queued') { $empty_label = __('No queued conversations waiting.', 'rapidchat'); } elseif ($filter === 'closed') { $empty_label = __('No closed conversations.', 'rapidchat'); } $output .= '

' . esc_html($empty_label) . '

'; $output .= '
'; return $output; } $unread_items = ''; $mine = ''; $queued = ''; $others = ''; $closed = ''; foreach ($conversations as $conversation) { $is_mine = ((int) $conversation['account_sender_id'] === $operator_id); $contact_name = $is_mine ? $conversation['receiver_name'] : $conversation['sender_name']; $contact_id = $is_mine ? $conversation['account_receiver_id'] : $conversation['account_sender_id']; $country = $is_mine ? $conversation['receiver_country'] : $conversation['sender_country']; $unread = (int) $conversation['unread_count']; $is_closed = ($conversation['state'] !== 'open'); $assigned_id = (int) $conversation['assigned_id']; $is_joined = ((int) $conversation['is_available'] === 3); $mine_now = ($assigned_id === $operator_id || (int) $conversation['is_available'] === 0 || $is_joined); $is_queued = (!$assigned_id && !$is_closed && ((int) $conversation['is_available'] === 1 || empty($conversation['assigned_id']))); $custom_fields = json_decode((string) $conversation['custom_fields'], true); $tags = (is_array($custom_fields) && !empty($custom_fields['tags'])) ? (array) $custom_fields['tags'] : array(); $tags_attr = esc_attr(implode(' ', array_map('strtolower', $tags))); $item = '
'; $item .= '
' . rapidchat_flag($country) . '
'; $item .= '
'; $item .= '
'; $item .= '' . esc_html($contact_name) . ''; $item .= '#' . esc_html($conversation['id']) . ''; $item .= '
'; $preview_prefix = ''; if (!empty($conversation['msg_type']) && $conversation['msg_type'] === 'note') { $preview_prefix = '๐Ÿ”’ [Note] '; } $item .= '
' . esc_html($preview_prefix . rapidchat_preview($conversation['msg'])) . '
'; $meta = array(); if ($is_closed) { $meta[] = '' . esc_html__('Closed', 'rapidchat') . ''; } $meta = (array) apply_filters('rapidchat_conversation_list_badges', $meta, $conversation); if ($assigned_id && !$is_closed) { if ($is_joined) { /* translators: %s: operator name who owns the chat */ $meta[] = '' . esc_html(sprintf(__('Joined ยท with %s', 'rapidchat'), $conversation['assigned_name'])) . ''; } else { $meta[] = $mine_now ? '' . esc_html__('You', 'rapidchat') . '' /* translators: %s: operator name currently handling the chat */ : '' . esc_html(sprintf(__('with %s', 'rapidchat'), $conversation['assigned_name'])) . ''; } } if (!empty($tags)) { foreach (array_slice($tags, 0, 2) as $t) { $meta[] = '' . esc_html($t) . ''; } if (count($tags) > 2) { $meta[] = '+' . (count($tags) - 2) . ''; } } if ($meta) { $item .= '
' . implode('', $meta) . '
'; } $item .= '
'; $item .= '
' . esc_html(rapidchat_short_date($conversation['msg_date'] ?: $conversation['submit_date'])) . '
'; if ($unread) { $item .= '
' . esc_html($unread > 99 ? '99+' : $unread) . '
'; } $item .= '
'; if ($filter === 'unread') { $unread_items .= $item; } elseif ($is_closed) { $closed .= $item; } elseif ($mine_now) { $mine .= $item; } elseif ($is_queued) { $queued .= $item; } elseif ($can_assign) { $others .= $item; } } if ($filter === 'unread') { if ($unread_items !== '') { $output .= '
' . rapidchat_icon('bell') . ' ' . esc_html__('Unread Messages', 'rapidchat') . '
' . $unread_items; } } elseif ($filter === 'mine') { if ($mine !== '') { $output .= '
' . rapidchat_icon('comments') . ' ' . esc_html__('My Active Chats', 'rapidchat') . '
' . $mine; } } elseif ($filter === 'queued') { if ($queued !== '') { $output .= '
' . rapidchat_icon('clock') . ' ' . esc_html__('Queued / Unassigned', 'rapidchat') . '
' . $queued; } } elseif ($filter === 'closed') { if ($closed !== '') { $output .= '
' . rapidchat_icon('check-double') . ' ' . esc_html__('Closed Conversations', 'rapidchat') . '
' . $closed; } } else { if ($mine !== '') { $output .= '
' . rapidchat_icon('comments') . ' ' . esc_html__('My Active Chats', 'rapidchat') . '
' . $mine; } if ($queued !== '' && $can_queue) { $output .= '
' . rapidchat_icon('clock') . ' ' . esc_html__('Queued / Unassigned', 'rapidchat') . '
' . $queued; } if ($others !== '') { $output .= '
' . rapidchat_icon('user') . ' ' . esc_html__('Other Agents', 'rapidchat') . '
' . $others; } if ($closed !== '') { $output .= '
' . rapidchat_icon('check-double') . ' ' . esc_html__('Closed Conversations', 'rapidchat') . '
' . $closed; } } $output .= ''; return $output; } add_action('wp_ajax_rapidchat_conversation_admin', 'rapidchat_conversation_admin'); function rapidchat_conversation_admin() { global $wpdb; $account = rapidchat_require_operator(); $operator_id = (int) $account['id']; $conversation_id = isset($_POST['conversation_id']) ? (int) $_POST['conversation_id'] : 0; if (!rapidchat_can_access_conversation($operator_id, $conversation_id, true)) { wp_send_json_error(__('Conversation not found.', 'rapidchat'), 403); } $conversation = $wpdb->get_row($wpdb->prepare( 'SELECT c.*, a.full_name AS sender_name, a.email AS sender_email, a.ip_address AS sender_ip, a.country AS sender_country, a.wp_user_id AS sender_wp_user_id, a.role AS sender_role, a.last_seen AS sender_last_seen, a.status AS sender_status, a2.full_name AS receiver_name, a2.email AS receiver_email, a2.ip_address AS receiver_ip, a2.country AS receiver_country, a2.wp_user_id AS receiver_wp_user_id, a2.role AS receiver_role, a2.last_seen AS receiver_last_seen, a2.status AS receiver_status FROM %i c JOIN %i a ON a.id = c.account_sender_id JOIN %i a2 ON a2.id = c.account_receiver_id WHERE c.id = %d', $wpdb->rapidchat_conversations, $wpdb->rapidchat_accounts, $wpdb->rapidchat_accounts, $conversation_id )); if (!$conversation) { wp_send_json_error(__('Conversation not found.', 'rapidchat'), 404); } list($conversation) = rapidchat_add_team_labels(array($conversation)); $sender_id = (int) $conversation->account_sender_id; $conversation->total_chats = (int) $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM %i WHERE account_sender_id = %d", $wpdb->rapidchat_conversations, $sender_id )); $assignments = rapidchat_conversation_assignments($conversation_id); $is_available = isset($assignments[$operator_id]) ? (int) $assignments[$operator_id]->is_available : (rapidchat_conversation_is_claimed($assignments) ? 2 : 1); if ($is_available === 0 || $is_available === 3) { $wpdb->query($wpdb->prepare( 'UPDATE %i SET is_read = 1 WHERE conversation_id = %d AND account_id <> %d AND is_read = 0', $wpdb->rapidchat_messages, $conversation_id, $operator_id )); } $messages = $wpdb->get_results($wpdb->prepare( 'SELECT id, account_id, msg, attachment_url, attachment_type, attachment_name, attachment_size, msg_type, submit_date FROM %i WHERE conversation_id = %d ORDER BY id ASC LIMIT 500', $wpdb->rapidchat_messages, $conversation_id )); $names = rapidchat_account_names(wp_list_pluck($messages, 'account_id')); $operator_ids = array_map('intval', array_keys($assignments)); $read_through = rapidchat_conversation_read_through($conversation_id, $operator_id); echo rapidchat_kses(rapidchat_render_admin_conversation($conversation, $messages, $names, $account, $assignments, $operator_ids, $is_available, $read_through)); wp_die(); } function rapidchat_conversation_is_claimed(array $assignments) { foreach ($assignments as $row) { if ((int) $row->is_available === 0) { return true; } } return false; } function rapidchat_conversation_assignments($conversation_id) { global $wpdb; return $wpdb->get_results( $wpdb->prepare( 'SELECT operator_id, is_available FROM %i WHERE conversation_id = %d', $wpdb->rapidchat_participants, (int) $conversation_id ), OBJECT_K ); } /** Every policy decision the conversation view needs, keyed by action. */ function rapidchat_conversation_permissions($conversation_id, array $account) { $perms = array(); foreach (array('claim', 'reply', 'note', 'manage', 'close', 'transfer', 'assign', 'join', 'invite', 'leave', 'delete') as $action) { $perms[$action] = rapidchat_operator_can($action, $conversation_id, $account); } return $perms; } function rapidchat_render_admin_conversation($conversation, $messages, array $names, array $account, array $assignments, array $operator_ids, $is_available, $read_through = 0) { $operator_id = (int) $account['id']; $perms = rapidchat_conversation_permissions((int) $conversation->id, $account); $chat_team = rapidchat_conversation_team((int) $conversation->id); $holder = null; foreach ($chat_team as $member) { if ((int) $member['state'] === 0) { $holder = $member; break; } } $is_owner = $holder && (int) $holder['id'] === $operator_id; $view = array( 'conversation' => $conversation, 'account' => $account, 'perms' => $perms, 'chat_team' => $chat_team, 'holder' => $holder, 'is_owner' => $is_owner, ); $is_sender = ($operator_id === (int) $conversation->account_sender_id); $contact_name = $is_sender ? $conversation->receiver_name : $conversation->sender_name; $contact_ctry = $is_sender ? $conversation->receiver_country : $conversation->sender_country; $output = '
'; if ((int) $is_available === 1) { $output .= '
'; $output .= ''; $output .= '
'; $output .= ''; $output .= '
'; $output .= '
'; $output .= '
'; $output .= '
' . rapidchat_icon('comments', 48) . '
'; $output .= '

' . esc_html__('Incoming Conversation', 'rapidchat') . '

'; $output .= '

' . esc_html__('This conversation is in the queue. Claim it to start responding or assign to another agent.', 'rapidchat') . '

'; $output .= '
'; if ($perms['claim']) { $output .= ''; } $output .= apply_filters('rapidchat_conversation_claim_actions', '', $view); $output .= '
'; $output .= '
'; $output .= '
'; $output .= '
'; $output .= rapidchat_render_profile_panel($conversation, $is_sender, $perms, $view); $output .= apply_filters('rapidchat_conversation_panels', '', $view); $output .= '
'; return $output; } $output .= '
'; $output .= '
'; $output .= ''; $output .= '
'; $output .= '' . esc_html($contact_name) . ''; $output .= '' . esc_html(ucfirst($conversation->state)) . ''; $output .= apply_filters('rapidchat_conversation_header_badges', '', $view); if ($chat_team) { $agent_names = array(); foreach ($chat_team as $member) { $label = ((int) $member['id'] === $operator_id) ? __('You', 'rapidchat') : $member['full_name']; $agent_names[] = ((int) $member['state'] === 0) ? '' . esc_html($label) . '' : esc_html($label); } $output .= '' . rapidchat_icon('user', 12) . ' ' . implode(', ', $agent_names) . ''; } $output .= '
'; $cid = esc_attr($conversation->id); $output .= '
'; $output .= ''; $output .= apply_filters('rapidchat_conversation_header_actions', '', $view); if ($perms['manage']) { $output .= ''; } if ($perms['close']) { $output .= ''; } $output .= '
'; $output .= '
'; $output .= apply_filters('rapidchat_conversation_before_messages', '', $view); $output .= ''; $output .= rapidchat_render_messages($messages, $names, $operator_id, $operator_ids, 'admin', $read_through); $output .= '
' . '
' . rapidchat_icon('sparkles', 13) . ' ' . esc_html__('Smart Suggestions', 'rapidchat') . '
' . '
' . '
'; $composer_mode = $perms['reply'] ? 'both' : ($perms['note'] ? 'note' : 'none'); $output .= rapidchat_render_admin_composer((int) $conversation->id, $conversation->state === 'open', $composer_mode); $output .= ''; $output .= rapidchat_render_profile_panel($conversation, $is_sender, $perms, $view); $output .= apply_filters('rapidchat_conversation_panels', '', $view); $output .= ''; return $output; } function rapidchat_render_admin_composer($conversation_id, $is_open, $mode = 'both') { if (!$is_open) { return '

' . esc_html__('This conversation is closed.', 'rapidchat') . '

'; } if ($mode === 'none') { return '

' . esc_html__('Read-only: you are not part of this chat.', 'rapidchat') . '

'; } $note_only = ($mode === 'note'); $output = '
'; $output .= '
'; if (!$note_only) { $output .= ''; } $output .= ''; $output .= '
'; $output .= '
'; $output .= ''; $output .= '
'; $output .= ''; $output .= ''; $output .= ''; $output .= ''; $output .= ''; $output .= ''; $output .= ''; $output .= ''; $output .= ''; $output .= ''; $output .= '
'; $output .= ''; $output .= '
'; $output .= '
'; return $output; } /** $perms: rapidchat_conversation_permissions() for the viewer. */ function rapidchat_render_profile_panel($conversation, $is_sender, array $perms, array $view = array()) { $can_delete = !empty($perms['delete']); $can_manage = !empty($perms['manage']); $name = $is_sender ? $conversation->receiver_name : $conversation->sender_name; $email = $is_sender ? $conversation->receiver_email : $conversation->sender_email; $ip = $is_sender ? $conversation->receiver_ip : $conversation->sender_ip; $country = $is_sender ? $conversation->receiver_country : $conversation->sender_country; $wp_user_id = $is_sender ? (int) ($conversation->receiver_wp_user_id ?? 0) : (int) ($conversation->sender_wp_user_id ?? 0); $role = $is_sender ? ($conversation->receiver_role ?? 'Guest') : ($conversation->sender_role ?? 'Guest'); $rating = isset($conversation->rating) ? (int) $conversation->rating : 0; $feedback = isset($conversation->feedback) ? $conversation->feedback : ''; $total_chats = isset($conversation->total_chats) ? (int) $conversation->total_chats : 1; $custom_fields = json_decode((string) $conversation->custom_fields, true); $context = (is_array($custom_fields) && !empty($custom_fields['context'])) ? (array) $custom_fields['context'] : array(); $tags = (is_array($custom_fields) && !empty($custom_fields['tags'])) ? (array) $custom_fields['tags'] : array(); $standard_tags = rapidchat_get_standard_tags(); $output = '
'; $output .= '
'; $output .= '' . esc_html__('Customer 360 & Details', 'rapidchat') . ''; $output .= ''; $output .= '
'; $output .= '
'; $output .= '
' . esc_html(rapidchat_initial($name)) . '
'; $output .= ''; if ($can_delete) { $output .= ''; } $output .= '
'; if ($can_delete) { $output .= ''; } $output .= '
'; $output .= '
' . esc_html__('Visitor Info', 'rapidchat') . '
'; $output .= '
' . esc_html__('Name', 'rapidchat') . '' . esc_html($name) . '
'; $output .= '
' . esc_html__('Email', 'rapidchat') . '' . ($email ? '' . esc_html($email) . '' : '' . esc_html__('Guest', 'rapidchat') . '') . '
'; if ($wp_user_id > 0) { $user_edit_link = get_edit_user_link($wp_user_id); $output .= '
' . esc_html__('WP Account', 'rapidchat') . '' . ($user_edit_link ? '#' . esc_html($wp_user_id) . ' (' . esc_html__('View Profile', 'rapidchat') . ')' : '#' . esc_html($wp_user_id)) . '
'; } $output .= '
' . esc_html__('IP Address', 'rapidchat') . '' . esc_html($ip ? $ip : 'โ€”') . '
'; $output .= '
' . esc_html__('Location', 'rapidchat') . '' . rapidchat_flag($country) . ' ' . esc_html($country ? $country : 'Unknown') . '
'; if (!empty($conversation->submit_date)) { $started_formatted = date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($conversation->submit_date)); $output .= '
' . esc_html__('Started', 'rapidchat') . '' . esc_html($started_formatted) . '
'; } /* translators: %d: number of conversations with this visitor. */ $history = sprintf(_n('%d conversation', '%d conversations', $total_chats, 'rapidchat'), $total_chats); $output .= '
' . esc_html__('History', 'rapidchat') . '' . esc_html($history) . '
'; if (!empty($context)) { $output .= '
' . esc_html__('Browsing Context', 'rapidchat') . '
'; if (!empty($context['title']) || !empty($context['url'])) { $page_title = !empty($context['title']) ? $context['title'] : $context['url']; $page_url = !empty($context['url']) ? $context['url'] : '#'; $output .= '
' . esc_html__('Current Page', 'rapidchat') . '' . esc_html(rapidchat_preview($page_title, 35)) . '
'; } if (!empty($context['referrer'])) { $output .= '
' . esc_html__('Referrer', 'rapidchat') . '' . esc_html(rapidchat_preview($context['referrer'], 35)) . '
'; } if (!empty($context['browser']) || !empty($context['os'])) { $device_str = trim(($context['browser'] ?? '') . ' on ' . ($context['os'] ?? '') . ' (' . ($context['device'] ?? '') . ')'); $output .= '
' . esc_html__('Device', 'rapidchat') . '' . esc_html($device_str) . '
'; } } $output .= '
' . esc_html__('Conversation Tags', 'rapidchat') . '
'; $output .= '
'; $output .= '
'; foreach ($tags as $tag) { $color = isset($standard_tags[$tag]) ? $standard_tags[$tag] : '#6b7280'; $output .= '' . esc_html($tag) . ($can_manage ? '' : '') . ''; } $output .= '
'; if ($can_manage) { $output .= '
'; foreach ($standard_tags as $stag => $scolor) { if (!in_array($stag, $tags, true)) { $output .= ''; } } $output .= '
'; $output .= '
'; $output .= ''; $output .= ''; $output .= '
'; } $output .= '
'; if ($rating > 0) { $stars = str_repeat('โญ', $rating); $output .= '
' . esc_html__('Customer Feedback', 'rapidchat') . '
'; $output .= '
' . $stars . ' (' . $rating . '/5)'; if ($feedback !== '') { $output .= '

"' . esc_html($feedback) . '"

'; } $output .= '
'; } $output .= '
'; $output .= apply_filters('rapidchat_profile_panel_actions', '', $view); if ($can_manage) { $output .= ''; } if (!empty($perms['close'])) { $output .= ''; } $output .= '
'; $output .= '
'; $output .= '
'; return $output; } add_action('wp_ajax_rapidchat_admin_post_message', 'rapidchat_admin_post_message'); function rapidchat_admin_post_message() { $account = rapidchat_require_operator(); $msg_type = isset($_POST['msg_type']) ? sanitize_text_field(wp_unslash($_POST['msg_type'])) : 'message'; $result = rapidchat_message_create(array( 'conversation_id' => isset($_POST['id']) ? (int) $_POST['id'] : 0, 'actor' => $account, 'is_operator' => true, 'msg' => isset($_POST['msg']) ? sanitize_textarea_field(wp_unslash($_POST['msg'])) : '', 'msg_type' => $msg_type, 'attachment_url' => isset($_POST['attachment_url']) ? esc_url_raw(wp_unslash($_POST['attachment_url'])) : '', 'attachment_type' => isset($_POST['attachment_type']) ? sanitize_key(wp_unslash($_POST['attachment_type'])) : '', 'attachment_name' => isset($_POST['attachment_name']) ? sanitize_text_field(wp_unslash($_POST['attachment_name'])) : '', 'attachment_size' => isset($_POST['attachment_size']) ? absint(wp_unslash($_POST['attachment_size'])) : 0, )); if (!is_wp_error($result)) { $result['message'] = ($msg_type === 'note') ? __('Note added successfully.', 'rapidchat') : __('Message submitted successfully!', 'rapidchat'); } rapidchat_ajax_respond($result); } add_action('wp_ajax_rapidchat_update_tags', 'rapidchat_update_tags'); function rapidchat_update_tags() { $account = rapidchat_require_operator(); $conversation_id = isset($_POST['conversation_id']) ? (int) $_POST['conversation_id'] : 0; $tags_raw = isset($_POST['tags']) ? map_deep(wp_unslash($_POST['tags']), 'sanitize_text_field') : ''; if (is_array($tags_raw)) { $tags = $tags_raw; } elseif (is_string($tags_raw)) { $tags = array_filter(array_map('trim', explode(',', $tags_raw))); } else { $tags = array(); } $result = rapidchat_conversation_update_tags(array( 'conversation_id' => $conversation_id, 'actor' => $account, 'tags' => $tags, )); if (is_wp_error($result)) { rapidchat_ajax_respond($result); } wp_send_json_success($result); } add_action('wp_ajax_rapidchat_get_smart_suggestions', 'rapidchat_get_smart_suggestions'); function rapidchat_get_smart_suggestions() { global $wpdb; $account = rapidchat_require_operator(); $conversation_id = isset($_POST['conversation_id']) ? (int) $_POST['conversation_id'] : 0; if ($conversation_id > 0) { rapidchat_require_operator_can('view', $conversation_id, $account); } $suggestions = array(); if ($wpdb->rapidchat_canned_responses && $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($wpdb->rapidchat_canned_responses))) === $wpdb->rapidchat_canned_responses) { $canned = $wpdb->get_results($wpdb->prepare('SELECT id, shortcut, title, content FROM %i LIMIT 8', $wpdb->rapidchat_canned_responses), ARRAY_A); foreach ($canned as $c) { $suggestions[] = array( 'id' => 'canned_' . $c['id'], 'title' => (!empty($c['shortcut']) ? '/' . $c['shortcut'] . ': ' : '') . $c['title'], 'text' => $c['content'], 'category' => 'Canned', ); } } $suggestions = (array) apply_filters('rapidchat_smart_suggestions', $suggestions, $conversation_id, $account); if (empty($suggestions)) { $suggestions = array( array('id' => 'def_1', 'title' => __('Hello & Welcome', 'rapidchat'), 'text' => __('Hello! Thanks for reaching out. How can I assist you today?', 'rapidchat'), 'category' => __('Quick', 'rapidchat')), array('id' => 'def_2', 'title' => __('Checking this now', 'rapidchat'), 'text' => __("I'm checking this for you right now, please give me just a moment.", 'rapidchat'), 'category' => __('Quick', 'rapidchat')), array('id' => 'def_3', 'title' => __('Anything else?', 'rapidchat'), 'text' => __('Is there anything else I can help you with today?', 'rapidchat'), 'category' => __('Quick', 'rapidchat')), array('id' => 'def_4', 'title' => __('Thank you & Goodbye', 'rapidchat'), 'text' => __('Thank you for chatting with us! Have a wonderful day.', 'rapidchat'), 'category' => __('Quick', 'rapidchat')), ); } wp_send_json_success(array('suggestions' => $suggestions)); } add_action('wp_ajax_rapidchat_close_conversation', 'rapidchat_close_conversation_handler'); function rapidchat_close_conversation_handler() { $account = rapidchat_require_operator(); $conversation_id = isset($_POST['conversation_id']) ? (int) $_POST['conversation_id'] : 0; $result = rapidchat_conversation_close($conversation_id, array('actor' => $account)); if (is_wp_error($result)) { rapidchat_ajax_respond($result); } wp_send_json_success(array('message' => __('Conversation ended.', 'rapidchat'), 'id' => $conversation_id)); } /** "Accept & Chat": the signed-in operator claims a queued conversation. */ add_action('wp_ajax_rapidchat_claim_conversation', 'rapidchat_claim_conversation_handler'); function rapidchat_claim_conversation_handler() { $account = rapidchat_require_operator('rapidchat_reply'); $conversation_id = isset($_POST['conversation_id']) ? (int) $_POST['conversation_id'] : 0; $ctx = rapidchat_operator_context((int) $account['id'], $conversation_id); if ($ctx && $ctx['state'] === 'open' && $ctx['holder_id'] === (int) $account['id']) { wp_send_json_success(array('message' => __('Chat accepted.', 'rapidchat'))); } rapidchat_require_operator_can('claim', $conversation_id, $account); if (!rapidchat_claim_if_unclaimed($conversation_id, (int) $account['id'])) { wp_send_json_error(__('Another agent has just accepted this chat.', 'rapidchat'), 409); } rapidchat_event('operator_assigned', $conversation_id, (int) $account['id']); wp_send_json_success(array('message' => __('Chat accepted.', 'rapidchat'))); } /** Email the conversation's transcript to the visitor. */ add_action('wp_ajax_rapidchat_admin_send_transcript', 'rapidchat_admin_send_transcript'); function rapidchat_admin_send_transcript() { $account = rapidchat_require_operator(); $result = rapidchat_conversation_transcript(array( 'conversation_id' => isset($_POST['id']) ? (int) $_POST['id'] : 0, 'actor' => $account, 'is_operator' => true, 'recipient' => 'visitor', )); if (is_wp_error($result)) { rapidchat_ajax_respond($result); } wp_send_json_success(__('Transcript emailed to the visitor.', 'rapidchat')); } add_action('wp_ajax_rapidchat_delete_chat', 'rapidchat_delete_chat'); function rapidchat_delete_chat() { $account = rapidchat_require_operator('rapidchat_manage_settings'); $conversation_id = isset($_POST['conversation_id']) ? (int) $_POST['conversation_id'] : 0; if (!$conversation_id) { wp_send_json_error(array('message' => __('Invalid conversation ID.', 'rapidchat'))); } if (!rapidchat_operator_can('delete', $conversation_id, $account) || !rapidchat_can_access_conversation((int) $account['id'], $conversation_id, true)) { wp_send_json_error(array('message' => __('Conversation not found.', 'rapidchat')), 403); } if (!rapidchat_delete_conversations(array($conversation_id))) { wp_send_json_error(array('message' => __('Delete query failed.', 'rapidchat'))); } wp_send_json_success(array('message' => __('Chat deleted successfully', 'rapidchat'))); }