Skip to content

feat(plugin-ecommerce): new hooks, cart logic moved to the server and fixed several bugs#15142

Merged
paulpopus merged 22 commits intomainfrom
feat/ecommerce-plugin-fixes-and-enhancements-new-validation-hooks
Jan 13, 2026
Merged

feat(plugin-ecommerce): new hooks, cart logic moved to the server and fixed several bugs#15142
paulpopus merged 22 commits intomainfrom
feat/ecommerce-plugin-fixes-and-enhancements-new-validation-hooks

Conversation

@paulpopus
Copy link
Copy Markdown
Contributor

@paulpopus paulpopus commented Jan 8, 2026

This PR fixes several bugs reported here or on our Discord server as well as adds some new features to further improve some of the workflows and DX.

New React Hooks & Config

Added useEcommerceConfig hook and config property on the ecommerce context for accessing collection slugs and API settings. This will be used in the future in the template to ensure that collection slugs remain consistent across our components.

  • onLogin hook to handle cart state after user authentication (merges guest cart with user's cart)
  • onLogout hook to clear ecommerce session data during logout
  • clearSession utility to reset all ecommerce state (cart, addresses, user)
  • mergeCart utility for manually merging carts (useful for custom authentication flows)
  • refreshCart hook to sync cart state with the server

Cart logic is now server side

The cart logic has been moved to the server side and carts as a collection now have new REST API endpoints, this allows to provide better support for customising the flows and support additional logic, it also simplifies the React Context provider.

  • Exported cart operations for server-side use: addItem, clearCart, removeItem, updateItem, defaultCartItemMatcher
  • update-item endpoint supports MongoDB-style { $inc: number } operator for quantity changes
  • update-item endpoint has removeOnZero option (defaults to true)
  • merge can merge a new guest cart with a user's saved cart when logging in
  • Added a custom cartItemMatcher utility

Example

/**
 * Custom cart item matcher that includes fulfillment option.
 * This ensures the same product with different fulfillment options
 * are listed as separate items in the cart.
 */
const fulfillmentCartItemMatcher: CartItemMatcher = ({ existingItem, newItem }) => {
  const existingProductID =
    typeof existingItem.product === 'object' ? existingItem.product.id : existingItem.product

  const existingVariantID =
    existingItem.variant && typeof existingItem.variant === 'object'
      ? existingItem.variant.id
      : existingItem.variant

  const productMatches = existingProductID === newItem.product

  // Variant matching: both must have same variant or both must have no variant
  const variantMatches = newItem.variant
    ? existingVariantID === newItem.variant
    : !existingVariantID

  // Fulfillment matching: items with different fulfillment options are separate
  const existingFulfillment = existingItem.fulfillment as string | undefined
  const newFulfillment = newItem.fulfillment as string | undefined
  const fulfillmentMatches = existingFulfillment === newFulfillment

  return productMatches && variantMatches && fulfillmentMatches
}

Bug fixes

Documentation

  • Added new "Hooks" section documenting onLogin, onLogout, clearSession, mergeCart, and refreshCart
  • Added "Session Management" section explaining authentication flows

Chores

  • Deprecated customerFieldAccess function in favour of isCustomer to improve clarity for how it's used - will be removed in V4
  • Guest cart secret is now passed via request context instead of query parameters for improved compatibility with other hooks or plugins modifications (backwards compatible with query params)

Future enhancements

Once this PR is merged we can then allow automatic merging of carts if a user adds an item and then logs in, currently it will lose the previous guest cart.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 8, 2026

📦 esbuild Bundle Analysis for payload

This analysis was generated by esbuild-bundle-analyzer. 🤖

Meta File Out File Size (raw) Note
packages/next/meta_index.json esbuild/index.js 934.89 KB ✅ No change
packages/payload/meta_index.json esbuild/index.js 1.24 MB ⚠️ +2.65 KB (+0.2%)
packages/payload/meta_shared.json esbuild/exports/shared.js 164.50 KB ✅ No change
packages/richtext-lexical/meta_client.json esbuild/exports/client_optimized/index.js 281.40 KB ✅ No change
packages/ui/meta_client.json esbuild/exports/client_optimized/index.js 1.16 MB ✅ No change
packages/ui/meta_shared.json esbuild/exports/shared_optimized/index.js 15.88 KB ✅ No change
Largest paths These visualization shows top 20 largest paths in the bundle.

Meta file: packages/next/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████████████▌ }}}$ 82.4%, 766.76 KB
dist/views/Version ${{\color{Goldenrod}{ █▎ }}}$ 5.4%, 50.25 KB
dist/views/Dashboard ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 16.48 KB
dist/views/Document ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 15.50 KB
dist/views/List ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 11.27 KB
dist/views/Root ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 9.03 KB
dist/views/API ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.03 KB
dist/views/Versions ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 5.98 KB
dist/elements/Nav ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 5.53 KB
dist/views/Account ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 5.46 KB
dist/elements/DocumentHeader ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 4.81 KB
dist/views/Login ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 4.41 KB
dist/views/ForgotPassword ${{\color{Goldenrod}{ }}}$ 0.3%, 3.09 KB
dist/layouts/Root ${{\color{Goldenrod}{ }}}$ 0.3%, 2.91 KB
dist/views/CreateFirstUser ${{\color{Goldenrod}{ }}}$ 0.3%, 2.81 KB
dist/templates/Default ${{\color{Goldenrod}{ }}}$ 0.3%, 2.63 KB
dist/views/BrowseByFolder ${{\color{Goldenrod}{ }}}$ 0.3%, 2.56 KB
dist/views/CollectionFolders ${{\color{Goldenrod}{ }}}$ 0.3%, 2.44 KB
dist/views/ResetPassword ${{\color{Goldenrod}{ }}}$ 0.3%, 2.40 KB
dist/views/Logout ${{\color{Goldenrod}{ }}}$ 0.2%, 1.94 KB
(other) ${{\color{Goldenrod}{ ████▍ }}}$ 17.6%, 163.45 KB

