diff --git a/packages/plugin-search/src/utilities/syncDocAsSearchIndex.ts b/packages/plugin-search/src/utilities/syncDocAsSearchIndex.ts index 7755f44a5..95167e918 100644 --- a/packages/plugin-search/src/utilities/syncDocAsSearchIndex.ts +++ b/packages/plugin-search/src/utilities/syncDocAsSearchIndex.ts @@ -43,11 +43,16 @@ export const syncDocAsSearchIndex = async ({ if (typeof beforeSync === 'function') { let docToSyncWith = doc if (payload.config?.localization) { + // Check if document is trashed (has deletedAt field) + const isTrashDocument = doc && 'deletedAt' in doc && doc.deletedAt + docToSyncWith = await payload.findByID({ id, collection, locale: syncLocale, req, + // Include trashed documents when the document being synced is trashed + trash: isTrashDocument, }) } dataToSave = await beforeSync({ @@ -157,6 +162,26 @@ export const syncDocAsSearchIndex = async ({ payload.logger.error({ err, msg: `Error updating ${searchSlug} document.` }) } } + + // Check if document is trashed and delete from search + const isTrashDocument = doc && 'deletedAt' in doc && doc.deletedAt + + if (isTrashDocument) { + try { + await payload.delete({ + id: searchDocID, + collection: searchSlug, + depth: 0, + req, + }) + } catch (err: unknown) { + payload.logger.error({ + err, + msg: `Error deleting ${searchSlug} document for trashed doc.`, + }) + } + } + if (deleteDrafts && status === 'draft') { // Check to see if there's a published version of the doc // We don't want to remove the search doc if there is a published version but a new draft has been created @@ -186,7 +211,7 @@ export const syncDocAsSearchIndex = async ({ }, }) - if (!docWithPublish) { + if (!docWithPublish && !isTrashDocument) { // do not include draft docs in search results, so delete the record try { await payload.delete({ diff --git a/test/plugin-search/collections/Posts.ts b/test/plugin-search/collections/Posts.ts index e653688b6..a232f427d 100644 --- a/test/plugin-search/collections/Posts.ts +++ b/test/plugin-search/collections/Posts.ts @@ -11,6 +11,7 @@ export const Posts: CollectionConfig = { admin: { useAsTitle: 'title', }, + trash: true, versions: { drafts: true, }, diff --git a/test/plugin-search/int.spec.ts b/test/plugin-search/int.spec.ts index 80e2a6e5b..e3ad05922 100644 --- a/test/plugin-search/int.spec.ts +++ b/test/plugin-search/int.spec.ts @@ -534,4 +534,67 @@ describe('@payloadcms/plugin-search', () => { expect(totalAfterReindex).toBe(totalBeforeReindex) }) + + it('should sync trashed documents correctly with search plugin', async () => { + // Create a published post + const publishedPost = await payload.create({ + collection: postsSlug, + data: { + title: 'Post to be trashed', + excerpt: 'This post will be soft deleted', + _status: 'published', + }, + }) + + // Wait for the search document to be created + await wait(200) + + // Verify the search document was created + const { docs: initialSearchResults } = await payload.find({ + collection: 'search', + depth: 0, + where: { + 'doc.value': { + equals: publishedPost.id, + }, + }, + }) + + expect(initialSearchResults).toHaveLength(1) + expect(initialSearchResults[0]?.title).toBe('Post to be trashed') + + // Soft delete the post (move to trash) + await payload.update({ + collection: postsSlug, + id: publishedPost.id, + data: { + deletedAt: new Date().toISOString(), + }, + }) + + // Wait for the search plugin to sync the trashed document + await wait(200) + + // Verify the search document still exists but is properly synced + // The search document should remain and be updated correctly + const { docs: trashedSearchResults } = await payload.find({ + collection: 'search', + depth: 0, + where: { + 'doc.value': { + equals: publishedPost.id, + }, + }, + }) + + // The search document should still exist + expect(trashedSearchResults).toHaveLength(0) + + // Clean up by permanently deleting the trashed post + await payload.delete({ + collection: postsSlug, + id: publishedPost.id, + trash: true, // permanently delete + }) + }) }) diff --git a/test/plugin-search/payload-types.ts b/test/plugin-search/payload-types.ts index 7478e3766..9e5f3b6f8 100644 --- a/test/plugin-search/payload-types.ts +++ b/test/plugin-search/payload-types.ts @@ -168,6 +168,7 @@ export interface Post { slug?: string | null; updatedAt: string; createdAt: string; + deletedAt?: string | null; _status?: ('draft' | 'published') | null; } /** @@ -336,6 +337,7 @@ export interface PostsSelect { slug?: T; updatedAt?: T; createdAt?: T; + deletedAt?: T; _status?: T; } /**