Search by

tmonier / sylius-withdrawal-plugin

thibmonier

EU withdrawal button (Directive (EU) 2023/2673, Art. 11a Consumer Rights Directive) for Sylius 2

Package info

github.com/thibmonier/sylius-withdrawal-plugin

Type:sylius-plugin

pkg:composer/tmonier/sylius-withdrawal-plugin

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-10-10 16:11 UTC

This package is auto-updated.

Last update: 2026-10-10 18:07:30 UTC


README

Build License: MIT

The EU "withdraw from contract here" button for Sylius 2.

Since 19 June 2026, every online shop selling to consumers in the European Union must offer a withdrawal function: a clearly labelled button letting consumers withdraw from a distance contract online, followed by a confirmation step and an acknowledgement of receipt on a durable medium (Article 11a of Directive 2011/83/EU, introduced by Directive (EU) 2023/2673).

This plugin implements it for Sylius 2.2+, free and open source.

Features

Requirement (Art. 11a) What the plugin does
Function labelled "withdraw from contract here", continuously available, easily accessible Link in the footer of every shop page and button on the customer's order page. No login required.
Consumer provides or confirms name, contract and e-mail Statement form, prefilled for logged-in customers (recital 37)
Separate step labelled only "confirm withdrawal" Dedicated confirmation page with a single confirm button; nothing is recorded before it
Acknowledgement of receipt on a durable medium with content, date and time E-mail sent immediately with the full statement and the server timestamp
Statement sent within the period is timely Statements are never refused; timeliness is computed and shown to the merchant

Also included:

  • Partial withdrawal: logged-in customers pick the order items; guests describe them in free text.
  • Back office: Sales → Withdrawals grid with filters, detail page, accept / reject workflow (Symfony Workflow), deadline and timeliness indicator, and proof that the acknowledgement was sent.
  • Order matching without order enumeration: a guest statement is linked to the order only when the number and the customer e-mail match, and the response is the same either way.
  • Merchant notification e-mail to the channel contact address.
  • Official wording in English, French, German, Spanish, Italian, Dutch and Polish, taken from the Official Journal and checked by tests.
  • Customisable through Twig Hooks; MySQL, MariaDB and PostgreSQL support.

Screenshots

Confirmation step Acknowledgement of receipt
Confirmation step Acknowledgement e-mail

Admin grid

Admin detail

Requirements

Version
PHP 8.2+
Sylius 2.2, 2.3
Symfony 6.4, 7.4, 8.0

Installation

  1. Require the package:

    composer require tmonier/sylius-withdrawal-plugin
  2. Register the bundle in config/bundles.php (Symfony Flex does it automatically once a recipe exists):

    Tmonier\SyliusWithdrawalPlugin\TmonierSyliusWithdrawalPlugin::class => ['all' => true],
  3. Import the configuration in config/packages/tmonier_sylius_withdrawal.yaml:

    imports:
        - { resource: "@TmonierSyliusWithdrawalPlugin/config/config.yaml" }
  4. Import the routes in config/routes/tmonier_sylius_withdrawal.yaml:

    tmonier_sylius_withdrawal:
        resource: "@TmonierSyliusWithdrawalPlugin/config/routes.yaml"
  5. Run the migrations:

    bin/console doctrine:migrations:migrate
  6. Make sure each channel has a contact e-mail if you want to receive merchant notifications.

Configuration

# config/packages/tmonier_sylius_withdrawal.yaml
tmonier_sylius_withdrawal:
    period_days: 14        # used to flag late statements; never used to refuse one
    notify_merchant: true  # copy of each statement to the channel contact e-mail

The withdrawal period starts when the goods are delivered (Art. 9). Sylius does not track delivery, so the plugin uses the last shipment date, falling back to the checkout completion date. The deadline is informational.

Customisation

Every page is built with Twig Hooks:

Hook Content
sylius_shop.base.footer.content.menu.help_links → tmonier_withdrawal Footer link
sylius_shop.account.order.show.content.main.header.buttons → tmonier_withdrawal Button on the account order page
tmonier_withdrawal.shop.withdrawal.form.content Statement form page
tmonier_withdrawal.shop.withdrawal.confirm.content Confirmation page
tmonier_withdrawal.shop.withdrawal.done.content Acknowledgement page
tmonier_withdrawal.admin.withdrawal_request.show.content.sections#left/#right Admin detail page

E-mail templates can be overridden in templates/bundles/TmonierSyliusWithdrawalPlugin/email/.

Important

If you move or restyle the footer link, keep it prominent and reachable from every page, and keep the confirm button labelled only with the official wording.

What you still have to do

The plugin provides the technical function. As a merchant you remain responsible for:

  • mentioning the existence and placement of the withdrawal function in your pre-contractual information and terms (Art. 6(1)(h) as amended);
  • processing refunds (for example with sylius/refund-plugin);
  • handling the exceptions of Art. 16 (personalised goods, perishables, etc.) when you review a statement;
  • checking national transposition specifics.

This plugin is not legal advice.

Development

docker compose up -d mysql mailhog   # or your own MySQL
composer install
(cd vendor/sylius/test-application && yarn install && yarn build)
vendor/bin/console doctrine:database:create
vendor/bin/console doctrine:migrations:migrate -n
vendor/bin/console sylius:fixtures:load -n

vendor/bin/phpunit --testsuite unit
APP_ENV=test vendor/bin/phpunit --testsuite non-unit   # needs a test database with fixtures
vendor/bin/phpstan analyse
vendor/bin/ecs check

License

MIT. See LICENSE.