Meta file: packages/payload/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ █████████████████ }}}$ 68.2%, 842.04 KB
dist/fields/hooks ${{\color{Goldenrod}{ ▉ }}}$ 3.5%, 43.59 KB
dist/collections/operations ${{\color{Goldenrod}{ ▊ }}}$ 3.0%, 37.01 KB
dist/auth/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.46 KB
dist/queues/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.80 KB
dist/fields/config ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.51 KB
dist/utilities/configToJSONSchema.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.04 KB
dist/globals/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.02 KB
dist/fields/validations.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 10.21 KB
dist/bin/generateImportMap ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.53 KB
dist/collections/config ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.90 KB
dist/uploads/fetchAPI-multipart ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.74 KB
dist/index.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.65 KB
dist/database/migrations ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.50 KB
dist/config/orderable ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.27 KB
dist/collections/endpoints ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.00 KB
dist/config/sanitize.js ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 5.58 KB
dist/auth/strategies ${{\color{Goldenrod}{ }}}$ 0.4%, 5.49 KB
dist/auth/endpoints ${{\color{Goldenrod}{ }}}$ 0.4%, 5.42 KB
dist/queues/config ${{\color{Goldenrod}{ }}}$ 0.4%, 5.34 KB
(other) ${{\color{Goldenrod}{ ███████▉ }}}$ 31.8%, 391.86 KB

Meta file: packages/payload/meta_shared.json, Out file: esbuild/exports/shared.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ███████████████████▋ }}}$ 78.8%, 126.93 KB
dist/fields/validations.js ${{\color{Goldenrod}{ █▌ }}}$ 6.3%, 10.21 KB
dist/fields/baseFields ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 2.79 KB
dist/utilities/deepCopyObject.js ${{\color{Goldenrod}{ ▍ }}}$ 1.6%, 2.54 KB
dist/auth/cookies.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 1.55 KB
dist/utilities/flattenTopLevelFields.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 1.42 KB
dist/fields/config ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 1.28 KB
dist/utilities/flattenAllFields.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 943 B
dist/folders/utils ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 916 B
dist/utilities/getVersionsConfig.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 895 B
dist/utilities/unflatten.js ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 779 B
dist/utilities/sanitizeUserDataForEmail.js ${{\color{Goldenrod}{ }}}$ 0.4%, 713 B
dist/utilities/getFieldPermissions.js ${{\color{Goldenrod}{ }}}$ 0.4%, 651 B
dist/collections/config ${{\color{Goldenrod}{ }}}$ 0.4%, 570 B
dist/bin/generateImportMap ${{\color{Goldenrod}{ }}}$ 0.3%, 561 B
dist/auth/sessions.js ${{\color{Goldenrod}{ }}}$ 0.3%, 525 B
dist/fields/getFieldPaths.js ${{\color{Goldenrod}{ }}}$ 0.3%, 485 B
dist/utilities/getSafeRedirect.js ${{\color{Goldenrod}{ }}}$ 0.3%, 423 B
dist/utilities/deepMerge.js ${{\color{Goldenrod}{ }}}$ 0.3%, 413 B
dist/utilities/formatLabels.js ${{\color{Goldenrod}{ }}}$ 0.2%, 380 B
(other) ${{\color{Goldenrod}{ █████▎ }}}$ 21.2%, 34.06 KB

