Product deletion is part of keeping a WooCommerce-powered Vespa index trustworthy. If a product is permanently removed from WooCommerce but remains searchable, customers can see stale prices, broken product links, or items that can no longer be purchased.
In Vespa, deleting a product means sending a document removal operation to the Document API. This is different from updating the document with an empty title, setting its availability to false, or excluding it at query time. A removal operation deletes the document from the content cluster and prevents it from being returned as a normal indexed product.
Delete a product with the Vespa Document API
The Document API uses an HTTP DELETE request. The general endpoint format is:
DELETE /document/v1/{namespace}/{document-type}/docid/{document-id}
For example, an index that stores WooCommerce products in the woocommerce namespace and uses a Vespa document type named product might use an endpoint similar to:
https://your-vespa-endpoint.example/document/v1/woocommerce/product/docid/12345
The exact endpoint depends on whether the application runs in Vespa Cloud or a self-managed Vespa environment. The namespace and document type must match the values used when the product was originally fed.
A basic request with cURL looks like this:
curl --request DELETE \
--header "Authorization: Bearer $VESPA_TOKEN" \
"https://your-vespa-endpoint.example/document/v1/woocommerce/product/docid/12345"
If the deployment uses Vespa Cloud certificate authentication rather than a bearer token, provide the client certificate and private key required by that deployment. Keep those credentials on the server that performs the synchronization; never expose them in browser-side WooCommerce code.
Use a stable document ID
Deletion only works reliably when the integration reconstructs the same Vespa document ID used during indexing. A common strategy is to use the WooCommerce product ID as the external key:
id:woocommerce:product::12345
Some integrations expose only the final key in the Document API path, while others use the complete Vespa ID. Follow the ID format accepted by the application’s document API configuration and URL-encode reserved characters when necessary.
Do not base the ID on a product name, slug, or URL. Those values can change, which makes it difficult to identify and remove the previous document. Store the Vespa document ID or deterministic ID rule alongside the WooCommerce product data used by the indexing job.
Connect deletion to WooCommerce lifecycle events
A permanent product deletion should produce a corresponding Vespa removal. In WordPress, the before_delete_post or deleted_post hooks can be used for permanently deleted products, provided the integration checks the post type before sending the request.
A simplified PHP example using the WordPress HTTP API is:
<?php
add_action('before_delete_post', function ($post_id) {
if (get_post_type($post_id) !== 'product') {
return;
}
$document_id = (string) $post_id;
$endpoint = 'https://your-vespa-endpoint.example/document/v1/woocommerce/product/docid/' . rawurlencode($document_id);
$response = wp_remote_request($endpoint, [
'method' => 'DELETE',
'timeout' => 10,
'headers' => [
'Authorization' => 'Bearer ' . VESPA_TOKEN,
],
]);
if (is_wp_error($response)) {
error_log(sprintf(
'Vespa deletion failed for WooCommerce product %d: %s',
$post_id,
$response->get_error_message()
));
return;
}
$status = wp_remote_retrieve_response_code($response);
if ($status < 200 || $status >= 300) {
error_log(sprintf(
'Vespa deletion returned HTTP %d for WooCommerce product %d',
$status,
$post_id
));
}
});
The example is intentionally small. Production integrations should enqueue the operation instead of making a potentially slow external request during a WordPress deletion transaction. A background worker, Action Scheduler task, or message queue can retry failed operations without blocking the administrator or checkout-related requests.
Distinguish trashing, unpublishing, and permanent deletion
WooCommerce products can be deleted permanently, moved to the trash, set to draft, or made unavailable through catalog visibility and stock settings. These events do not necessarily have the same search behavior:
- Permanent deletion: send a Vespa document removal.
- Moved to trash: remove the document immediately if trashed products must disappear from search, or update an indexed status field if restoration is expected.
- Draft or private status: usually remove the product from the public index while retaining it in an administrative or staging index if required.
- Out of stock or hidden catalog visibility: update availability fields or remove the document according to the storefront’s search rules.
Do not treat every product status change as a permanent delete. If a product can be restored, an update or reversible visibility flag may be more appropriate than removing the document and requiring a full refeed later.
Make deletion operations retryable
Vespa feed operations are distributed and may be accepted before every query node has observed the change. A successful HTTP response confirms that Vespa accepted the operation, not necessarily that every read path has already converged.
For reliable synchronization, record an outbox event containing the WooCommerce product ID, document ID, operation type, and creation time. Process the event asynchronously and retry transient failures such as connection timeouts, rate limiting, and temporary service errors.
{
"operation": "delete",
"product_id": 12345,
"vespa_document_id": "id:woocommerce:product::12345",
"attempts": 1,
"created_at": "2025-01-15T12:00:00Z"
}
Use bounded retries with backoff and move repeatedly failing events to a dead-letter queue. A delete operation is naturally idempotent: repeating it for a document that has already been removed should not recreate the product. This makes retries safer than trying to infer deletion state from a later full product export.
Verify that the document is gone
After deleting a product, verify both the document endpoint and a representative search query. A direct document lookup can help distinguish a missing document from a query-ranking or filtering problem.
curl --request GET \
--header "Authorization: Bearer $VESPA_TOKEN" \
"https://your-vespa-endpoint.example/document/v1/woocommerce/product/docid/12345"
Also test the product identifier through the application’s query endpoint. Search results can briefly differ during propagation, so validation jobs should allow for the expected synchronization delay before marking a deletion as failed.
Protect against stale reindex jobs
A common race condition occurs when a product is deleted while an older indexing task is still queued. If that task runs after the delete request, it can recreate the product in Vespa.
Prevent this by attaching a WooCommerce revision, modification timestamp, or monotonically increasing synchronization version to each operation. The worker should discard an older update when a newer delete exists. Another practical approach is to process updates and deletes through the same per-product queue so operations for one document are applied in order.
For large catalogs, schedule periodic reconciliation. Compare the set of eligible WooCommerce product IDs with the set of indexed product IDs, then generate deletion events for documents that exist in Vespa but no longer qualify for indexing. This catches missed WordPress hooks, failed workers, manual database changes, and products removed by import tools.