Plugins

Shop

The official shop plugin turns the product catalogue into a store. It ships inside the framework (plugins/shop), so there is nothing to download.

node node_modules/nuxtcms/scripts/plugin.mjs add shop
pnpm build:cf && pnpm deploy

shop is a paid plugin: licensed domains (and the hub owner's own sites) activate it automatically in Admin → Plugins. nuxt dev runs it without a license.

What you get

AreaFeatures
Productsprice, compare-at (sale) price, SKU, stock (or untracked), options / variants with their own price and stock, gallery, badge, per-product tax rate, "price on request" and catalogue-only mode
Storefrontprices on product cards, buy box with options and quantity, gallery, header cart button, slide-over cart, floating cart button, /cart, /checkout, /order/<number>, /order (find my order)
Checkoutguest checkout, delivery (flat fee, free over an amount, allowed countries) or store pickup, coupons (percent, fixed, free delivery; dates, limits, minimum), VAT included or added on top, minimum order, terms checkbox, Turnstile and rate limits
PaymentsStripe Checkout, PayPal, Paytrail (Finland, EUR), WeChat Pay and Alipay (mainland China, CNY), bank transfer, cash on delivery / at pickup
Ordersstatuses pending → paid → processing → shipped → completed, cancelled, refunded; stock reserved at checkout and released on cancel / refund; sales counters; timeline; carrier + tracking number; internal notes; CSV export
E-mailsorder received (with bank details or pickup address), paid, shipped (tracking), completed, cancelled, refunded; new-order notice to the shop owner
Automationscheduled task cancels unpaid online orders after N hours; events order.created, order.paid, order.status_changed for webhooks (DingTalk, Feishu, WeCom robots…)
SEOschema.org Offer (price, currency, availability) and sku in the product JSON-LD

Shipping templates

Shop → Shipping in the admin sets delivery fees per region; without any template the flat fee and "free over" amount from the shop settings apply.

FieldMeaning
Countries / regionsISO codes, * = everywhere; regions (provinces, states) empty = the whole countries, e.g. "Bavaria, Berlin"
Feeflat; per piece (first N pieces cost X, each further M pieces add Y); by weight (first and further weight in kilograms, a started step counts as a whole one)
Free deliveryover an amount (after the coupon discount) and / or from a number of pieces

Matching: a template whose regions include the address region first, then one listing the country, then *; equal ones by sort number. Addresses no template covers cannot choose delivery. Before the customer enters an address the checkout estimates with the first nationwide template. Weights come from the Shop card of each product (grams); products without a weight count as 0. Free delivery coupons apply to every template.

Member accounts

Turn on Member accounts in the shop settings and:

  • an account icon appears in the header; customers sign up, sign in (/member/login) and reset their password (e-mailed link, valid 1 hour, unusable once the password changes).
  • My account (/member): order history (each opens the order page), profile, password; Addresses (/member/addresses): add, edit, delete, choose the default (up to 20).
  • checkout is pre-filled with name, e-mail, phone and the default address; saved addresses can be picked, and a new one can be saved to the address book.
  • with Allow guest checkout off, signing in is required to check out (guests are allowed by default).
  • Shop → Members in the admin: members with order count, amount paid and last order; disable / enable accounts (disabling signs the member out at once).

Members are not admin users: they live in their own tables (shop_customers, shop_addresses) with their own cookie and can never open the admin. Sign-up, sign-in and password reset use the login captcha from Security and are rate limited. Orders placed while signed in are linked to the member (shop_orders.customer_id, added automatically on existing installs); guest orders are not attached to an account by e-mail.

Points

With member accounts on, turn on Points in the shop settings:

SettingMeaning
Points earned per currency unitawarded when an order is completed, on the amount paid for goods (no shipping, no added tax); 0 = none
Points worth one currency unite.g. 100: 100 points = 1.00
Points may pay up to %e.g. 50: at most half of the goods
Points for signing upgiven to new members

At checkout members tick "Use points"; the quote applies their balance up to the limit and the points are taken when the order is placed. Cancelling or refunding an order gives back the points used and takes back the points it earned (what is left of them). Members see their balance and history under My account; in Shop → Members a click on the points adds or removes points (never below zero). Every change is a row in shop_points_ledger.

Stores

Add stores under Shop → Stores (name, address, opening hours, phone, notification e-mail, area served, pickup). Without stores nothing changes: pickup uses the address from the settings and orders are not assigned.

  • Pickup: with "Offer pickup" on, customers choose one of the pickup stores at checkout (a choice is required); the order page and the confirmation e-mail show that store's address, hours and phone.
  • Deliveries go to the store whose area covers the address, matched like shipping templates (region > country, then sort order). A store without countries is the fallback for addresses no other store covers.
  • Notifications: a store with an e-mail address receives its new orders (the same message as the shop owner).
  • Admin: filter orders by store (or "No store"), reassign an order in its details (noted in the timeline). Deleting a store leaves its orders unassigned.

Store stock

Shop → Store stock has one row per product (per variant for products with variants) and one column per store:

  • As soon as a product or variant has stock at any store it is counted per store: its stock for sale is the sum of the enabled stores (written back to the product, so the storefront and the quantity limits work as before). The stock field of the product form no longer changes it.
  • Orders take from their store; cancelling or refunding gives back to it; reassigning an order moves its stock to the new store.
  • Pickup is only possible at stores holding every item (checkout greys out the others). Deliveries go to a store in the area that has the items, else to another store that has them. When no single store has everything the order is refused (order the items separately).
  • Disabled stores are not counted; deleting a store deletes its stock.
  • Leave every store blank to go back to the product's own stock; products never given store stock keep working as before.

Marketplace merchants

With member accounts on, turn on Marketplace in the shop settings and set the default platform commission, the days after completion before merchants are paid and the smallest payout.

  1. Apply: members open the merchant centre (/merchant, linked from My account) and send their store name, contact and phone.
  2. Approve under Shop → Merchants, or reject with a reason (the merchant can correct and send again). Each merchant may get its own commission; blank = the default.
  3. Assign products: click a merchant's product count and tick what it sells. Titles, descriptions and images stay in the shop admin; merchants never touch page content or uploads.
  4. Day to day merchants change prices, compare-at prices and stock of their products and variants (store-counted stock stays the shop's), see the orders with their items — only their lines and the delivery details, never the buyer's e-mail — and enter carrier and tracking number (noted on the order). Paid orders are e-mailed to the merchant (store e-mail, else the member's).
  5. Settlement: when an order is paid each merchant gets an earnings row: their sales minus the commission (rounded to the cent). It is settled into the balance the set number of days after the order is completed; cancelling or refunding cancels unsettled earnings and takes settled ones back (the balance may go negative, later earnings settle it first).
  6. Payouts: requested amounts leave the balance at once; after transferring, mark them paid under Payouts, or reject with a reason (the amount comes back). One open request at a time.

Coupons, points and shipping are the shop's and do not change what merchants earn; the shop's own products (not assigned) sell as before. A suspended merchant cannot use the merchant centre, but orders of its products still earn. Tables: shop_merchants, shop_merchant_earnings, shop_merchant_payouts; products and order lines carry merchant_id.

Two-level affiliate program

With member accounts on, turn on Two-level affiliate program in the shop settings:

SettingMeaning
Level 1 commission %on orders an affiliate brings in, of the amount paid for goods (no shipping, no added tax)
Level 2 commission %paid to the affiliate's inviter; 0 = one level only
Affiliates need approvalapplications wait for approval in the admin
Share link lifetimeorders within this many days of the click count (default 30)
Days after completion before commission is crediteddefault 7; a refund in this time cancels the commission
Smallest withdrawalbelow this amount no withdrawal can be requested

How it works:

  1. Members join under My account → Affiliate and get a code and a share link; ?ref=CODE works on any page.
  2. The browser keeps the code of the link. A visitor who signs up stays bound to that affiliate for good; guests and existing members are credited through the link while it lasts.
  3. When an order is paid, commission rows are created (pending): level 1 for the affiliate, level 2 for the affiliate's inviter. They are credited the set number of days after the order is completed, by the scheduled task "Shop: cancel stale unpaid orders" (and whenever the affiliate page or the admin page is opened).
  4. Cancelling or refunding an order cancels pending commission and takes back credited commission; the balance may go negative and later commission settles it first.
  5. Affiliates request withdrawals (Alipay, WeChat, bank account, other); the amount leaves the balance right away. After paying it outside the shop, mark it paid in Shop → Affiliates → Withdrawals (optionally with a reference), or reject it with a reason to give the amount back. One open request per affiliate at a time.

Limits: two levels at most; buying through one's own link earns nothing; disabled affiliates earn no new commission (their balance stays); affiliates only see masked order numbers, never the buyer. Tables: shop_commissions, shop_withdrawals.

Invoices and receipts

Invoices / receipts in the shop settings: off, invoice requests, automatic receipts, or both.

  • Invoice requests (mainland China style): customers tick "I need an invoice" at checkout or request one from the order page once paid, with a personal or company name and tax ID (required for companies). Shop → Invoices in the admin: upload the PDF issued in your tax system (up to 5 MB) and the customer is e-mailed and downloads it from the order page, or reject with a reason so they can correct it. PDFs are stored under private/ in the media storage, never served by /api/media, only to holders of the order link.
  • Automatic receipts (international): once paid, the order page links a printable receipt / invoice (seller name, address and tax ID, buyer, lines, taxes, points and discounts); "Print → Save as PDF" in the browser keeps it. Seller details come from the shop settings, falling back to the site name and company address.

Setting it up

  1. Admin → Plugins → Shop → Configure (or Shop → Shop settings): currency, tax, delivery, pickup, order prefix, notification e-mail and the payment methods you use.
  2. Open a product: the Shop card in the editor sidebar holds price, stock, options and gallery. It is saved together with the product. Commerce data is keyed by the product slug, so all translations of a product share price and stock.
  3. Configure SMTP in Admin → E-mail so customers receive order e-mails.
  4. Make sure the cron Worker runs (deploy/cron-worker) for the "cancel stale unpaid orders" task.

Payment providers

ProviderSettingsNotes
StripeSecret key sk_…; optional webhook secret whsec_…Payment is confirmed when the customer returns (API lookup). For extra safety add the webhook /api/shop/webhooks/stripe with checkout.session.completed and checkout.session.async_payment_succeeded.
PayPalClient ID + secret, sandbox switchOrders v2, captured when the customer returns.
PaytrailMerchant ID + secretEUR only. Redirects and the server callback /api/shop/webhooks/paytrail are HMAC-verified and the amount is checked. Test credentials: merchant 375917, secret SAIPPUAKAUPPIAS.
WeChat PayMerchant ID, AppID, API v3 key, merchant certificate serial number, merchant private key (apiclient_key.pem); optional WeChat Pay public key + IDCNY only, API v3. Desktop shows a QR code on the order page (Native pay) that updates by itself once paid; mobile browsers use H5 pay when "H5" is on (enable H5 pay and its domain on the merchant platform), otherwise the QR code. Inside WeChat the QR code is shown (long-press to pay). Callback /api/shop/webhooks/wechat (https): decrypted with the API v3 key, signature checked when the public key is set.
AlipayAppID, app private key (RSA2, PKCS8 or PKCS1), Alipay public key; sandbox switchCNY only, public-key mode. Desktop: page pay (QR code or login on Alipay's page); mobile: WAP pay into the Alipay app. Not offered inside WeChat (it blocks Alipay). Notification /api/shop/webhooks/alipay is RSA2-verified; returns are confirmed with alipay.trade.query.
Bank transferInstructions textOrder stays awaiting payment until you mark it paid.
Cash on delivery—Same; mark it paid when you receive the money.

Every online payment is checked against the order total and currency on the server before the order is marked paid. WeChat Pay and Alipay payments stop being payable when the order would be cancelled as unpaid (time_expire); a payment that still arrives for a cancelled order is noted on the order so it can be refunded. The browser never sends prices: carts are priced again by /api/shop/quote and /api/shop/checkout.

Site presets and environment credentials

Preset settings in the site's nuxtcms.plugins.json (values saved in the admin win) and keep payment secrets in the environment instead of the database:

{ "plugins": [{ "id": "shop", "package": "nuxtcms/plugins/shop", "license": "NCMS-…",
  "settings": { "currency": "EUR", "taxRate": 14, "pickupEnabled": true, "orderPrefix": "LC" } }] }
VariableSetting
NUXT_SHOP_STRIPE_SECRET_KEY / NUXT_SHOP_STRIPE_WEBHOOK_SECRETStripe
NUXT_SHOP_PAYPAL_CLIENT_ID / NUXT_SHOP_PAYPAL_SECRETPayPal
NUXT_SHOP_PAYTRAIL_MERCHANT_ID / NUXT_SHOP_PAYTRAIL_SECRETPaytrail
NUXT_SHOP_WECHAT_MCH_ID / _APP_ID / _API_V3_KEY / _SERIAL_NO / _PRIVATE_KEY / _PUBLIC_KEY_ID / _PUBLIC_KEYWeChat Pay
NUXT_SHOP_ALIPAY_APP_ID / NUXT_SHOP_ALIPAY_PRIVATE_KEY / NUXT_SHOP_ALIPAY_PUBLIC_KEYAlipay

Customising

Everything renders through extension points, so sites keep their own layouts. In the site's app/app.config.ts:

export default defineAppConfig({
  nuxtcms: {
    slots: {
      'header:actions': { ShopCartButton: false }, // the site header has its own cart icon
    },
  },
})

The global components ShopCartButton, ShopBuyBox, ShopCardPrice and ShopGallery can be placed in custom layouts directly (<ShopCartButton />). A site can override any plugin page at the same path (e.g. its own app/pages/checkout.vue).

Tables ({prefix}shop_products, shop_orders, shop_order_items, shop_order_notes, shop_coupons) are created automatically on first use on SQLite / D1, PostgreSQL and MySQL.