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 +98 -80 3.2.23.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'));
@@ -990,18 +993,10 @@
990 993 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
991 994 exit;
992 995 }
993 996
994 - // Fetch URL — use browser-like headers so servers with bot protection don't block us
995 - $response = wp_remote_get($submitted_url, array(
996 - 'timeout' => 30,
997 - 'sslverify' => false,
998 - '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',
999 - 'headers' => array(
1000 - 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
1001 - 'Accept-Language' => 'en-US,en;q=0.9',
1002 - ),
1003 - ));
997 + // Fetch URL
998 + $response = wp_remote_get($submitted_url, array('timeout' => 30));
1004 999
1005 1000 if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
1006 1001 $error_message = is_wp_error($response) ? $response->get_error_message() : 'HTTP Status: ' . wp_remote_retrieve_response_code($response);
1007 1002 set_transient('mxchat_admin_notice_error',
@@ -2835,12 +2830,11 @@
2835 2830 foreach ($primary_indexes as $path => $source) {
2836 2831 $url = trailingslashit($site_url) . $path;
2837 2832
2838 2833 $response = wp_remote_head($url, array(
2839 - 'timeout' => 10,
2834 + 'timeout' => 3, // Short timeout
2840 2835 'sslverify' => false,
2841 - 'redirection' => 1,
2842 - '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
2843 2837 ));
2844 2838
2845 2839 if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
2846 2840 // Found a sitemap index - parse it to get sub-sitemaps
@@ -2898,15 +2892,10 @@
2898 2892 private function parse_sitemap_index($url) {
2899 2893 $sub_sitemaps = array();
2900 2894
2901 2895 $response = wp_remote_get($url, array(
2902 - 'timeout' => 30,
2903 - 'sslverify' => false,
2904 - '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',
2905 - 'headers' => array(
2906 - 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
2907 - 'Accept-Language' => 'en-US,en;q=0.9',
2908 - ),
2896 + 'timeout' => 5,
2897 + 'sslverify' => false
2909 2898 ));
2910 2899
2911 2900 if (is_wp_error($response)) {
2912 2901 return $sub_sitemaps;
@@ -2957,15 +2946,10 @@
2957 2946 * Get URL count from a sitemap
2958 2947 */
2959 2948 private function get_sitemap_url_count($url) {
2960 2949 $response = wp_remote_get($url, array(
2961 - 'timeout' => 30,
2962 - 'sslverify' => false,
2963 - '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',
2964 - 'headers' => array(
2965 - 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
2966 - 'Accept-Language' => 'en-US,en;q=0.9',
2967 - ),
2950 + 'timeout' => 10,
2951 + 'sslverify' => false
2968 2952 ));
2969 2953
2970 2954 if (is_wp_error($response)) {
2971 2955 return 0;
@@ -2988,11 +2972,10 @@
2988 2972 $sitemaps = array();
2989 2973 $robots_url = trailingslashit($site_url) . 'robots.txt';
2990 2974
2991 2975 $response = wp_remote_get($robots_url, array(
2992 - 'timeout' => 15,
2993 - 'sslverify' => false,
2994 - '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
2995 2978 ));
2996 2979
2997 2980 if (is_wp_error($response)) {
2998 2981 return $sitemaps;
@@ -5181,33 +5164,40 @@
5181 5164 // If the post was previously published but is now not published, remove from knowledge base
5182 5165 if ($previous_status === 'publish' && $post->post_status !== 'publish') {
5183 5166 // Use the stored URL from when it was published, or fall back to current permalink
5184 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';
5185 5173
5186 - if ($source_url) {
5187 - // Chunk-aware deletion (routes to Pinecone or WP DB and removes base + all chunks)
5188 - 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 + }
5189 5188 }
5190 -
5189 +
5191 5190 // Clean up the transients and exit early
5192 5191 delete_transient($previous_status_key);
5193 5192 delete_transient($previous_url_key);
5194 5193 return;
5195 5194 }
5196 -
5197 - // Slug/permalink rename while still published: delete the old vectors before upserting new ones.
5198 - // Without this, md5(old_url) vectors (base + chunks) would be orphaned under the stale URL.
5199 - if ($post->post_status === 'publish' && !empty($previous_url)) {
5200 - $current_url = get_permalink($post_id);
5201 - if ($current_url && $current_url !== $previous_url) {
5202 - MxChat_Utils::delete_chunks_for_url($previous_url, 'default');
5203 - }
5204 - }
5205 -
5195 +
5206 5196 // Store the current status for next time (if this is an update)
5207 5197 if ($update) {
5208 5198 set_transient($previous_status_key, $post->post_status, DAY_IN_SECONDS);
5209 -
5199 +
5210 5200 // If the post is currently published, also store its URL
5211 5201 if ($post->post_status === 'publish') {
5212 5202 $current_url = get_permalink($post_id);
5213 5203 set_transient($previous_url_key, $current_url, DAY_IN_SECONDS);
@@ -5437,14 +5427,12 @@
5437 5427 if (!$should_sync) {
5438 5428 return;
5439 5429 }
5440 5430
5441 - // Resolve the pre-trash URL. wp_trash_post renames the slug with "__trashed" before firing
5442 - // this hook, so get_permalink() here would return the trashed URL and md5() would miss the
5443 - // real vector IDs stored under the original URL.
5444 - $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);
5445 5433 if (!$source_url) {
5446 - //error_log('MXChat: Failed to resolve source URL for post ' . $post_id);
5434 + //error_log('MXChat: Failed to get permalink for post ' . $post_id);
5447 5435 return;
5448 5436 }
5449 5437
5450 5438 // Use chunk-aware deletion (handles both chunked and non-chunked content)
@@ -5452,36 +5440,56 @@
5452 5440
5453 5441 if (is_wp_error($delete_result)) {
5454 5442 //error_log('MXChat: Chunk-aware deletion failed for URL: ' . $source_url . ' - ' . $delete_result->get_error_message());
5455 5443 }
5444 +}
5456 5445
5457 - delete_transient('mxchat_prev_url_' . $post_id);
5458 - delete_transient('mxchat_prev_status_' . $post_id);
5459 -}
5460 5446
5461 -/**
5462 - * Resolve the source URL for a post being trashed/deleted.
5463 - *
5464 - * Why: wp_trash_post appends "__trashed" to the slug before the wp_trash_post action fires, so
5465 - * get_permalink() returns a URL whose md5() won't match the vector IDs stored in Pinecone or
5466 - * the source_url rows in the WP DB. Prefer the URL captured by mxchat_store_pre_update_status
5467 - * (runs on pre_post_update, before the rename); fall back to stripping the __trashed suffix.
5468 - */
5469 -private function mxchat_resolve_pre_trash_url($post_id) {
5470 - $previous_url = get_transient('mxchat_prev_url_' . $post_id);
5471 - if (!empty($previous_url)) {
5472 - return $previous_url;
5473 - }
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'] ?? '';
5474 5453
5475 - $current = get_permalink($post_id);
5476 - if (!$current) {
5477 - return '';
5478 - }
5479 - return preg_replace('#__trashed(/?)$#', '$1', $current);
5480 -}
5454 + if (empty($host) || empty($api_key)) {
5455 + //error_log('MXChat: Pinecone deletion failed - missing configuration');
5456 + return false;
5457 + }
5481 5458
5459 + $api_endpoint = "https://{$host}/vectors/delete";
5460 + $vector_id = md5($source_url);
5482 5461
5462 + $request_body = array(
5463 + 'ids' => array($vector_id)
5464 + );
5483 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 +
5484 5492 public function mxchat_handle_product_change($post_id, $post, $update) {
5485 5493 if ($post->post_type !== 'product') {
5486 5494 return;
5487 5495 }
@@ -5633,18 +5641,28 @@
5633 5641 if (get_post_type($post_id) !== 'product') {
5634 5642 return;
5635 5643 }
5636 5644
5637 - $source_url = $this->mxchat_resolve_pre_trash_url($post_id);
5638 - if (!$source_url) {
5639 - return;
5640 - }
5645 + $source_url = get_permalink($post_id);
5641 5646
5642 - // Chunk-aware deletion (routes to Pinecone or WP DB and removes base + all chunks)
5643 - 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';
5644 5650
5645 - delete_transient('mxchat_prev_url_' . $post_id);
5646 - 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 + }
5647 5665 }
5648 5666
5649 5667 /**
5650 5668 * Handle individual Pinecone content deletion