From 19 June 2026, every shop selling to EU consumers has to put a clearly labelled, one-click "withdraw from contract" function in the storefront. That's Directive (EU) 2023/2673, which adds a new Article 11a to the old Consumer Rights Directive. WooCommerce has no native support for it - there's just an open request (#65443) sitting there with no roadmap.
So you need a plugin. The wp.org repo has a pile of them now, all claiming compliance. I didn't trust the readme screenshots. I installed all 11 I could find, one at a time, on a real WooCommerce site and drove the actual withdrawal flow as a guest. Then I scored each one against what the directive literally asks for.
This is the "I did the tedious testing so you don't have to" post. Here's what I found, including two I'd actively avoid for this job.
Updated 25 June 2026: the winner changed after a re-test. In the original round the top pick was Vendidero's EU Order Withdrawal Button (17/18) - WebToffee lost a point because guest partial withdrawal was login-gated. WebToffee then shipped v1.0.4 (24 June 2026), opening guest partial up without login. I re-tested it: it now scores a clean 18/18 and tops the table. Vendidero's plugin is now the runner-up - still an excellent pick, and the better choice if you want the largest install base or partial visible without an email round-trip. Details in the WebToffee and runner-up sections below.
What the law actually wants
First, the thing everyone gets wrong: this is not a new right. The 14-day cooling-off period already existed. Refund timelines, return-shipping rules - all unchanged. What changed is the method. If a customer can buy in a few clicks, they have to be able to withdraw with comparable ease, through a clear electronic function. Not by hunting for a PDF or emailing your support inbox.
In practice the directive boils down to a few hard requirements:
- A visible button/link, reachable from every page. "withdraw from contract here" (PL: "Odstąp od umowy tutaj") or an unambiguous equivalent. A buried footer link that looks like your T&Cs is no longer enough.
- Guest access. If you allow guest checkout, guests have to be able to withdraw without registering or logging in. This is the one that kills half the "return" plugins.
- A two-step flow. Initiate, then a separate "confirm withdrawal" action so nobody submits by accident.
- Whole order or part of it. Partial withdrawal - per item, per quantity - is explicitly required.
- No extra mandatory fields. You can ask for name, order ID and an email for the confirmation. You can't force IBAN or a reason-for-return as required fields.
- A durable-medium acknowledgement. A timestamped email (or account record) confirming receipt, without undue delay.
One easy-to-miss knock-on: your pre-contractual info under Art. 6 now has to mention the function exists and where it is. So your return-policy and terms pages need a small update too, not just the UI.
How I tested (and scored)
This wasn't a desk review. I spun up a real WooCommerce site on my local wp-test stack - store country Poland, currency PLN, guest checkout on - and installed each plugin on its own, one at a time. Then I placed a real guest order (#13, [email protected]) and drove the withdrawal flow in a real browser as a logged-out guest.
For the durable-medium step I hooked wp_mail and captured what each plugin actually queued, because the test box can't send real mail. So "email verified" here means "the plugin generated a timestamped customer + admin email", not "it landed in an inbox". That's an honest limitation - confirm deliverability on your own staging with real SMTP.
I scored nine criteria, 0-2 each, mapped straight to Art. 11a (max 18):
| C1 | Site-wide visible button, reachable from every page |
| C2 | Guest access - usable without login, by order # + email |
| C3 | Two-step flow - initiate, then a separate confirm |
| C4 | Durable-medium acknowledgement - timestamped email/record |
| C5 | Partial withdrawal - select specific items / quantities |
| C6 | No extra mandatory fields - IBAN / reason not forced |
| C7 | Admin management - request list / status flag / order-note trail |
| C8 | Polish i18n - translatable, label editable to "Odstąp od umowy" |
| C9 | Doesn't break the store - no fatal, HPOS-compatible |
0 = no, 1 = partial or paywalled, 2 = yes, free.
The scoreboard - all 11
| Plugin | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 | C9 | Total |
|---|---|---|---|---|---|---|---|---|---|---|
| WebToffee EU Order Withdrawal (v1.0.4) ★ | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 18 |
| EU Order Withdrawal Button (Vendidero) (runner-up) | 2 | 2 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 17 |
| EU Withdrawal Button | 2 | 2 | 2 | 2 | 2 | 2 | 1 | 2 | 2 | 17 |
| WWU Withdrawal Button (OSS) | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 17 |
| WPify Woo (module) | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 17 |
| Germanized (bundles the runner-up) | 2 | 2 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 17 |
| Easy Return | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 1 | 17 |
| EU Withdrawal Compliance | 1 | 2 | 2 | 2 | 1 | 2 | 2 | 2 | 2 | 16 |
| BuddyPilot Withdrawal * | 1 | 2 | 2 | 1 | 1 | 2 | 2 | 2 | 2 | 15 |
| Bitron Right of Withdrawal | 1 | 2 | 1 | 2 | 1 | 1 | 1 | 2 | 2 | 13 |
| WP Desk Flexible Refund | 0 | 0 | 1 | 1 | 1 | 1 | 2 | 1 | 2 | 9 |
* BuddyPilot: C4/C5 scored conservatively. The architecture (magic-link, partial, PDF declaration) is clearly there, but it doesn't use wp_mail and the access-link step wouldn't complete in my headless harness, so I couldn't verify the end-to-end email live. It's likely higher on a real-mail staging site.

After the re-test, WebToffee is the only clean 18/18. Six plugins tie just behind at 17/18 - including the runner-up - so the top of the table is closer than one point makes it look, and the gaps are in different places. For a Poland-only store the practical pick is still clear, as I get into below.
The winner: WebToffee EU Order Withdrawal Button
EU Order Withdrawal Button for WooCommerce by WebToffee - wordpress.org/plugins/wt-eu-withdrawal-button, v1.0.4, ~20 installs, HPOS-ready, free core. The only plugin in this round to score a clean 18/18.
I had this lower in the first round - WebToffee lost a point because its guest form had no item selection, so partial was effectively login-gated. The vendor flagged that the next release fixed it, and on v1.0.4 (released 24 June 2026) I re-tested and they were right: guest partial now works without login. With that gap closed it satisfies every Art. 11a criterion, and it does it with zero configuration - the site-wide footer link is on by default. Backed by WebToffee, an established WooCommerce-plugin vendor with long support continuity.


What I verified on v1.0.4:
- Site-wide link (C1): the "Request Withdrawal" footer link is on by default (
embed_footer_link=yes) - no toggle needed - plus a My-Account order button. - Guest (C2): recovered guest order #13 logged out, by order # + billing email only. No name field, no IBAN.
- Two-step (C3): a genuine confirm step - submit, then an email-verification link, and the request only proceeds once the customer verifies.
- Durable medium (C4): timestamped customer + admin emails, now carrying a per-request SHA-256 verification code stored on the record.
- Partial (C5) - the change: after verifying, the guest sees an "Items to withdraw" panel (per-item checkboxes + quantity). I submitted a real guest partial and confirmed the stored row in the database -
customer_user_id=0(guest),request_type=partial, only the chosen item initems_json. On v1.0.2 this was login-gated; on v1.0.4 it isn't. - Admin/audit (C7): dedicated
pending_withdrawals/withdrawals/withdrawal_logstables plus an admin menu.
Honest cons: the guest has to complete the email-verification round-trip before the item picker appears, so partial is one step further away than on plugins that show items inline. Records live in the plugin's own tables rather than as WooCommerce order notes/status. No Polish bundled (a .pot only, labels editable). And it's still a small-install (~20) newcomer next to the leaders' track records.
The runner-up: EU Order Withdrawal Button (Vendidero)
EU Order Withdrawal Button for WooCommerce - wordpress.org/plugins/eu-order-withdrawal-button-for-woocommerce, v2.2.1, ~1,000 installs, ★5, HPOS-ready, free core. This was the #1 pick in the first round and is still an excellent choice - for many stores the better one. It's the same engine Germanized bundles, from a serious legal-compliance vendor, and it's the install leader (~1,000, ★5). Prefer it over WebToffee if you want the largest install base, partial visible without an email round-trip, or the withdrawn items recorded directly on the WooCommerce order.


What I verified on the test site:
- Site-wide button (C1): one toggle (
embed_everywhere) drops a sticky "Withdraw from contract" button on every page. - Guest (C2): submitted as a logged-out guest against order #13, no account. Only the email is required - the
email_repeatfield is a hidden anti-spam honeypot, not a real field. - Partial (C5): "I want to select items manually", shown inline with no verification round-trip, and the admin distinguishes Full vs partial.
- Durable medium (C4): I captured two real
wp_mailcalls - a customer "Your withdrawal request for order #13 has been received" and an admin notification, both timestamped. - Admin/audit (C7): a dedicated Withdrawals queue, a custom "Pending withdrawal" order status, and an order note logging the exact items. This is the best merchant side of the bunch - arguably stronger than the winner's.
Why it's the runner-up now: it scores 17/18 to WebToffee's 18. The single dropped point is C3 - its confirm is a single-page "Confirm withdrawal" rather than a separate review/verification step. Everything else is best-in-class. Site-wide visibility is off by default (flip the toggle), and there's no Polish bundled, though the page title and button label are freely editable to "Odstąp od umowy tutaj".
Three alternatives worth knowing
Most legally rigorous: WWU Withdrawal Button (OSS) - 17/18
If compliance evidence is your priority, nothing beats this open-source one. Every declaration gets a PDF plus an OpenTimestamps cryptographic timestamp, precise legal wording, EU/EEA applicability rules, exclusions and consent-IP capture. The catch: it's off the wp.org repo (GitHub install, no automatic updates), disabled by default, and has more knobs than the leaders. Great for the audit-minded, more upkeep.


Ships Polish out of the box, now ties the leaders: Easy Return - 17/18
Gorgeous 3-step wizard, good guest order recovery, and the only plugin that ships pl_PL out of the box. A re-audit bumped its score: it does have an automatic site-wide button after all. The Injections setting withbuea_injection_show_footer_button (off by default) drops a sticky "Withdraw from contract" button on every page - verified as a guest. That's a config toggle, not a paywall, exactly like the winner's embed_everywhere, so C1 goes 1→2 and it joins the 17/18 tie.

It still sits behind the winner and runner-up, though. It's SaaS-coupled (easyreturn.eu): in free/unconnected mode the confirmation email is literally labelled "This is a test withdrawal confirmation email", and it doesn't declare HPOS. The durable-medium email is the one part of this you can't get wrong, so for a production store I'd still reach for the winner - but it's a genuinely strong option, especially if you want Polish with zero translation work.
Nicest customer UX: EU Withdrawal Button for WooCommerce - 17/18
wordpress.org/plugins/eu-withdrawal-button-for-woocommerce, v2.0.1, freemium - the one the research brief originally picked. This has the nicest customer-facing UX of the lot: a genuine two-step modal (Continue, review, Confirm) and the cleanest inline partial picker I saw - per-item checkboxes and editable quantities with a live total. IBAN and reason are both explicitly optional, with helpful copy.

Why it sits here and not higher: the admin side is weak (C7=1). There's no dedicated request dashboard, and the selected partial items aren't stored on the order - they only go out in the email. For a merchant who has to act on each request, that's an operational gap the leaders don't have. It also defaults to "My Account only" and needs a couple of toggles to go truly site-wide. If you care most about the customer experience and you're fine managing requests from the email, it's a genuinely lovely pick.
What I'd avoid for this job
Two plugins came up when I searched but are the wrong tool here:
- WP Desk Flexible Refund (9/18). It's a capable refund/RMA tool, but the free form is login-gated behind My Account with no guest path. It fails the two non-negotiable tests - site-wide and guest - so for the withdrawal-button obligation it's the wrong category, even though the plugin itself is fine at what it does.
- Bitron Right of Withdrawal (13/18). The same logged-in-vs-guest split WebToffee used to have before v1.0.4 fixed it - except Bitron hasn't: re-auditing it, the logged-in form does have a multi-step flow (order picker → Continue → an items step) with quantity-level item partial. But the guest form - the path that matters - has neither. It's a single-step free-text declaration, and the order ID is optional and unvalidated, so the submission isn't even reliably tied to a real order. The re-audit lifted C3 and C5 from 0 to 1 on the strength of that logged-in path (now 13/18), but for the guest obligation it's still too loose.

And a note on two more of the 17/18 plugins: WPify Woo and Germanized both do the feature well - Germanized actually bundles the runner-up's engine (Vendidero's). But both are heavy suites (Czech and DACH respectively). Only pick them if you also need the rest of the suite. For a Poland-only store that just wants the button, a standalone pick like the winner or runner-up is a fraction of the weight.
A reader suggestion, tested after publishing: Withdrawal EU Law (trecenode) - 16/18
After this went up, someone on Reddit pointed me at one I hadn't found: Withdrawal EU Law by 13Node, on GitHub as trecenode/eu-withdrawal-compliance (v1.3.0). So I put it through the exact same test - a real guest order on the live site, with wp_mail captured - and it earns a credible 16/18. It doesn't change the recommendation, but it's a genuinely solid newcomer and worth knowing about.
eu-withdrawal-compliance, which already belongs to ayudawp's "EU Withdrawal Compliance" (the 16/18 one in the scoreboard). Despite the shared slug it's a completely different plugin and codebase - different author (13Node), different text domain (trece-withdrawal-eu). Don't confuse the two when you go looking.

