| @@ -1,362 +1,538 @@ | ||
| 1 | -<?php | |
| 2 | -if (!defined('ABSPATH')) exit; // Exit if accessed directly | |
| 3 | -/** | |
| 4 | - * Common functions class | |
| 5 | - */ | |
| 6 | -class Qcld_WPBot_Common_Functions { | |
| 7 | - | |
| 8 | - | |
| 9 | - private static $instance = null; | |
| 10 | - | |
| 11 | - public static function instance() { | |
| 12 | - if ( is_null( self::$instance ) ) { | |
| 13 | - self::$instance = new self(); | |
| 14 | - } | |
| 15 | - return self::$instance; | |
| 16 | - } | |
| 17 | - | |
| 18 | - private function __construct() { | |
| 19 | - add_action('wp_ajax_wpbot_save_feedback', array( $this, 'wpbot_save_feedback') ); | |
| 20 | - add_action('wp_ajax_nopriv_wpbot_save_feedback', array( $this,'wpbot_save_feedback') ); | |
| 21 | - add_action( 'wp_ajax_wpbot_save_report', array( $this, 'wpbot_save_report') ); | |
| 22 | - add_action( 'wp_ajax_nopriv_wpbot_save_report', array( $this, 'wpbot_save_report') ); | |
| 23 | - add_action('wp_ajax_nopriv_get_relevant_pages', array($this, 'qcld_get_relevant_pages_ajax')); | |
| 24 | - add_action('wp_ajax_rate_limit_settings_option', array($this, 'rate_limit_settings_option_callback')); | |
| 25 | - register_activation_hook(__FILE__, array('qcld_wpopenai_addons', 'schedule_rate_limit_reset_events')); | |
| 26 | - add_filter('cron_schedules', array($this, 'qcld_user_role_rate_cron_schedule')); | |
| 27 | - add_action('rate_limit_checker', array($this, 'rate_limit_checker')); | |
| 28 | - add_action('qcld_openai_user_rate_cal', array($this, 'qcld_openai_user_rate_cal')); | |
| 29 | - add_action('reset_rate_limit_used_counts', [$this, 'reset_rate_limit_used_counts'], 10, 1); | |
| 30 | - | |
| 31 | - } | |
| 32 | - /** | |
| 33 | - * Remove stopwords from search query | |
| 34 | - * | |
| 35 | - * @param string $query The search query | |
| 36 | - * @param array $stopwords Array of stopwords to remove | |
| 37 | - * @return string Query with stopwords removed | |
| 38 | - */ | |
| 39 | - public static function qcpd_remove_wa_stopwords($query, $stopwords) { | |
| 40 | - return preg_replace('/\b('.implode('|',$stopwords).')\b/','',$query); | |
| 41 | - } | |
| 42 | - | |
| 43 | - /** | |
| 44 | - * Get relevant page links based on search query | |
| 45 | - * | |
| 46 | - * @param string $search_query The search query | |
| 47 | - * @return array Array of relevant page links | |
| 48 | - */ | |
| 49 | - public static function qcpd_relevant_pagelink($search_query) { | |
| 50 | - $stopwords = explode(',', get_option('qlcd_wp_chatbot_stop_words')); | |
| 51 | - | |
| 52 | - $finalQueryWordsWithoutStopWords = self::qcpd_remove_wa_stopwords(strtolower($search_query), $stopwords); | |
| 53 | - | |
| 54 | - $cleanWordsWithoutPunctuationMarks = preg_replace('/[\p{P}]/u', '', $finalQueryWordsWithoutStopWords); | |
| 55 | - | |
| 56 | - $q = trim($cleanWordsWithoutPunctuationMarks); | |
| 57 | - | |
| 58 | - $links = []; | |
| 59 | - | |
| 60 | - $post_type_array = get_option('qcld_openai_relevant_post'); | |
| 61 | - | |
| 62 | - $the_query = new WP_Query(array( | |
| 63 | - 'post_status' => 'publish', | |
| 64 | - 'posts_per_page' => 5, | |
| 65 | - 's' => esc_attr($q), | |
| 66 | - 'post_type' => $post_type_array | |
| 67 | - )); | |
| 68 | - | |
| 69 | - if($the_query->have_posts()) { | |
| 70 | - while($the_query->have_posts()) { | |
| 71 | - $the_query->the_post(); | |
| 72 | - | |
| 73 | - $url = esc_url(get_permalink()); | |
| 74 | - $link = '<a href=' . $url . ' target="_blank">' . get_the_title() . '</a>'; | |
| 75 | - array_push($links, $link); | |
| 76 | - } | |
| 77 | - wp_reset_postdata(); | |
| 78 | - } | |
| 79 | - | |
| 80 | - $links = array_unique($links); | |
| 81 | - return $links; | |
| 82 | - } | |
| 83 | - | |
| 84 | - | |
| 85 | - public function wpbot_save_feedback() { | |
| 86 | - check_ajax_referer('wp_chatbot', 'nonce'); | |
| 87 | - global $wpdb; | |
| 88 | - | |
| 89 | - $table = $wpdb->prefix . 'wpbot_chat_report'; | |
| 90 | - | |
| 91 | - $user_id = intval(wp_unslash($_POST['user_id'])); | |
| 92 | - $conversation_id= intval(wp_unslash($_POST['conversation_id'])); | |
| 93 | - $message = sanitize_text_field(wp_unslash($_POST['message'])); | |
| 94 | - $feedback = sanitize_text_field(wp_unslash($_POST['feedback'])); // "like" or "dislike" | |
| 95 | - $meta_info = sanitize_textarea_field(wp_unslash($_POST['meta_info'])); | |
| 96 | - $date = current_time('mysql'); | |
| 97 | - | |
| 98 | - $inserted = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery | |
| 99 | - $table, array( | |
| 100 | - 'user_id' => $user_id, | |
| 101 | - 'conversation_id'=> $conversation_id, | |
| 102 | - 'message' => $message, | |
| 103 | - 'feedback' => $feedback, | |
| 104 | - 'meta_info' => $meta_info, | |
| 105 | - 'created_at' => $date | |
| 106 | - )); | |
| 107 | - | |
| 108 | - if ($inserted !== false) { | |
| 109 | - wp_send_json_success(array('message' => 'Feedback saved.')); | |
| 110 | - } else { | |
| 111 | - wp_send_json_error(array('message' => 'Failed to save feedback.')); | |
| 112 | - } | |
| 113 | - } | |
| 114 | - | |
| 115 | - /** | |
| 116 | - * Save report func | |
| 117 | - * | |
| 118 | - */ | |
| 119 | - | |
| 120 | - | |
| 121 | - public function wpbot_save_report() { | |
| 122 | - check_ajax_referer('wp_chatbot', 'nonce'); | |
| 123 | - global $wpdb; | |
| 124 | - $table_report = $wpdb->prefix . 'wpbot_chat_report'; | |
| 125 | - | |
| 126 | - $email = sanitize_email(wp_unslash($_POST['email'])); | |
| 127 | - $message = sanitize_textarea_field(wp_unslash($_POST['message'])); | |
| 128 | - $report_text = sanitize_textarea_field(wp_unslash($_POST['report_text'])); | |
| 129 | - | |
| 130 | - $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery | |
| 131 | - $table_report, | |
| 132 | - [ | |
| 133 | - 'user_id' => get_current_user_id(), // or match from wpbot_user. | |
| 134 | - 'message' => $message, | |
| 135 | - 'meta_info' => maybe_serialize( [ 'email' => $email, 'report_text' => $report_text ] ), | |
| 136 | - ], | |
| 137 | - [ '%d', '%s', '%s' ] | |
| 138 | - ); | |
| 139 | - | |
| 140 | - // Send report email to admin | |
| 141 | - $admin_email = get_option( 'admin_email' ); | |
| 142 | - $subject = "New Chat Report"; | |
| 143 | - $body = "Reported Message:\n{$message}\n\nReport Text:\n{$report_text}\n\nUser Email: {$email}"; | |
| 144 | - wp_mail( $admin_email, $subject, $body ); | |
| 145 | - | |
| 146 | - wp_send_json_success(); | |
| 147 | - } | |
| 148 | - public function rate_limit_settings_option_callback() | |
| 149 | - { | |
| 150 | - | |
| 151 | - // Check is admin and verify nonce | |
| 152 | - if (! current_user_can('manage_options')) { | |
| 153 | - wp_send_json_error('Unauthorized'); | |
| 154 | - wp_die(); | |
| 155 | - } | |
| 156 | - check_ajax_referer( 'wp_chatbot', 'nonce' ); | |
| 157 | - // Save the rate limiting enabled/disabled setting | |
| 158 | - if (isset($_POST['is_rate_limiting_enabled'])) { | |
| 159 | - $is_rate_limiting_enabled = intval( wp_unslash( $_POST['is_rate_limiting_enabled'] ) ); | |
| 160 | - update_option('is_rate_limiting_enabled', $is_rate_limiting_enabled); | |
| 161 | - } | |
| 162 | - // Save the rate limits for each role | |
| 163 | - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput | |
| 164 | - if (isset($_POST['rate_limits']) && is_array( $_POST['rate_limits'] )) { | |
| 165 | - $rate_limits = array_map( 'sanitize_text_field', wp_unslash( $_POST['rate_limits'] ) ); | |
| 166 | - foreach ($rate_limits as $role => $limit) { | |
| 167 | - $option_name = 'rate_limit_' . sanitize_key( $role ); | |
| 168 | - $limit_value = intval($limit); | |
| 169 | - update_option($option_name, $limit_value); | |
| 170 | - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput | |
| 171 | - $timeframe_raw = isset( $_POST['rate_limit_timeframes'][ $role ] ) ? sanitize_text_field( wp_unslash( $_POST['rate_limit_timeframes'][ $role ] ) ) : '24'; | |
| 172 | - $timeframe = intval($timeframe_raw) * 3600; // Convert hours to seconds | |
| 173 | - update_option('rate_limit_timeframe_' . $role, $timeframe); | |
| 174 | - } | |
| 175 | - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput | |
| 176 | - $guest_timeframe_raw = isset( $_POST['rate_limit_timeframes']['guest'] ) ? sanitize_text_field( wp_unslash( $_POST['rate_limit_timeframes']['guest'] ) ) : '24'; | |
| 177 | - $timeframe = intval($guest_timeframe_raw) * 3600; // Convert hours to seconds | |
| 178 | - update_option('rate_limit_timeframe_guest', $timeframe); | |
| 179 | - } | |
| 180 | - // In your rate_limit_settings_option_callback(), after updating options: | |
| 181 | - $this->schedule_rate_limit_reset_events(); | |
| 182 | - wp_send_json_success('Settings saved'); | |
| 183 | - wp_die(); | |
| 184 | - } | |
| 185 | - public function qcld_user_role_rate_cron_schedule($schedules) | |
| 186 | - { | |
| 187 | - $roles = wp_roles()->roles; | |
| 188 | - foreach ($roles as $role => $details) { | |
| 189 | - $timeframe = intval(get_option('rate_limit_timeframe_' . $role, true)); | |
| 190 | - // Minimum 3600 seconds | |
| 191 | - $schedules['session_schedules_rate_limit_' . $role] = array( | |
| 192 | - 'interval' => $timeframe, | |
| 193 | - 'display' => esc_html( 'session_schedules_rate_limit_' . $role ), | |
| 194 | - ); | |
| 195 | - // Schedule the cron job for each role if not already scheduled); | |
| 196 | - } | |
| 197 | - return $schedules; | |
| 198 | - } | |
| 199 | - // wpshedule event to reset the rate limit used counts | |
| 200 | - public function schedule_rate_limit_reset_events() | |
| 201 | - { | |
| 202 | - // Ensure WordPress cron functions are available | |
| 203 | - if (! function_exists('wp_schedule_event')) { | |
| 204 | - require_once ABSPATH . 'wp-includes/wp-cron.php'; | |
| 205 | - } | |
| 206 | - $roles = wp_roles()->roles; | |
| 207 | - foreach ($roles as $role => $d) { | |
| 208 | - // Unschedule all existing events for this role | |
| 209 | - $timestamp = wp_next_scheduled('reset_rate_limit_used_counts', array($role)); | |
| 210 | - while ($timestamp) { | |
| 211 | - wp_unschedule_event($timestamp, 'reset_rate_limit_used_counts', array($role)); | |
| 212 | - $timestamp = wp_next_scheduled('reset_rate_limit_used_counts', array($role)); | |
| 213 | - } | |
| 214 | - // Schedule new event with updated interval | |
| 215 | - wp_schedule_event(time(), 'session_schedules_rate_limit_' . $role, 'reset_rate_limit_used_counts', array($role)); | |
| 216 | - } | |
| 217 | - } | |
| 218 | - public function qcld_wpsession_cron_deactivation() | |
| 219 | - { | |
| 220 | - $timestamp = wp_next_scheduled('reset_rate_limit_used_counts'); | |
| 221 | - wp_unschedule_event($timestamp, 'reset_rate_limit_used_counts'); | |
| 222 | - } | |
| 223 | - public function rate_limit_checker() | |
| 224 | - { | |
| 225 | - $qlcd_wp_chatbot_ai_rate_limiting_message = qcld_wb_chatbot_func_str_replace( | |
| 226 | - maybe_unserialize(get_option('qlcd_wp_chatbot_ai_rate_limiting_message', true)) | |
| 227 | - ); | |
| 228 | - if (get_option('is_stream_enabled') == 1) { | |
| 229 | - $response = array( | |
| 230 | - 'status' => 'error', | |
| 231 | - 'message' => esc_html( | |
| 232 | - ( is_array( $qlcd_wp_chatbot_ai_rate_limiting_message ) && ! empty( $qlcd_wp_chatbot_ai_rate_limiting_message[0] ) ) | |
| 233 | - ? $qlcd_wp_chatbot_ai_rate_limiting_message[0] | |
| 234 | - : __( 'Rate limit exceeded. Please try again later.', 'chatbot' ) | |
| 235 | - ), | |
| 236 | - ); | |
| 237 | - } else { | |
| 238 | - $response = array( | |
| 239 | - 'status' => 'success', | |
| 240 | - 'message' => esc_html( | |
| 241 | - ( is_array( $qlcd_wp_chatbot_ai_rate_limiting_message ) && ! empty( $qlcd_wp_chatbot_ai_rate_limiting_message[0] ) ) | |
| 242 | - ? $qlcd_wp_chatbot_ai_rate_limiting_message[0] | |
| 243 | - : __( 'Rate limit exceeded. Please try again later.', 'chatbot' ) | |
| 244 | - ), | |
| 245 | - ); | |
| 246 | - } | |
| 247 | - if (is_user_logged_in()) { | |
| 248 | - $user = wp_get_current_user(); | |
| 249 | - if (! empty($user->roles) && is_array($user->roles)) { | |
| 250 | - $role = $user->roles[0]; | |
| 251 | - $option_name = 'rate_limit_' . $role; | |
| 252 | - $limit = get_option($option_name); | |
| 253 | - $rate_limit = get_user_meta(get_current_user_id(), 'qcld_openai_user_rate_limit', true); | |
| 254 | - if (($limit >= $rate_limit) || $limit == 0) { | |
| 255 | - return; // allowed | |
| 256 | - } else { | |
| 257 | - if (get_option('is_stream_enabled') == 1) { | |
| 258 | - wp_send_json($response); //Proper JSON with header. | |
| 259 | - } else { | |
| 260 | - echo json_encode($response); | |
| 261 | - wp_die(); | |
| 262 | - } | |
| 263 | - } | |
| 264 | - } | |
| 265 | - } else { | |
| 266 | - $option_name = 'rate_limit_guest'; | |
| 267 | - $limit = get_option($option_name); | |
| 268 | - | |
| 269 | - if (session_status() == PHP_SESSION_NONE) { | |
| 270 | - session_start(); | |
| 271 | - } | |
| 272 | - | |
| 273 | - $guest_rate_limit = isset($_SESSION['guest_rate_limit']) ? intval($_SESSION['guest_rate_limit']) : 0; | |
| 274 | - | |
| 275 | - if ($limit >= $guest_rate_limit || $limit == 0) { | |
| 276 | - return; // allowed | |
| 277 | - } else { | |
| 278 | - if (get_option('is_stream_enabled') == 1) { | |
| 279 | - wp_send_json($response); //Proper JSON with header. | |
| 280 | - } else { | |
| 281 | - echo json_encode($response); | |
| 282 | - // Return role if limit exceeded | |
| 283 | - wp_die(); | |
| 284 | - } | |
| 285 | - } | |
| 286 | - } | |
| 287 | - } | |
| 288 | - | |
| 289 | - public function reset_rate_limit_used_counts($role) | |
| 290 | - { | |
| 291 | - if (empty($role)) { | |
| 292 | - return; | |
| 293 | - } | |
| 294 | - // Resetting rate limit used counts for role. | |
| 295 | - // loop through each role | |
| 296 | - // for each role get all users with that role | |
| 297 | - $roles = wp_roles()->roles; | |
| 298 | - foreach ($roles as $list_roll => $details) { | |
| 299 | - if ($list_roll != $role) { | |
| 300 | - continue; | |
| 301 | - } else { | |
| 302 | - $option_name = 'rate_limit_' . $role; | |
| 303 | - $limit = get_option($option_name); // Default to if not set | |
| 304 | - $users = get_users(array('role' => $role)); | |
| 305 | - foreach ($users as $user) { | |
| 306 | - update_user_meta($user->ID, 'qcld_openai_user_rate_limit', 0); | |
| 307 | - } | |
| 308 | - } | |
| 309 | - } | |
| 310 | - } | |
| 311 | - public function qcld_openai_user_rate_cal($update) | |
| 312 | - { | |
| 313 | - if (is_user_logged_in()) { | |
| 314 | - $rate_limit = get_user_meta(get_current_user_id(), 'qcld_openai_user_rate_limit', true); | |
| 315 | - if ($update != '') { | |
| 316 | - $rate_limit = intval($rate_limit) + intval($update); | |
| 317 | - } | |
| 318 | - update_user_meta(get_current_user_id(), 'qcld_openai_user_rate_limit', $rate_limit); | |
| 319 | - return; | |
| 320 | - } else { | |
| 321 | - // for guest users we will use session to store the rate limit | |
| 322 | - // if session is not started then start it | |
| 323 | - if (session_status() == PHP_SESSION_NONE) { | |
| 324 | - session_start(); | |
| 325 | - } | |
| 326 | - // we will use guest_id to identify the guest user | |
| 327 | - if (! isset($_SESSION['guest_id'])) { | |
| 328 | - $user_ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : ''; | |
| 329 | - $session_id = md5($user_ip . time()); | |
| 330 | - $_SESSION['guest_id'] = $session_id; | |
| 331 | - $_SESSION['guest_id_time'][$session_id] = time(); | |
| 332 | - get_option('rate_', 10); | |
| 333 | - // if guest_id_time is set and it is older than 24 hours then unset the guest_id | |
| 334 | - // we will store the time when the guest_id was created in session | |
| 335 | - $timeframe = get_option('rate_limit_timeframe_guest', true); | |
| 336 | - $timeframe = intval($timeframe) * 3600; // convert hours to seconds | |
| 337 | - if (isset($_SESSION['guest_id_time'][$session_id]) && (time() - $_SESSION['guest_id_time'][$session_id]) > $timeframe) { | |
| 338 | - unset($_SESSION['guest_id']); | |
| 339 | - unset($_SESSION['guest_id_time']); | |
| 340 | - } | |
| 341 | - // we will store the time when the guest_id was created in session | |
| 342 | - $_SESSION['guest_id_time'][$session_id] = time(); | |
| 343 | - $_SESSION['guest_rate_limit'] = 0; | |
| 344 | - } | |
| 345 | - // update the rate limit | |
| 346 | - // if update is not empty then add it to the existing rate limit else set it | |
| 347 | - if ($update != '') { | |
| 348 | - $guest_rate_limit = isset($_SESSION['guest_rate_limit']) ? intval($_SESSION['guest_rate_limit']) : 0; | |
| 349 | - // add the update to the existing rate limit | |
| 350 | - // set the rate limit in session | |
| 351 | - $_SESSION['guest_rate_limit'] = $guest_rate_limit + $update; | |
| 352 | - return; | |
| 353 | - } | |
| 354 | - } | |
| 355 | - } | |
| 356 | - | |
| 357 | -} | |
| 358 | - | |
| 359 | -/** | |
| 360 | - * Instantiate the class | |
| 361 | - */ | |
| 362 | -Qcld_WPBot_Common_Functions::instance(); | |
| 1 | +<?php | |
| 2 | +if (!defined('ABSPATH')) exit; // Exit if accessed directly | |
| 3 | +/** | |
| 4 | + * Common functions class | |
| 5 | + */ | |
| 6 | +class Qcld_WPBot_Common_Functions { | |
| 7 | + | |
| 8 | + | |
| 9 | + private static $instance = null; | |
| 10 | + | |
| 11 | + public static function instance() { | |
| 12 | + if ( is_null( self::$instance ) ) { | |
| 13 | + self::$instance = new self(); | |
| 14 | + } | |
| 15 | + return self::$instance; | |
| 16 | + } | |
| 17 | + | |
| 18 | + private function __construct() { | |
| 19 | + add_action('wp_ajax_wpbot_save_feedback', array( $this, 'wpbot_save_feedback') ); | |
| 20 | + add_action('wp_ajax_nopriv_wpbot_save_feedback', array( $this,'wpbot_save_feedback') ); | |
| 21 | + add_action( 'wp_ajax_wpbot_save_report', array( $this, 'wpbot_save_report') ); | |
| 22 | + add_action( 'wp_ajax_nopriv_wpbot_save_report', array( $this, 'wpbot_save_report') ); | |
| 23 | + add_action('wp_ajax_nopriv_get_relevant_pages', array($this, 'qcld_get_relevant_pages_ajax')); | |
| 24 | + add_action('wp_ajax_rate_limit_settings_option', array($this, 'rate_limit_settings_option_callback')); | |
| 25 | + register_activation_hook(__FILE__, array('qcld_wpopenai_addons', 'schedule_rate_limit_reset_events')); | |
| 26 | + add_filter('cron_schedules', array($this, 'qcld_user_role_rate_cron_schedule')); | |
| 27 | + add_action('rate_limit_checker', array($this, 'rate_limit_checker')); | |
| 28 | + add_action('qcld_openai_user_rate_cal', array($this, 'qcld_openai_user_rate_cal')); | |
| 29 | + add_action('reset_rate_limit_used_counts', [$this, 'reset_rate_limit_used_counts'], 10, 1); | |
| 30 | + | |
| 31 | + } | |
| 32 | + /** | |
| 33 | + * Remove stopwords from search query | |
| 34 | + * | |
| 35 | + * @param string $query The search query | |
| 36 | + * @param array $stopwords Array of stopwords to remove | |
| 37 | + * @return string Query with stopwords removed | |
| 38 | + */ | |
| 39 | + public static function qcpd_remove_wa_stopwords($query, $stopwords) { | |
| 40 | + return preg_replace('/\b('.implode('|',$stopwords).')\b/','',$query); | |
| 41 | + } | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * Get relevant page links based on search query | |
| 45 | + * | |
| 46 | + * @param string $search_query The search query | |
| 47 | + * @return array Array of relevant page links | |
| 48 | + */ | |
| 49 | + public static function qcpd_relevant_pagelink($search_query) { | |
| 50 | + $stopwords = explode(',', get_option('qlcd_wp_chatbot_stop_words')); | |
| 51 | + | |
| 52 | + $finalQueryWordsWithoutStopWords = self::qcpd_remove_wa_stopwords(strtolower($search_query), $stopwords); | |
| 53 | + | |
| 54 | + $cleanWordsWithoutPunctuationMarks = preg_replace('/[\p{P}]/u', '', $finalQueryWordsWithoutStopWords); | |
| 55 | + | |
| 56 | + $q = trim($cleanWordsWithoutPunctuationMarks); | |
| 57 | + | |
| 58 | + $links = []; | |
| 59 | + | |
| 60 | + $post_type_array = get_option('qcld_openai_relevant_post'); | |
| 61 | + | |
| 62 | + $the_query = new WP_Query(array( | |
| 63 | + 'post_status' => 'publish', | |
| 64 | + 'posts_per_page' => 5, | |
| 65 | + 's' => esc_attr($q), | |
| 66 | + 'post_type' => $post_type_array | |
| 67 | + )); | |
| 68 | + | |
| 69 | + if($the_query->have_posts()) { | |
| 70 | + while($the_query->have_posts()) { | |
| 71 | + $the_query->the_post(); | |
| 72 | + | |
| 73 | + $url = esc_url(get_permalink()); | |
| 74 | + $link = '<a href=' . $url . ' target="_blank">' . get_the_title() . '</a>'; | |
| 75 | + array_push($links, $link); | |
| 76 | + } | |
| 77 | + wp_reset_postdata(); | |
| 78 | + } | |
| 79 | + | |
| 80 | + $links = array_unique($links); | |
| 81 | + return $links; | |
| 82 | + } | |
| 83 | + | |
| 84 | + | |
| 85 | + public function wpbot_save_feedback() { | |
| 86 | + check_ajax_referer('wp_chatbot', 'nonce'); | |
| 87 | + global $wpdb; | |
| 88 | + | |
| 89 | + $table = $wpdb->prefix . 'wpbot_chat_report'; | |
| 90 | + | |
| 91 | + $user_id = intval(wp_unslash($_POST['user_id'])); | |
| 92 | + $conversation_id= intval(wp_unslash($_POST['conversation_id'])); | |
| 93 | + $message = sanitize_text_field(wp_unslash($_POST['message'])); | |
| 94 | + $feedback = sanitize_text_field(wp_unslash($_POST['feedback'])); // "like" or "dislike" | |
| 95 | + $meta_info = sanitize_textarea_field(wp_unslash($_POST['meta_info'])); | |
| 96 | + $date = current_time('mysql'); | |
| 97 | + | |
| 98 | + $inserted = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery | |
| 99 | + $table, array( | |
| 100 | + 'user_id' => $user_id, | |
| 101 | + 'conversation_id'=> $conversation_id, | |
| 102 | + 'message' => $message, | |
| 103 | + 'feedback' => $feedback, | |
| 104 | + 'meta_info' => $meta_info, | |
| 105 | + 'created_at' => $date | |
| 106 | + )); | |
| 107 | + | |
| 108 | + if ($inserted !== false) { | |
| 109 | + wp_send_json_success(array('message' => 'Feedback saved.')); | |
| 110 | + } else { | |
| 111 | + wp_send_json_error(array('message' => 'Failed to save feedback.')); | |
| 112 | + } | |
| 113 | + } | |
| 114 | + | |
| 115 | + /** | |
| 116 | + * Save report func | |
| 117 | + * | |
| 118 | + */ | |
| 119 | + | |
| 120 | + | |
| 121 | + public function wpbot_save_report() { | |
| 122 | + check_ajax_referer('wp_chatbot', 'nonce'); | |
| 123 | + global $wpdb; | |
| 124 | + $table_report = $wpdb->prefix . 'wpbot_chat_report'; | |
| 125 | + | |
| 126 | + $email = sanitize_email(wp_unslash($_POST['email'])); | |
| 127 | + $message = sanitize_textarea_field(wp_unslash($_POST['message'])); | |
| 128 | + $report_text = sanitize_textarea_field(wp_unslash($_POST['report_text'])); | |
| 129 | + | |
| 130 | + $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery | |
| 131 | + $table_report, | |
| 132 | + [ | |
| 133 | + 'user_id' => get_current_user_id(), // or match from wpbot_user. | |
| 134 | + 'message' => $message, | |
| 135 | + 'meta_info' => maybe_serialize( [ 'email' => $email, 'report_text' => $report_text ] ), | |
| 136 | + ], | |
| 137 | + [ '%d', '%s', '%s' ] | |
| 138 | + ); | |
| 139 | + | |
| 140 | + // Send report email to admin | |
| 141 | + $admin_email = get_option( 'admin_email' ); | |
| 142 | + $subject = "New Chat Report"; | |
| 143 | + $body = "Reported Message:\n{$message}\n\nReport Text:\n{$report_text}\n\nUser Email: {$email}"; | |
| 144 | + wp_mail( $admin_email, $subject, $body ); | |
| 145 | + | |
| 146 | + wp_send_json_success(); | |
| 147 | + } | |
| 148 | + public function rate_limit_settings_option_callback() | |
| 149 | + { | |
| 150 | + | |
| 151 | + // Check is admin and verify nonce | |
| 152 | + if (! current_user_can('manage_options')) { | |
| 153 | + wp_send_json_error('Unauthorized'); | |
| 154 | + wp_die(); | |
| 155 | + } | |
| 156 | + check_ajax_referer( 'wp_chatbot', 'nonce' ); | |
| 157 | + // Save the rate limiting enabled/disabled setting | |
| 158 | + if (isset($_POST['is_rate_limiting_enabled'])) { | |
| 159 | + $is_rate_limiting_enabled = intval( wp_unslash( $_POST['is_rate_limiting_enabled'] ) ); | |
| 160 | + update_option('is_rate_limiting_enabled', $is_rate_limiting_enabled); | |
| 161 | + } | |
| 162 | + // Save the rate limits for each role | |
| 163 | + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput | |
| 164 | + if (isset($_POST['rate_limits']) && is_array( $_POST['rate_limits'] )) { | |
| 165 | + $rate_limits = array_map( 'sanitize_text_field', wp_unslash( $_POST['rate_limits'] ) ); | |
| 166 | + foreach ($rate_limits as $role => $limit) { | |
| 167 | + $option_name = 'rate_limit_' . sanitize_key( $role ); | |
| 168 | + $limit_value = intval($limit); | |
| 169 | + update_option($option_name, $limit_value); | |
| 170 | + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput | |
| 171 | + $timeframe_raw = isset( $_POST['rate_limit_timeframes'][ $role ] ) ? sanitize_text_field( wp_unslash( $_POST['rate_limit_timeframes'][ $role ] ) ) : '24'; | |
| 172 | + $timeframe = intval($timeframe_raw) * 3600; // Convert hours to seconds | |
| 173 | + update_option('rate_limit_timeframe_' . $role, $timeframe); | |
| 174 | + } | |
| 175 | + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput | |
| 176 | + $guest_timeframe_raw = isset( $_POST['rate_limit_timeframes']['guest'] ) ? sanitize_text_field( wp_unslash( $_POST['rate_limit_timeframes']['guest'] ) ) : '24'; | |
| 177 | + $timeframe = intval($guest_timeframe_raw) * 3600; // Convert hours to seconds | |
| 178 | + update_option('rate_limit_timeframe_guest', $timeframe); | |
| 179 | + } | |
| 180 | + // In your rate_limit_settings_option_callback(), after updating options: | |
| 181 | + $this->schedule_rate_limit_reset_events(); | |
| 182 | + wp_send_json_success('Settings saved'); | |
| 183 | + wp_die(); | |
| 184 | + } | |
| 185 | + public function qcld_user_role_rate_cron_schedule($schedules) | |
| 186 | + { | |
| 187 | + $roles = wp_roles()->roles; | |
| 188 | + foreach ($roles as $role => $details) { | |
| 189 | + $timeframe = intval(get_option('rate_limit_timeframe_' . $role, true)); | |
| 190 | + // Minimum 3600 seconds | |
| 191 | + $schedules['session_schedules_rate_limit_' . $role] = array( | |
| 192 | + 'interval' => $timeframe, | |
| 193 | + 'display' => esc_html( 'session_schedules_rate_limit_' . $role ), | |
| 194 | + ); | |
| 195 | + // Schedule the cron job for each role if not already scheduled); | |
| 196 | + } | |
| 197 | + return $schedules; | |
| 198 | + } | |
| 199 | + // wpshedule event to reset the rate limit used counts | |
| 200 | + public function schedule_rate_limit_reset_events() | |
| 201 | + { | |
| 202 | + // Ensure WordPress cron functions are available | |
| 203 | + if (! function_exists('wp_schedule_event')) { | |
| 204 | + require_once ABSPATH . 'wp-includes/wp-cron.php'; | |
| 205 | + } | |
| 206 | + $roles = wp_roles()->roles; | |
| 207 | + foreach ($roles as $role => $d) { | |
| 208 | + // Unschedule all existing events for this role | |
| 209 | + $timestamp = wp_next_scheduled('reset_rate_limit_used_counts', array($role)); | |
| 210 | + while ($timestamp) { | |
| 211 | + wp_unschedule_event($timestamp, 'reset_rate_limit_used_counts', array($role)); | |
| 212 | + $timestamp = wp_next_scheduled('reset_rate_limit_used_counts', array($role)); | |
| 213 | + } | |
| 214 | + // Schedule new event with updated interval | |
| 215 | + wp_schedule_event(time(), 'session_schedules_rate_limit_' . $role, 'reset_rate_limit_used_counts', array($role)); | |
| 216 | + } | |
| 217 | + } | |
| 218 | + public function qcld_wpsession_cron_deactivation() | |
| 219 | + { | |
| 220 | + $timestamp = wp_next_scheduled('reset_rate_limit_used_counts'); | |
| 221 | + wp_unschedule_event($timestamp, 'reset_rate_limit_used_counts'); | |
| 222 | + } | |
| 223 | + public function rate_limit_checker() | |
| 224 | + { | |
| 225 | + $qlcd_wp_chatbot_ai_rate_limiting_message = qcld_wb_chatbot_func_str_replace( | |
| 226 | + maybe_unserialize(get_option('qlcd_wp_chatbot_ai_rate_limiting_message', true)) | |
| 227 | + ); | |
| 228 | + if (get_option('is_stream_enabled') == 1) { | |
| 229 | + $response = array( | |
| 230 | + 'status' => 'error', | |
| 231 | + 'message' => esc_html( | |
| 232 | + ( is_array( $qlcd_wp_chatbot_ai_rate_limiting_message ) && ! empty( $qlcd_wp_chatbot_ai_rate_limiting_message[0] ) ) | |
| 233 | + ? $qlcd_wp_chatbot_ai_rate_limiting_message[0] | |
| 234 | + : __( 'Rate limit exceeded. Please try again later.', 'chatbot' ) | |
| 235 | + ), | |
| 236 | + ); | |
| 237 | + } else { | |
| 238 | + $response = array( | |
| 239 | + 'status' => 'success', | |
| 240 | + 'message' => esc_html( | |
| 241 | + ( is_array( $qlcd_wp_chatbot_ai_rate_limiting_message ) && ! empty( $qlcd_wp_chatbot_ai_rate_limiting_message[0] ) ) | |
| 242 | + ? $qlcd_wp_chatbot_ai_rate_limiting_message[0] | |
| 243 | + : __( 'Rate limit exceeded. Please try again later.', 'chatbot' ) | |
| 244 | + ), | |
| 245 | + ); | |
| 246 | + } | |
| 247 | + if (is_user_logged_in()) { | |
| 248 | + $user = wp_get_current_user(); | |
| 249 | + if (! empty($user->roles) && is_array($user->roles)) { | |
| 250 | + $role = $user->roles[0]; | |
| 251 | + $option_name = 'rate_limit_' . $role; | |
| 252 | + $limit = get_option($option_name); | |
| 253 | + $rate_limit = get_user_meta(get_current_user_id(), 'qcld_openai_user_rate_limit', true); | |
| 254 | + if (($limit >= $rate_limit) || $limit == 0) { | |
| 255 | + return; // allowed | |
| 256 | + } else { | |
| 257 | + if (get_option('is_stream_enabled') == 1) { | |
| 258 | + wp_send_json($response); //Proper JSON with header. | |
| 259 | + } else { | |
| 260 | + echo json_encode($response); | |
| 261 | + wp_die(); | |
| 262 | + } | |
| 263 | + } | |
| 264 | + } | |
| 265 | + } else { | |
| 266 | + $option_name = 'rate_limit_guest'; | |
| 267 | + $limit = get_option($option_name); | |
| 268 | + | |
| 269 | + if (session_status() == PHP_SESSION_NONE) { | |
| 270 | + session_start(); | |
| 271 | + } | |
| 272 | + | |
| 273 | + $guest_rate_limit = isset($_SESSION['guest_rate_limit']) ? intval($_SESSION['guest_rate_limit']) : 0; | |
| 274 | + | |
| 275 | + if ($limit >= $guest_rate_limit || $limit == 0) { | |
| 276 | + return; // allowed | |
| 277 | + } else { | |
| 278 | + if (get_option('is_stream_enabled') == 1) { | |
| 279 | + wp_send_json($response); //Proper JSON with header. | |
| 280 | + } else { | |
| 281 | + echo json_encode($response); | |
| 282 | + // Return role if limit exceeded | |
| 283 | + wp_die(); | |
| 284 | + } | |
| 285 | + } | |
| 286 | + } | |
| 287 | + } | |
| 288 | + | |
| 289 | + public function reset_rate_limit_used_counts($role) | |
| 290 | + { | |
| 291 | + if (empty($role)) { | |
| 292 | + return; | |
| 293 | + } | |
| 294 | + // Resetting rate limit used counts for role. | |
| 295 | + // loop through each role | |
| 296 | + // for each role get all users with that role | |
| 297 | + $roles = wp_roles()->roles; | |
| 298 | + foreach ($roles as $list_roll => $details) { | |
| 299 | + if ($list_roll != $role) { | |
| 300 | + continue; | |
| 301 | + } else { | |
| 302 | + $option_name = 'rate_limit_' . $role; | |
| 303 | + $limit = get_option($option_name); // Default to if not set | |
| 304 | + $users = get_users(array('role' => $role)); | |
| 305 | + foreach ($users as $user) { | |
| 306 | + update_user_meta($user->ID, 'qcld_openai_user_rate_limit', 0); | |
| 307 | + } | |
| 308 | + } | |
| 309 | + } | |
| 310 | + } | |
| 311 | + public function qcld_openai_user_rate_cal($update) | |
| 312 | + { | |
| 313 | + if (is_user_logged_in()) { | |
| 314 | + $rate_limit = get_user_meta(get_current_user_id(), 'qcld_openai_user_rate_limit', true); | |
| 315 | + if ($update != '') { | |
| 316 | + $rate_limit = intval($rate_limit) + intval($update); | |
| 317 | + } | |
| 318 | + update_user_meta(get_current_user_id(), 'qcld_openai_user_rate_limit', $rate_limit); | |
| 319 | + return; | |
| 320 | + } else { | |
| 321 | + // for guest users we will use session to store the rate limit | |
| 322 | + // if session is not started then start it | |
| 323 | + if (session_status() == PHP_SESSION_NONE) { | |
| 324 | + session_start(); | |
| 325 | + } | |
| 326 | + // we will use guest_id to identify the guest user | |
| 327 | + if (! isset($_SESSION['guest_id'])) { | |
| 328 | + $user_ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : ''; | |
| 329 | + $session_id = md5($user_ip . time()); | |
| 330 | + $_SESSION['guest_id'] = $session_id; | |
| 331 | + $_SESSION['guest_id_time'][$session_id] = time(); | |
| 332 | + get_option('rate_', 10); | |
| 333 | + // if guest_id_time is set and it is older than 24 hours then unset the guest_id | |
| 334 | + // we will store the time when the guest_id was created in session | |
| 335 | + $timeframe = get_option('rate_limit_timeframe_guest', true); | |
| 336 | + $timeframe = intval($timeframe) * 3600; // convert hours to seconds | |
| 337 | + if (isset($_SESSION['guest_id_time'][$session_id]) && (time() - $_SESSION['guest_id_time'][$session_id]) > $timeframe) { | |
| 338 | + unset($_SESSION['guest_id']); | |
| 339 | + unset($_SESSION['guest_id_time']); | |
| 340 | + } | |
| 341 | + // we will store the time when the guest_id was created in session | |
| 342 | + $_SESSION['guest_id_time'][$session_id] = time(); | |
| 343 | + $_SESSION['guest_rate_limit'] = 0; | |
| 344 | + } | |
| 345 | + // update the rate limit | |
| 346 | + // if update is not empty then add it to the existing rate limit else set it | |
| 347 | + if ($update != '') { | |
| 348 | + $guest_rate_limit = isset($_SESSION['guest_rate_limit']) ? intval($_SESSION['guest_rate_limit']) : 0; | |
| 349 | + // add the update to the existing rate limit | |
| 350 | + // set the rate limit in session | |
| 351 | + $_SESSION['guest_rate_limit'] = $guest_rate_limit + $update; | |
| 352 | + return; | |
| 353 | + } | |
| 354 | + } | |
| 355 | + } | |
| 356 | + | |
| 357 | + public static function format_and_save_ai_form_response($msg) { | |
| 358 | + if (empty($msg) || (strpos($msg, 'AI_FORM_DATA') === false)) { | |
| 359 | + return $msg; | |
| 360 | + } | |
| 361 | + | |
| 362 | + $pattern = '/(?:<[^>]+>)*\s*(?:__|<strong>|<b>)?AI_FORM_DATA(?:__|<\/strong>|<\/b>)?[\s\S]*?(?:__|<strong>|<b>)?AI_FORM_DATA_END(?:__|<\/strong>|<\/b>)?\s*(?:<\/[^>]+>)*/i'; | |
| 363 | + | |
| 364 | + if (preg_match($pattern, $msg, $matches)) { | |
| 365 | + $block = $matches[0]; | |
| 366 | + if (preg_match('/\{[\s\S]*\}/', $block, $json_matches)) { | |
| 367 | + $json_str = trim($json_matches[0]); | |
| 368 | + $data = json_decode($json_str, true); | |
| 369 | + | |
| 370 | + if ($data && isset($data['form_title'])) { | |
| 371 | + $post_title = sanitize_text_field($data['form_title']) . ' - ' . current_time('mysql'); | |
| 372 | + $post_id = wp_insert_post(array( | |
| 373 | + 'post_title' => $post_title, | |
| 374 | + 'post_type' => 'wpbot_form_entry', | |
| 375 | + 'post_status' => 'publish' | |
| 376 | + )); | |
| 377 | + | |
| 378 | + if ($post_id && isset($data['data']) && is_array($data['data'])) { | |
| 379 | + $email_body = "<h2>" . esc_html__('New AI Chat Submission', 'chatbot') . "</h2>"; | |
| 380 | + $email_body .= "<p><strong>" . esc_html__('Chat', 'chatbot') . ":</strong> " . sanitize_text_field($data['form_title']) . "</p>"; | |
| 381 | + $email_body .= "<table border='1' cellpadding='10' cellspacing='0' style='border-collapse: collapse; width: 100%; max-width: 600px; font-family: sans-serif;'>"; | |
| 382 | + | |
| 383 | + // Extract user's email for Reply-To (not From, to avoid SMTP rejection) | |
| 384 | + $reply_to = ''; | |
| 385 | + foreach ($data['data'] as $key => $value) { | |
| 386 | + update_post_meta($post_id, sanitize_text_field($key), sanitize_text_field($value)); | |
| 387 | + $clean_key = ucwords(str_replace(array('-', '_'), ' ', sanitize_text_field($key))); | |
| 388 | + $email_body .= "<tr><td style='background: #f4f4f4; width: 40%;'><strong>" . esc_html($clean_key) . "</strong></td><td>" . esc_html(sanitize_text_field($value)) . "</td></tr>"; | |
| 389 | + | |
| 390 | + // Extract email from value — handles plain, [bracketed], and combined answers | |
| 391 | + if (preg_match('/\[?([a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,})\]?/', $value, $email_match)) { | |
| 392 | + $candidate = sanitize_email(trim($email_match[1])); | |
| 393 | + if (is_email($candidate)) { | |
| 394 | + $reply_to = $candidate; | |
| 395 | + } | |
| 396 | + } | |
| 397 | + } | |
| 398 | + $email_body .= "</table>"; | |
| 399 | + | |
| 400 | + $email_enabled = true; | |
| 401 | + $saved_forms = get_option('wpbot_ai_forms', array()); | |
| 402 | + if (is_array($saved_forms)) { | |
| 403 | + foreach ($saved_forms as $form) { | |
| 404 | + if ($form['title'] == sanitize_text_field($data['form_title'])) { | |
| 405 | + if (isset($form['email'])) { | |
| 406 | + $email_enabled = $form['email'] == 1; | |
| 407 | + } | |
| 408 | + $per_action_emails = isset($form['email_addresses']) ? trim($form['email_addresses']) : ''; | |
| 409 | + break; | |
| 410 | + } | |
| 411 | + } | |
| 412 | + } | |
| 413 | + | |
| 414 | + if ($email_enabled) { | |
| 415 | + if (!empty($per_action_emails)) { | |
| 416 | + $to = array_map('trim', explode(',', $per_action_emails)); | |
| 417 | + } else { | |
| 418 | + $default = get_option('qlcd_wp_chatbot_admin_email', ''); | |
| 419 | + $to = !empty($default) ? array_map('trim', explode(',', $default)) : get_option('admin_email'); | |
| 420 | + } | |
| 421 | + $subject = sanitize_text_field($data['form_title']) . " - " . esc_html__('New AI Chat Submission', 'chatbot'); | |
| 422 | + $headers = array('Content-Type: text/html; charset=UTF-8'); | |
| 423 | + if (!empty($reply_to)) { | |
| 424 | + $headers[] = 'Reply-To: ' . $reply_to; | |
| 425 | + } | |
| 426 | + wp_mail($to, $subject, $email_body, $headers); | |
| 427 | + } | |
| 428 | + } | |
| 429 | + | |
| 430 | + $summary_html = '<div class="ai-form-summary-card" style="background: #f4f6f9; border-left: 4px solid #0073aa; padding: 12px 14px; margin: 10px 0; border-radius: 4px; font-size: 13px; line-height: 1.5; color: #333;">'; | |
| 431 | + if (!empty($data['form_title'])) { | |
| 432 | + $summary_html .= '<div style="font-weight: 600; color: #0073aa; margin-bottom: 8px; text-transform: capitalize; font-size: 14px;">' . esc_html($data['form_title']) . '</div>'; | |
| 433 | + } | |
| 434 | + if (!empty($data['data']) && is_array($data['data'])) { | |
| 435 | + $summary_html .= '<table style="width: 100%; border-collapse: collapse; margin-top: 4px;">'; | |
| 436 | + foreach ($data['data'] as $k => $v) { | |
| 437 | + $clean_k = ucwords(str_replace(array('-', '_'), ' ', sanitize_text_field($k))); | |
| 438 | + $summary_html .= '<tr><td style="padding: 3px 6px 3px 0; color: #555; font-weight: 600; width: 42%; vertical-align: top;">' . esc_html($clean_k) . ':</td><td style="padding: 3px 0; color: #222; vertical-align: top;">' . esc_html($v) . '</td></tr>'; | |
| 439 | + } | |
| 440 | + $summary_html .= '</table>'; | |
| 441 | + } | |
| 442 | + $summary_html .= '</div>'; | |
| 443 | + | |
| 444 | + $msg = preg_replace($pattern, $summary_html, $msg); | |
| 445 | + } | |
| 446 | + } | |
| 447 | + } | |
| 448 | + | |
| 449 | + return $msg; | |
| 450 | + } | |
| 451 | + | |
| 452 | + public static function is_ai_action_in_progress($history = array(), $keyword = '') { | |
| 453 | + if (!empty($_POST['action_prompt']) || !empty($_POST['is_ai_actions_playground'])) { | |
| 454 | + return true; | |
| 455 | + } | |
| 456 | + $saved_ai_forms = get_option('wpbot_ai_forms', array()); | |
| 457 | + if (empty($saved_ai_forms) || !is_array($saved_ai_forms)) { | |
| 458 | + return false; | |
| 459 | + } | |
| 460 | + | |
| 461 | + $form_titles = array(); | |
| 462 | + foreach ($saved_ai_forms as $form) { | |
| 463 | + if (!empty($form['title'])) { | |
| 464 | + $form_titles[] = strtolower(trim($form['title'])); | |
| 465 | + } | |
| 466 | + } | |
| 467 | + | |
| 468 | + if (empty($form_titles)) { | |
| 469 | + return false; | |
| 470 | + } | |
| 471 | + | |
| 472 | + $clean_kw = strtolower(trim($keyword)); | |
| 473 | + if (!empty($clean_kw)) { | |
| 474 | + foreach ($form_titles as $title) { | |
| 475 | + if ($clean_kw === $title || strpos($clean_kw, $title) !== false || strpos($title, $clean_kw) !== false) { | |
| 476 | + return true; | |
| 477 | + } | |
| 478 | + } | |
| 479 | + } | |
| 480 | + | |
| 481 | + if (empty($history)) { | |
| 482 | + if (!empty($_POST['ai_history'])) { | |
| 483 | + $history = json_decode(wp_unslash($_POST['ai_history']), true); | |
| 484 | + } elseif (!empty($_POST['wpwHistory'])) { | |
| 485 | + $history_html = wp_unslash($_POST['wpwHistory']); | |
| 486 | + if (is_string($history_html)) { | |
| 487 | + $dom = new \DOMDocument(); | |
| 488 | + libxml_use_internal_errors(true); | |
| 489 | + $dom->loadHTML('<?xml encoding="utf-8" ?>' . $history_html); | |
| 490 | + libxml_clear_errors(); | |
| 491 | + $xpath = new \DOMXPath($dom); | |
| 492 | + $lis = $xpath->query('//li'); | |
| 493 | + $history = array(); | |
| 494 | + if ($lis && $lis->length > 0) { | |
| 495 | + foreach ($lis as $li) { | |
| 496 | + $class = $li->getAttribute('class'); | |
| 497 | + $text = trim($li->textContent); | |
| 498 | + if ($text !== '') { | |
| 499 | + $role = (strpos($class, 'chatbot-msg') !== false) ? 'assistant' : 'user'; | |
| 500 | + $history[] = array('role' => $role, 'content' => $text); | |
| 501 | + } | |
| 502 | + } | |
| 503 | + } | |
| 504 | + } | |
| 505 | + } | |
| 506 | + } | |
| 507 | + | |
| 508 | + if (!empty($history) && is_array($history)) { | |
| 509 | + $last_form_start_idx = -1; | |
| 510 | + $last_form_end_idx = -1; | |
| 511 | + foreach ($history as $idx => $item) { | |
| 512 | + $content = is_array($item) ? strtolower($item['content'] ?? '') : ''; | |
| 513 | + if (empty($content) && is_string($item)) { | |
| 514 | + $content = strtolower($item); | |
| 515 | + } | |
| 516 | + foreach ($form_titles as $title) { | |
| 517 | + if (!empty($title) && strpos($content, $title) !== false) { | |
| 518 | + $last_form_start_idx = $idx; | |
| 519 | + } | |
| 520 | + } | |
| 521 | + if (strpos($content, 'ai_form_data') !== false || strpos($content, 'ai-form-summary-card') !== false) { | |
| 522 | + $last_form_end_idx = $idx; | |
| 523 | + } | |
| 524 | + } | |
| 525 | + | |
| 526 | + if ($last_form_start_idx !== -1 && $last_form_start_idx >= $last_form_end_idx) { | |
| 527 | + return true; | |
| 528 | + } | |
| 529 | + } | |
| 530 | + | |
| 531 | + return false; | |
| 532 | + } | |
| 533 | +} | |
| 534 | + | |
| 535 | +/** | |
| 536 | + * Instantiate the class | |
| 537 | + */ | |
| 538 | +Qcld_WPBot_Common_Functions::instance(); | |