Meta file: packages/richtext-lexical/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
dist/features/blocks ${{\color{Goldenrod}{ ███▏ }}}$ 12.6%, 35.14 KB
dist/lexical/plugins ${{\color{Goldenrod}{ ██▉ }}}$ 11.5%, 32.00 KB
dist/lexical/ui ${{\color{Goldenrod}{ ██▏ }}}$ 8.8%, 24.36 KB
dist/features/experimental_table ${{\color{Goldenrod}{ ██▏ }}}$ 8.5%, 23.70 KB
dist/packages/@lexical ${{\color{Goldenrod}{ █▋ }}}$ 6.8%, 18.99 KB
dist/features/link ${{\color{Goldenrod}{ █▋ }}}$ 6.5%, 18.11 KB
dist/features/toolbars ${{\color{Goldenrod}{ █▌ }}}$ 6.4%, 17.75 KB
dist/features/upload ${{\color{Goldenrod}{ █▎ }}}$ 5.0%, 13.77 KB
dist/features/textState ${{\color{Goldenrod}{ █ }}}$ 4.0%, 11.08 KB
dist/features/relationship ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 9.03 KB
dist/lexical/utils ${{\color{Goldenrod}{ ▊ }}}$ 3.0%, 8.22 KB
dist/features/debug ${{\color{Goldenrod}{ ▋ }}}$ 2.7%, 7.39 KB
dist/utilities/fieldsDrawer ${{\color{Goldenrod}{ ▋ }}}$ 2.6%, 7.15 KB
dist/features/converters ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 7.05 KB
dist/lexical/config ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 5.08 KB
dist/features/lists ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 5.00 KB
dist/features/format ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 3.46 KB
dist/lexical/LexicalEditor.js ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 3.17 KB
dist/lexical/theme ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 2.62 KB
dist/features/indent ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 2.50 KB
(other) ${{\color{Goldenrod}{ █████████████████████▊ }}}$ 87.4%, 243.00 KB

Meta file: packages/ui/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████▍ }}}$ 49.6%, 572.92 KB
dist/elements/FolderView ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 29.29 KB
dist/elements/BulkUpload ${{\color{Goldenrod}{ ▌ }}}$ 2.4%, 27.64 KB
dist/elements/WhereBuilder ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 16.91 KB
dist/views/Edit ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 16.39 KB
dist/fields/Relationship ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 15.78 KB
dist/elements/Table ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.48 KB
dist/forms/Form ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.32 KB
dist/fields/Upload ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 14.15 KB
dist/fields/Blocks ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 13.70 KB
dist/elements/QueryPresets ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 10.33 KB
dist/elements/PublishButton ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 8.82 KB
dist/providers/Folders ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.47 KB
dist/elements/LivePreview ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.38 KB
dist/elements/ListHeader ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.90 KB
dist/elements/HTMLDiff ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.81 KB
dist/fields/Array ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.72 KB
dist/views/CollectionFolder ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.38 KB
dist/elements/ReactSelect ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.34 KB
dist/views/List ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.99 KB
(other) ${{\color{Goldenrod}{ ████████████▌ }}}$ 50.4%, 581.82 KB

Meta file: packages/ui/meta_shared.json, Out file: esbuild/exports/shared_optimized/index.js

Path Size
dist/graphics/Logo ${{\color{Goldenrod}{ █████▏ }}}$ 20.5%, 3.12 KB
../../node_modules ${{\color{Goldenrod}{ ████▎ }}}$ 17.4%, 2.65 KB
dist/graphics/Icon ${{\color{Goldenrod}{ ██▌ }}}$ 10.0%, 1.52 KB
dist/utilities/formatDocTitle ${{\color{Goldenrod}{ ██▏ }}}$ 8.7%, 1.32 KB
dist/providers/TableColumns ${{\color{Goldenrod}{ █▍ }}}$ 5.7%, 862 B
dist/utilities/groupNavItems.js ${{\color{Goldenrod}{ █▎ }}}$ 5.3%, 812 B
dist/utilities/getGlobalData.js ${{\color{Goldenrod}{ █▎ }}}$ 5.0%, 762 B
dist/utilities/api.js ${{\color{Goldenrod}{ █▎ }}}$ 5.0%, 756 B
dist/elements/Translation ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 493 B
dist/utilities/handleTakeOver.js ${{\color{Goldenrod}{ ▋ }}}$ 2.9%, 440 B
dist/elements/withMergedProps ${{\color{Goldenrod}{ ▌ }}}$ 2.2%, 339 B
dist/utilities/getVisibleEntities.js ${{\color{Goldenrod}{ ▌ }}}$ 2.2%, 329 B
dist/utilities/getNavGroups.js ${{\color{Goldenrod}{ ▌ }}}$ 2.0%, 301 B
dist/elements/WithServerSideProps ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 232 B
dist/utilities/handleGoBack.js ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 180 B
dist/fields/mergeFieldStyles.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 159 B
dist/utilities/handleBackToDashboard.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 152 B
dist/forms/Form ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 147 B
dist/utilities/abortAndIgnore.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 146 B
dist/utilities/hasSavePermission.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 136 B
(other) ${{\color{Goldenrod}{ ███████████████████▉ }}}$ 79.5%, 12.11 KB
Details

