';
$this->fallbackResponse = [
'text' => "",
'html' => $html_output,
];
// Save response in chat history
$this->mxchat_save_chat_message($session_id, 'bot', $html_output);
} else {
/*
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log("Brave Image API response did not contain expected data structure or was empty: " . print_r($body, true));
}
*/
$this->fallbackResponse = [
'text' => __("I'm sorry, I couldn't retrieve any images based on your request.", 'mxchat'),
'html' => "",
];
}
}
public function mxchat_interpret_search_query($user_query) {
$system_prompt = "Interpret the user's request to provide only the essential keywords or phrases for image searching. Remove conversational language, politeness, or extra context. Return a concise search query that doesn't lose any of the original meaning.";
// Retrieve OpenAI API key using 'api_key' as the option key
$api_key = isset($this->options['api_key']) ? sanitize_text_field($this->options['api_key']) : sanitize_text_field(get_option('mxchat_options')['api_key']);
/*
// Log the API key check, without exposing the key
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log("Retrieved OpenAI API Key: " . ($api_key ? "Present" : "Missing"));
}
*/
if (empty($api_key)) {
//error_log("OpenAI API key is missing.");
return sanitize_text_field($user_query); // Default to the original query if API key is missing
}
$url = 'https://api.openai.com/v1/chat/completions';
$args = [
'headers' => [
'Authorization' => 'Bearer ' . $api_key,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode([
'model' => 'gpt-3.5-turbo',
'messages' => [
['role' => 'system', 'content' => $system_prompt],
['role' => 'user', 'content' => sanitize_text_field($user_query)],
],
'temperature' => 0.2,
'max_tokens' => 20,
]),
'method' => 'POST',
];
$response = wp_remote_post($url, $args);
if (is_wp_error($response)) {
//error_log("OpenAI request failed: " . $response->get_error_message());
return sanitize_text_field($user_query); // Fallback to the original query if there's an error
}
$body = json_decode(wp_remote_retrieve_body($response), true);
// Check for a valid response and sanitize output
if (isset($body['choices'][0]['message']['content'])) {
$interpreted_query = sanitize_text_field(trim($body['choices'][0]['message']['content']));
/*
// Log the interpreted query for debugging
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log("Interpreted search query: " . $interpreted_query);
}
*/
return $interpreted_query;
} else {
//error_log("Unexpected API response format: " . print_r($body, true));
return sanitize_text_field($user_query);
}
}
//very good
public function mxchat_handle_add_to_cart_intent($message, $user_id, $session_id) {
// Check if WooCommerce is active before proceeding
if (!class_exists('WooCommerce')) {
// error_log("WooCommerce is not active. Add-to-cart intent cannot be processed.");
return false;
}
// Sanitize user ID for transient key
$sanitized_user_id = sanitize_key($user_id);
// Retrieve the last discussed product ID from the transient
$last_product_id = get_transient('mxchat_last_discussed_product_' . $sanitized_user_id);
if ($last_product_id) {
// Attempt to add the product to the WooCommerce cart
$added = WC()->cart->add_to_cart($last_product_id);
$product = wc_get_product($last_product_id);
if ($added && $product) {
// Escape product name for safety
$product_name = esc_html($product->get_name());
// Success response if the product is added to the cart
$response = "The product '{$product_name}' has been added to your cart. To proceed to checkout, please type 'checkout'.";
set_transient('mxchat_checkout_prompt_' . $sanitized_user_id, true, 5 * MINUTE_IN_SECONDS);
// Save the response in chat history and send a JSON response
$this->mxchat_save_chat_message($session_id, 'bot', $response);
wp_send_json(['message' => $response]);
wp_die();
} else {
// Failure response if the product could not be added
$response = "Sorry, I couldn't add the product to your cart. Please try again.";
$this->mxchat_save_chat_message($session_id, 'bot', $response);
wp_send_json(['message' => $response]);
wp_die();
}
} else {
// Prompt the user to specify the product name if no product was found
$response = "I couldn't find the product to add. Please mention the product name again.";
$this->mxchat_save_chat_message($session_id, 'bot', $response);
wp_send_json(['message' => $response]);
wp_die();
}
}
public function mxchat_handle_checkout_intent($message, $user_id, $session_id) {
// Ensure WooCommerce is available and perform checkout actions
if (class_exists('WooCommerce')) {
// Sanitize user ID for transient key
$sanitized_user_id = sanitize_key($user_id);
$checkout_prompt = get_transient('mxchat_checkout_prompt_' . $sanitized_user_id);
// Check if there is an active checkout prompt and if the cart has items
if ($checkout_prompt && WC()->cart->get_cart_contents_count() > 0) {
// Get and escape the checkout URL
$checkout_url = wc_get_checkout_url();
$checkout_url = esc_url_raw($checkout_url);
$response = "Great! Redirecting you to the checkout page...";
// Clear the checkout prompt transient to avoid duplicate responses
delete_transient('mxchat_checkout_prompt_' . $sanitized_user_id);
// Save and send the response with the checkout URL for redirection
$this->mxchat_save_chat_message($session_id, 'bot', $response);
wp_send_json(['message' => $response, 'redirect_url' => $checkout_url]);
wp_die();
} else {
// If no active checkout prompt or empty cart, prompt user to add items first
$response = "It seems like there is no active checkout prompt or no items in your cart. Please add a product to the cart first.";
$this->mxchat_save_chat_message($session_id, 'bot', $response);
wp_send_json(['message' => $response]);
wp_die();
}
} else {
// WooCommerce is not available, send an error message
$response = "WooCommerce is not active on this site, so checkout is not possible.";
$this->mxchat_save_chat_message($session_id, 'bot', $response);
wp_send_json(['message' => $response]);
wp_die();
}
}
//very good
public static function mxchat_extract_product_id_from_message($message) {
// Sanitize the message input
$message = sanitize_text_field($message);
// Convert Markdown links to plain URLs
$message = preg_replace('/\[(.*?)\]\((.*?)\)/', '$2', $message);
// Match all URLs in the message
preg_match_all('/https?:\/\/[^\s]+/', $message, $matches);
if (!empty($matches[0])) {
foreach ($matches[0] as $url) {
// Sanitize the URL
$url = esc_url_raw($url);
// Try to get the post ID from the URL
$post_id = url_to_postid($url);
if ($post_id) {
// Check if the post type is 'product'
if (get_post_type($post_id) === 'product') {
return $post_id;
}
}
}
}
return false;
}
//very good
private function add_email_to_loops($email) {
// Sanitize the email
$email = sanitize_email($email);
// Retrieve and sanitize options
$api_key = isset($this->options['loops_api_key']) ? sanitize_text_field($this->options['loops_api_key']) : '';
$mailing_list_id = isset($this->options['loops_mailing_list']) ? sanitize_text_field($this->options['loops_mailing_list']) : '';
// Check for missing API key or mailing list ID
if (empty($api_key) || empty($mailing_list_id)) {
//error_log('Loops API key or mailing list ID is missing.');
return;
}
$data = array(
'email' => $email,
'subscribed' => true,
'source' => 'MxChat AI Chatbot',
'mailingLists' => array($mailing_list_id => true),
);
$url = 'https://app.loops.so/api/v1/contacts/create';
$args = array(
'body' => wp_json_encode($data),
'headers' => array(
'Authorization' => 'Bearer ' . $api_key,
'Content-Type' => 'application/json',
),
'method' => 'POST',
'timeout' => 45,
);
$response = wp_remote_post($url, $args);
// Handle errors in the API request
if (is_wp_error($response)) {
//error_log('Error adding email to Loops: ' . $response->get_error_message());
return;
}
// Check for non-200 HTTP responses
$response_code = wp_remote_retrieve_response_code($response);
if ($response_code != 200) {
$response_body = wp_remote_retrieve_body($response);
//error_log('Loops API responded with code ' . $response_code . ': ' . $response_body);
}
}
public function mxchat_handle_pdf_discussion($message, $user_id, $session_id) {
// Get the maximum number of pages allowed from admin settings
$max_pages = isset($this->options['pdf_max_pages']) ? intval($this->options['pdf_max_pages']) : 69; // Default to 69
// Retrieve options for dynamic texts
$trigger_text = $this->options['pdf_intent_trigger_text'] ?? "Please provide the URL to the PDF you'd like to discuss.";
$success_text = $this->options['pdf_intent_success_text'] ?? "I've processed the PDF. What questions do you have about it?";
$error_text = $this->options['pdf_intent_error_text'] ?? "Sorry, I couldn't process the PDF. Please ensure it's a valid file.";
// Check if we're waiting for a URL
$waiting_for_url = get_transient('mxchat_waiting_for_pdf_url_' . $session_id);
// Check if we already have a PDF URL stored for this session
$pdf_url = get_transient('mxchat_pdf_url_' . $session_id);
// Always process a new URL if detected in the current message
if (preg_match('/https?:\/\/[^\s"]+/i', $message, $matches)) {
$new_pdf_url = $matches[0];
// Validate HTTPS
if (!wp_http_validate_url($new_pdf_url) || parse_url($new_pdf_url, PHP_URL_SCHEME) !== 'https') {
//error_log("Invalid PDF URL: $new_pdf_url");
$this->fallbackResponse['text'] = $trigger_text;
return;
}
// Reset previous transients if a new URL is provided
if ($pdf_url !== $new_pdf_url) {
//error_log("New PDF URL detected. Resetting previous transients for session $session_id.");
delete_transient('mxchat_pdf_url_' . $session_id);
delete_transient('mxchat_pdf_embeddings_' . $session_id);
delete_transient('mxchat_include_pdf_in_context_' . $session_id);
// Store the new PDF URL
set_transient('mxchat_pdf_url_' . $session_id, $new_pdf_url, HOUR_IN_SECONDS);
// Fetch and process the new PDF
$embeddings = $this->fetch_and_split_pdf_pages($new_pdf_url, $max_pages); // Ensure both arguments are passed
if ($embeddings === 'too_many_pages') {
//error_log("PDF exceeds maximum allowed pages ($max_pages) for URL: $new_pdf_url");
$error_text = sprintf(
$this->options['pdf_intent_error_text'] ?? "The provided PDF exceeds the maximum allowed limit of %d pages. Please provide a smaller document.",
$max_pages
);
$this->fallbackResponse['text'] = $error_text;
delete_transient('mxchat_pdf_url_' . $session_id);
} elseif ($embeddings) {
//error_log("PDF processed successfully for URL: $new_pdf_url");
set_transient('mxchat_pdf_embeddings_' . $session_id, $embeddings, HOUR_IN_SECONDS);
set_transient('mxchat_include_pdf_in_context_' . $session_id, true, HOUR_IN_SECONDS);
$this->fallbackResponse['text'] = $success_text;
} else {
//error_log("Failed to process PDF for URL: $new_pdf_url");
$this->fallbackResponse['text'] = $error_text;
delete_transient('mxchat_pdf_url_' . $session_id);
}
return;
}
}
if (!$pdf_url) {
//error_log("No PDF URL provided or stored for session $session_id.");
set_transient('mxchat_waiting_for_pdf_url_' . $session_id, true, HOUR_IN_SECONDS);
$this->fallbackResponse['text'] = $trigger_text;
return;
}
// Retrieve stored embeddings or fetch if missing
$embeddings = get_transient('mxchat_pdf_embeddings_' . $session_id);
if (!$embeddings) {
//error_log("No embeddings found for PDF URL: $pdf_url. Attempting to process again.");
$embeddings = $this->fetch_and_split_pdf_pages($pdf_url, $max_pages); // Ensure both arguments are passed
if ($embeddings === 'too_many_pages') {
//error_log("PDF exceeds maximum allowed pages ($max_pages) for URL: $pdf_url");
$this->fallbackResponse['text'] = "The provided PDF exceeds the maximum allowed limit of {$max_pages} pages. Please provide a smaller document.";
delete_transient('mxchat_pdf_url_' . $session_id);
} elseif ($embeddings) {
//error_log("PDF processed successfully for URL: $pdf_url");
set_transient('mxchat_pdf_embeddings_' . $session_id, $embeddings, HOUR_IN_SECONDS);
set_transient('mxchat_include_pdf_in_context_' . $session_id, true, HOUR_IN_SECONDS);
$this->fallbackResponse['text'] = $success_text;
} else {
//error_log("Failed to process PDF for URL: $pdf_url");
$this->fallbackResponse['text'] = $error_text;
delete_transient('mxchat_pdf_url_' . $session_id);
}
} else {
//error_log("Using stored embeddings for session $session_id.");
set_transient('mxchat_include_pdf_in_context_' . $session_id, true, HOUR_IN_SECONDS);
$this->fallbackResponse['text'] = ''; // Proceed without additional message
}
}
private function fetch_and_split_pdf_pages($pdf_url, $max_pages) {
$upload_dir = wp_upload_dir();
$local_pdf_path = $upload_dir['path'] . '/' . basename(parse_url($pdf_url, PHP_URL_PATH));
$response = wp_remote_get($pdf_url, ['timeout' => 60]);
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
//error_log("Failed to download PDF. Error: " . print_r($response, true));
return false;
}
file_put_contents($local_pdf_path, wp_remote_retrieve_body($response));
try {
$parser = new \Smalot\PdfParser\Parser();
$pdf = $parser->parseFile($local_pdf_path);
$pages = $pdf->getPages();
if (count($pages) > $max_pages) {
unlink($local_pdf_path);
return 'too_many_pages';
}
$embeddings = [];
foreach ($pages as $page_number => $page) {
$text = $page->getText();
$embedding = $this->mxchat_generate_embedding("Page " . ($page_number + 1) . ": " . $text, $this->options['api_key']);
if ($embedding) {
$embeddings[] = [
'page_number' => $page_number + 1,
'embedding' => $embedding,
'text' => $text,
];
} else {
//error_log("Failed to generate embedding for page " . ($page_number + 1));
}
}
unlink($local_pdf_path);
return $embeddings;
} catch (\Exception $e) {
unlink($local_pdf_path);
//error_log("Error parsing or processing PDF: " . $e->getMessage());
return false;
}
}
private function find_relevant_pdf_pages($query_embedding, $embeddings) {
//error_log("find_relevant_pdf_pages called.");
$most_relevant = null;
$highest_similarity = -INF;
foreach ($embeddings as $page_data) {
$similarity = $this->mxchat_calculate_cosine_similarity($query_embedding, $page_data['embedding']);
if ($similarity > $highest_similarity) {
$highest_similarity = $similarity;
$most_relevant = $page_data['page_number'];
}
}
if (!is_null($most_relevant)) {
$page_numbers = range(max(1, $most_relevant - 1), min(count($embeddings), $most_relevant + 1));
return array_filter($embeddings, function ($page) use ($page_numbers) {
return in_array($page['page_number'], $page_numbers);
});
}
return [];
}
private function mxchat_get_user_identifier() {
return MxChat_User::mxchat_get_user_identifier();
}
private function mxchat_generate_embedding($text, $api_key) {
$endpoint = 'https://api.openai.com/v1/embeddings';
$body = wp_json_encode([
'input' => $text,
'model' => 'text-embedding-ada-002'
]);
$args = [
'body' => $body,
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
],
'timeout' => 60,
'redirection' => 5,
'blocking' => true,
'httpversion' => '1.0',
'sslverify' => true,
];
$response = wp_remote_post($endpoint, $args);
if (is_wp_error($response)) {
return null;
}
$response_body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($response_body['data'][0]['embedding']) && is_array($response_body['data'][0]['embedding'])) {
return $response_body['data'][0]['embedding'];
} else {
return null;
}
}
private function mxchat_find_relevant_content($user_embedding) {
global $wpdb;
$system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
// Define a cache key for embeddings
$cache_key = 'mxchat_system_prompt_embeddings';
// Attempt to get the embeddings from the cache
$embeddings = wp_cache_get($cache_key, 'mxchat_system_prompts');
if ($embeddings === false) {
// Cache miss, query the database and cache the results
$query = "SELECT id, embedding_vector FROM {$system_prompt_table}";
$embeddings = $wpdb->get_results($query);
if ($embeddings === null || empty($embeddings)) {
return null; // Return null to handle no embeddings gracefully
}
// Cache the results if successful
wp_cache_set($cache_key, $embeddings, 'mxchat_system_prompts', 3600); // Cache for 1 hour
}
$most_relevant_id = null;
$highest_similarity = -INF;
foreach ($embeddings as $embedding) {
$database_embedding = $embedding->embedding_vector
? unserialize($embedding->embedding_vector, ['allowed_classes' => false])
: null;
if (is_array($database_embedding) && is_array($user_embedding)) {
$similarity = $this->mxchat_calculate_cosine_similarity($user_embedding, $database_embedding);
if ($similarity > $highest_similarity) {
$highest_similarity = $similarity;
$most_relevant_id = $embedding->id;
}
}
}
if ($most_relevant_id !== null) {
// Fetch content with product links
return $this->fetch_content_with_product_links($most_relevant_id);
}
return null; // Return null if no relevant content is found
}
private function fetch_content_with_product_links($most_relevant_id) {
global $wpdb;
$system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
// Fetch the article content and associated product URL
$query = $wpdb->prepare("SELECT article_content, source_url FROM {$system_prompt_table} WHERE id = %d", $most_relevant_id);
$result = $wpdb->get_row($query);
if ($result) {
// Append the product link to the content if available
$content = $result->article_content;
if (!empty($result->source_url)) {
$content .= "\n\nFor more details, check out this product: " . esc_url($result->source_url);
}
return $content;
}
return null;
}
private function mxchat_generate_response($relevant_content, $api_key, $xai_api_key, $claude_api_key, $conversation_history) {
if (!$relevant_content) {
return "I'm sorry, I couldn't find relevant information on that topic.";
}
// Check the selected model
$selected_model = isset($this->options['model']) ? $this->options['model'] : 'gpt-3.5-turbo';
// Call the appropriate function based on the selected model
if (strpos($selected_model, 'claude') !== false) {
return $this->mxchat_generate_response_claude($selected_model, $claude_api_key, $conversation_history, $relevant_content);
} elseif ($selected_model === 'grok-beta') {
return $this->mxchat_generate_response_xai($selected_model, $xai_api_key, $conversation_history, $relevant_content);
} else {
return $this->mxchat_generate_response_openai($selected_model, $api_key, $conversation_history, $relevant_content);
}
}
private function mxchat_generate_response_openai($selected_model, $api_key, $conversation_history, $relevant_content) {
// Get system prompt instructions from options
$system_prompt_instructions = isset($this->options['system_prompt_instructions']) ? $this->options['system_prompt_instructions'] : '';
// Add system prompt to relevant content
$content_with_instructions = $system_prompt_instructions . " " . $relevant_content;
// Prepend system instructions to the conversation history
array_unshift($conversation_history, [
'role' => 'system',
'content' => "Here are your instructions: " . $content_with_instructions
]);
// Ensure consistency: Replace 'bot' role with 'assistant' in conversation history
foreach ($conversation_history as &$message) {
if ($message['role'] === 'bot') {
$message['role'] = 'assistant';
}
}
// Build the request body
$body = json_encode([
'model' => $selected_model,
'messages' => $conversation_history,
'temperature' => 0.8,
'stream' => false
]);
// Set up the API request
$args = [
'body' => $body,
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
],
'timeout' => 60,
'redirection' => 5,
'blocking' => true,
'httpversion' => '1.0',
'sslverify' => true,
];
// Make the API request
$response = wp_remote_post('https://api.openai.com/v1/chat/completions', $args);
// Process the response
if (is_wp_error($response)) {
return "Sorry, there was an error processing your request.";
}
$response_body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($response_body['choices'][0]['message']['content'])) {
return trim($response_body['choices'][0]['message']['content']);
} else {
return "Sorry, I couldn't process that request.";
}
}
private function mxchat_generate_response_xai($selected_model, $xai_api_key, $conversation_history, $relevant_content) {
// Get system prompt instructions from options
$system_prompt_instructions = isset($this->options['system_prompt_instructions']) ? $this->options['system_prompt_instructions'] : '';
// Add system prompt to relevant content
$content_with_instructions = $system_prompt_instructions . " " . $relevant_content;
// Prepend system instructions to the conversation history
array_unshift($conversation_history, [
'role' => 'system',
'content' => "Here are your instructions: " . $content_with_instructions
]);
// Ensure consistency: Replace 'bot' role with 'assistant' in conversation history
foreach ($conversation_history as &$message) {
if ($message['role'] === 'bot') {
$message['role'] = 'assistant';
}
}
// Build the request body
$body = json_encode([
'model' => $selected_model,
'messages' => $conversation_history,
'temperature' => 0.8,
'stream' => false
]);
// Set up the API request
$args = [
'body' => $body,
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $xai_api_key,
],
'timeout' => 60,
'redirection' => 5,
'blocking' => true,
'httpversion' => '1.0',
'sslverify' => true,
];
// Make the API request
$response = wp_remote_post('https://api.x.ai/v1/chat/completions', $args);
// Process the response
if (is_wp_error($response)) {
return "Sorry, there was an error processing your request.";
}
$response_body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($response_body['choices'][0]['message']['content'])) {
return trim($response_body['choices'][0]['message']['content']);
} else {
return "Sorry, I couldn't process that request.";
}
}
private function mxchat_generate_response_claude($selected_model, $claude_api_key, $conversation_history, $relevant_content) {
// Get system prompt instructions from options for Claude's top-level system parameter
$system_prompt_instructions = isset($this->options['system_prompt_instructions']) ? $this->options['system_prompt_instructions'] : '';
// Ensure consistency: Replace 'bot' role with 'assistant' in conversation history
foreach ($conversation_history as &$message) {
if ($message['role'] === 'bot') {
$message['role'] = 'assistant';
}
}
// Add relevant content as the latest user message in conversation history
$conversation_history[] = [
'role' => 'user',
'content' => $relevant_content
];
// Build the request body with Claude's expected structure, using system instructions as a top-level parameter
$body = json_encode([
'model' => $selected_model,
'max_tokens' => 1000,
'temperature' => 0.8,
'system' => $system_prompt_instructions, // Set the system prompt at the top level as required
'messages' => $conversation_history
]);
// Set up the API request with the necessary headers
$args = [
'body' => $body,
'headers' => [
'Content-Type' => 'application/json',
'x-api-key' => $claude_api_key,
'anthropic-version' => '2023-06-01',
],
'timeout' => 60,
'redirection' => 5,
'blocking' => true,
'httpversion' => '1.0',
'sslverify' => true,
];
// Make the API request
$response = wp_remote_post('https://api.anthropic.com/v1/messages', $args);
/*
// Check for errors and log the response for debugging
if (is_wp_error($response)) {
error_log("Claude API request error: " . print_r($response->get_error_message(), true));
return "Sorry, there was an error processing your request.";
}
*/
// Decode the response and parse according to the expected Claude response structure
$response_body = json_decode(wp_remote_retrieve_body($response), true);
//error_log("Claude API response: " . print_r($response_body, true));
// Check if the response has the expected 'content' array with 'text' blocks
if (isset($response_body['content'][0]['text'])) {
return trim($response_body['content'][0]['text']);
} else {
return "Sorry, I couldn't process that request.";
}
}
public function mxchat_dismiss_pre_chat_message() {
// Get and sanitize the user identifier
$user_id = $this->mxchat_get_user_identifier();
$user_id = sanitize_key($user_id);
// Set a transient to track that the user has dismissed the pre-chat message
$transient_key = 'mxchat_pre_chat_message_dismissed_' . $user_id;
set_transient($transient_key, true, DAY_IN_SECONDS);
wp_send_json_success();
}
public function mxchat_check_pre_chat_message_status() {
// Get and sanitize the user identifier
$user_id = $this->mxchat_get_user_identifier();
$user_id = sanitize_key($user_id);
// Check if the transient exists (i.e., if the message was dismissed)
$transient_key = 'mxchat_pre_chat_message_dismissed_' . $user_id;
$dismissed = get_transient($transient_key);
// Log the result to see if it's being set correctly
//error_log("Check pre-chat message dismissed for $user_id: " . ($dismissed ? 'Yes' : 'No'));
if ($dismissed) {
wp_send_json_success(['dismissed' => true]);
} else {
wp_send_json_success(['dismissed' => false]);
}
wp_die();
}
private function mxchat_calculate_cosine_similarity($vectorA, $vectorB) {
if (!is_array($vectorA) || !is_array($vectorB) || empty($vectorA) || empty($vectorB)) {
return 0;
}
$dotProduct = array_sum(array_map(function ($a, $b) {
return $a * $b;
}, $vectorA, $vectorB));
$normA = sqrt(array_sum(array_map(function ($a) {
return $a * $a;
}, $vectorA)));
$normB = sqrt(array_sum(array_map(function ($b) {
return $b * $b;
}, $vectorB)));
if ($normA == 0 || $normB == 0) {
return 0;
}
return $dotProduct / ($normA * $normB);
}
public function mxchat_enqueue_scripts_styles() {
// Define version numbers for the styles and scripts
$chat_style_version = '1.4.4'; // Replace with your actual version
$chat_script_version = '1.4.4'; // Replace with your actual version
// Correct path to the script file
wp_enqueue_script(
'mxchat-chat-js', // Handle for the script
plugin_dir_url(__FILE__) . '../js/chat-script.js', // Correct path using __FILE__
array('jquery'), // Dependencies
$chat_script_version, // Version for cache busting
true // Load script in footer
);
// Enqueue the CSS file similarly
wp_enqueue_style(
'mxchat-chat-css', // Handle for the style
plugin_dir_url(__FILE__) . '../css/chat-style.css', // Correct path using __FILE__
array(), // No dependencies
$chat_style_version // Version for cache busting
);
// Fetch options from the database
$this->options = get_option('mxchat_options');
// Prepare settings to pass to JavaScript
$style_settings = array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('mxchat_chat_nonce'), // Nonce for security
'rate_limit_message' => $this->options['rate_limit_message'] ?? 'Rate limit exceeded. Please try again later.',
'appendWidgetToBody' => $this->options['append_to_body'] ?? 'off'
);
// Localize the script with necessary data
wp_localize_script('mxchat-chat-js', 'mxchatChat', $style_settings);
}
public function mxchat_reset_rate_limits() {
global $wpdb;
// Define a cache key pattern for rate limits
$cache_key_pattern = 'mxchat_chat_limit_%';
// Retrieve all option names matching the pattern
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
$option_names = $wpdb->get_col("SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE 'mxchat_chat_limit_%'");
// db call ok; no-cache ok
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- db call ok
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE 'mxchat_chat_limit_%'");
// Clear the relevant cache entries
foreach ($option_names as $option_name) {
wp_cache_delete($option_name, 'options');
}
// Optionally, clear a general cache if you have one
wp_cache_delete('mxchat_all_chat_limits', 'options');
}
private function mxchat_fetch_woocommerce_products() {
// Ensure WooCommerce is active
if (!class_exists('WooCommerce')) {
return [];
}
$args = array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => -1,
);
$products = get_posts($args);
$product_data = [];
foreach ($products as $product) {
$product_id = $product->ID;
$product_obj = wc_get_product($product_id);
$product_data[] = array(
'id' => $product_id,
'name' => $product_obj->get_name(),
'description' => $product_obj->get_description(),
'short_description' => $product_obj->get_short_description(),
'url' => get_permalink($product_id),
'price' => $product_obj->get_regular_price(),
'sale_price' => $product_obj->get_sale_price(),
'stock_status' => $product_obj->get_stock_status(),
'sku' => $product_obj->get_sku(),
'in_stock' => $product_obj->is_in_stock(),
'total_sales' => $product_obj->get_total_sales(),
);
}
return $product_data;
}
}
?>