PluginProbe
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services / 8.7.1
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services v8.7.1
8.7.7 8.7.6 8.7.5 8.7.4 8.7.3 8.7.2 8.7.1 8.7.0 8.6.9 8.6.8 8.6.7 8.6.6 8.6.5 8.6.4 8.6.2 8.6.1 8.6.0 8.5.9 8.5.8 8.5.7 8.5.6 8.5.5 8.5.4 8.5.3 8.5.2 All 533 releases
chatbot / includes / chat-sessions / wpbot-chat-sessions.php

wpbot-chat-sessions.php in WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services 8.7.1, at includes/chat-sessions/wpbot-chat-sessions.php

1,289 lines 74.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WPBot Sessions & Analytics — Built-in Chat Session Module
4 *
5 * Provides full chat session recording, analytics, AI Insight, and
6 * "Questions Not Answered" reporting natively in the free chatbot plugin.
7 *
8 * This module is a port of the Pro plugin's chat-session-addon.
9 * It uses the SAME database table names (wpbot_user, wpbot_conversation,
10 * wpbot_failed_response) so data is shared if the Pro addon is later activated.
11 *
12 * Everything is guarded with function_exists() checks so that when the Pro
13 * addon IS active it takes full precedence and this code is skipped entirely.
14 */
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit;
18 }
19
20 // ─── Guard: Do not run if the Pro addon is active ────────────────────────────
21 // The Pro addon defines qcwp_chat_session_menu_fnc(); if that function already
22 // exists we skip everything here to avoid duplicate menus / conflicts.
23 if ( function_exists( 'qcwp_chat_session_menu_fnc' ) ) {
24 return;
25 }
26
27 // ─── Constants ────────────────────────────────────────────────────────────────
28 // Define our own URL / path constants for assets.
29 // Also define the legacy constant names that all copied report partials reference,
30 // so those files work without modification.
31
32 if ( ! defined( 'QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL' ) ) {
33 define( 'QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
34 }
35 if ( ! defined( 'QCLD_CHATBOT_FREE_SESSION_DIR_PATH' ) ) {
36 define( 'QCLD_CHATBOT_FREE_SESSION_DIR_PATH', plugin_dir_path( __FILE__ ) );
37 }
38
39 // Legacy alias constants — used by all copied partials / report files.
40 if ( ! defined( 'QCLD_wpCHATBOT_HISTORY_PLUGIN_URL' ) ) {
41 define( 'QCLD_wpCHATBOT_HISTORY_PLUGIN_URL', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL );
42 }
43 if ( ! defined( 'QCLD_WPCHATBOT_HISTORY_DIR_PATH' ) ) {
44 define( 'QCLD_WPCHATBOT_HISTORY_DIR_PATH', QCLD_CHATBOT_FREE_SESSION_DIR_PATH );
45 }
46
47 // ─── Database Structure ───────────────────────────────────────────────────────
48 require_once QCLD_CHATBOT_FREE_SESSION_DIR_PATH . 'inc/chatsession-db-structure.php';
49
50 // ─── Admin Menu ───────────────────────────────────────────────────────────────
51 add_action( 'admin_menu', 'qcwp_chat_session_menu_fnc_free' );
52
53 function qcwp_chat_session_menu_fnc_free() {
54
55 $capability = function_exists( 'qcld_wpbot_get_menu_capability' ) ? qcld_wpbot_get_menu_capability( 'sessions' ) : 'manage_options';
56
57 if ( current_user_can( $capability ) ) {
58
59 add_menu_page(
60 'WPBot - Sessions & Analytics',
61 'WPBot - Sessions & Analytics',
62 $capability,
63 'wbcs-botsessions-page',
64 'qc_wpbot_cs_menu_page_callback_func',
65 'dashicons-chart-bar',
66 '9'
67 );
68
69 add_submenu_page(
70 'wbcs-botsessions-page',
71 'Questions Not Answered',
72 'Questions Not Answered',
73 $capability,
74 'wbcs-botsessions-notansweredpage',
75 'qcld_wpbot_not_answered_question'
76 );
77
78 add_submenu_page(
79 'wbcs-botsessions-page',
80 'AI Insight',
81 'AI Insight',
82 $capability,
83 'wbcs-schedule-session-reporting',
84 'qcld_wpbot_schedule_session_reporting'
85 );
86 }
87 }
88
89 // ─── Admin Scripts & Styles ───────────────────────────────────────────────────
90 add_action( 'admin_enqueue_scripts', 'qcld_wb_chatbot_session_admin_scripts_free' );
91
92 function qcld_wb_chatbot_session_admin_scripts_free( $hook ) {
93 // WordPress generates hook suffixes as follows:
94 // top-level page → toplevel_page_{slug}
95 // sub-pages → {parent-menu-title}_page_{slug} (title, lowercased, spaces→hyphens)
96 // Our parent title is "WPBot Sessions & Analytics" → "wpbot-sessions-analytics"
97 $session_hooks = array(
98 'toplevel_page_wbcs-botsessions-page',
99 'wpbot-sessions-analytics_page_wbcs-botsessions-notansweredpage',
100 'wpbot-sessions-analytics_page_wbcs-botsessions-reports',
101 'wpbot-sessions-analytics_page_wbcs-schedule-session-reporting',
102 );
103 $is_session_page = false;
104 foreach ( $session_hooks as $session_hook ) {
105 if ( strpos( $hook, $session_hook ) !== false || ( isset( $_GET['page'] ) && $_GET['page'] === str_replace( 'toplevel_page_', '', $session_hook ) ) ) {
106 $is_session_page = true;
107 break;
108 }
109 }
110
111 if ( isset( $_GET['page'] ) && in_array( $_GET['page'], array( 'wbcs-botsessions-page', 'wbcs-botsessions-notansweredpage', 'wbcs-botsessions-reports', 'wbcs-schedule-session-reporting' ) ) ) {
112 $is_session_page = true;
113 }
114
115 if ( ! $is_session_page ) {
116 return;
117 }
118
119 wp_register_style( 'qlcd-wp-bootstrap-cs', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'css/qlcd-wp-bootstrap.css', array(), QCLD_wpCHATBOT_VERSION, 'screen' );
120 wp_enqueue_style( 'qlcd-wp-bootstrap-cs' );
121
122 wp_register_style( 'qlcd-wp-bootstrap-icons-cs', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'css/qlcd-wp-bootstrap-icons.css', array(), QCLD_wpCHATBOT_VERSION, 'screen' );
123 wp_enqueue_style( 'qlcd-wp-bootstrap-icons-cs' );
124
125 wp_register_style( 'qlcd-wp-dataTables-cs', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'css/qlcd-wp-dataTables.css', array(), QCLD_wpCHATBOT_VERSION, 'screen' );
126 wp_enqueue_style( 'qlcd-wp-dataTables-cs' );
127
128 wp_register_style( 'qlcd-wp-session-style-cs', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'reports/view/assets/style.css', array(), QCLD_wpCHATBOT_VERSION, 'screen' );
129 wp_enqueue_style( 'qlcd-wp-session-style-cs' );
130
131 // SweetAlert2 — used by admin.js for Swal.fire() and Swal.showLoading()
132 wp_register_script( 'qcld-wp-chatbot-sweetalrt-cs', QCLD_wpCHATBOT_PLUGIN_URL . 'js/sweetalrt.js', array( 'jquery' ), QCLD_wpCHATBOT_VERSION, true );
133 wp_enqueue_script( 'qcld-wp-chatbot-sweetalrt-cs' );
134
135 // admin.js depends on SweetAlert2 being loaded first
136 wp_register_script( 'qcld-wp-session-admin-cs', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'js/admin.js', array( 'jquery', 'qcld-wp-chatbot-sweetalrt-cs' ), QCLD_wpCHATBOT_VERSION, true );
137 wp_enqueue_script( 'qcld-wp-session-admin-cs' );
138 wp_localize_script(
139 'qcld-wp-session-admin-cs',
140 'ajax_object',
141 array(
142 'ajax_url' => admin_url( 'admin-ajax.php' ),
143 'ajax_nonce' => wp_create_nonce( 'wpbot_session_ajax_nonce' )
144 )
145 );
146
147 wp_register_script( 'qcld-wp-dataTables-cs', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'js/qcld-dataTables.min.js', array( 'jquery' ), QCLD_wpCHATBOT_VERSION, true );
148 wp_enqueue_script( 'qcld-wp-dataTables-cs' );
149 }
150
151
152 // ─── AI Insight Page Callback ─────────────────────────────────────────────────
153 function qcld_wpbot_schedule_session_reporting() {
154 wp_register_style( 'qcld-wp-chatbot-history-style', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'css/history-style.css', array(), QCLD_wpCHATBOT_VERSION, 'screen' );
155 wp_enqueue_style( 'qcld-wp-chatbot-history-style' );
156 ?>
157 <div class="wrap wpbot-ai-insight-page">
158 <div class="wpbot-ai-insight-header">
159 <h2><?php echo esc_html__( 'AI Insight', 'chatbot' ); ?></h2>
160 <p><?php echo esc_html__( 'Scheduled AI summaries of your chat conversations.', 'chatbot' ); ?></p>
161 </div>
162
163 <div class="wpbot-ai-insight-locked">
164 <div class="wpbot-ai-insight-locked__icon" aria-hidden="true">
165 <span class="dashicons dashicons-lock"></span>
166 </div>
167 <h3><?php echo esc_html__( 'Feature Locked', 'chatbot' ); ?></h3>
168 <p class="wpbot-ai-insight-locked__desc">
169 <?php echo esc_html__( 'The AI Insight feature allows you to receive an AI-based summary of all chat conversations emailed directly to you on a schedule.', 'chatbot' ); ?>
170 </p>
171 <p class="wpbot-ai-insight-locked__cta">
172 <?php echo esc_html__( 'Please upgrade to WPBot Pro to unlock this feature!', 'chatbot' ); ?>
173 </p>
174 <a href="https://www.wpbot.pro/" target="_blank" rel="noopener noreferrer" class="wpbot-ai-insight-locked__btn">
175 <?php echo esc_html__( 'Upgrade to Pro', 'chatbot' ); ?>
176 </a>
177 </div>
178 </div>
179 <?php
180 }
181
182
183 // ─── Questions Not Answered Page Callback ─────────────────────────────────────
184 function qcld_wpbot_not_answered_question() {
185 global $wpdb;
186 $wpdb->show_errors = true; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
187 $table = $wpdb->prefix . 'wpbot_failed_response'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
188
189 if ( isset( $_GET['msg'] ) && $_GET['msg'] == 'success' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
190 echo '<div class="notice notice-success"><p>Record has been Deleted Successfully!</p></div>';
191 }
192
193 if ( isset( $_GET['action'] ) && $_GET['action'] == 'deleteall' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
194 $wpdb->query( "TRUNCATE TABLE `$table`" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
195 echo '<div class="notice notice-success"><p>All Records have been deleted successfully!</p></div>';
196 }
197
198 $sql = "SELECT * FROM $table WHERE 1 ORDER BY `id` DESC"; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
199 $sql1 = "SELECT count(*) FROM $table WHERE 1 ORDER BY `id` DESC"; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
200
201 $total = $wpdb->get_var( $sql1 ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
202 $items_per_page = 30;
203 $page = isset( $_GET['cpage'] ) ? abs( (int) $_GET['cpage'] ) : 1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
204 $offset = ( $page * $items_per_page ) - $items_per_page;
205 $sql .= " LIMIT {$offset}, {$items_per_page}";
206 $result = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
207 $totalPage = ceil( $total / $items_per_page );
208 $customPagHTML = '';
209 if ( $totalPage > 1 ) {
210 $customPagHTML = '<div><span class="wpbot_pagination">Page ' . esc_html( $page ) . ' of ' . esc_html( $totalPage ) . '</span>' . paginate_links(
211 array(
212 'base' => add_query_arg( 'cpage', '%#%' ),
213 'format' => '',
214 'prev_text' => __( '« prev' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
215 'next_text' => __( 'next »' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
216 'total' => esc_html( $totalPage ),
217 'current' => esc_html( $page ),
218 )
219 ) . '</div>';
220 }
221
222 wp_register_style( 'qcld-wp-chatbot-history-style', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'css/history-style.css', array(), QCLD_wpCHATBOT_VERSION, 'screen' );
223 wp_enqueue_style( 'qcld-wp-chatbot-history-style' );
224 ?>
225
226 <div class="sld_menu_title qcld_session_chat_menu_title">
227 <h2><?php echo esc_html__( 'Questions Not Answered', 'chatbot' ) . ' (' . intval( $total ) . ')'; ?></h2>
228 </div>
229
230 <?php if ( $customPagHTML != '' ) : ?>
231 <div class="sld_menu_title sld_menu_title_align"><?php echo wp_kses_post( $customPagHTML ); ?></div>
232 <?php endif; ?>
233
234 <?php
235 require_once QCLD_CHATBOT_FREE_SESSION_DIR_PATH . 'reports/view/partials/questions-not-answered.php';
236 }
237
238 // ─── Main Chat Sessions Page Callback ────────────────────────────────────────
239 function qc_wpbot_cs_menu_page_callback_func() {
240
241 global $wpdb;
242 $wpdb->show_errors = true; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
243
244 $tableuser = $wpdb->prefix . 'wpbot_user'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
245 $tableconversation = $wpdb->prefix . 'wpbot_conversation'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
246 $mainurl = admin_url( 'admin.php?page=wbcs-botsessions-page' );
247
248 if ( isset( $_GET['min_interaction'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
249 $mainurl .= '&min_interaction=' . intval( $_GET['min_interaction'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
250 }
251 if ( isset( $_GET['wp_user'] ) && $_GET['wp_user'] != '' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
252 $mainurl .= '&wp_user=' . intval( $_GET['wp_user'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
253 }
254
255 $msg = '';
256
257 if ( isset( $_GET['action'] ) && $_GET['action'] == 'deleteall' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
258 $wpdb->query( "TRUNCATE TABLE `$tableuser`" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
259 $wpdb->query( "TRUNCATE TABLE `$tableconversation`" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
260 $msg = esc_html( 'All Sessions have been deleted successfully!' );
261 }
262
263 if ( isset( $_GET['msg'] ) && $_GET['msg'] == 'success' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
264 echo '<div class="notice notice-success"><p>Record has been Deleted Successfully!</p></div>';
265 }
266
267 if ( isset( $_GET['userid'] ) && $_GET['userid'] != '' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
268 require_once QCLD_CHATBOT_FREE_SESSION_DIR_PATH . 'reports/view/partials/view-single-chat.php';
269 } else {
270
271 wp_register_style( 'qcld-wp-chatbot-history-style', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'css/history-style.css', array(), QCLD_wpCHATBOT_VERSION, 'screen' );
272 wp_enqueue_style( 'qcld-wp-chatbot-history-style' );
273 wp_register_style( 'qcld-wp-chatbot-jquery-ui', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'css/jqueryui.css', array(), '', 'screen' );
274 wp_enqueue_style( 'qcld-wp-chatbot-jquery-ui' );
275 wp_register_script( 'qcld-wp-chatsession-admin-js', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'js/chatsession.js', array( 'jquery' ), QCLD_wpCHATBOT_VERSION, true );
276 wp_enqueue_script( 'qcld-wp-chatsession-admin-js' );
277 wp_localize_script(
278 'qcld-wp-chatsession-admin-js',
279 'ajax_object',
280 array(
281 'ajax_url' => admin_url( 'admin-ajax.php' ),
282 'ajax_nonce' => wp_create_nonce( 'wpbot_session_ajax_nonce' )
283 )
284 );
285 wp_register_script( 'qcld-wp-jqueryui-js', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'js/jqueryui.js', array( 'jquery' ), QCLD_wpCHATBOT_VERSION, true );
286 wp_enqueue_script( 'qcld-wp-jqueryui-js' );
287
288 $where = '';
289 if ( isset( $_GET['min_interaction'] ) && $_GET['min_interaction'] != 'all' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
290 if ( isset( $_GET['min_interaction'] ) && $_GET['min_interaction'] > 0 ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
291 $where = ' and `interaction` >= ' . intval( $_GET['min_interaction'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
292 }
293 if ( isset( $_GET['min_interaction'] ) && $_GET['min_interaction'] == 0 ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
294 $where = ' and `interaction` = 0';
295 }
296 }
297
298 $wwhere = '';
299 if ( isset( $_GET['wp_user'] ) && $_GET['wp_user'] != 'all' && $_GET['wp_user'] != 0 && $_GET['wp_user'] != '' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
300 $wwhere = ' and `user_id` = ' . intval( $_GET['wp_user'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
301 }
302
303 $sql = "SELECT * FROM $tableuser WHERE 1 $where $wwhere ORDER BY `date` DESC"; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
304 $sql1 = "SELECT count(*) FROM $tableuser WHERE 1 $where $wwhere"; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
305
306 $dateFilter = '';
307 if ( isset( $_GET['FilterDate'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
308 if ( $_GET['FilterDate'] === 'LastWeek' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
309 $dateFilter = " WHERE `date` >= CURDATE() - INTERVAL 7 DAY";
310 }
311 if ( $_GET['FilterDate'] === 'LastMonth' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
312 $dateFilter = " WHERE `date` >= CURDATE() - INTERVAL 30 DAY";
313 }
314 if ( $_GET['FilterDate'] === 'Last3Months' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
315 $dateFilter = " WHERE `date` >= CURDATE() - INTERVAL 90 DAY";
316 }
317 $sql = "SELECT * FROM $tableuser $dateFilter $wwhere ORDER BY `date` DESC"; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
318 $sql1 = "SELECT count(*) FROM $tableuser $dateFilter"; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
319 }
320
321 $total = $wpdb->get_var( $sql1 ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
322 $items_per_page = 30;
323 $page = isset( $_GET['cpage'] ) ? abs( (int) $_GET['cpage'] ) : 1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
324 $offset = ( $page * $items_per_page ) - $items_per_page;
325 $sql .= " LIMIT {$offset}, {$items_per_page}";
326 $result = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
327 $totalPage = ceil( $total / $items_per_page );
328 $customPagHTML = '';
329 if ( $totalPage > 1 ) {
330 $customPagHTML = '<div class="qcld-session-pagination"><span class="wpbot_pagination">Page ' . esc_html( $page ) . ' of ' . esc_html( $totalPage ) . '</span>' . paginate_links(
331 array(
332 'base' => add_query_arg( 'cpage', '%#%' ),
333 'format' => '',
334 'prev_text' => __( '« prev' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
335 'next_text' => __( 'next »' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
336 'total' => esc_html( $totalPage ),
337 'current' => esc_html( $page ),
338 )
339 ) . '</div>';
340 }
341
342 $deleteurl = admin_url( 'admin.php?page=wbcs-botsessions-page&action=deleteall' );
343 ?>
344
345 <div class="qchero_sliders_list_wrapper qcld-session-history_menu_box">
346 <?php if ( $msg != '' ) : ?>
347 <div class="notice notice-success is-dismissible">
348 <p><?php echo esc_html( $msg ); ?></p>
349 </div>
350 <?php endif; ?>
351
352 <div class="sld_menu_title qcld-session-history_menu_title">
353 <h2><?php echo esc_html__( 'Chat Sessions', 'chatbot' ) . ' (' . intval( $total ) . ')'; ?></h2>
354 </div>
355
356 <div>
357 <?php
358 if ( isset( $_GET['FilterDate'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
359 $filterText = '';
360 if ( $_GET['FilterDate'] === 'LastWeek' ) { $filterText = 'LAST WEEK'; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended
361 if ( $_GET['FilterDate'] === 'LastMonth' ) { $filterText = 'LAST MONTH'; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended
362 if ( $_GET['FilterDate'] === 'Last3Months' ) { $filterText = 'LAST 3 MONTHS'; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended
363 echo '<div class="sld_menu_title"><em>Filtering Records by: <strong>' . esc_html( $filterText ) . '</strong></em></div>';
364 }
365 ?>
366 </div>
367
368
369 <form id="wpcs_form_sessions" action="<?php echo esc_url( $mainurl ); ?>" method="POST" style="width:98%">
370 <?php wp_nonce_field( 'wpcs_bulk_action' ); ?>
371 <input type="hidden" name="wpbot_session_remove" />
372
373 <?php if ( ! empty( $result ) ) : ?>
374 <?php require_once QCLD_CHATBOT_FREE_SESSION_DIR_PATH . 'reports/view/partials/chatsession-table.php'; ?>
375 <?php else : ?>
376 <div class="sld_menu_title"><h2>No result found.</h2></div>
377 <?php endif; ?>
378 </form>
379 </div>
380 <?php
381 }
382 }
383
384 // ─── Request Handler (delete, export, redirect) ───────────────────────────────
385 add_action( 'init', 'qc_wp_cs_request_handle_free' );
386
387 function qc_wp_cs_request_handle_free() {
388 if ( ! is_admin() || ! current_user_can( 'manage_options' ) ) {
389 return;
390 }
391
392 global $wpdb;
393 $wpdb->show_errors = true; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
394
395 $tableuser1 = $wpdb->prefix . 'wpbot_user'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
396 $tableconversation1 = $wpdb->prefix . 'wpbot_conversation'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
397 $table = $wpdb->prefix . 'wpbot_failed_response'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
398
399 // Delete single "not answered" record.
400 if ( isset( $_GET['page'] ) && $_GET['page'] == 'wbcs-botsessions-notansweredpage' && isset( $_GET['act'] ) && $_GET['act'] == 'delete' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
401 $userid = intval( $_GET['id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
402 check_admin_referer( 'wpcs_delete_session_' . $userid );
403 $wpdb->delete( $table, array( 'id' => $userid ), array( '%d' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
404 wp_safe_redirect( admin_url( 'admin.php?page=wbcs-botsessions-notansweredpage&msg=success' ) );
405 exit;
406 }
407
408 // Delete single chat session.
409 if ( isset( $_GET['page'] ) && $_GET['page'] == 'wbcs-botsessions-page' && isset( $_GET['act'] ) && $_GET['act'] == 'delete' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
410 $userid = intval( $_GET['userid'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
411 check_admin_referer( 'wpcs_delete_session_' . $userid );
412 $wpdb->delete( $tableuser1, array( 'id' => $userid ), array( '%d' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
413 $wpdb->delete( $tableconversation1, array( 'user_id' => $userid ), array( '%d' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
414 wp_safe_redirect( admin_url( 'admin.php?page=wbcs-botsessions-page&msg=success' ) );
415 exit;
416 }
417
418 // Export all sessions as CSV.
419 if ( isset( $_POST['wpbot_session_export_all'] ) && isset( $_POST['wpbot_session_remove'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
420 check_admin_referer( 'wpcs_bulk_action' );
421 $users = $wpdb->get_results( "SELECT wu.`id`, wu.`session_id`, wu.`name`, wu.`email`, wu.`date`, wu.`phone`, wu.`interaction`, wc.`conversation` FROM $tableuser1 as wu, $tableconversation1 as wc WHERE 1 AND wu.id = wc.user_id LIMIT 5000" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
422 $sessions = array();
423 if ( ! empty( $users ) ) {
424 foreach ( $users as $user ) {
425 $sessions[] = wpbot_conversations_export( $user );
426 }
427 }
428 qcld_wpbot_chatsession_download_send_headers( 'wpbot_chatsession_' . date( 'Y-m-d' ) . '.csv' );
429 print wpbot_chatsession_array2csv( $sessions ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- raw CSV download, escaping would corrupt the file.
430 exit;
431 }
432
433 // Export selected sessions or delete selected sessions.
434 if ( isset( $_POST['wpbot_session_remove'] ) && ! empty( $_POST['sessions'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
435 check_admin_referer( 'wpcs_bulk_action' );
436 $userids = array_map( 'intval', $_POST['sessions'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
437
438 if ( isset( $_POST['wpbot_session_export'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
439 $sessions = array();
440 foreach ( $userids as $userid ) {
441 $user = $wpdb->get_row( $wpdb->prepare( "SELECT wu.`id`, wu.`session_id`, wu.`name`, wu.`email`, wu.`date`, wu.`phone`, wu.`interaction`, wc.`conversation` FROM $tableuser1 as wu, $tableconversation1 as wc WHERE 1 AND wu.id = wc.user_id AND wu.id = %d", $userid ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
442 $sessions[] = wpbot_conversations_export( $user );
443 }
444 qcld_wpbot_chatsession_download_send_headers( 'wpbot_chatsession_' . date( 'Y-m-d' ) . '.csv' );
445 print wpbot_chatsession_array2csv( $sessions ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- raw CSV download, escaping would corrupt the file.
446 exit;
447 }
448
449 if ( isset( $_POST['wpbot_session_delete'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
450 foreach ( $userids as $userid ) {
451 $wpdb->delete( $tableuser1, array( 'id' => $userid ), array( '%d' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
452 $wpdb->delete( $tableconversation1, array( 'user_id' => $userid ), array( '%d' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
453 }
454 wp_safe_redirect( admin_url( 'admin.php?page=wbcs-botsessions-page&msg=success' ) );
455 exit;
456 }
457 }
458 }
459
460 // ─── Admin Footer: Email Modal ────────────────────────────────────────────────
461 add_action( 'admin_footer', 'wpcs_admin_footer_content_free' );
462
463 function wpcs_admin_footer_content_free() {
464 if ( isset( $_GET['page'] ) && $_GET['page'] == 'wbcs-botsessions-page' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
465 ?>
466 <div id="wpcsmyModal" class="wpcsmodal">
467 <div class="wpcsmodal-content">
468 <span class="wpcsclose">&times;</span>
469 <h2><?php echo esc_html( 'Send an Email to' ); ?> <span id="wpcs_show_email"></span></h2>
470 <div class="wpcs_form_container">
471 <form id="wpcs_email_form" action="">
472 <label for="fname"><?php echo esc_html( 'Subject' ); ?></label>
473 <input type="text" class="wpcs_text_field" id="wpcs_email_subject" name="wpcs_email_subject" placeholder="Subject.." required>
474 <label for="lname"><?php echo esc_html( 'Your Message' ); ?></label>
475 <textarea id="wpcs_email_message" class="wpcs_text_field" name="wpcs_email_message" placeholder="" style="height:200px" required></textarea>
476 <input type="hidden" id="wpcs_to_email_address" value="" />
477 <input type="submit" class="wpcs_submit_field" id="wpcs_email_submit" value="Submit">
478 <span id="wpcs_email_loading" style="display:none;"><img style="width:20px;" src="<?php echo esc_url( QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'images/ajax-loader.gif' ); ?>"></span>
479 <span id="wpcs_email_status"></span>
480 </form>
481 </div>
482 </div>
483 </div>
484 <?php
485 }
486 }
487
488 // ─── AJAX: Send Email to User ─────────────────────────────────────────────────
489 add_action( 'wp_ajax_wpcs_send_email', 'wpcs_send_email' );
490
491 function wpcs_send_email() {
492 if ( ! current_user_can( 'manage_options' ) ) {
493 wp_die();
494 }
495 check_ajax_referer( 'wpbot_session_ajax_nonce', 'security' );
496
497 $subject = sanitize_text_field( $_POST['data']['subject'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
498 $message = sanitize_text_field( $_POST['data']['message'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
499 $to = sanitize_email( $_POST['data']['to'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
500
501 global $wpdb;
502 $tableuser = $wpdb->prefix . 'wpbot_user';
503 $user_exists = $wpdb->get_var( $wpdb->prepare( 'SELECT id FROM %i WHERE email = %s LIMIT 1', $tableuser, $to ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
504 $admin_email = get_option('admin_email');
505 if ( ! $user_exists && $to !== $admin_email ) {
506 wp_send_json( array( 'status' => 'fail', 'message' => 'Invalid recipient address. Email must be a stored session email or admin email.' ) );
507 }
508
509 $url = get_site_url();
510 $url = wp_parse_url( $url );
511 $domain = $url['host'];
512 $fromEmail = 'wordpress@' . $domain;
513 $headers = array(
514 'Content-Type: text/html; charset=UTF-8',
515 'From: ' . esc_html( $domain ) . ' <' . esc_html( $fromEmail ) . '>',
516 );
517
518 $result = wp_mail( $to, $subject, $message, $headers );
519 if ( $result ) {
520 $response = array( 'status' => 'success', 'message' => 'Email has been sent successfully!' );
521 } else {
522 $response = array( 'status' => 'fail', 'message' => 'Unable to send email. Please contact your server administrator.' );
523 }
524 ob_clean();
525 echo wp_json_encode( $response );
526 die();
527 }
528
529 // ─── AJAX: Save Email Notification Preference ─────────────────────────────────
530 add_action( 'wp_ajax_session_email_notification_update', 'session_email_notification_update_free' );
531
532 function session_email_notification_update_free() {
533 if ( ! current_user_can( 'manage_options' ) ) {
534 wp_die();
535 }
536 $email_notification = sanitize_text_field( $_POST['email_notification'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
537 update_option( 'session_email_notification_update', $email_notification );
538 wp_send_json( array( 'success' => true ) );
539 }
540
541 // ─── AJAX: Conversation Save (Frontend) ──────────────────────────────────────
542 // This is the main conversation-save handler. Guarded with function_exists
543 // so the Pro addon's definition wins if it's active.
544 if ( ! function_exists( 'qcld_wb_chatbot_conversation_save' ) ) {
545
546 function qcld_wb_chatbot_conversation_save() {
547
548 check_ajax_referer( 'qcsecretbotnonceval123qc', 'security' );
549 global $wpdb;
550
551 $tableuser = $wpdb->prefix . 'wpbot_user'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
552 $tableconversation = $wpdb->prefix . 'wpbot_conversation'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
553
554 $allowed_html = array_merge(
555 wp_kses_allowed_html( 'post' ),
556 array(
557 'div' => array( 'class' => true, 'id' => true, 'style' => true, 'data-*' => true ),
558 'span' => array( 'class' => true, 'id' => true, 'style' => true, 'data-*' => true ),
559 'ul' => array( 'class' => true ),
560 'li' => array( 'class' => true ),
561 'img' => array( 'src' => true, 'alt' => true, 'class' => true, 'style' => true ),
562 )
563 );
564 $raw_conversation = isset( $_POST['conversation'] ) ? wp_unslash( $_POST['conversation'] ) : '';
565 $clean_conversation = wp_kses( $raw_conversation, $allowed_html );
566 $conversation = qcld_wpbot_input_validation( $clean_conversation ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
567 $email = isset( $_POST['email'] ) ? sanitize_email( $_POST['email'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
568 $phone = isset( $_POST['phone'] ) ? sanitize_text_field( $_POST['phone'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
569 $name = isset( $_POST['name'] ) ? sanitize_text_field( $_POST['name'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
570 $session_id = isset( $_POST['session_id'] ) ? sanitize_text_field( $_POST['session_id'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
571 $wpuser_id = isset( $_POST['user_id'] ) ? sanitize_text_field( $_POST['user_id'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
572 $source_url = isset( $_POST['source_url'] ) && ! empty( $_POST['source_url'] ) ? sanitize_url( wp_unslash( $_POST['source_url'] ) ) : ( isset( $_SERVER['HTTP_REFERER'] ) ? sanitize_url( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : '' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
573 $user_agent = isset( $_POST['user_agent'] ) && ! empty( $_POST['user_agent'] ) ? sanitize_text_field( wp_unslash( $_POST['user_agent'] ) ) : ( isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
574 $session_mailed = isset( $_POST['session_mailed'] ) ? sanitize_text_field( $_POST['session_mailed'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
575
576 // Prepend source URL to conversation.
577 $conversation = '&#x3C;ul&#x3E;&#x3C;li class=&#x22;session_start_url&#x22;&#x3E;&#x3C;span&#x3E;Source URL: &#x3C;/span&#x3E;&#x3C;a href=&#x22;' . $source_url . '&#x22;&#x3E;' . $source_url . '&#x3C;/a&#x3E;&#x3C;/li&#x3E;&#x3C;/ul&#x3E;' . $conversation;
578
579 $response = array();
580 $response['status'] = 'success';
581
582 $user_exists = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $tableuser WHERE 1 AND session_id = %s", $session_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
583 $is_new_insert = false;
584
585 if ( empty( $user_exists ) ) {
586 $lock_key = 'wpcs_lock_' . md5( $session_id );
587 if ( add_option( $lock_key, '1', '', 'no' ) ) {
588 $interaction = (int) substr_count( $conversation, 'wp-chat-user-msg' );
589 if ( $interaction == 0 ) {
590 $interaction = (int) substr_count( $conversation, 'woo-chat-user-msg' );
591 }
592
593 if ( $interaction != 0 ) {
594 $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
595 $tableuser,
596 array(
597 'date' => current_time( 'mysql' ),
598 'name' => $name,
599 'email' => $email,
600 'phone' => $phone,
601 'session_id' => $session_id,
602 'interaction' => $interaction,
603 'user_id' => $wpuser_id,
604 )
605 );
606 $user_id = $wpdb->insert_id; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
607 $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
608 $tableconversation,
609 array(
610 'user_id' => $user_id,
611 'conversation' => $conversation,
612 'interaction' => $interaction,
613 'environment_info' => $user_agent,
614 )
615 );
616 $is_new_insert = true;
617 }
618 delete_option( $lock_key );
619 } else {
620 $retries = 3;
621 while ( $retries > 0 ) {
622 usleep( 500000 );
623 $user_exists = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $tableuser WHERE 1 AND session_id = %s", $session_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
624 if ( ! empty( $user_exists ) ) {
625 break;
626 }
627 $retries--;
628 }
629 }
630 }
631
632 if ( ! $is_new_insert && ! empty( $user_exists ) ) {
633 $interaction = (int) substr_count( $conversation, 'wp-chat-user-msg' );
634 if ( $interaction == 0 ) {
635 $interaction = (int) substr_count( $conversation, 'woo-chat-user-msg' );
636 }
637
638 $user_id = isset( $user_exists->id ) ? $user_exists->id : get_current_user_id();
639 $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
640 $tableuser,
641 array(
642 'date' => current_time( 'mysql' ),
643 'name' => $name,
644 'email' => $email,
645 'phone' => $phone,
646 'interaction' => $interaction,
647 'user_id' => $wpuser_id,
648 ),
649 array( 'id' => $user_id ),
650 array( '%s', '%s', '%s', '%s', '%d', '%d' ),
651 array( '%d' )
652 );
653 $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
654 $tableconversation,
655 array(
656 'conversation' => $conversation,
657 'interaction' => $interaction,
658 ),
659 array( 'user_id' => $user_id ),
660 array( '%s', '%d' ),
661 array( '%d' )
662 );
663 }
664
665 // Email notification for new session.
666 if ( $is_new_insert && ( get_option( 'session_email_notification_update' ) == 'checked' ) ) {
667 $admin_email = get_option( 'admin_email' );
668 $subject = esc_html__( 'Someone has started a new chat session with ChatBot.', 'chatbot' );
669 $bodyContent = '<p>' . esc_html__( 'Hi,', 'chatbot' ) . '</p>';
670 $bodyContent .= '<p>' . esc_html__( 'Someone has started a new chat session with ChatBot. Please go to ', 'chatbot' ) . '<a href="' . admin_url() . 'admin.php?page=wbcs-botsessions-page&userid='. $user_id .'">' . esc_html__( 'Bot Sessions Dashboard', 'chatbot' ) . '</a>' . esc_html__( ' and find him/her.', 'chatbot' ) . '</p>';
671
672 $bodyContent .= '<ul>';
673 $bodyContent .= '<li>' . esc_html__( 'Session ID:', 'chatbot' ) . ' <strong>' . esc_html( $session_id ) . '</strong></li>';
674 if ( ! empty( $email ) ) {
675 $bodyContent .= '<li>' . esc_html__( 'Email:', 'chatbot' ) . ' <strong>' . esc_html( $email ) . '</strong></li>';
676 }
677 if ( ! empty( $phone ) ) {
678 $bodyContent .= '<li>' . esc_html__( 'Phone:', 'chatbot' ) . ' <strong>' . esc_html( $phone ) . '</strong></li>';
679 }
680 if ( ! empty( $source_url ) ) {
681 $bodyContent .= '<li>' . esc_html__( 'Page Link:', 'chatbot' ) . ' <strong><a href="' . esc_url( $source_url ) . '">' . esc_html( $source_url ) . '</a></strong></li>';
682 }
683 if ( ! empty( $user_agent ) ) {
684 $bodyContent .= '<li>' . esc_html__( 'Browser:', 'chatbot' ) . ' <strong>' . esc_html( $user_agent ) . '</strong></li>';
685 }
686 $bodyContent .= '</ul>';
687
688 $bodyContent .= '<p>' . esc_html__( 'Thanks', 'chatbot' ) . '</p>';
689 $bodyContent .= '<p>' . esc_html__( '(You can disable email notifications from ', 'chatbot' ) . '<a href="' . admin_url() . 'admin.php?page=wbcs-botsessions-page">' . esc_html__( 'Bot - Sessions)', 'chatbot' ) . '</a></p>';
690
691 $to = get_option( 'qlcd_wp_chatbot_admin_email' ) != '' ? get_option( 'qlcd_wp_chatbot_admin_email' ) : $admin_email;
692 $headers = array( 'Content-Type: text/html; charset=UTF-8' );
693 wp_mail( $to, $subject, $bodyContent, $headers );
694 }
695
696 // WPBot Automator Trigger - Debounced by 3 minutes
697 $cron_args = array( $session_id );
698 if ( wp_next_scheduled( 'wpbot_automator_delayed_trigger', $cron_args ) ) {
699 wp_clear_scheduled_hook( 'wpbot_automator_delayed_trigger', $cron_args );
700 }
701 wp_schedule_single_event( time() + 60, 'wpbot_automator_delayed_trigger', $cron_args );
702
703 echo wp_json_encode( $response );
704 die();
705 }
706 }
707 add_action( 'wp_ajax_qcld_wb_chatbot_conversation_save', 'qcld_wb_chatbot_conversation_save' );
708 add_action( 'wp_ajax_nopriv_qcld_wb_chatbot_conversation_save', 'qcld_wb_chatbot_conversation_save' );
709
710 // ─── AJAX: Date Filter ────────────────────────────────────────────────────────
711 add_action( 'wp_ajax_qcld_chatbot_session_date_filter', 'qcld_chatbot_session_date_filter_free' );
712
713 function qcld_chatbot_session_date_filter_free() {
714 if ( ! current_user_can( 'manage_options' ) ) {
715 wp_die();
716 }
717 check_ajax_referer( 'wpbot_session_ajax_nonce', 'security' );
718 global $wpdb;
719 $tableuser = $wpdb->prefix . 'wpbot_user'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
720 $start_date = sanitize_text_field( $_POST['start_date'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
721 $end_date = sanitize_text_field( $_POST['end_date'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
722 $result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $tableuser WHERE date BETWEEN %s AND %s", $start_date, $end_date ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
723 echo wp_json_encode( $result );
724 wp_die();
725 }
726
727 // ─── AJAX: Email Transcript ───────────────────────────────────────────────────
728 add_action( 'wp_ajax_wpbot_send_email_transcript', 'wpbot_send_email_transcript_free' );
729
730 function wpbot_send_email_transcript_free() {
731 if ( ! current_user_can( 'manage_options' ) ) {
732 wp_send_json( array( 'status' => 'fail', 'message' => 'Unauthorized' ) );
733 }
734 check_ajax_referer( 'wpbot_session_ajax_nonce', 'security' );
735
736 global $wpdb;
737
738 $session = trim( sanitize_text_field( $_POST['session'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
739
740 $url = wp_parse_url( get_site_url() );
741 $domain = $url['host'];
742 $admin_email = get_option( 'admin_email' );
743 $fromEmail = get_option( 'qlcd_wp_chatbot_from_email' ) ? get_option( 'qlcd_wp_chatbot_from_email' ) : 'wordpress@' . $domain;
744 $subject = 'Chat transcript by ' . get_bloginfo( 'name' );
745
746 $tableuser = $wpdb->prefix . 'wpbot_user'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
747 $tableconversation = $wpdb->prefix . 'wpbot_conversation'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
748
749 $user = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $tableuser WHERE 1 AND session_id = %s", $session ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
750
751 $response = array( 'status' => 'fail', 'message' => 'Session not found.' );
752
753 if ( ! empty( $user ) ) {
754 $email = sanitize_email( $user->email ); // Use email from user record
755 if ( empty( $email ) ) {
756 wp_send_json( array( 'status' => 'fail', 'message' => 'User has no email.' ) );
757 }
758
759 $result = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $tableconversation WHERE 1 AND user_id = %d", $user->id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
760 $bodyContent = '';
761 $bodyContent .= '<p><strong>' . esc_html__( 'User Details', 'chatbot' ) . ':</strong></p><hr>';
762 $bodyContent .= '<p>' . esc_html__( 'Name', 'chatbot' ) . ' : ' . esc_html( $user->name ) . '</p>';
763 $bodyContent .= '<p>' . esc_html__( 'Email', 'chatbot' ) . ' : ' . esc_html( $email ) . '</p>';
764 $bodyContent .= '<p><b>Conversations</b></p><p>-----------------------</p>';
765 $messages = qcld_wpch_conversation_extract( htmlspecialchars_decode( $result->conversation ) );
766 foreach ( $messages as $message ) {
767 if ( isset( $message['bot'] ) && trim( $message['bot'] ) != '' ) {
768 $bodyContent .= '<p>Chatbot : ' . esc_html( trim( $message['bot'] ) ) . '</p>';
769 }
770 if ( isset( $message['user'] ) && trim( $message['user'] ) != '' ) {
771 $bodyContent .= '<p>' . esc_html( $user->name ) . ' : ' . esc_html( trim( $message['user'] ) ) . '</p>';
772 }
773 }
774 $bodyContent .= '<p>-----------------------</p>';
775 $bodyContent .= '<p>Mail Generated on: ' . current_time( 'F j, Y, g:i a' ) . '</p>';
776 $headers = array(
777 'Content-Type: text/html; charset=UTF-8',
778 'From: ' . esc_html( $user->name ) . ' <' . esc_html( $fromEmail ) . '>',
779 'Reply-To: ' . esc_html( $user->name ) . ' <' . esc_html( $email ) . '>',
780 );
781 $result_mail = wp_mail( $email, $subject, $bodyContent, $headers );
782 if ( $result_mail ) {
783 $response = array( 'status' => 'success', 'message' => 'Email transcript sent successfully.' );
784 }
785 }
786 echo wp_json_encode( $response );
787 die();
788 }
789
790 // ─── AJAX: Forward Session to Email ──────────────────────────────────────────
791 add_action( 'wp_ajax_forward_session_to_email', 'forward_session_to_email_free' );
792
793 function forward_session_to_email_free() {
794 if ( ! current_user_can( 'manage_options' ) ) {
795 wp_send_json( array( 'success' => false, 'msg' => esc_html__( 'Insufficient permissions', 'chatbot' ) ) );
796 wp_die();
797 }
798 check_ajax_referer( 'wpbot_session_ajax_nonce', 'security' );
799 global $wpdb;
800
801 $session_id = sanitize_text_field( $_POST['session_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
802 $to = sanitize_email( $_POST['email'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
803 $tableuser = $wpdb->prefix . 'wpbot_user'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
804 $tableconversation = $wpdb->prefix . 'wpbot_conversation'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
805
806 $userinfo = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $tableuser WHERE 1 AND session_id = %s", $session_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
807 $result = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $tableconversation WHERE 1 AND user_id = %d", $userinfo->id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
808
809 if ( ! empty( $result ) ) {
810 $raw_html = isset( $result->conversation ) ? (string) $result->conversation : '';
811 $decoded_content = html_entity_decode( $raw_html );
812 $doc = new DOMDocument();
813 libxml_use_internal_errors( true );
814 $doc->loadHTML( '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . $decoded_content );
815 libxml_clear_errors();
816
817 $decoded_content = '';
818 $body_nodes = $doc->getElementsByTagName( 'body' );
819 if ( $body_nodes->length > 0 ) {
820 foreach ( $body_nodes->item( 0 )->childNodes as $child_node ) {
821 $decoded_content .= $doc->saveHTML( $child_node );
822 }
823 }
824
825 $email_body = '<!DOCTYPE html><html><head><style>
826 .wp-chatbot-messages-container { list-style: none; padding: 20px; background: #f4f7f6; font-family: sans-serif; }
827 .wp-chatbot-msg { margin-bottom: 15px; display: flex; flex-wrap: wrap; }
828 .wp-chatbot-agent { font-weight: bold; color: #333; display: block; margin-bottom: 4px; }
829 .wp-chatbot-paragraph { background: #ffffff; padding: 10px; border-radius: 8px; border: 1px solid #ddd; flex: 1; }
830 .wp-chat-user-msg { display: flex; flex-wrap: wrap; flex-direction: row-reverse; }
831 .wp-chat-user-msg .wp-chatbot-paragraph { background: #ffffff; padding: 10px; border-radius: 8px; border: 1px solid #ddd; flex: none; }
832 body ul { width:100%; max-width: 640px; list-style: none; padding: 0; margin: 0 auto; }
833 </style></head><body>' . $decoded_content . '</body></html>';
834
835 $subject = isset( $_POST['subject'] ) ? sanitize_text_field( wp_unslash( $_POST['subject'] ) ) : 'Chat Session Transcript'; // phpcs:ignore WordPress.Security.NonceVerification.Missing
836 if ( empty( $subject ) ) { $subject = 'Chat Session Transcript'; }
837 $headers = array( 'Content-Type: text/html; charset=UTF-8' );
838 wp_mail( $to, $subject, $email_body, $headers );
839 wp_send_json( array( 'success' => true, 'msg' => esc_html__( 'Session has been forwarded to email successfully', 'chatbot' ) ) );
840 wp_die();
841 } else {
842 wp_send_json( array( 'success' => false, 'msg' => esc_html__( 'No conversation found for this session', 'chatbot' ) ) );
843 wp_die();
844 }
845 }
846
847 // ─── AJAX: Session Hover Details ─────────────────────────────────────────────
848 add_action( 'wp_ajax_wpbot_session_hover_details', 'wpbot_session_hover_details_free' );
849
850 function wpbot_session_hover_details_free() {
851 if ( ! current_user_can( 'manage_options' ) ) {
852 wp_send_json( array( 'success' => false, 'msg' => esc_html__( 'Insufficient permissions', 'chatbot' ) ) );
853 wp_die();
854 }
855 check_ajax_referer( 'wpbot_session_ajax_nonce', 'security' );
856 global $wpdb;
857 $session_id = sanitize_text_field( $_POST['session_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
858 $tableconversation = $wpdb->prefix . 'wpbot_conversation';
859 $tableuser = $wpdb->prefix . 'wpbot_user';
860 $email_from = get_option( 'qlcd_wp_chatbot_from_email' );
861 $result = $wpdb->get_row( $wpdb->prepare( "SELECT c.*, u.email, u.name, u.session_id as user_session_id FROM $tableconversation AS c LEFT JOIN $tableuser AS u ON c.user_id = u.id WHERE c.user_id = %d", $session_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
862 if ( ! empty( $result ) ) {
863 $result->email_from = $email_from;
864 $result->status = 'success';
865 }
866 echo wp_json_encode( $result );
867 wp_die();
868 }
869
870 // ─── AJAX: Send Reply Email ───────────────────────────────────────────────────
871 add_action( 'wp_ajax_wpbot_send_reply_email', 'wpbot_send_reply_email_free' );
872
873 function wpbot_send_reply_email_free() {
874 if ( ! current_user_can( 'manage_options' ) ) {
875 wp_send_json( array( 'success' => false, 'msg' => esc_html__( 'Insufficient permissions', 'chatbot' ) ) );
876 wp_die();
877 }
878 check_ajax_referer( 'wpbot_session_ajax_nonce', 'security' );
879
880 $to = isset( $_POST['email'] ) ? sanitize_email( $_POST['email'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
881 $from_raw = isset( $_POST['from_email'] ) ? trim( wp_unslash( $_POST['from_email'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
882 $from = sanitize_email( $from_raw );
883 $subject = isset( $_POST['subject'] ) ? sanitize_text_field( wp_unslash( $_POST['subject'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
884 $message = isset( $_POST['message'] ) ? wp_kses_post( wp_unslash( $_POST['message'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
885
886 if ( empty( $to ) || empty( $message ) ) {
887 wp_send_json( array( 'success' => false, 'msg' => esc_html__( 'Email and Message are required', 'chatbot' ) ) );
888 wp_die();
889 }
890
891 // if ( ! empty( $from_raw ) && ( $from_raw !== $from || ! is_email( $from ) ) ) {
892 // wp_send_json( array( 'success' => false, 'msg' => esc_html__( 'Please enter a valid From email address', 'chatbot' ) ) );
893 // wp_die();
894 // }
895
896 $headers = array( 'Content-Type: text/html; charset=UTF-8' );
897 if ( ! empty( $from ) && is_email( $from ) ) {
898 $headers[] = 'From: ' . $from;
899 }
900
901 // Convert newlines to HTML line breaks
902 $email_body = nl2br( $message );
903
904 $sent = wp_mail( $to, $subject, $email_body, $headers );
905
906 if ( $sent ) {
907 wp_send_json( array( 'success' => true, 'msg' => esc_html__( 'Email replied successfully', 'chatbot' ) ) );
908 } else {
909 wp_send_json( array( 'success' => false, 'msg' => esc_html__( 'Failed to send email', 'chatbot' ) ) );
910 }
911 wp_die();
912 }
913
914 // ─── AJAX: Save Cron Settings ─────────────────────────────────────────────────
915 add_action( 'wp_ajax_wpbot_seesion_corn_save', 'wpbot_seesion_corn_save_free' );
916
917 function wpbot_seesion_corn_save_free() {
918 if ( ! current_user_can( 'manage_options' ) ) {
919 wp_send_json( array( 'success' => false, 'msg' => esc_html__( 'Insufficient permissions', 'chatbot' ) ) );
920 wp_die();
921 }
922
923 $wbsession_ai_enabled = isset( $_POST['ai_enabled'] ) ? sanitize_text_field( $_POST['ai_enabled'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
924 $wbsession_corn_schedule_interval = isset( $_POST['corn_schedule_interval'] ) ? sanitize_text_field( $_POST['corn_schedule_interval'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
925 $qcld_wpsession_corn_promt = isset( $_POST['qcld_wpsession_corn_promt'] ) ? sanitize_text_field( $_POST['qcld_wpsession_corn_promt'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
926 $qcld_wbsession_corn_starttime = isset( $_POST['qcld_wbsession_corn_starttime'] ) ? sanitize_text_field( $_POST['qcld_wbsession_corn_starttime'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
927
928 $openai_enabled = get_option( 'ai_enabled' );
929 $apiKey = get_option( 'open_ai_api_key' );
930
931 if ( $openai_enabled != '1' ) {
932 wp_send_json( array( 'success' => false, 'icon' => 'error', 'response' => esc_html__( 'OpenAI is Not Enabled', 'chatbot' ) ) );
933 wp_die();
934 }
935 if ( $apiKey == '' ) {
936 wp_send_json( array( 'success' => false, 'icon' => 'error', 'response' => esc_html__( 'OpenAI API key is not set', 'chatbot' ) ) );
937 wp_die();
938 }
939
940 update_option( 'qcld_wbsession_ai_enable', $wbsession_ai_enabled );
941 update_option( 'qcld_wbsession_corn_interval', $wbsession_corn_schedule_interval );
942 update_option( 'qcld_wbsession_corn_starttime', $qcld_wbsession_corn_starttime );
943 update_option( 'qcld_wpsession_corn_promt', $qcld_wpsession_corn_promt );
944
945 wp_clear_scheduled_hook( 'qcld_wpsession_mysql_scraper_event' );
946 wp_send_json( array( 'success' => true, 'icon' => 'success', 'response' => esc_html__( 'Settings Saved Successfully', 'chatbot' ) ) );
947 wp_die();
948 }
949
950 // ─── AJAX: Manual AI Scraper ──────────────────────────────────────────────────
951 add_action( 'wp_ajax_qcld_chatbot_session_mannual_scraper', 'qcld_chatbot_session_mannual_scraper_free' );
952
953 if ( ! function_exists( 'qcld_chatbot_session_mannual_scraper_free' ) ) {
954 function qcld_chatbot_session_mannual_scraper_free() {
955 if ( ! current_user_can( 'manage_options' ) ) {
956 wp_send_json_error( array( 'msg' => 'Insufficient permissions.' ) );
957 wp_die();
958 }
959 if ( get_option( 'qcld_wbsession_ai_enable' ) != '1' ) {
960 wp_send_json( array( 'success' => false, 'icon' => 'error', 'response' => esc_html__( 'AI Insight is not enabled.', 'chatbot' ) ) );
961 wp_die();
962 }
963
964 global $wpdb;
965 $num = isset( $_POST['wpchatbot_session_mannual_number'] ) ? intval( $_POST['wpchatbot_session_mannual_number'] ) : 20; // phpcs:ignore WordPress.Security.NonceVerification.Missing
966 if ( ! is_numeric( $num ) || $num <= 0 ) {
967 wp_send_json( array( 'success' => false, 'icon' => 'error', 'response' => esc_html__( 'Invalid number of sessions.', 'chatbot' ) ) );
968 wp_die();
969 }
970
971 $tableuser = $wpdb->prefix . 'wpbot_user';
972 $tableconversation = $wpdb->prefix . 'wpbot_conversation';
973 $results = $wpdb->get_results( $wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
974 "SELECT u.id, c.user_id, u.date, u.session_id, c.id AS conversation_id, c.conversation
975 FROM $tableuser AS u LEFT JOIN $tableconversation AS c ON u.id = c.user_id
976 ORDER BY u.date DESC LIMIT %d", $num ) // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
977 );
978
979 $remarkable_session = array();
980 foreach ( $results as $row ) {
981 $trimmed = wpsession_message_html_filter_free( htmlspecialchars_decode( $row->conversation ) );
982 $remarkable_session[] = array( 'id' => $row->session_id, 'conversation' => $trimmed );
983 }
984
985 $keyword = get_option( 'qcld_wpsession_corn_promt' ) ?: 'Below is Chat conversation session data from our users on our website. Each conversation starts with an ID. Can you analyze each conversation and summarize each of them? Note down the total number of conversations you analyzed. Create a condensed summary at the end of your report for all the conversations. Point out the important questions asked by the users below the summary and include the IDs for the important points.';
986 $gptkeyword = array(
987 array( 'role' => 'system', 'content' => array( array( 'type' => 'input_text', 'text' => $keyword ) ) ),
988 array( 'role' => 'user', 'content' => array( array( 'type' => 'input_text', 'text' => wp_json_encode( $remarkable_session ) ) ) ),
989 );
990
991 $api_key = get_option( 'open_ai_api_key' );
992 $engines = get_option( 'openai_engines' );
993 $post_fields = array( 'model' => $engines, 'input' => $gptkeyword );
994 $header = array( 'Content-Type: application/json', 'Authorization: Bearer ' . $api_key );
995
996 $ch = curl_init();
997 curl_setopt( $ch, CURLOPT_URL, 'https://api.openai.com/v1/responses' );
998 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
999 curl_setopt( $ch, CURLOPT_POST, 1 );
1000 curl_setopt( $ch, CURLOPT_POSTFIELDS, wp_json_encode( $post_fields ) );
1001 curl_setopt( $ch, CURLOPT_HTTPHEADER, $header );
1002 $result = curl_exec( $ch );
1003 curl_close( $ch );
1004
1005 $mess = json_decode( $result );
1006 if ( ! empty( $mess->error ) ) {
1007 wp_send_json( array( 'status' => 'error', 'icon' => 'error', 'msg' => esc_html( $mess->error->code ), 'response' => esc_html( $mess->error->message ) ) );
1008 wp_die();
1009 }
1010
1011 $msg = isset( $mess->output[0]->content ) ? $mess->output[0]->content[0]->text : ( $mess->output[1]->content[0]->text ?? '' );
1012 $msg = preg_replace( "/\r\n|\r|\n/", '<br/>', $msg );
1013
1014 $to = get_option( 'qlcd_wp_chatbot_admin_email' ) ?: get_option( 'admin_email' );
1015 $headers = array(
1016 'Content-Type: text/html; charset=UTF-8',
1017 'From: ' . esc_html( get_bloginfo( 'name' ) ) . ' <wordpress@' . wp_parse_url( get_site_url(), PHP_URL_HOST ) . '>',
1018 );
1019 wp_mail( $to, 'ChatBot Sessions Analysis', $msg, $headers );
1020
1021 wp_send_json( array( 'status' => 'success', 'icon' => 'success', 'response' => 'Please Check Email for Report' ) );
1022 wp_die();
1023 }
1024 }
1025
1026 // ─── Helper: HTML filter for AI scraper ──────────────────────────────────────
1027 if ( ! function_exists( 'wpsession_message_html_filter_free' ) ) {
1028 function wpsession_message_html_filter_free( $html ) {
1029 $dom = new DOMDocument();
1030 libxml_use_internal_errors( true );
1031 $dom->loadHTML( '<?xml encoding="utf-8" ?>' . $html );
1032
1033 $lis = $dom->getElementsByTagName( 'li' );
1034 $full_conversation = array();
1035 foreach ( $lis as $li ) {
1036 $agentDiv = $li->getElementsByTagName( 'div' )->item( 1 );
1037 $paragraphDiv = $li->getElementsByTagName( 'div' )->item( 2 );
1038 if ( $paragraphDiv ) {
1039 $full_conversation[] = array(
1040 'id' => trim( $agentDiv->textContent ),
1041 'conversation' => trim( $paragraphDiv->textContent ),
1042 );
1043 }
1044 }
1045 return wp_json_encode( $full_conversation );
1046 }
1047 }
1048
1049 // ─── Helper: Conversation Extract ────────────────────────────────────────────
1050 if ( ! function_exists( 'qcld_wpch_conversation_extract' ) ) {
1051 function qcld_wpch_conversation_extract( $html ) {
1052 $doc = new DOMDocument();
1053 libxml_use_internal_errors( true );
1054 $doc->loadHTML( '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . $html );
1055 $lis = iterator_to_array( $doc->getElementsByTagName( 'li' ) );
1056 $messages = array();
1057 foreach ( $lis as $li ) {
1058 if ( strpos( $li->getAttribute( 'class' ), 'wp-chatbot-msg' ) !== false ) {
1059 $messages[]['bot'] = trim( $li->textContent );
1060 }
1061 if ( strpos( $li->getAttribute( 'class' ), 'wp-chat-user-msg' ) !== false ) {
1062 $messages[]['user'] = trim( $li->textContent );
1063 }
1064 }
1065 $messages = array_filter( $messages, function( $val ) {
1066 if ( isset( $val['bot'] ) && empty( $val['bot'] ) ) { return false; }
1067 return true;
1068 } );
1069 return $messages;
1070 }
1071 }
1072
1073 // ─── CSV Export Helpers ───────────────────────────────────────────────────────
1074 add_action( 'admin_post_wpbot_conversations.csv', 'wpbot_conversations_csv_export_free' );
1075
1076 function wpbot_conversations_csv_export_free() {
1077 if ( ! current_user_can( 'manage_options' ) ) {
1078 wp_die( esc_html__( 'Unauthorized', 'wpbot' ) );
1079 }
1080
1081 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'wpbot_conversations_csv' ) ) {
1082 wp_die( esc_html__( 'Security check failed.', 'wpbot' ) );
1083 }
1084
1085 global $wpdb;
1086 $tableuser = $wpdb->prefix . 'wpbot_user'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
1087 $tableconversation = $wpdb->prefix . 'wpbot_conversation'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
1088 $userid = sanitize_text_field( $_GET['user_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1089
1090 $userinfo = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $tableuser WHERE 1 AND id = %d", $userid ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
1091 $result = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $tableconversation WHERE 1 AND user_id = %d", $userid ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
1092 $data = array();
1093
1094 if ( ! empty( $result ) ) {
1095 $data[] = array( 'User Name', $userinfo->name );
1096 $data[] = array( 'User Email', $userinfo->email );
1097 $data[] = array( 'Session ID', $userinfo->session_id );
1098 $data[] = array( 'Date', date( 'M,d,Y h:i:s A', strtotime( $userinfo->date ) ) );
1099 $data[] = array( 'Bot Message', 'User Message' );
1100 $messages = qcld_wpch_conversation_extract( htmlspecialchars_decode( $result->conversation ) );
1101 foreach ( $messages as $message ) {
1102 if ( isset( $message['bot'] ) && trim( $message['bot'] ) != '' ) {
1103 $data[] = array( str_replace( '&nbsp;', ' ', trim( $message['bot'] ) ), '' );
1104 }
1105 if ( isset( $message['user'] ) && trim( $message['user'] ) != '' ) {
1106 $data[] = array( '', str_replace( '&nbsp;', ' ', trim( $message['user'] ) ) );
1107 }
1108 }
1109 }
1110 qcld_wpbot_chatsession_download_send_headers( $userinfo->name . '_wpbot_chatsession_' . date( 'Y-m-d' ) . '.csv' );
1111 print wpbot_chatsession_array2csv( $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- raw CSV download, escaping would corrupt the file.
1112 }
1113
1114 if ( ! function_exists( 'wpbot_conversations_export' ) ) {
1115 function wpbot_conversations_export( $user ) {
1116 $user_id = isset( $user->id ) ? $user->id : $user;
1117 $dataArray = array();
1118 if ( ! empty( $user ) ) {
1119 $messages = qcld_wpch_conversation_extract( htmlspecialchars_decode( $user->conversation ) );
1120 $dataArray = array(
1121 'Session ID' => $user->session_id,
1122 'Date' => date( 'M,d,Y h:i:s A', strtotime( $user->date ) ),
1123 'User Name' => $user->name,
1124 'User Email' => $user->email,
1125 );
1126 $conversations = '';
1127 foreach ( $messages as $message ) {
1128 if ( isset( $message['bot'] ) && trim( $message['bot'] ) != '' ) {
1129 $conversations .= 'Bot Message: ' . str_replace( '&nbsp;', ' ', trim( $message['bot'] ) ) . "\n";
1130 }
1131 if ( isset( $message['user'] ) && trim( $message['user'] ) != '' ) {
1132 $conversations .= 'User Message: ' . str_replace( '&nbsp;', ' ', trim( $message['user'] ) ) . "\n";
1133 }
1134 }
1135 $dataArray['Conversations'] = $conversations;
1136 }
1137 $dataArray['Interaction'] = $user->interaction;
1138 return $dataArray;
1139 }
1140 }
1141
1142 if ( ! function_exists( 'qcld_wpbot_chatsession_download_send_headers' ) ) {
1143 function qcld_wpbot_chatsession_download_send_headers( $filename ) {
1144 $now = gmdate( 'D, d M Y H:i:s' );
1145 header( 'Expires: Tue, 03 Jul 2001 06:00:00 GMT' );
1146 header( 'Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate' );
1147 header( "Last-Modified: {$now} GMT" );
1148 header( 'Content-Encoding: UTF-8' );
1149 header( 'Content-type: text/csv; charset=UTF-8' );
1150 header( "Content-Disposition: attachment;filename={$filename}" );
1151 header( 'Content-Transfer-Encoding: binary' );
1152 }
1153 }
1154
1155 if ( ! function_exists( 'wpbot_chatsession_array2csv' ) ) {
1156 function wpbot_chatsession_array2csv( array &$array ) {
1157 if ( count( $array ) == 0 ) { return null; }
1158 ob_start();
1159 $df = fopen( 'php://output', 'w' );
1160 fputs( $df, chr( 0xEF ) . chr( 0xBB ) . chr( 0xBF ) ); // UTF-8 BOM
1161 foreach ( $array as $data ) {
1162 fputcsv( $df, array_keys( $data ), ',', '"', '\\' );
1163 break;
1164 }
1165 foreach ( $array as $row ) {
1166 fputcsv( $df, $row, ',', '"', '\\' );
1167 }
1168 fclose( $df );
1169 return ob_get_clean();
1170 }
1171 }
1172
1173 // ─── Shortcode: User Session History ─────────────────────────────────────────
1174 if ( ! function_exists( 'qc_current_user_session' ) ) {
1175 function qc_current_user_session() {
1176 $user = wp_get_current_user();
1177 global $wpdb;
1178 $tableuser = $wpdb->prefix . 'wpbot_user';
1179 $conversatios_table = $wpdb->prefix . 'wpbot_conversation';
1180 $result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $tableuser AS u LEFT JOIN $conversatios_table AS c ON u.user_id = c.user_id WHERE u.user_id = %d", $user->ID ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
1181 if ( ! $user->exists() ) {
1182 return '<p>No user logged in.</p>';
1183 }
1184 ob_start(); ?>
1185 <style>
1186 .cell-content #wp-chatbot-messages-container { height: 200px; overflow: scroll; overflow-x: hidden; }
1187 .session_start_url { display: none; }
1188 .table-striped tr { border: 2px solid #888; }
1189 </style>
1190 <table class="table table-striped align-middle" id="chatsession-table">
1191 <thead>
1192 <tr class="table-primary">
1193 <th class="text-left"><?php echo esc_html__( 'Date', 'chatbot' ); ?></th>
1194 <th class="text-left"><?php echo esc_html__( 'Session ID', 'chatbot' ); ?></th>
1195 <th class="text-left"><?php echo esc_html__( 'Name', 'chatbot' ); ?></th>
1196 <th class="text-left" data-dt-order="disable"><?php echo esc_html__( 'Conversation', 'chatbot' ); ?></th>
1197 </tr>
1198 <?php foreach ( $result as $key => $value ) : ?>
1199 <tr>
1200 <td class="text-left"><?php echo esc_html( $value->date ); ?></td>
1201 <td class="text-left"><?php echo esc_html( $value->session_id ); ?></td>
1202 <td class="text-left"><?php echo esc_html( $value->name ); ?></td>
1203 <td class="text-left"><div class="cell-content"><a class="qcld-modal-content" data-value="<?php echo esc_attr( $value->conversation ); ?>">view data</a></div></td>
1204 </tr>
1205 <?php endforeach; ?>
1206 </thead>
1207 </table>
1208 <?php
1209 return ob_get_clean();
1210 }
1211 }
1212 add_shortcode( 'qcpress_user', 'qc_current_user_session' );
1213
1214 // ─── WP-Cron: AI Insight Scheduled Email ─────────────────────────────────────
1215 add_filter( 'cron_schedules', 'qcld_wpsession_wp_cron_schedule_free' );
1216
1217 if ( ! function_exists( 'qcld_wpsession_wp_cron_schedule_free' ) ) {
1218 function qcld_wpsession_wp_cron_schedule_free( $schedules ) {
1219 $schedules['session_schedules'] = array(
1220 'interval' => ( get_option( 'qcld_wbsession_corn_interval' ) != null ) ? get_option( 'qcld_wbsession_corn_interval' ) : 86400,
1221 'display' => esc_attr( 'Session min', 'wpchatbot' ),
1222 );
1223 return $schedules;
1224 }
1225 }
1226
1227 $wpsession_corn_start_times = wp_date( 'Y-m-d' ) . ' ' . get_option( 'qcld_wbsession_corn_starttime' );
1228 $wpsession_corn_start_time = strtotime( $wpsession_corn_start_times );
1229 if ( ! wp_next_scheduled( 'qcld_wpsession_mysql_scraper_event' ) && ( get_option( 'qcld_wbsession_ai_enable' ) == '1' ) ) {
1230 wp_schedule_event( $wpsession_corn_start_time, 'session_schedules', 'qcld_wpsession_mysql_scraper_event' );
1231 }
1232
1233 add_action( 'qcld_wpsession_mysql_scraper_event', 'qcld_wpsession_mysql_scraper_function_free' );
1234
1235 if ( ! function_exists( 'qcld_wpsession_mysql_scraper_function_free' ) ) {
1236 function qcld_wpsession_mysql_scraper_function_free() {
1237 if ( get_option( 'qcld_wbsession_ai_enable' ) != '1' ) { return; }
1238
1239 global $wpdb;
1240 $interval_hours = ( (int) get_option( 'qcld_wbsession_corn_interval' ) ?: 86400 ) / 3600;
1241 $tableuser = $wpdb->prefix . 'wpbot_user';
1242 $tableconversation = $wpdb->prefix . 'wpbot_conversation';
1243 $results = $wpdb->get_results( $wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
1244 "SELECT u.id, c.user_id, u.date, u.session_id, c.id, c.conversation
1245 FROM $tableuser AS u LEFT JOIN $tableconversation AS c ON u.id = c.user_id
1246 WHERE u.date >= (NOW() - INTERVAL %d HOUR) ORDER BY u.date DESC", $interval_hours ) // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1247 );
1248
1249 $remarkable_session = array();
1250 foreach ( $results as $row ) {
1251 $remarkable_session[] = array( 'id' => $row->session_id, 'conversation' => wpsession_message_html_filter_free( htmlspecialchars_decode( $row->conversation ) ) );
1252 }
1253
1254 $keyword = get_option( 'qcld_wpsession_corn_promt' ) ?: 'Below is Chat conversation session data from our users on our website. Each conversation starts with an ID. Can you analyze each conversation and summarize each of them?';
1255 $gptkeyword = array(
1256 array( 'role' => 'system', 'content' => array( array( 'type' => 'input_text', 'text' => $keyword ) ) ),
1257 array( 'role' => 'user', 'content' => array( array( 'type' => 'input_text', 'text' => wp_json_encode( $remarkable_session ) ) ) ),
1258 );
1259
1260 $api_key = get_option( 'open_ai_api_key' );
1261 $engines = get_option( 'openai_engines' );
1262 $post_fields = array( 'model' => $engines, 'input' => $gptkeyword );
1263 $header = array( 'Content-Type: application/json', 'Authorization: Bearer ' . $api_key );
1264
1265 $ch = curl_init();
1266 curl_setopt( $ch, CURLOPT_URL, 'https://api.openai.com/v1/responses' );
1267 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
1268 curl_setopt( $ch, CURLOPT_POST, 1 );
1269 curl_setopt( $ch, CURLOPT_POSTFIELDS, wp_json_encode( $post_fields ) );
1270 curl_setopt( $ch, CURLOPT_HTTPHEADER, $header );
1271 $result = curl_exec( $ch );
1272 curl_close( $ch );
1273
1274 $mess = json_decode( $result );
1275 $msg = isset( $mess->output[0]->content[0]->text ) ? $mess->output[0]->content[0]->text : ( isset( $mess->output[1]->content[0]->text ) ? $mess->output[1]->content[0]->text : 'No response from OpenAI.' );
1276 $msg = preg_replace( "/\r\n|\r|\n/", '<br/>', $msg );
1277
1278 $to = get_option( 'qlcd_wp_chatbot_admin_email' ) ?: get_option( 'admin_email' );
1279 $headers = array(
1280 'Content-Type: text/html; charset=UTF-8',
1281 'From: ' . esc_html( get_bloginfo( 'name' ) ) . ' <wordpress@' . wp_parse_url( get_site_url(), PHP_URL_HOST ) . '>',
1282 );
1283 wp_mail( $to, 'ChatBot Sessions Analysis', $msg, $headers );
1284 }
1285 }
1286
1287 // ─── Reports (Bot - Reports submenu) ─────────────────────────────────────────
1288 require_once QCLD_CHATBOT_FREE_SESSION_DIR_PATH . 'reports/chatbot-history-reporting.php';
1289