PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 3.1.4
MxChat – AI Chatbot & Content Generation for WordPress v3.1.4
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 | includes/class-mxchat-utils.php +23 -40 3.2.23.1.4 View file →
@@ -177,15 +177,9 @@
177 177 }
178 178
179 179 // ===== FIXED: Generate unique identifier for manual content =====
180 180 $original_source_url = $source_url;
181 - // Check if this is truly manual content (no URL at all) vs a real URL that filter_var rejects
182 - // filter_var(FILTER_VALIDATE_URL) rejects valid URLs with encoded chars, non-ASCII, fragments, etc.
183 - // Use a looser check: if it starts with http(s):// or has a scheme, it's a URL
184 - $has_url_scheme = !empty($source_url) && preg_match('#^https?://#i', $source_url);
185 - // Treat legacy mxchat.ai source URLs as manual — old bug assigned the site URL to manual entries
186 - $is_legacy_mxchat_url = $has_url_scheme && strpos($source_url, 'mxchat.ai') !== false;
187 - $is_manual_content = empty($source_url) || $source_url === '' || !$has_url_scheme || $is_legacy_mxchat_url;
181 + $is_manual_content = empty($source_url) || $source_url === '' || !filter_var($source_url, FILTER_VALIDATE_URL);
188 182
189 183 if ($is_manual_content) {
190 184 // Generate unique identifier for manual content to prevent overwrites
191 185 $source_url = 'mxchat://manual-content/' . time() . '-' . wp_generate_password(8, false);
@@ -309,14 +303,14 @@
309 303 // ===== UPDATED: Handle manual content with unique vector IDs =====
310 304 if ($vector_id) {
311 305 // Use provided vector ID
312 306 //error_log('[MXCHAT-PINECONE-MAIN] Using provided vector ID: ' . $vector_id);
313 - } elseif (!empty($url) && preg_match('#^https?://#i', $url)) {
314 - // For URLs, use URL-based ID (existing behavior)
307 + } elseif (!empty($url) && filter_var($url, FILTER_VALIDATE_URL)) {
308 + // For valid URLs, use URL-based ID (existing behavior)
315 309 $vector_id = md5($url);
316 310 //error_log('[MXCHAT-PINECONE-MAIN] Generated vector ID from URL: ' . $vector_id);
317 311 } else {
318 - // For manual content (empty/no URL scheme), generate unique ID
312 + // For manual content (empty/invalid URL), generate unique ID
319 313 $vector_id = 'manual_' . time() . '_' . substr(md5($content . microtime(true)), 0, 8);
320 314 //error_log('[MXCHAT-PINECONE-MAIN] Generated unique vector ID for manual content: ' . $vector_id);
321 315 }
322 316 // ===== END UPDATE =====
@@ -352,9 +346,9 @@
352 346 // Fallback to old detection logic for backwards compatibility
353 347 $is_product = false;
354 348 $content_type = 'manual'; // Default for manual content
355 349
356 - if (!empty($url) && preg_match('#^https?://#i', $url)) {
350 + if (!empty($url) && filter_var($url, FILTER_VALIDATE_URL)) {
357 351 $is_product = (strpos($url, '/product/') !== false || strpos($url, '/shop/') !== false);
358 352 $content_type = $is_product ? 'product' : 'content';
359 353 }
360 354 }
@@ -804,34 +798,31 @@
804 798
805 799 // Add the original single-vector ID (for non-chunked content)
806 800 $vectors_to_delete[] = $base_vector_id;
807 801
808 - // Pinecone /vectors/list is a GET endpoint with query-string parameters; a POST here returns a
809 - // non-200 silently and we end up only deleting the base vector, leaving chunks orphaned.
810 - $query_params = array(
802 + // Use Pinecone list API to find all chunk vectors with this prefix
803 + $list_url = "https://{$host}/vectors/list";
804 +
805 + $list_body = array(
811 806 'prefix' => $base_vector_id . '_chunk_',
812 - 'limit' => 100,
807 + 'limit' => 100
813 808 );
809 +
814 810 if (!empty($namespace)) {
815 - $query_params['namespace'] = $namespace;
811 + $list_body['namespace'] = $namespace;
816 812 }
817 813
818 - $list_url = "https://{$host}/vectors/list?" . http_build_query($query_params);
814 + $list_response = wp_remote_post($list_url, array(
815 + 'headers' => array(
816 + 'Api-Key' => $api_key,
817 + 'accept' => 'application/json',
818 + 'content-type' => 'application/json'
819 + ),
820 + 'body' => wp_json_encode($list_body),
821 + 'timeout' => 30
822 + ));
819 823
820 - // Paginate in case a URL has more than 100 chunks.
821 - do {
822 - $list_response = wp_remote_get($list_url, array(
823 - 'headers' => array(
824 - 'Api-Key' => $api_key,
825 - 'accept' => 'application/json',
826 - ),
827 - 'timeout' => 30,
828 - ));
829 -
830 - if (is_wp_error($list_response) || wp_remote_retrieve_response_code($list_response) !== 200) {
831 - break;
832 - }
833 -
824 + if (!is_wp_error($list_response)) {
834 825 $list_data = json_decode(wp_remote_retrieve_body($list_response), true);
835 826 if (!empty($list_data['vectors'])) {
836 827 foreach ($list_data['vectors'] as $vector) {
837 828 if (isset($vector['id'])) {
@@ -838,17 +829,9 @@
838 829 $vectors_to_delete[] = $vector['id'];
839 830 }
840 831 }
841 832 }
842 -
843 - $next_token = $list_data['pagination']['next'] ?? '';
844 - if (empty($next_token)) {
845 - break;
846 - }
847 -
848 - $query_params['paginationToken'] = $next_token;
849 - $list_url = "https://{$host}/vectors/list?" . http_build_query($query_params);
850 - } while (true);
833 + }
851 834
852 835 if (empty($vectors_to_delete)) {
853 836 //error_log('[MXCHAT-CHUNK-DELETE] No vectors found to delete');
854 837 return true;