PluginProbe
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services / 8.6.2
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services v8.6.2
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.6.2, at includes/chat-sessions/wpbot-chat-sessions.php

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