01
Exist, and be findable
An electronic function, reachable from the shop, that a consumer can use to declare withdrawal. A contact form or an email address is not one.
EU Directive 2023/2673, Article 11a
Since 19 June 2026 an EU shop has had to offer an electronic withdrawal function. This plugin adds one, records the declaration, and sends the customer a timestamped receipt they can keep.
Free, GPL, on WordPress.org. FDesign sells the setup, the legal wording review and the ongoing care, not the plugin.
| Reference | FDWB-DB8FF1 |
|---|---|
| Received | 30/08/2026 11:55:41 EEST |
| Order | 40 |
| Withdrawn from | Pattern bundle × 2 |
This message confirms that we received your declaration. It is not, by itself, our acceptance of the withdrawal.
Integrity code deb53a4250cd55b84200275c9f1e0a63
What the law asks for
Article 11a is short, and each sentence of it turns into a requirement a shop can either meet or not. These are the four that decide whether what you have counts.
01
An electronic function, reachable from the shop, that a consumer can use to declare withdrawal. A contact form or an email address is not one.
02
Most orders are placed as a guest. If the function needs a login, the customers who most need it cannot reach it.
03
The shop has to acknowledge the declaration, without undue delay, in a form the consumer can keep. An on-screen message disappears. An email does not.
04
The principle behind the whole article. If checkout takes three clicks, withdrawing should not take a phone call.
The stake
National authorities set their own fines, and those vary. The consequence that bites first is written into the directive itself and applies everywhere in the EU.
Where the required information or function is not provided, the cooling-off period extends from fourteen days to twelve months and fourteen days. An order from last autumn stays withdrawable.
If a customer says they withdrew and the shop has no record, the shop is the one without evidence. A timestamped acknowledgement is what closes that argument.
19 June 2026 has passed. A shop selling to EU consumers without a withdrawal function is not preparing for a deadline, it is already exposed to the extended period.
The pre-contractual information has to disclose the function. Installing the plugin is half the job; the terms and returns pages are the other half.
Section by section
Every part of this has been run against a live WooCommerce shop, not only read. The numbers further down say how.
Three ways in
A single form serves three different people, because a withdrawal function that only works for one of them is not a withdrawal function.
Two steps
The customer sees exactly what they are declaring, then confirms as a separate action. The two step shape is what makes the record defensible: nobody withdrew by accident.
Partial withdrawal
Consumers withdraw from part of an order more often than from all of it. The plugin counts what is genuinely left rather than what was originally bought.
The acknowledgement
An email the customer can keep, carrying the exact time of receipt and an integrity code derived from the declaration itself. It is the evidence, and it is worded to be evidence.
The queue
One screen under WooCommerce, with the pending count in the menu so nothing sits unnoticed.
Five emails
Access link, acknowledgement, shop notification, accepted, rejected. All five appear under WooCommerce, Settings, Emails alongside the rest.
Deletion
Spam, duplicates and the test entries every shop leaves behind while setting up should be removable. A genuine declaration is a different thing: it is the record that a customer exercised a legal right on a date, and that is your evidence as much as theirs.
Privacy
Declarations appear in Tools, Export Personal Data and Tools, Erase Personal Data, and the plugin contributes suggested wording to your privacy policy draft.
Engineering
A withdrawal function fails quietly. These are the failures that would not announce themselves, and what was done about each.
Thirty two bytes from a cryptographic source, stored only as a SHA-256 hash, single purpose, and expired by the query rather than by a check afterwards. A leaked database backup hands over nothing usable.
Opening the emailed link exchanges it for an HttpOnly cookie scoped to the withdrawal page, then redirects to a clean URL. Without that, the credential reaches every third party asset the page loads, in the Referer header.
Using the signal WP Rocket, LiteSpeed Cache, W3 Total Cache, WP Super Cache and WP Fastest Cache all respect, and on every translation of the page, not only the original. A cached withdrawal page hands one customer another customer's session.
Rate limited per address and per visitor, with a honeypot and a signed timing check. A wrong order number and a wrong email produce exactly the same message as a correct pair.
Kept in the plugin's own table, not in a transient. A transient can be evicted under memory pressure, so a limiter built on one fails open exactly when the site is busiest. WooCommerce reached the same conclusion for its own limiter.
No monetary amount, because what you owe depends on delivery costs, apportioned discounts and the condition of the goods. A figure stored at declaration time would look authoritative and be wrong.
0
errors in
Plugin Check
0
PHPStan level 5
findings
80
attack checks,
all passing
8
languages
shipped
3
ways into
the form
Alternatives
Six comparable plugins exist on WordPress.org and all six are free. The rows below were verified by reading their code on 29 August 2026, not their marketing.
| FDesign | Vendidero | WebToffee | Four others | |
|---|---|---|---|---|
| Active installs | new | 5,000 | 1,000 | 50 to 500 |
| Guest path without an account | yes | yes | yes | varies |
| Access links stored hashed | yes | yes | no | varies |
| Rate limiting on the lookup | yes | no | no | no |
| Refunds reduce what is left | yes | no | no | no |
| Page cache exclusion | yes | no | no | no |
| Reason attached to a rejection | yes | yes | yes, required | no |
| Shop can reword the emails | closing paragraph too | standard block | no | two of four |
| Greek interface | complete | no | partial | no |
Install counts are WordPress.org's own figures, read on 29 August 2026. Vendidero is the most widely used and the most complete of the six; where it does something better, this plugin borrowed it. The rejection reason came from WebToffee, which will not let an administrator reject without typing one.
Security
Reviewing a plugin against a mental list of vulnerabilities means reviewing it against the ones you happen to remember. The list came from the National Vulnerability Database instead.
Every one published between 1 May and 29 August 2026, sorted twice: by how often each class appears, and by how badly it ends. The two orders are almost opposite.
Cross site scripting leads the count with 545 records and appears zero times among the critical. Unrestricted file upload is eighth by count and first by severity.
Weak password recovery sits nineteenth by count and seventh among the critical. An emailed access link is one of those in everything but name, so every classic failure of one was tested for.
What that produced
Two attack suites, eighty checks between them, run against a live WooCommerce shop rather than a mock. The emailed link is built from the site's own address and never from a request header, so it cannot be pointed at somebody else's server. Expiry is enforced inside the query. Fifty issued tokens are fifty distinct values, and the raw token appears nowhere in the database.
Verified against NIST National Vulnerability Database, WordPress Plugin Check, PHP_CodeSniffer with the WordPress standards, and PHPStan at level 5. Figures read on 29 August 2026.
Languages
What ships
The interface is translated in all eight. Greek is complete at 299 of 299 strings, including every admin screen, because a Greek merchant should not meet a Greek shop front and an English dashboard.
Vertrag widerrufen for German, Odstąp od umowy for Polish, Recesso dal contratto for Italian.The plugin
There is no held back version. What is on WordPress.org is what this page describes, and FDesign does not sell a licence for it.
What FDesign sells is the part a plugin cannot do for you: choosing the withdrawal window and the status that starts it, wiring the disclosure into your terms and returns pages, checking the wording against how your shop actually handles returns, and being there when a customer's declaration arrives on a Friday evening.
Download
Install from the WordPress plugins screen, or download and upload the zip.
Services
Two families. The one off gets the function live and defensible. The monthly one keeps it that way as WooCommerce, WordPress and your own catalogue change.
One off
One shop
from €140
A single WooCommerce shop, live and tested.
Five shops
from €490
Agencies and portfolio owners. About 30% less per shop.
Larger or unusual
on assessment
Multisite, marketplaces, or a heavily customised checkout.
Monthly
One shop
from €29 / month
The function keeps working while everything around it changes.
Five shops
from €116 / month
About 20% less per shop.
Larger or unusual
on assessment
Volume, or an obligation that reaches past WooCommerce.
Prices exclude VAT. Greek VAT of 24% is added where it applies.
The plugin itself is free and stays free. These prices are for the work around it.
Who built it
WordPress and WooCommerce, Athens, since 2015
FDesign builds and looks after WooCommerce shops, and writes the plugins those shops turn out to need. This one started as a requirement on a client's own shop and became the thing that was missing from every alternative: a withdrawal function that treats the declaration as evidence rather than as a form submission.
Questions
Yes. It is GPL and published on WordPress.org, and there is no premium build with the useful parts in it. FDesign earns from the setup, the wording review and the monthly care, which are the parts a plugin cannot do for you. That also keeps the incentives honest: nothing gets crippled to sell an upgrade.
No, and any plugin that claims otherwise is overselling. The plugin provides the electronic function and the timestamped acknowledgement. What it cannot do is write your terms and returns pages, disclose the function as Article 6 requires, or decide how your team handles a return when it arrives. Confirm both against the law as transposed in your country.
Not safely. The directive points to unambiguous wording along the lines of withdraw from contract. A label a customer does not recognise as the withdrawal function is unlikely to discharge the obligation, and Cancel reads as abandoning an order that has not shipped yet.
No, deliberately. Refunds stay in your normal WooCommerce flow, through your existing gateway, decided by you after you have inspected the returned goods. The plugin also stores no monetary amount, because what a shop owes depends on delivery costs, apportioned discounts and the condition of the goods. A figure stored at declaration time would look authoritative and be wrong.
Sealed health, hygiene and cosmetic products lose the right of withdrawal only once the customer has opened them. An unopened item is still fully withdrawable. The plugin therefore does not let you exclude such products automatically, because no software can tell whether a package has been opened. That check belongs to your team when the return arrives.
Yes. The withdrawal page excludes itself from caching using the standard signal that WP Rocket, LiteSpeed Cache, W3 Total Cache, WP Super Cache and WP Fastest Cache all honour. Behind a CDN there is one setting to turn on, because otherwise every visitor appears to arrive from the same address and shares one rate limiting budget. If you run a cache everything rule at the CDN, add a bypass for that page.
By default it is kept, and the erasure report says so and why. The declaration is the record of a legal act and your evidence that you honoured it. If you would rather it went, switch on erasure under Withdrawal, Advanced: the name, address and free text are then replaced with anonymised values while the declaration, its reference and its date survive.
Install it yourself in ten minutes, or have FDesign put it in, word it for your shop, and test the guest path on your own staging before it meets a real customer.
Setup includes the guest path tested end to end on your staging, before go live.