BACK TO DIRECTORY

ErreD EU Order Withdrawal for WooCommerce

by Dany Ray

0.0
(0 ratings)

From 19 June 2026, EU Directive 2023/2673 requires online stores across the European Union to
provide a digital withdrawal function: a way to cancel a distance contract online that is at
least as easy to use as the purchase flow itself. A single “cancel” button is not enough. The law
requires a clearly labelled, continuously available function, a two-step confirmation, and an
acknowledgement on a durable medium whose timestamp fixes the legal moment of communication.

ErreD EU Order Withdrawal for WooCommerce implements that function end to end — not just the
button, but the declaration flow, the two-step confirmation, the durable-medium receipt, the
eligibility rules and the merchant review tools needed to actually comply.

It ships the Italian transposition out of the box (art. 54-bis of the Codice del Consumo,
introduced by D.Lgs. 209/2025) with the legally-fixed label «recedere dal contratto qui», and it
is fully translatable for other EU markets.

The plugin does not create a right of withdrawal: it provides the online channel to exercise an
existing one, honouring the legal exceptions (e.g. art. 59 in Italy). It is built security-first,
is WooCommerce High-Performance Order Storage (HPOS) native, and works fully offline (no external
service calls).

For consumers

  • A clearly labelled, continuously available withdrawal function on the My Account orders screen and
    in a dedicated “Right of withdrawal” tab listing every order still eligible.
  • A two-step declaration and confirmation flow (“conferma recesso”), server-rendered so it works
    even with JavaScript disabled.
  • An acknowledgement on a durable medium (email plus a stored PDF receipt) whose timestamp fixes
    the moment of communication — the legal start date (dies a quo) for refund deadlines.
  • Reachable by guest-checkout customers through a per-order signed link in their order emails and on
    the order-received page, with no order enumeration.

For merchants

  • A React admin screen to review requests, filter by status, search by order, name or email, view
    the audit timeline, view/regenerate the durable receipt and mark requests refunded or rejected.
  • A menu badge counting the requests awaiting action.
  • A conservative, configurable eligibility engine (withdrawal window, start trigger, eligible order
    statuses, per-product and per-category exclusions) that fails closed when configuration is missing.
  • Article 16 checkout consents — digital content (art. 16(m)) and early-started services
    (art. 14(4)(a)) — in both the classic checkout and the WooCommerce Checkout block, shown either on
    every checkout or only for the carts that actually call for them.
  • Role-based access to the requests screen, so the personal data each request holds is visible to
    the people you choose rather than to everyone who can edit the shop.
  • Optional WooCommerce Subscriptions support: a confirmed withdrawal cancels the subscription
    (status transition only — subscription data is never deleted).
  • An append-only audit trail and tamper-evident receipts (SHA-256 of the receipt payload).

Built to standard

  • Security-first: capability + nonce/REST permission checks and input sanitisation / output
    escaping on every privileged path; signed, rate-limited guest access.
  • Accessibility: WCAG 2.2 AA, verified with automated axe checks.
  • Fully translatable; ships a complete Italian (it_IT) translation.

This plugin encodes legal and security intent; it is not legal advice. The mapping of the art. 59
exceptions to your catalogue and the durable-medium content must be validated by a qualified legal
professional before relying on them.

Source code and build process

This plugin ships its complete, human-readable source. The compiled assets in build/ are
generated from the React/JS/CSS source in assets/ with @wordpress/scripts.

  • JS/CSS source: assets/admin/ and assets/frontend/
  • Generated bundles: build/admin/ and build/frontend/
  • Rebuild the bundles: composer install && npm ci && npm run build
  • Runtime PHP dependencies (Dompdf) are managed with Composer.

Development repository: https://github.com/erred74/ErreD-EU-Order-Withdrawal-for-WooCommerce

Hooks for developers

All hooks are prefixed recesso_dig_. Names and signatures are stable within a major version.

Filters:

  • recesso_dig_is_eligible( EligibilityResult $result, WC_Order $order ). The last word on
    whether an order can be withdrawn from. Use it to refine the decision for your catalogue.
  • recesso_dig_withdrawable_statuses( string[] $statuses ). Which order statuses a withdrawal
    may be started from, after the setting has been applied.
  • recesso_dig_entry_token_ttl( int $seconds ). Lifetime of the signed link emailed to
    guest-checkout customers. Default 60 days, floor of one day.
  • recesso_dig_consent_applies( bool $applies, string $consent ) where $consent is digital
    or service. Decides per cart whether a consent is asked for. Both checkouts read this same
    decision, so the classic checkout and the Checkout block cannot disagree.
  • recesso_dig_consent_required( bool $required, string $consent ). Makes a consent blocking or
    optional. Must not depend on the cart: the Checkout block registers its fields once per request,
    before any cart is known.
  • recesso_dig_consent_render_hook( string $hook ). Moves the consent checkboxes to another
    checkout hook; return an empty string to suppress the render and place them yourself. Classic
    checkout only — in the Checkout block, WooCommerce decides placement.
  • recesso_dig_consent_render_priority( int $priority, string $hook ). Classic checkout only.

Actions:

  • recesso_dig_request_created( WithdrawalRequest $request ). After step one is stored, before
    the consumer has confirmed. Not yet a legal record.
  • recesso_dig_request_confirmed( WithdrawalRequest $request ). After step two. This is the
    moment of communication; confirmed_at_gmt is set and never changes.
  • recesso_dig_request_processed( int $request_id, string $action ). After a merchant decision.
  • recesso_dig_after_declaration_form — fires inside the flow container, below the declaration form.

Screenshots

Step one: the withdrawal declaration ("recedere dal contratto qui"), pre-filled from the order.

Step one: the withdrawal declaration ("recedere dal contratto qui"), pre-filled from the order.

Step two: the explicit "conferma recesso" confirmation.

Step two: the explicit "conferma recesso" confirmation.

The acknowledgement screen shown after confirmation.

The acknowledgement screen shown after confirmation.

The admin requests screen: status filter, free-text search and per-request actions.

The admin requests screen: status filter, free-text search and per-request actions.

The request detail: audit timeline, durable-medium receipt (PDF) and status processing.

The request detail: audit timeline, durable-medium receipt (PDF) and status processing.

Plugin Details

Active Installs
0
Total Downloads
374
Version
0.8.0
Requires WP
6.9
Requires PHP
8.2
Tested Up To
7.1
Added
2026-07-07
Last Updated
2026-09-03 8:50am GMT

Ratings

5
0
4
0
3
0
2
0
1
0