Skip to content

medusa-plugin-wishlist

@evolve-framework/medusa-plugin-wishlist · v1.0.0

Adds wishlists to Medusa v2, so a shopper can keep several named lists of products, with or without an account.

Each list has a name, a description and a quantity per item.

When to use

Install it in a Medusa backend whose Evolve storefront offers wishlists. The plugin owns the lists and their Store API routes; the storefront and the GraphQL layer decide how they look.

Get started

  1. Install the package with the peer dependencies it needs. It comes from the Evolve registry, which needs a one-time sign-in.

    pnpm add @evolve-framework/medusa-plugin-wishlist @medusajs/cli @medusajs/framework @medusajs/medusa
    Requirements4
    node>=20
    @medusajs/cli2.21.2
    @medusajs/framework2.21.2
    @medusajs/medusa2.21.2

For example:

// medusa-config.ts
// After adding the plugin, run `npx medusa db:migrate` to create its tables.
import { defineConfig } from "@medusajs/framework/utils";
module.exports = defineConfig({
// projectConfig, modules and other plugins as before
plugins: [
{ resolve: "@evolve-framework/medusa-plugin-wishlist", options: {} },
],
});

Owners

A list belongs to either a signed-in customer or an anonymous session. The second half is the point: saving something for later is what a shopper does before they sign in, and a wishlist that needs an account is an account benefit rather than a wishlist.

Medusa has no anonymous identity: the Store API authenticates a customer or nobody. So the caller mints an opaque id, keeps it on its own signed session token, and sends it as x-wishlist-anonymous-id. That makes the header exactly as strong as the session behind it, which is the same bargain Medusa already makes for anonymous carts: holding the cart id is holding the cart.

A signed-in caller is never treated as anonymous, even if it also sends the header. A stale id left in a storefront would otherwise write to a list the customer cannot see.

POST /store/wishlists/claim moves the anonymous session's lists onto the signed-in customer. They are moved, not merged. Two lists that happen to share a name are not the same list, and folding them together is not something the shopper could undo, where ending up with two is obvious and fixable in one click. Calling it twice is harmless.

Routes

GET /store/wishlists the caller's lists, with items
POST /store/wishlists create one
GET /store/wishlists/:id one list
POST /store/wishlists/:id rename or re-describe
DELETE /store/wishlists/:id delete it and its items
POST /store/wishlists/:id/items/batch {create, update, delete} in one call
POST /store/wishlists/claim take over an anonymous session's lists

Items are edited through one batch endpoint because that is how a storefront uses them: a list edit is a set of changes applied together, and three round trips would let a page half-apply.

A list that is not the caller's reads as absent rather than forbidden, so an id cannot be used to discover whose lists exist. Adding a variant that is already on a list raises its quantity instead of failing on the unique index, and setting a quantity to zero removes the line: a count of things to buy has no meaningful zero.

What it stores

Only the variant id and a quantity. Everything a storefront renders (name, price, availability) is read from the catalog at display time, so a list never shows a price that stopped being true the day it was saved.

Why not one of the published plugins

Several wishlist plugins exist for Medusa v2. They model a single unnamed list per customer, where the Evolve contract has several named lists with descriptions and per-item quantities, and expects them to work anonymously.