PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 3.1.7
MxChat – AI Chatbot & Content Generation for WordPress v3.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
← All changes | admin/class-knowledge-manager.php +99 -82 3.2.33.1.7 View file →
@@ -59,8 +59,11 @@
59 59 add_action('wp_ajax_mxchat_paginate_entries', array($this, 'ajax_mxchat_paginate_entries'));
60 60 add_action('wp_ajax_mxchat_get_entry_content', array($this, 'ajax_mxchat_get_entry_content'));
61 61 add_action('wp_ajax_mxchat_save_entry_content', array($this, 'ajax_mxchat_save_entry_content'));
62 62
63 + // Hook for content deletion
64 + add_action('mxchat_delete_content', array($this, 'mxchat_delete_from_pinecone_by_url'), 10, 1);
65 +
63 66 // WordPress post management hooks
64 67 add_action('pre_post_update', array($this, 'mxchat_store_pre_update_status'), 10, 2);
65 68 add_action('post_updated', array($this, 'mxchat_handle_post_update'), 10, 3);
66 69 add_action('before_delete_post', array($this, 'mxchat_handle_post_delete'));
@@ -602,12 +605,11 @@
602 605 array(
603 606 'article_content' => $article_content,
604 607 'embedding_vector' => $embedding_vector_serialized,
605 608 'source_url' => $article_url,
606 - 'embedding_model' => MxChat_Utils::get_active_embedding_model(),
607 609 ),
608 610 array('id' => $prompt_id),
609 - array('%s', '%s', '%s', '%s'),
611 + array('%s', '%s', '%s'),
610 612 array('%d')
611 613 );
612 614 if ($updated !== false) {
613 615 wp_send_json_success();
@@ -991,18 +993,10 @@
991 993 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
992 994 exit;
993 995 }
994 996
995 - // Fetch URL — use browser-like headers so servers with bot protection don't block us
996 - $response = wp_remote_get($submitted_url, array(
997 - 'timeout' => 30,
998 - 'sslverify' => false,
999 - 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
1000 - 'headers' => array(
1001 - 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
1002 - 'Accept-Language' => 'en-US,en;q=0.9',
1003 - ),
1004 - ));
997 + // Fetch URL
998 + $response = wp_remote_get($submitted_url, array('timeout' => 30));
1005 999
1006 1000 if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
1007 1001 $error_message = is_wp_error($response) ? $response->get_error_message() : 'HTTP Status: ' . wp_remote_retrieve_response_code($response);
1008 1002 set_transient('mxchat_admin_notice_error',
@@ -2836,12 +2830,11 @@
2836 2830 foreach ($primary_indexes as $path => $source) {
2837 2831 $url = trailingslashit($site_url) . $path;
2838 2832
2839 2833 $response = wp_remote_head($url, array(
2840 - 'timeout' => 10,
2834 + 'timeout' => 3, // Short timeout
2841 2835 'sslverify' => false,
2842 - 'redirection' => 1,
2843 - 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
2836 + 'redirection' => 1
2844 2837 ));
2845 2838
2846 2839 if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
2847 2840 // Found a sitemap index - parse it to get sub-sitemaps
@@ -2899,15 +2892,10 @@
2899 2892 private function parse_sitemap_index($url) {
2900 2893 $sub_sitemaps = array();
2901 2894
2902 2895 $response = wp_remote_get($url, array(
2903 - 'timeout' => 30,
2904 - 'sslverify' => false,
2905 - 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
2906 - 'headers' => array(
2907 - 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
2908 - 'Accept-Language' => 'en-US,en;q=0.9',
2909 - ),
2896 + 'timeout' => 5,
2897 + 'sslverify' => false
2910 2898 ));
2911 2899
2912 2900 if (is_wp_error($response)) {
2913 2901 return $sub_sitemaps;
@@ -2958,15 +2946,10 @@
2958 2946 * Get URL count from a sitemap
2959 2947 */
2960 2948 private function get_sitemap_url_count($url) {
2961 2949 $response = wp_remote_get($url, array(
2962 - 'timeout' => 30,
2963 - 'sslverify' => false,
2964 - 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
2965 - 'headers' => array(
2966 - 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
2967 - 'Accept-Language' => 'en-US,en;q=0.9',
2968 - ),
2950 + 'timeout' => 10,
2951 + 'sslverify' => false
2969 2952 ));
2970 2953
2971 2954 if (is_wp_error($response)) {
2972 2955 return 0;
@@ -2989,11 +2972,10 @@
2989 2972 $sitemaps = array();
2990 2973 $robots_url = trailingslashit($site_url) . 'robots.txt';
2991 2974
2992 2975 $response = wp_remote_get($robots_url, array(
2993 - 'timeout' => 15,
2994 - 'sslverify' => false,
2995 - 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
2976 + 'timeout' => 5,
2977 + 'sslverify' => false
2996 2978 ));
2997 2979
2998 2980 if (is_wp_error($response)) {
2999 2981 return $sitemaps;
@@ -5182,33 +5164,40 @@
5182 5164 // If the post was previously published but is now not published, remove from knowledge base
5183 5165 if ($previous_status === 'publish' && $post->post_status !== 'publish') {
5184 5166 // Use the stored URL from when it was published, or fall back to current permalink
5185 5167 $source_url = $previous_url ?: get_permalink($post_id);
5168 +
5169 + if ($source_url) {
5170 + // Check if Pinecone is enabled
5171 + $pinecone_options = get_option('mxchat_pinecone_addon_options', array());
5172 + $use_pinecone = ($pinecone_options['mxchat_use_pinecone'] ?? '0') === '1';
5186 5173
5187 - if ($source_url) {
5188 - // Chunk-aware deletion (routes to Pinecone or WP DB and removes base + all chunks)
5189 - MxChat_Utils::delete_chunks_for_url($source_url, 'default');
5174 + if ($use_pinecone && !empty($pinecone_options['mxchat_pinecone_api_key'])) {
5175 + // Delete from Pinecone
5176 + $this->mxchat_delete_from_pinecone_by_url($source_url, $pinecone_options);
5177 + } else {
5178 + // Delete from WordPress DB
5179 + global $wpdb;
5180 + $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
5181 +
5182 + $result = $wpdb->delete(
5183 + $table_name,
5184 + array('source_url' => $source_url),
5185 + array('%s')
5186 + );
5187 + }
5190 5188 }
5191 -
5189 +
5192 5190 // Clean up the transients and exit early
5193 5191 delete_transient($previous_status_key);
5194 5192 delete_transient($previous_url_key);
5195 5193 return;
5196 5194 }
5197 -
5198 - // Slug/permalink rename while still published: delete the old vectors before upserting new ones.
5199 - // Without this, md5(old_url) vectors (base + chunks) would be orphaned under the stale URL.
5200 - if ($post->post_status === 'publish' && !empty($previous_url)) {
5201 - $current_url = get_permalink($post_id);
5202 - if ($current_url && $current_url !== $previous_url) {
5203 - MxChat_Utils::delete_chunks_for_url($previous_url, 'default');
5204 - }
5205 - }
5206 -
5195 +
5207 5196 // Store the current status for next time (if this is an update)
5208 5197 if ($update) {
5209 5198 set_transient($previous_status_key, $post->post_status, DAY_IN_SECONDS);
5210 -
5199 +
5211 5200 // If the post is currently published, also store its URL
5212 5201 if ($post->post_status === 'publish') {
5213 5202 $current_url = get_permalink($post_id);
5214 5203 set_transient($previous_url_key, $current_url, DAY_IN_SECONDS);
@@ -5438,14 +5427,12 @@
5438 5427 if (!$should_sync) {
5439 5428 return;
5440 5429 }
5441 5430
5442 - // Resolve the pre-trash URL. wp_trash_post renames the slug with "__trashed" before firing
5443 - // this hook, so get_permalink() here would return the trashed URL and md5() would miss the
5444 - // real vector IDs stored under the original URL.
5445 - $source_url = $this->mxchat_resolve_pre_trash_url($post_id);
5431 + // Get the URL before post is deleted
5432 + $source_url = get_permalink($post_id);
5446 5433 if (!$source_url) {
5447 - //error_log('MXChat: Failed to resolve source URL for post ' . $post_id);
5434 + //error_log('MXChat: Failed to get permalink for post ' . $post_id);
5448 5435 return;
5449 5436 }
5450 5437
5451 5438 // Use chunk-aware deletion (handles both chunked and non-chunked content)
@@ -5453,36 +5440,56 @@
5453 5440
5454 5441 if (is_wp_error($delete_result)) {
5455 5442 //error_log('MXChat: Chunk-aware deletion failed for URL: ' . $source_url . ' - ' . $delete_result->get_error_message());
5456 5443 }
5444 +}
5457 5445
5458 - delete_transient('mxchat_prev_url_' . $post_id);
5459 - delete_transient('mxchat_prev_status_' . $post_id);
5460 -}
5461 5446
5462 -/**
5463 - * Resolve the source URL for a post being trashed/deleted.
5464 - *
5465 - * Why: wp_trash_post appends "__trashed" to the slug before the wp_trash_post action fires, so
5466 - * get_permalink() returns a URL whose md5() won't match the vector IDs stored in Pinecone or
5467 - * the source_url rows in the WP DB. Prefer the URL captured by mxchat_store_pre_update_status
5468 - * (runs on pre_post_update, before the rename); fall back to stripping the __trashed suffix.
5469 - */
5470 -private function mxchat_resolve_pre_trash_url($post_id) {
5471 - $previous_url = get_transient('mxchat_prev_url_' . $post_id);
5472 - if (!empty($previous_url)) {
5473 - return $previous_url;
5474 - }
5447 + /**
5448 + * Deletes data from Pinecone using a source URL
5449 + */
5450 + public function mxchat_delete_from_pinecone_by_url($source_url, $pinecone_options) {
5451 + $host = $pinecone_options['mxchat_pinecone_host'] ?? '';
5452 + $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? '';
5475 5453
5476 - $current = get_permalink($post_id);
5477 - if (!$current) {
5478 - return '';
5479 - }
5480 - return preg_replace('#__trashed(/?)$#', '$1', $current);
5481 -}
5454 + if (empty($host) || empty($api_key)) {
5455 + //error_log('MXChat: Pinecone deletion failed - missing configuration');
5456 + return false;
5457 + }
5482 5458
5459 + $api_endpoint = "https://{$host}/vectors/delete";
5460 + $vector_id = md5($source_url);
5483 5461
5462 + $request_body = array(
5463 + 'ids' => array($vector_id)
5464 + );
5484 5465
5466 + $response = wp_remote_post($api_endpoint, array(
5467 + 'headers' => array(
5468 + 'Api-Key' => $api_key,
5469 + 'accept' => 'application/json',
5470 + 'content-type' => 'application/json'
5471 + ),
5472 + 'body' => wp_json_encode($request_body),
5473 + 'timeout' => 30
5474 + ));
5475 +
5476 + if (is_wp_error($response)) {
5477 + //error_log('MXChat: Pinecone deletion error - ' . $response->get_error_message());
5478 + return false;
5479 + }
5480 +
5481 + $response_code = wp_remote_retrieve_response_code($response);
5482 + if ($response_code !== 200) {
5483 + //error_log('MXChat: Pinecone deletion failed with status ' . $response_code);
5484 + return false;
5485 + }
5486 +
5487 + return true;
5488 + }
5489 +
5490 +
5491 +
5485 5492 public function mxchat_handle_product_change($post_id, $post, $update) {
5486 5493 if ($post->post_type !== 'product') {
5487 5494 return;
5488 5495 }
@@ -5634,18 +5641,28 @@
5634 5641 if (get_post_type($post_id) !== 'product') {
5635 5642 return;
5636 5643 }
5637 5644
5638 - $source_url = $this->mxchat_resolve_pre_trash_url($post_id);
5639 - if (!$source_url) {
5640 - return;
5641 - }
5645 + $source_url = get_permalink($post_id);
5642 5646
5643 - // Chunk-aware deletion (routes to Pinecone or WP DB and removes base + all chunks)
5644 - MxChat_Utils::delete_chunks_for_url($source_url, 'default');
5647 + // Check if Pinecone is enabled
5648 + $pinecone_options = get_option('mxchat_pinecone_addon_options', array());
5649 + $use_pinecone = ($pinecone_options['mxchat_use_pinecone'] ?? '0') === '1';
5645 5650
5646 - delete_transient('mxchat_prev_url_' . $post_id);
5647 - delete_transient('mxchat_prev_status_' . $post_id);
5651 + if ($use_pinecone && !empty($pinecone_options['mxchat_pinecone_api_key'])) {
5652 + // Delete from Pinecone
5653 + $this->mxchat_delete_from_pinecone_by_url($source_url, $pinecone_options);
5654 + } else {
5655 + // Delete from WordPress DB
5656 + global $wpdb;
5657 + $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
5658 +
5659 + $wpdb->delete(
5660 + $table_name,
5661 + array('source_url' => $source_url),
5662 + array('%s')
5663 + );
5664 + }
5648 5665 }
5649 5666
5650 5667 /**
5651 5668 * Handle individual Pinecone content deletion