PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 1.1.7
MxChat – AI Chatbot & Content Generation for WordPress v1.1.7
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
mxchat-basic / includes / class-mxchat-integrator.php

class-mxchat-integrator.php in MxChat – AI Chatbot & Content Generation for WordPress 1.1.7, at includes/class-mxchat-integrator.php

673 lines 24.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) {
3 exit;
4 }
5
6 class MxChat_Integrator {
7 private $options;
8 private $chat_count;
9
10 public function __construct() {
11 $this->options = get_option('mxchat_options');
12 $this->chat_count = get_option('mxchat_chat_count', 0);
13
14 // Add WooCommerce hooks
15 add_action('wp_insert_post', array($this, 'mxchat_handle_product_change'), 10, 3);
16
17 // Ensure embeddings are removed when a product is moved to trash or permanently deleted
18 add_action('wp_trash_post', array($this, 'mxchat_handle_product_delete'));
19 add_action('before_delete_post', array($this, 'mxchat_handle_product_delete'));
20
21 add_action('wp_enqueue_scripts', array($this, 'mxchat_enqueue_scripts_styles'));
22 add_action('wp_ajax_mxchat_handle_chat_request', array($this, 'mxchat_handle_chat_request'));
23 add_action('wp_ajax_nopriv_mxchat_handle_chat_request', array($this, 'mxchat_handle_chat_request'));
24 add_action('wp_ajax_mxchat_dismiss_pre_chat_message', array($this, 'mxchat_dismiss_pre_chat_message'));
25 add_action('wp_ajax_nopriv_mxchat_dismiss_pre_chat_message', array($this, 'mxchat_dismiss_pre_chat_message'));
26
27 add_action('wp_ajax_mxchat_fetch_conversation_history', [$this, 'mxchat_fetch_conversation_history']);
28 add_action('wp_ajax_nopriv_mxchat_fetch_conversation_history', [$this, 'mxchat_fetch_conversation_history']);
29
30
31
32 if (!wp_next_scheduled('mxchat_reset_rate_limits')) {
33 wp_schedule_event(time(), 'daily', 'mxchat_reset_rate_limits');
34 }
35
36 add_action('mxchat_reset_rate_limits', array($this, 'mxchat_reset_rate_limits'));
37 }
38
39 public function mxchat_handle_product_change($post_id, $post, $update) {
40 // Ensure this is a product post type
41 if ($post->post_type !== 'product') {
42 return;
43 }
44
45 // Only generate embeddings if the product is published
46 if ($post->post_status === 'publish') {
47 // Delay the embedding slightly to ensure all product data is available
48 add_action('shutdown', function() use ($post_id) {
49 $product = wc_get_product($post_id);
50 if ($product && $product->get_price() !== '') {
51 $this->mxchat_store_product_embedding($product);
52 } else {
53 // Optionally, log or handle the case where product data is incomplete
54 // error_log("Product {$post_id} does not have complete data. Embedding not generated.");
55 }
56 });
57 }
58 }
59
60 public function mxchat_handle_product_delete($post_id) {
61 if (get_post_type($post_id) !== 'product') {
62 return;
63 }
64
65 global $wpdb;
66 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
67
68 // Delete the embedding associated with this product
69 $wpdb->delete($table_name, array('source_url' => get_permalink($post_id)), array('%s'));
70 }
71
72 private function mxchat_store_product_embedding($product) {
73 if (isset($this->options['enable_woocommerce_integration']) && $this->options['enable_woocommerce_integration'] === '1') {
74
75 $source_url = get_permalink($product->get_id());
76 $regular_price = $product->get_regular_price();
77 $sale_price = $product->get_sale_price();
78 $price = $sale_price ?: $regular_price;
79
80 $description = $product->get_description() . "\n\n" .
81 "Short Description: " . $product->get_short_description() . "\n" .
82 "Price: " . $regular_price . "\n" .
83 "Sale Price: " . ($sale_price ?: 'N/A') . "\n" .
84 "SKU: " . $product->get_sku();
85
86 global $wpdb;
87 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
88
89 // Delete any existing embedding for this product
90 $wpdb->delete($table_name, array('source_url' => $source_url), array('%s'));
91
92 // Submit the new content and embedding to the database
93 MxChat_Utils::submit_content_to_db($description, $source_url, $this->options['api_key']);
94 }
95 }
96
97
98
99
100
101 private function mxchat_increment_chat_count() {
102 $chat_count = get_option('mxchat_chat_count', 0);
103 $chat_count++;
104 update_option('mxchat_chat_count', $chat_count);
105 }
106
107 function mxchat_fetch_conversation_history() {
108 if (empty($_POST['session_id'])) {
109 wp_send_json_error(['message' => 'Session ID missing.']);
110 wp_die();
111 }
112
113 $session_id = sanitize_text_field($_POST['session_id']);
114 $history = get_option("mxchat_history_{$session_id}", []); // Retrieve stored history
115
116 if (empty($history)) {
117 wp_send_json_error(['message' => 'No history found.']);
118 wp_die();
119 }
120
121 wp_send_json_success(['conversation' => $history]);
122 wp_die();
123 }
124 private function mxchat_fetch_conversation_history_for_ajax($session_id) {
125 $history = get_option("mxchat_history_{$session_id}", []); // Retrieve stored history based on session ID
126 $formatted_history = [];
127
128 // Format the history to align with the expected structure for OpenAI
129 foreach ($history as $entry) {
130 $formatted_history[] = [
131 'role' => $entry['role'], // Ensure this matches 'user' or 'assistant'
132 'content' => $entry['content']
133 ];
134 }
135
136 return $formatted_history;
137 }
138
139
140 private function mxchat_save_chat_message($session_id, $role, $message) {
141 global $wpdb;
142 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
143
144 $user_id = is_user_logged_in() ? get_current_user_id() : 0;
145 $user_identifier = MxChat_User::mxchat_get_user_identifier();
146 $user_email = MxChat_User::mxchat_get_user_email();
147
148 $history = get_option("mxchat_history_{$session_id}", []);
149 $history[] = ['role' => $role, 'content' => $message];
150 update_option("mxchat_history_{$session_id}", $history);
151
152 $wpdb->insert($table_name, [
153 'user_id' => $user_id,
154 'user_identifier' => $user_identifier,
155 'user_email' => $user_email,
156 'session_id' => $session_id,
157 'role' => $role,
158 'message' => $message,
159 'timestamp' => current_time('mysql', 1)
160 ]);
161 }
162
163
164 public function mxchat_handle_chat_request() {
165 global $wpdb;
166
167 // Get and sanitize the user identifier
168 $user_id = $this->mxchat_get_user_identifier();
169 $user_id = sanitize_key($user_id);
170
171 // Setup rate limiting
172 $rate_limit_transient_key = 'mxchat_chat_limit_' . $user_id;
173 $chat_count = get_transient($rate_limit_transient_key) ?: 0;
174
175 // Retrieve the session ID from the client's POST data
176 $session_id = isset($_POST['session_id']) ? sanitize_text_field($_POST['session_id']) : '';
177
178 if (empty($session_id)) {
179 // Handle the case where the session ID is missing
180 wp_send_json_error('Session ID is missing.');
181 wp_die();
182 }
183
184 // No need to set transients or server-side cookies for the session ID
185
186 // Check rate limit
187 $rate_limit_option = $this->options['rate_limit'] ?? 'unlimited';
188 if ($rate_limit_option !== 'unlimited' && $chat_count >= intval($rate_limit_option)) {
189 wp_send_json_error(['message' => $this->options['rate_limit_message'] ?? 'Rate limit exceeded. Please try again later.']);
190 wp_die();
191 }
192 set_transient($rate_limit_transient_key, $chat_count + 1, DAY_IN_SECONDS);
193
194 // Validate and sanitize the incoming message
195 if (empty($_POST['message'])) {
196 wp_send_json_error('No message received');
197 wp_die();
198 }
199
200 $message = sanitize_text_field($_POST['message']);
201 $this->mxchat_save_chat_message($session_id, 'user', $message);
202
203 // Track email capture and WooCommerce flows with individual transients
204 $email_capture_prompt = get_transient('mxchat_email_capture_' . $user_id);
205 $interaction_count = get_transient('mxchat_email_interaction_count_' . $user_id) ?: 0;
206 $woocommerce_prompt = get_transient('mxchat_woocommerce_prompt_' . $user_id);
207
208 // Handle email capture flow
209 if ($email_capture_prompt) {
210 if (preg_match('/[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}/i', $message, $matches)) {
211 $email = $matches[0];
212 $this->add_email_to_loops($email);
213 $response = $this->options['email_capture_response'] ?? 'Thank you for providing your email! You\'ve been added to our list.';
214
215 delete_transient('mxchat_email_capture_' . $user_id);
216 delete_transient('mxchat_email_interaction_count_' . $user_id);
217 delete_transient('mxchat_woocommerce_prompt_' . $user_id);
218
219 $this->mxchat_save_chat_message($session_id, 'bot', $response);
220 wp_send_json(['message' => $response]);
221 wp_die();
222 } else {
223 if ($interaction_count >= 3) {
224 delete_transient('mxchat_email_capture_' . $user_id);
225 delete_transient('mxchat_email_interaction_count_' . $user_id);
226 } else {
227 set_transient('mxchat_email_interaction_count_' . $user_id, ++$interaction_count, 5 * MINUTE_IN_SECONDS);
228 }
229 }
230 }
231
232 // Handle WooCommerce add-to-cart flow
233 if (class_exists('WooCommerce') && stripos($message, 'add to cart') !== false) {
234 $last_product_id = get_transient('mxchat_last_discussed_product_' . $user_id);
235 if ($last_product_id) {
236 $added = WC()->cart->add_to_cart($last_product_id);
237 $product = wc_get_product($last_product_id);
238
239 if ($added) {
240 $response = "The product '{$product->get_name()}' has been added to your cart. To proceed to checkout, please type 'checkout'.";
241 set_transient('mxchat_checkout_prompt_' . $user_id, true, 5 * MINUTE_IN_SECONDS);
242 $this->mxchat_save_chat_message($session_id, 'bot', $response);
243 wp_send_json(['message' => $response]);
244 wp_die();
245 } else {
246 $response = "Sorry, I couldn't add the product to your cart. Please try again.";
247 $this->mxchat_save_chat_message($session_id, 'bot', $response);
248 wp_send_json(['message' => $response]);
249 wp_die();
250 }
251 } else {
252 $response = "I couldn't find the product to add. Please mention the product name again.";
253 $this->mxchat_save_chat_message($session_id, 'bot', $response);
254 wp_send_json(['message' => $response]);
255 wp_die();
256 }
257 }
258
259 // Handle checkout response
260 if (class_exists('WooCommerce') && stripos($message, 'checkout') !== false) {
261 $checkout_prompt = get_transient('mxchat_checkout_prompt_' . $user_id);
262 if ($checkout_prompt && WC()->cart->get_cart_contents_count() > 0) {
263 $checkout_url = wc_get_checkout_url();
264 $response = "Great! Redirecting you to the checkout page...";
265 delete_transient('mxchat_checkout_prompt_' . $user_id);
266
267 $this->mxchat_save_chat_message($session_id, 'bot', $response);
268 wp_send_json(['message' => $response, 'redirect_url' => $checkout_url]);
269 wp_die();
270 } else {
271 $response = "It seems like there is no active checkout prompt or no items in your cart. Please add a product to the cart first.";
272 $this->mxchat_save_chat_message($session_id, 'bot', $response);
273 wp_send_json(['message' => $response]);
274 wp_die();
275 }
276 }
277
278 // Handle order-related queries
279 if (class_exists('WooCommerce') && MxChat_WooCommerce::mxchat_is_order_related_query($message)) {
280 $response = MxChat_WooCommerce::mxchat_fetch_user_orders_details();
281 $this->mxchat_save_chat_message($session_id, 'bot', $response);
282 wp_send_json(['message' => $response]);
283 wp_die();
284 }
285
286 // Check for trigger keywords to initiate email capture
287 $trigger_keywords = explode(',', $this->options['trigger_keywords'] ?? '');
288 if (!empty($trigger_keywords) && $trigger_keywords[0] !== '') {
289 foreach ($trigger_keywords as $keyword) {
290 if (stripos($message, trim($keyword)) !== false) {
291 $response = $this->options['triggered_phrase_response'] ?? "Would you like to join our mailing list? Please provide your email below.";
292 set_transient('mxchat_email_capture_' . $user_id, true, 5 * MINUTE_IN_SECONDS);
293 $this->mxchat_save_chat_message($session_id, 'bot', $response);
294 wp_send_json(['message' => $response]);
295 wp_die();
296 }
297 }
298 }
299
300 // Store product discussion in transient
301 $last_discussed_product_id = MxChat_WooCommerce::mxchat_extract_product_id_from_message($message);
302 if ($last_discussed_product_id) {
303 set_transient('mxchat_last_discussed_product_' . $user_id, $last_discussed_product_id, 3600);
304 }
305
306 // Standard chat processing
307 $user_message_embedding = $this->mxchat_generate_embedding($message, $this->options['api_key']);
308 if (!is_array($user_message_embedding)) {
309 wp_send_json_error('Error processing your message.');
310 wp_die();
311 }
312
313 $relevant_content = $this->mxchat_find_relevant_content($user_message_embedding);
314 $conversation_history = $this->mxchat_fetch_conversation_history_for_ajax($session_id);
315 $this->mxchat_increment_chat_count();
316 $response = $this->mxchat_generate_response($relevant_content, $this->options['api_key'], $conversation_history);
317
318 $this->mxchat_save_chat_message($session_id, 'bot', $response);
319 wp_send_json(['message' => $response, 'session_id' => $session_id]);
320 wp_die();
321 }
322
323
324 // Function to add the captured email to Loops
325 private function add_email_to_loops($email) {
326 $api_key = $this->options['loops_api_key'];
327 $mailing_list_id = $this->options['loops_mailing_list'];
328
329 $data = array(
330 'email' => $email,
331 'subscribed' => true,
332 'source' => 'MxChat AI Chatbot',
333 'mailingLists' => array($mailing_list_id => true),
334 );
335
336 $url = "https://app.loops.so/api/v1/contacts/create";
337 $args = array(
338 'body' => json_encode($data),
339 'headers' => array(
340 'Authorization' => 'Bearer ' . $api_key,
341 'Content-Type' => 'application/json',
342 ),
343 'method' => 'POST',
344 'timeout' => 45,
345 );
346
347 wp_remote_post($url, $args);
348 }
349
350
351 private function mxchat_get_user_identifier() {
352 return MxChat_User::mxchat_get_user_identifier();
353 }
354
355
356
357 private function mxchat_generate_embedding($text, $api_key) {
358 $endpoint = 'https://api.openai.com/v1/embeddings';
359
360 $body = wp_json_encode([
361 'input' => $text,
362 'model' => 'text-embedding-ada-002'
363 ]);
364
365 $args = [
366 'body' => $body,
367 'headers' => [
368 'Content-Type' => 'application/json',
369 'Authorization' => 'Bearer ' . $api_key,
370 ],
371 'timeout' => 60,
372 'redirection' => 5,
373 'blocking' => true,
374 'httpversion' => '1.0',
375 'sslverify' => true,
376 ];
377
378 $response = wp_remote_post($endpoint, $args);
379
380 if (is_wp_error($response)) {
381 return null;
382 }
383
384 $response_body = json_decode(wp_remote_retrieve_body($response), true);
385
386 if (isset($response_body['data'][0]['embedding']) && is_array($response_body['data'][0]['embedding'])) {
387 return $response_body['data'][0]['embedding'];
388 } else {
389 return null;
390 }
391 }
392
393 private function mxchat_find_relevant_content($user_embedding) {
394 global $wpdb;
395 $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
396
397 // Define a cache key for embeddings
398 $cache_key = 'mxchat_system_prompt_embeddings';
399
400 // Attempt to get the embeddings from the cache
401 $embeddings = wp_cache_get($cache_key, 'mxchat_system_prompts');
402
403 if ($embeddings === false) {
404 // Cache miss, query the database and cache the results
405 $query = "SELECT id, embedding_vector FROM {$system_prompt_table}";
406 $embeddings = $wpdb->get_results($query);
407
408 if ($embeddings === null || empty($embeddings)) {
409 //error_log("No embeddings found in the database.");
410 return null; // Return null to handle no embeddings gracefully
411 }
412
413 // Cache the results if successful
414 wp_cache_set($cache_key, $embeddings, 'mxchat_system_prompts', 3600); // Cache for 1 hour
415 }
416
417 $most_relevant_id = null;
418 $highest_similarity = -INF;
419
420 foreach ($embeddings as $embedding) {
421 $database_embedding = maybe_unserialize($embedding->embedding_vector);
422
423 // Debugging: Log the embeddings
424 // if (!is_array($database_embedding)) {
425 // error_log("Invalid database embedding format for ID {$embedding->id}: " . print_r($database_embedding, true));
426 // continue;
427 // }
428
429 if (is_array($user_embedding)) {
430 $similarity = $this->mxchat_calculate_cosine_similarity($user_embedding, $database_embedding);
431
432 // Debugging: Log the similarity score
433 // error_log("Calculated similarity for ID {$embedding->id}: {$similarity}");
434
435 if ($similarity > $highest_similarity) {
436 $highest_similarity = $similarity;
437 $most_relevant_id = $embedding->id;
438 }
439 } else {
440 // error_log("User embedding is not an array. Embedding data: " . print_r($user_embedding, true));
441 }
442 }
443
444 if ($most_relevant_id !== null) {
445 // Fetch content with product links
446 return $this->fetch_content_with_product_links($most_relevant_id);
447 }
448
449 //error_log("No relevant content found. Most relevant ID was null.");
450 return null; // Return null if no relevant content is found
451 }
452
453
454 private function fetch_content_with_product_links($most_relevant_id) {
455 global $wpdb;
456 $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
457
458 // Fetch the article content and associated product URL
459 $query = $wpdb->prepare("SELECT article_content, source_url FROM {$system_prompt_table} WHERE id = %d", $most_relevant_id);
460 $result = $wpdb->get_row($query);
461
462 if ($result) {
463 // Append the product link to the content if available
464 $content = $result->article_content;
465 if (!empty($result->source_url)) {
466 $content .= "\n\nFor more details, check out this product: " . esc_url($result->source_url);
467 }
468 return $content;
469 }
470
471 return null;
472 }
473
474
475 private function mxchat_generate_response($relevant_content, $api_key, $conversation_history) {
476 if (!$relevant_content) {
477 return "I'm sorry, I couldn't find relevant information on that topic.";
478 }
479
480 $system_prompt_instructions = isset($this->options['system_prompt_instructions']) ? $this->options['system_prompt_instructions'] : '';
481
482 $content_with_instructions = $system_prompt_instructions . " " . $relevant_content;
483
484 array_unshift($conversation_history, [
485 'role' => 'system',
486 'content' => "Here are your instructions: " . $content_with_instructions
487 ]);
488
489 foreach ($conversation_history as &$message) {
490 if ($message['role'] === 'bot') {
491 $message['role'] = 'assistant';
492 }
493 }
494
495 $api_url = 'https://api.openai.com/v1/chat/completions';
496
497 $body = json_encode([
498 'model' => isset($this->options['model']) ? $this->options['model'] : 'gpt-3.5',
499 'messages' => $conversation_history,
500 ]);
501
502 $args = [
503 'body' => $body,
504 'headers' => [
505 'Content-Type' => 'application/json',
506 'Authorization' => 'Bearer ' . $api_key,
507 ],
508 'timeout' => 60,
509 'redirection' => 5,
510 'blocking' => true,
511 'httpversion' => '1.0',
512 'sslverify' => true,
513 ];
514
515 $response = wp_remote_post($api_url, $args);
516
517 if (is_wp_error($response)) {
518 return "Sorry, there was an error processing your request.";
519 }
520
521 $response_body = json_decode(wp_remote_retrieve_body($response), true);
522
523 if (isset($response_body['choices'][0]['message']['content'])) {
524 if (isset($response_body['usage'])) {
525 $prompt_tokens = $response_body['usage']['prompt_tokens'];
526 $total_tokens = $response_body['usage']['total_tokens'];
527 }
528 return trim($response_body['choices'][0]['message']['content']);
529 } else {
530 return "Sorry, I couldn't process that request.";
531 }
532 }
533
534
535 public function mxchat_dismiss_pre_chat_message() {
536 // Get and sanitize the user identifier
537 $user_id = $this->mxchat_get_user_identifier();
538 $user_id = sanitize_key($user_id);
539
540 // Set a transient to track that the user has dismissed the pre-chat message
541 $transient_key = 'mxchat_pre_chat_message_dismissed_' . $user_id;
542 set_transient($transient_key, true, DAY_IN_SECONDS);
543
544 wp_send_json_success();
545 }
546
547
548
549 private function mxchat_calculate_cosine_similarity($vectorA, $vectorB) {
550 if (!is_array($vectorA) || !is_array($vectorB) || empty($vectorA) || empty($vectorB)) {
551 return 0;
552 }
553
554 $dotProduct = array_sum(array_map(function ($a, $b) {
555 return $a * $b;
556 }, $vectorA, $vectorB));
557 $normA = sqrt(array_sum(array_map(function ($a) {
558 return $a * $a;
559 }, $vectorA)));
560 $normB = sqrt(array_sum(array_map(function ($b) {
561 return $b * $b;
562 }, $vectorB)));
563
564 if ($normA == 0 || $normB == 0) {
565 return 0;
566 }
567
568 return $dotProduct / ($normA * $normB);
569 }
570
571 public function mxchat_enqueue_scripts_styles() {
572 // Define version numbers for the styles and scripts
573 $chat_style_version = '1.1.7'; // Replace with your actual version
574 $chat_script_version = '1.1.7'; // Replace with your actual version
575
576 // Correct path to the script file
577 wp_enqueue_script(
578 'mxchat-chat-js', // Handle for the script
579 plugin_dir_url(__FILE__) . '../js/chat-script.js', // Correct path using __FILE__
580 array('jquery'), // Dependencies
581 $chat_script_version, // Version for cache busting
582 true // Load script in footer
583 );
584
585 // Enqueue the CSS file similarly
586 wp_enqueue_style(
587 'mxchat-chat-css', // Handle for the style
588 plugin_dir_url(__FILE__) . '../css/chat-style.css', // Correct path using __FILE__
589 array(), // No dependencies
590 $chat_style_version // Version for cache busting
591 );
592
593 // Fetch options from the database
594 $this->options = get_option('mxchat_options');
595
596 // Prepare settings to pass to JavaScript
597 $style_settings = array(
598 'ajax_url' => admin_url('admin-ajax.php'),
599 'nonce' => wp_create_nonce('mxchat_chat_nonce'), // Nonce for security
600 'rate_limit_message' => $this->options['rate_limit_message'] ?? 'Rate limit exceeded. Please try again later.',
601 'appendWidgetToBody' => $this->options['append_to_body'] ?? 'off'
602 );
603
604 // Localize the script with necessary data
605 wp_localize_script('mxchat-chat-js', 'mxchatChat', $style_settings);
606 }
607
608
609
610 public function mxchat_reset_rate_limits() {
611 global $wpdb;
612
613 // Define a cache key pattern for rate limits
614 $cache_key_pattern = 'mxchat_chat_limit_%';
615
616 // Retrieve all option names matching the pattern
617 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
618 $option_names = $wpdb->get_col("SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE 'mxchat_chat_limit_%'");
619
620 // db call ok; no-cache ok
621 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- db call ok
622 $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE 'mxchat_chat_limit_%'");
623
624 // Clear the relevant cache entries
625 foreach ($option_names as $option_name) {
626 wp_cache_delete($option_name, 'options');
627 }
628
629 // Optionally, clear a general cache if you have one
630 wp_cache_delete('mxchat_all_chat_limits', 'options');
631 }
632
633
634 private function mxchat_fetch_woocommerce_products() {
635 // Ensure WooCommerce is active
636 if (!class_exists('WooCommerce')) {
637 return [];
638 }
639
640 $args = array(
641 'post_type' => 'product',
642 'post_status' => 'publish',
643 'posts_per_page' => -1,
644 );
645
646 $products = get_posts($args);
647 $product_data = [];
648
649 foreach ($products as $product) {
650 $product_id = $product->ID;
651 $product_obj = wc_get_product($product_id);
652
653 $product_data[] = array(
654 'id' => $product_id,
655 'name' => $product_obj->get_name(),
656 'description' => $product_obj->get_description(),
657 'short_description' => $product_obj->get_short_description(),
658 'url' => get_permalink($product_id),
659 'price' => $product_obj->get_regular_price(),
660 'sale_price' => $product_obj->get_sale_price(),
661 'stock_status' => $product_obj->get_stock_status(),
662 'sku' => $product_obj->get_sku(),
663 'in_stock' => $product_obj->is_in_stock(),
664 'total_sales' => $product_obj->get_total_sales(),
665 );
666 }
667
668 return $product_data;
669 }
670
671 }
672 ?>
673