Next to the size is how much the size has increased or decreased compared with the base branch of this PR.

  • ‼️: Size increased by 20% or more. Special attention should be given to this.
  • ⚠️: Size increased in acceptable range (lower than 20%).
  • ✅: No change or even downsized.
  • 🗑️: The out file is deleted: not found in base branch.
  • 🆕: The out file is newly found: will be added to base branch.

@paulpopus paulpopus changed the title feat(plugin-ecommerce): new features and bug fixes feat(plugin-ecommerce): cart logic is now server side and fixed several bugs Jan 9, 2026
@paulpopus paulpopus changed the title feat(plugin-ecommerce): cart logic is now server side and fixed several bugs feat(plugin-ecommerce): cart logic moved to the server with new REST endpoints and fixed several bugs Jan 9, 2026
@paulpopus paulpopus changed the title feat(plugin-ecommerce): cart logic moved to the server with new REST endpoints and fixed several bugs feat(plugin-ecommerce): new hooks, cart logic moved to the server and fixed several bugs Jan 13, 2026
@paulpopus paulpopus requested a review from Copilot January 13, 2026 18:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the plugin-ecommerce by moving cart logic to the server-side, adding new React hooks for cart/session management, fixing multiple bugs, and adding comprehensive translations for 40+ languages.

Changes:

  • Cart operations moved to server-side REST API endpoints with MongoDB-style operators support
  • New hooks: onLogin, onLogout, clearSession, mergeCart, refreshCart, useEcommerceConfig
  • Bug fixes for guest checkouts, hardcoded collection slugs, addresses beforeChange hook, and type definitions
  • Complete translation support added for 40+ languages with proper structure

Reviewed changes

Copilot reviewed 81 out of 82 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tools/scripts/src/generateTranslations/plugin-ecommerce.ts New script for generating plugin translations
tools/scripts/package.json Added generateTranslations:plugin-ecommerce command
test/plugin-ecommerce/int.spec.ts Comprehensive integration tests for cart endpoints and operations
templates/ecommerce/src/components/product/Gallery.tsx Fixed .toArray() implementation using Array.from()
packages/plugin-ecommerce/src/ui/VariantOptionsSelector/index.tsx Fixed hardcoded collection slugs using field.custom
packages/plugin-ecommerce/src/types/index.ts Updated CartItem.id type and added new types for cart operations
packages/plugin-ecommerce/src/translations/* Added complete translation files for 40+ languages
packages/plugin-ecommerce/src/react/provider/index.tsx Refactored cart operations to use server endpoints, added session management
packages/plugin-ecommerce/src/payments/adapters/stripe/confirmOrder.ts Added cartsSlug parameter support
packages/plugin-ecommerce/src/index.ts Exported cart operations and types
packages/plugin-ecommerce/src/endpoints/* Updated to support cart secret via request context
packages/plugin-ecommerce/src/collections/variants/createVariantsCollection/index.ts Added variantTypesSlug parameter
packages/plugin-ecommerce/src/collections/carts/operations/removeItem.ts New server-side removeItem operation
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/plugin-ecommerce/src/translations/languages/hy.ts Outdated
Comment thread packages/plugin-ecommerce/src/translations/languages/hy.ts Outdated
Comment thread packages/plugin-ecommerce/src/translations/languages/hy.ts Outdated
Comment thread packages/plugin-ecommerce/src/react/provider/index.tsx
@paulpopus paulpopus marked this pull request as ready for review January 13, 2026 19:05
Copy link
Copy Markdown
Contributor

@DanRibbens DanRibbens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really good!

@paulpopus paulpopus merged commit dcd4030 into main Jan 13, 2026
99 checks passed
@paulpopus paulpopus deleted the feat/ecommerce-plugin-fixes-and-enhancements-new-validation-hooks branch January 13, 2026 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

3 participants