Skip to content

Withdraw

Withdraw adds a withdrawal function to WooCommerce, aligned with EU Directive 2023/2673 (the “withdrawal button”, Art. 11a). Customers declare that they withdraw from a distance contract, in full or per item, within the withdrawal period you configure.

It is a request-and-log plugin. It records the customer’s declaration, emails a confirmation to the customer and a notification to the shop, and tracks the request status in the admin. It never moves money. You issue any refund yourself on the normal WooCommerce order screen, which matches the legal model where the consumer declares and the trader acts.

  • [withdraw_form] shortcode with a three-step public form: look up an order by number and billing email, choose items and quantities, then read the finished declaration back and confirm it. Nothing is stored until that confirmation, which is what Article 11a(3) asks for.
  • [withdraw_link] shortcode and an optional footer link, so the withdrawal function stays reachable for the whole period rather than only inside a signed-in order view.
  • Full or partial withdrawal: every order line gets a quantity field capped at the ordered quantity. After a partial withdrawal, the remaining items stay open for future declarations.
  • SHA-256 receipt verification hash (Art. 11a(4)): unique cryptographic verification hash printed on the confirmation screen, included in the customer acknowledgement email, and visible in admin detail view.
  • WooCommerce Orders list column: displays the withdrawal request status badge directly in the orders table with a link to the requests log and an indicator for late submissions.
  • CSV log export: download withdrawal requests with status and date filters, with CSV formula injection protection.
  • Statutory exclusions (Art. 16(c), (d), (e)): flag made-to-specification, perishable or sealed hygiene products at product or category level with pre-purchase disclosure.
  • Regulation 1182/71 Art. 3 deadline calculation: the period ends at midnight of the last day and a weekend deadline moves to the following Monday. Optional grace days and advisory mode to accept late submissions with a flag.
  • Unmatched declarations (optional): allows shoppers to submit declarations when order details do not match automatically, logged for manual matching by the merchant. The shopper gets a short acknowledgement email (date, time and receipt code) without any of the text they typed, because the address is unverified.
  • Optional free-text reason, and a declaration checkbox on the items step.
  • Withdraw from contract here control rendered under the WooCommerce order details table, linking to your withdrawal page with the order number pre-filled. The wording is the one Article 11a(1) prescribes.
  • Configurable withdrawal period, measured from the order completion date or, when the order was never completed, from the order creation date. An order of only virtual products (services, digital content) counts from the order creation date, the day the contract is concluded (Directive 2011/83/EU, Art. 9(2)(a) and (c)). The form prints the resulting deadline.
  • Eligibility gate: order status, deadline and “no open request for this order”, all re-checked on the server when the form is submitted.
  • Admin log under WooCommerce > Withdrawal Requests, filterable by status, with a per-row status change (pending, accepted, rejected, processed).
  • Plain-text confirmation email to the customer and notification email to the shop on submit.
  • Editable form intro text and model withdrawal text, both printed on the public form.
  • Guest friendly: the order number plus billing email lookup needs no account.
  • Privacy tools: a personal-data exporter for declarations, and an eraser that anonymises the stored email and reason.
  • HPOS and cart/checkout blocks compatibility declared, and the request table is created per site, so Multisite works.
  • It issues no refunds and changes no order status.
  • It writes no order note back to WooCommerce, so the declaration lives in its own log, not on the order screen.
  • It sends no email when you change a request status. Accepting, rejecting or marking a request processed is an internal state change only, so tell the customer yourself.
  • It exposes no REST or AJAX endpoint, runs no cron job, and generates no PDF or downloadable model form.
  1. The customer opens your withdrawal page and enters the order number and the billing email used at checkout. The match is case-insensitive.
  2. Withdraw checks that the order status is one of the eligible statuses, that the withdrawal period is still open, and that no pending or accepted request already exists for that order.
  3. The customer picks items and quantities, optionally writes a reason, ticks the declaration checkbox and submits.
  4. The same eligibility checks run again before anything is written, so a stale or tampered form cannot slip through.
  5. The request is stored in the plugin’s own table, both emails go out, and a confirmation naming the request ID, the order number and the withdrawn items replaces the form.
  6. The request appears on WooCommerce > Withdrawal Requests, where you set its status. Any refund happens on the normal WooCommerce order screen.
  • Getting started, install and set up the withdrawal page.
  • Configuration, the settings reference, the period calculation, the request log and storage.
  • FAQ, refunds, guests, emails, privacy, HPOS and uninstall.