Notes / March 6, 2026

Custom order forms in Shopware 6

Capturing structured data before checkout and turning it into line items, attributes, and audit trails.

Standard checkout assumes SKU + quantity + shipping. Regulated and B2B flows often need structured attestations first: vet license numbers, contract PO references, delivery dock instructions, or “I confirm I am not shipping to a banned jurisdiction.” Those answers must be validated, auditable, and visible in admin + ERP exports—not buried in free-text order comments.

This note is the architecture pattern I use when extending Shopware checkout without forking core templates blindly.


1. Capture layer (storefront)

Options

Approach When it fits
Classic Symfony Form + Twig Server-rendered, fast to secure, easy CSRF
Storefront JS app posting JSON Complex multi-step UI; still needs identical server validation

Non-negotiables

  • CSRF on POST; rate limiting on public routes (IP + customer id when logged in).
  • Schema versioning in payload: {"v":1,"fields":{...}} so you can migrate old orders when fields rename.
  • PII policy: collect only what legal approved; redact in logs.

2. Validation layer (server)

Mirror compliance language in assertions (Symfony Callback constraints, custom validators):

  • Regex for license formats
  • Cross-field rules (“if country = X then document Y required”)
  • Max lengths aligned with DB columns to avoid truncation surprises

Return field-level errors as JSON for SPA or re-render Twig with error bags.


3. Cart bridge — three patterns we have used

Pattern A — Hidden “service” line items

Create a virtual product (hidden from search) per fee/attestation bundle. Cart processor adds line with:

  • payload containing JSON answers (or a reference id to a order_draft table if payload size is a concern)
  • stackable rules documented so promotions do not zero it accidentally

Pros: Appears on invoice PDFs naturally.
Cons: Tax engines (Avalara) may treat it as taxable—coordinate early.

Pattern B — Quote custom fields only

Store structured answers on cart or order customFields without new SKUs.

Pros: Simpler tax.
Cons: ERP that only reads line items may miss data—add export mapping.

Pattern C — Sidecar order_draft table

POST creates order_draft row; checkout references draftUuid until order placed; on OrderPlacedEvent, attach FK to order.

Pros: Large payloads, file uploads.
Cons: More moving parts—must garbage-collect abandoned drafts.


4. Checkout gating

  • Cart validator or subscriber: if required fields missing → CartException with translated snippet key.
  • Payment step: re-validate (client can tamper); block pay route until server state clean.
  • Admin order detail: custom tab rendering JSON pretty + copy button for support.

5. Events worth subscribing to

  • CheckoutOrderPlacedEvent — push to ERP / OMS; include structured fields in payload builder.
  • StateMachineTransitionEvent for fulfillment—sometimes answers change which transition is legal.

6. Testing matrix

  • Guest vs logged-in; session expiry mid-flow.
  • Multi-shipment orders—ensure answers follow the header order, not a single delivery.
  • Reorder from account—should not silently clone stale attestations without user confirmation.

Resume framing

“Delivered regulated Shopware checkout: server validation, cart bridge pattern chosen with tax/ERP trade-offs, checkout gating, and admin visibility for support.”