| @@ -59,11 +59,8 @@ | ||
| 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 | - | |
| 66 | 63 | // WordPress post management hooks |
| 67 | 64 | add_action('pre_post_update', array($this, 'mxchat_store_pre_update_status'), 10, 2); |
| 68 | 65 | add_action('post_updated', array($this, 'mxchat_handle_post_update'), 10, 3); |
| 69 | 66 | add_action('before_delete_post', array($this, 'mxchat_handle_post_delete')); |
| @@ -5184,40 +5181,33 @@ | ||
| 5184 | 5181 | // If the post was previously published but is now not published, remove from knowledge base |
| 5185 | 5182 | if ($previous_status === 'publish' && $post->post_status !== 'publish') { |
| 5186 | 5183 | // Use the stored URL from when it was published, or fall back to current permalink |
| 5187 | 5184 | $source_url = $previous_url ?: get_permalink($post_id); |
| 5188 | - | |
| 5185 | + | |
| 5189 | 5186 | if ($source_url) { |
| 5190 | - // Check if Pinecone is enabled | |
| 5191 | - $pinecone_options = get_option('mxchat_pinecone_addon_options', array()); | |
| 5192 | - $use_pinecone = ($pinecone_options['mxchat_use_pinecone'] ?? '0') === '1'; | |
| 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'); | |
| 5189 | + } | |
| 5193 | 5190 | |
| 5194 | - if ($use_pinecone && !empty($pinecone_options['mxchat_pinecone_api_key'])) { | |
| 5195 | - // Delete from Pinecone | |
| 5196 | - $this->mxchat_delete_from_pinecone_by_url($source_url, $pinecone_options); | |
| 5197 | - } else { | |
| 5198 | - // Delete from WordPress DB | |
| 5199 | - global $wpdb; | |
| 5200 | - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; | |
| 5201 | - | |
| 5202 | - $result = $wpdb->delete( | |
| 5203 | - $table_name, | |
| 5204 | - array('source_url' => $source_url), | |
| 5205 | - array('%s') | |
| 5206 | - ); | |
| 5207 | - } | |
| 5208 | - } | |
| 5209 | - | |
| 5210 | 5191 | // Clean up the transients and exit early |
| 5211 | 5192 | delete_transient($previous_status_key); |
| 5212 | 5193 | delete_transient($previous_url_key); |
| 5213 | 5194 | return; |
| 5214 | 5195 | } |
| 5215 | - | |
| 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 | + | |
| 5216 | 5206 | // Store the current status for next time (if this is an update) |
| 5217 | 5207 | if ($update) { |
| 5218 | 5208 | set_transient($previous_status_key, $post->post_status, DAY_IN_SECONDS); |
| 5219 | - | |
| 5209 | + | |
| 5220 | 5210 | // If the post is currently published, also store its URL |
| 5221 | 5211 | if ($post->post_status === 'publish') { |
| 5222 | 5212 | $current_url = get_permalink($post_id); |
| 5223 | 5213 | set_transient($previous_url_key, $current_url, DAY_IN_SECONDS); |
| @@ -5447,12 +5437,14 @@ | ||
| 5447 | 5437 | if (!$should_sync) { |
| 5448 | 5438 | return; |
| 5449 | 5439 | } |
| 5450 | 5440 | |
| 5451 | - // Get the URL before post is deleted | |
| 5452 | - $source_url = get_permalink($post_id); | |
| 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); | |
| 5453 | 5445 | if (!$source_url) { |
| 5454 | - //error_log('MXChat: Failed to get permalink for post ' . $post_id); | |
| 5446 | + //error_log('MXChat: Failed to resolve source URL for post ' . $post_id); | |
| 5455 | 5447 | return; |
| 5456 | 5448 | } |
| 5457 | 5449 | |
| 5458 | 5450 | // Use chunk-aware deletion (handles both chunked and non-chunked content) |
| @@ -5460,56 +5452,36 @@ | ||
| 5460 | 5452 | |
| 5461 | 5453 | if (is_wp_error($delete_result)) { |
| 5462 | 5454 | //error_log('MXChat: Chunk-aware deletion failed for URL: ' . $source_url . ' - ' . $delete_result->get_error_message()); |
| 5463 | 5455 | } |
| 5456 | + | |
| 5457 | + delete_transient('mxchat_prev_url_' . $post_id); | |
| 5458 | + delete_transient('mxchat_prev_status_' . $post_id); | |
| 5464 | 5459 | } |
| 5465 | 5460 | |
| 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 | + } | |
| 5466 | 5474 | |
| 5467 | - /** | |
| 5468 | - * Deletes data from Pinecone using a source URL | |
| 5469 | - */ | |
| 5470 | - public function mxchat_delete_from_pinecone_by_url($source_url, $pinecone_options) { | |
| 5471 | - $host = $pinecone_options['mxchat_pinecone_host'] ?? ''; | |
| 5472 | - $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; | |
| 5475 | + $current = get_permalink($post_id); | |
| 5476 | + if (!$current) { | |
| 5477 | + return ''; | |
| 5478 | + } | |
| 5479 | + return preg_replace('#__trashed(/?)$#', '$1', $current); | |
| 5480 | +} | |
| 5473 | 5481 | |
| 5474 | - if (empty($host) || empty($api_key)) { | |
| 5475 | - //error_log('MXChat: Pinecone deletion failed - missing configuration'); | |
| 5476 | - return false; | |
| 5477 | - } | |
| 5478 | 5482 | |
| 5479 | - $api_endpoint = "https://{$host}/vectors/delete"; | |
| 5480 | - $vector_id = md5($source_url); | |
| 5481 | 5483 | |
| 5482 | - $request_body = array( | |
| 5483 | - 'ids' => array($vector_id) | |
| 5484 | - ); | |
| 5485 | - | |
| 5486 | - $response = wp_remote_post($api_endpoint, array( | |
| 5487 | - 'headers' => array( | |
| 5488 | - 'Api-Key' => $api_key, | |
| 5489 | - 'accept' => 'application/json', | |
| 5490 | - 'content-type' => 'application/json' | |
| 5491 | - ), | |
| 5492 | - 'body' => wp_json_encode($request_body), | |
| 5493 | - 'timeout' => 30 | |
| 5494 | - )); | |
| 5495 | - | |
| 5496 | - if (is_wp_error($response)) { | |
| 5497 | - //error_log('MXChat: Pinecone deletion error - ' . $response->get_error_message()); | |
| 5498 | - return false; | |
| 5499 | - } | |
| 5500 | - | |
| 5501 | - $response_code = wp_remote_retrieve_response_code($response); | |
| 5502 | - if ($response_code !== 200) { | |
| 5503 | - //error_log('MXChat: Pinecone deletion failed with status ' . $response_code); | |
| 5504 | - return false; | |
| 5505 | - } | |
| 5506 | - | |
| 5507 | - return true; | |
| 5508 | - } | |
| 5509 | - | |
| 5510 | - | |
| 5511 | - | |
| 5512 | 5484 | public function mxchat_handle_product_change($post_id, $post, $update) { |
| 5513 | 5485 | if ($post->post_type !== 'product') { |
| 5514 | 5486 | return; |
| 5515 | 5487 | } |
| @@ -5661,28 +5633,18 @@ | ||
| 5661 | 5633 | if (get_post_type($post_id) !== 'product') { |
| 5662 | 5634 | return; |
| 5663 | 5635 | } |
| 5664 | 5636 | |
| 5665 | - $source_url = get_permalink($post_id); | |
| 5637 | + $source_url = $this->mxchat_resolve_pre_trash_url($post_id); | |
| 5638 | + if (!$source_url) { | |
| 5639 | + return; | |
| 5640 | + } | |
| 5666 | 5641 | |
| 5667 | - // Check if Pinecone is enabled | |
| 5668 | - $pinecone_options = get_option('mxchat_pinecone_addon_options', array()); | |
| 5669 | - $use_pinecone = ($pinecone_options['mxchat_use_pinecone'] ?? '0') === '1'; | |
| 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'); | |
| 5670 | 5644 | |
| 5671 | - if ($use_pinecone && !empty($pinecone_options['mxchat_pinecone_api_key'])) { | |
| 5672 | - // Delete from Pinecone | |
| 5673 | - $this->mxchat_delete_from_pinecone_by_url($source_url, $pinecone_options); | |
| 5674 | - } else { | |
| 5675 | - // Delete from WordPress DB | |
| 5676 | - global $wpdb; | |
| 5677 | - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; | |
| 5678 | - | |
| 5679 | - $wpdb->delete( | |
| 5680 | - $table_name, | |
| 5681 | - array('source_url' => $source_url), | |
| 5682 | - array('%s') | |
| 5683 | - ); | |
| 5684 | - } | |
| 5645 | + delete_transient('mxchat_prev_url_' . $post_id); | |
| 5646 | + delete_transient('mxchat_prev_status_' . $post_id); | |
| 5685 | 5647 | } |
| 5686 | 5648 | |
| 5687 | 5649 | /** |
| 5688 | 5650 | * Handle individual Pinecone content deletion |