What it does well: a genuine form → review → confirm two-step, with structured per-item partial selection on the review screen (better than its namesake's free-text box). It generates a SHA-256 receipt hash, fires durable customer and admin emails (both captured, timestamped), stores each request as a CPT with a custom "Withdrawal requested" order status, and declares HPOS compatibility. The guest flow is clean.
Why it sits at 16 and not higher: it forces a required "Order date" field on top of name, email and order number (C6=1) - that's extra friction Art. 11a doesn't ask for. There's no automatic site-wide button either (C1=1); you place the form or link manually via shortcode or menu. And like WWU, it's off the wp.org repo - GitHub install, no automatic updates - and it's brand new with no track record yet.
Net: it ties ayudawp's EU Withdrawal Compliance at 16/18 - now the only other plugin on that rung - but it doesn't unseat the winner (WebToffee, 18/18) or the runner-up (Vendidero, 17/18). If you like its receipt-hash approach and don't mind manual updates, it's a legitimate option. For a production Polish store I'd still reach for one of the leaders.
The Poland gotcha
Here's where Poland is different from "just install it before the 19th". Poland missed the 19 December 2025 transposition deadline. The withdrawal-button rules were meant to ride into the ustawa o prawach konsumenta via a consumer-credit vehicle (UC82), steered by UOKiK. In May 2026 the government pulled that and said it would start new work. So there's likely no Polish statute in force on 19 June. Commentators are calling the date "nierealne".
Does that mean you can wait? I wouldn't. A few reasons:
- The directive is binding EU law. Polish transposition is a when, not an if - and it may land with a short runway.
- If you ship to other EU consumers, those countries' rules already apply to those sales from 19 June. Germany (§356a BGB) and France (Art. 54-bis) have transposed.
- Big platforms are rolling it out now, so it's becoming a baseline trust signal. Doing it calmly this week is cheap. Retrofitting under enforcement pressure later is not.
So which plugin for a Polish store?
The rubric winner is now WebToffee, and if you want the cleanest 18/18 score it's a fine choice. But for a production Polish store my practical pick is still the runner-up, EU Order Withdrawal Button (Vendidero) - it's the install leader with the best admin tooling, and neither it nor WebToffee ships a Polish translation, so you're typing the labels yourself either way. With Vendidero everything is editable, so the page title and button become "Odstąp od umowy tutaj" and the confirm becomes "Potwierdź odstąpienie od umowy". Two minutes of work, and you get the best admin queue of the bunch.
The only plugin that ships pl_PL out of the box is Easy Return. If you want zero translation work and a polished Polish wizard, it's tempting. I'd still hesitate on the free tier - its confirmation email is labelled "test", and the durable-medium email is the one part of this you can't get wrong. For a Polish store I'd rather spend two minutes translating the winner than rely on Easy Return's free-tier email. If you're already paying for Easy Return's connected service, that calculus changes.
What it costs if you skip it
The penalties vary by member state, but one consequence is EU-wide and it's the one that actually bites day to day: if a compliant withdrawal function is missing, the 14-day cooling-off window can extend to 12 months and 14 days. Customers can send things back the better part of a year after delivery. That's the real commercial risk, well before any regulator gets involved.
On top of that, fines exist where the rule is enforceable:
- Poland (UOKiK): collective-consumer-interest fines up to 10% of annual turnover, once it's transposed and enforceable.
- Germany: administrative fines up to €75,000 for legal persons, per current commentary.
- Cross-border (CPC / Omnibus): coordinated actions can reach up to 4% of annual turnover in the member states concerned.
What I'd actually do
If this were a client store on Poland/PLN, here's the path. It's a 1-2 hour job on staging, not a fire:
- Install EU Order Withdrawal Button for WooCommerce on a clone first.
- Turn on site-wide embed. Rename the page and button to "Odstąp od umowy tutaj" and the confirm to "Potwierdź odstąpienie od umowy". Labels are editable, no PL pack ships.
- Check only name + order ID + email are required. Leave IBAN and reason off.
- Wire real SMTP and confirm the timestamped acknowledgement email actually fires. The durable-medium email is the legal bit, so don't skip it.
- Update your return-policy / terms pages to disclose the function and where it lives (Art. 6).
- Cache-exclude the withdrawal page so the no-login form isn't served stale. If you're on a full-page cache, this matters - I wrote about the cache-bypass cookie logic in my WooCommerce performance stack post.
- Keep refunds manual through your existing gateway. The form only registers the legal declaration.
On step 2: the winner lets you edit the button text in its settings and rename the page, which is the simplest route. If you'd rather pin the labels in code - handy when you manage several stores - a small gettext filter does it without a translation file. This works for any plugin that runs its strings through WordPress translation:
// Force Polish labels without shipping a .po file.
// Drop this in a tiny mu-plugin or your theme's functions.php.
add_filter( 'gettext', function ( $translated, $text ) {
$pl = [
'Withdraw from contract' => 'Odstąp od umowy tutaj',
'Confirm withdrawal' => 'Potwierdź odstąpienie od umowy',
];
return $pl[ $text ] ?? $translated;
}, 20, 2 );
That's it. The good news is the hard part - figuring out which plugin to trust - is already done. WooCommerce will probably ship something native eventually, but #65443 has no roadmap, so I wouldn't wait for core on a deadline.
If you want more WooCommerce config wins while you're in there, my 30 WordPress & WooCommerce performance tips is a decent companion read.
FAQ
Do I need the withdrawal button if I'm a small Polish store?
Yes, in practice. The obligation applies to any business selling to EU consumers from 19 June 2026, regardless of size. Poland's own statute is delayed (see above), but the directive is binding and your cross-border EU sales are already covered. There's no small-shop exemption.
Can I just label the button "Cancel" or "Return"?
No. The directive points to clear wording like "withdraw from contract here" to open the form and "confirm withdrawal" to submit. Ambiguous labels like "Cancel" are likely treated as insufficient. In Polish, use "Odstąp od umowy tutaj" and "Potwierdź odstąpienie od umowy".
Is a footer link to my returns policy enough?
Not anymore. A policy page you have to read, or a "email us for the form" line, no longer satisfies the rule. You need a working digital function - reachable from every page, usable by guests without logging in, with a two-step confirm and a timestamped acknowledgement email.
Does the plugin handle the actual refund?
No, and that's fine. The withdrawal function only registers the legal declaration and timestamps it. The refund still goes through your normal WooCommerce flow and payment gateway, and the physical return and inspection rules are unchanged. Keep refunds manual.
Will WooCommerce add this to core?
Maybe eventually. There's an open enhancement request (#65443) but no roadmap or shipped support as of June 2026. I wouldn't wait for core on a deadline - install a plugin.
WooCommerce is my thing
I dig into WooCommerce internals for a living - performance, compliance, the stuff that breaks at the worst time. If you'd rather hand this off, or your store is slow and you're not sure why, I can help. Hands-on, real fixes, not a report.