{"id":330627,"date":"2026-07-07T11:14:11","date_gmt":"2026-07-07T11:14:11","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/erred-eu-order-withdrawal-for-woocommerce\/"},"modified":"2026-09-03T08:50:11","modified_gmt":"2026-09-03T08:50:11","slug":"erred-eu-order-withdrawal-for-woocommerce","status":"publish","type":"plugin","link":"https:\/\/mn.wordpress.org\/plugins\/erred-eu-order-withdrawal-for-woocommerce\/","author":17873296,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.8.0","stable_tag":"0.8.0","tested":"7.1","requires":"6.9","requires_php":"8.2","requires_plugins":null,"header_name":"ErreD EU Order Withdrawal for WooCommerce","header_author":"ErreD","header_description":"Digital withdrawal function for WooCommerce: the EU \"easy withdrawal\" duty (Directive 2023\/2673, in force 19 June 2026) and its Italian transposition (art. 54-bis Codice del Consumo). HPOS-native, security-first.","assets_banners_color":"335cad","last_updated":"2026-09-03 08:50:11","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":352,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.5.10":{"tag":"0.5.10","author":"draison","date":"2026-08-13 06:57:14","revision":3644399},"0.5.4":{"tag":"0.5.4","author":"draison","date":"2026-07-07 11:13:59","revision":3598932},"0.5.9":{"tag":"0.5.9","author":"draison","date":"2026-07-20 06:58:50","revision":3614287},"0.6.0":{"tag":"0.6.0","author":"draison","date":"2026-08-13 19:57:00","revision":3646121},"0.7.0":{"tag":"0.7.0","author":"draison","date":"2026-08-15 09:18:02","revision":3648333},"0.8.0":{"tag":"0.8.0","author":"draison","date":"2026-09-03 08:50:11","revision":3679367}},"upgrade_notice":{"0.8.0":"<p>The order lookup screen&#039;s four texts and the withdrawal page&#039;s button colour are now settings, and the buttons can inherit your theme&#039;s style instead. Fixes two options left behind on uninstall. Nothing changes until you change it. No data migration required.<\/p>","0.7.0":"<p>Customers can follow their withdrawal requests, and the receipt PDF, from My Account. Fixes a\nwithdrawal page that was deleted or unpublished silently sending every withdrawal link to your home\npage. Recommended for all sites. No data migration required.<\/p>","0.6.1":"<p>Fixes two broken links in the requests screen: Export CSV reporting an expired link, and the\ndurable-medium receipt refusing to open from the request detail panel. Both affected every use, not\njust occasional ones. Recommended for all sites. No data migration required.<\/p>","0.6.0":"<p>Checkout consents now work in the Checkout block, My Account gains a &quot;Right of withdrawal&quot; tab, and\nthe settings screen is far more configurable. Fixes missing order notes on decisions taken from the\n&quot;Set status&quot; dropdown. Adds one optional database column, applied automatically.<\/p>","0.5.10":"<p>Compatibility release for WordPress 7.1 and WooCommerce 11, with the admin screen aligned to the\nnew 40px control size. Also updates the bundled Dompdf library to 3.1.6, which carries security\nfixes. Recommended for all sites. No data migration required.<\/p>","0.5.4":"<p>Admin menu entries now default to English for non-Italian sites; Italian labels are unchanged via\nthe bundled translation. No data migration required.<\/p>","0.5.3":"<p>Safer uninstall: only the page the plugin itself auto-created can be removed when deleting data on\nuninstall; a page you selected yourself in settings is never touched. No data migration required.<\/p>","0.5.2":"<p>A single, correctly-working withdrawal button for guests and members, a tidier styled confirmation\nstep, and admin improvements: abandoned (unconfirmed) requests are hidden and restartable, and the\nmenu badge counts all open requests with the standard styling. No data migration required.<\/p>","0.5.1":"<p>Bundles the full JS\/CSS source alongside the compiled assets and links the public development\nrepository, updates the bundled Dompdf to 3.1.5, and hardens the admin receipt download and the\nproduct withdrawal-status save. No data migration required.<\/p>","0.5.0":"<p>Adds a withdrawal-status column to the orders screen and replaces the request detail panel&#039;s action\nbuttons with a single &quot;Set status&quot; dropdown plus a &quot;Save status&quot; button. No data migration required.<\/p>","0.4.0":"<p>Richer per-product\/category withdrawal status (art. 59 exceptions), a post-activation welcome notice, a\nreorganised settings screen, and a redesigned Annex I.B model form. No data migration required.<\/p>","0.3.1":"<p>Fixes the in-place schema upgrade (empty requests list \/ blank withdrawal submission after updating to\n0.3.0) and prevents the withdrawal form from white-screening on a transient error.<\/p>","0.3.0":"<p>Adds art. 59 product\/category configuration, checkout consents, the Annex I.B model form, status\nemails, admin actions\/stats\/CSV export, GDPR tools and more. Adds two optional database columns\n(applied automatically). Review the new settings under Recesso digitale \u2192 Settings.<\/p>","0.2.0":"<p>Clearer withdrawal page (checkbox product picker with thumbnails and per-product quantities) and a\nfuller durable-medium acknowledgement that lists the selected products. No data migration required.<\/p>","0.1.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon.svg":{"filename":"icon.svg","revision":3598932,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3598932,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3598932,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":{"recesso-digitale\/withdrawal-button":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"recesso-digitale\/withdrawal-button","version":"0.1.0","title":"ErreD EU Order Withdrawal for WooCommerce","category":"widgets","icon":"undo","description":"Renders the withdrawal (recesso) flow and the \u00abrecedere dal contratto qui\u00bb entry control.","keywords":["recesso","withdrawal","woocommerce","consumer"],"textdomain":"erred-eu-order-withdrawal-for-woocommerce","supports":{"html":false,"multiple":false},"editorScript":"file:.\/index.js","viewScript":"file:.\/view.js","viewStyle":"file:.\/style-view.css"}},"tagged_versions":["0.5.10","0.5.4","0.5.9","0.6.0","0.7.0","0.8.0"],"block_files":[],"assets_screenshots":{"screenshot-1.jpg":{"filename":"screenshot-1.jpg","revision":3598932,"resolution":"1","location":"assets","locale":"","width":2763,"height":1443},"screenshot-2.jpg":{"filename":"screenshot-2.jpg","revision":3598932,"resolution":"2","location":"assets","locale":"","width":2731,"height":702},"screenshot-3.jpg":{"filename":"screenshot-3.jpg","revision":3598932,"resolution":"3","location":"assets","locale":"","width":2788,"height":426},"screenshot-4.jpg":{"filename":"screenshot-4.jpg","revision":3598932,"resolution":"4","location":"assets","locale":"","width":4785,"height":1688},"screenshot-5.jpg":{"filename":"screenshot-5.jpg","revision":3598932,"resolution":"5","location":"assets","locale":"","width":4767,"height":2364}},"screenshots":{"1":"Step one: the withdrawal declaration (\"recedere dal contratto qui\"), pre-filled from the order.","2":"Step two: the explicit \"conferma recesso\" confirmation.","3":"The acknowledgement screen shown after confirmation.","4":"The admin requests screen: status filter, free-text search and per-request actions.","5":"The request detail: audit timeline, durable-medium receipt (PDF) and status processing."}},"plugin_section":[],"plugin_tags":[258660,32899,269342,245590,286],"plugin_category":[45],"plugin_contributors":[270459],"plugin_business_model":[],"class_list":["post-330627","plugin","type-plugin","status-publish","hentry","plugin_tags-cancellation","plugin_tags-consumer","plugin_tags-recesso","plugin_tags-withdrawal","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_contributors-draison","plugin_committers-draison"],"banners":{"banner":"https:\/\/ps.w.org\/erred-eu-order-withdrawal-for-woocommerce\/assets\/banner-772x250.png?rev=3598932","banner_2x":"https:\/\/ps.w.org\/erred-eu-order-withdrawal-for-woocommerce\/assets\/banner-1544x500.png?rev=3598932","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/erred-eu-order-withdrawal-for-woocommerce\/assets\/icon.svg?rev=3598932","icon":"https:\/\/ps.w.org\/erred-eu-order-withdrawal-for-woocommerce\/assets\/icon.svg?rev=3598932","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/erred-eu-order-withdrawal-for-woocommerce\/assets\/screenshot-1.jpg?rev=3598932","caption":"Step one: the withdrawal declaration (\"recedere dal contratto qui\"), pre-filled from the order."},{"src":"https:\/\/ps.w.org\/erred-eu-order-withdrawal-for-woocommerce\/assets\/screenshot-2.jpg?rev=3598932","caption":"Step two: the explicit \"conferma recesso\" confirmation."},{"src":"https:\/\/ps.w.org\/erred-eu-order-withdrawal-for-woocommerce\/assets\/screenshot-3.jpg?rev=3598932","caption":"The acknowledgement screen shown after confirmation."},{"src":"https:\/\/ps.w.org\/erred-eu-order-withdrawal-for-woocommerce\/assets\/screenshot-4.jpg?rev=3598932","caption":"The admin requests screen: status filter, free-text search and per-request actions."},{"src":"https:\/\/ps.w.org\/erred-eu-order-withdrawal-for-woocommerce\/assets\/screenshot-5.jpg?rev=3598932","caption":"The request detail: audit timeline, durable-medium receipt (PDF) and status processing."}],"raw_content":"<!--section=description-->\n<p>From 19 June 2026, EU Directive 2023\/2673 requires online stores across the European Union to\nprovide a <strong>digital withdrawal function<\/strong>: a way to cancel a distance contract online that is at\nleast as easy to use as the purchase flow itself. A single \"cancel\" button is not enough. The law\nrequires a clearly labelled, continuously available function, a two-step confirmation, and an\nacknowledgement on a durable medium whose timestamp fixes the legal moment of communication.<\/p>\n\n<p>ErreD EU Order Withdrawal for WooCommerce implements that function end to end \u2014 not just the\nbutton, but the declaration flow, the two-step confirmation, the durable-medium receipt, the\neligibility rules and the merchant review tools needed to actually comply.<\/p>\n\n<p>It ships the Italian transposition out of the box (art. 54-bis of the Codice del Consumo,\nintroduced by D.Lgs. 209\/2025) with the legally-fixed label \u00abrecedere dal contratto qui\u00bb, and it\nis fully translatable for other EU markets.<\/p>\n\n<p>The plugin does not create a right of withdrawal: it provides the online channel to exercise an\nexisting one, honouring the legal exceptions (e.g. art. 59 in Italy). It is built security-first,\nis WooCommerce High-Performance Order Storage (HPOS) native, and works fully offline (no external\nservice calls).<\/p>\n\n<p><strong>For consumers<\/strong><\/p>\n\n<ul>\n<li>A clearly labelled, continuously available withdrawal function on the My Account orders screen and\nin a dedicated \"Right of withdrawal\" tab listing every order still eligible.<\/li>\n<li>A two-step declaration and confirmation flow (\"conferma recesso\"), server-rendered so it works\neven with JavaScript disabled.<\/li>\n<li>An acknowledgement on a durable medium (email plus a stored PDF receipt) whose timestamp fixes\nthe moment of communication \u2014 the legal start date (dies a quo) for refund deadlines.<\/li>\n<li>Reachable by guest-checkout customers through a per-order signed link in their order emails and on\nthe order-received page, with no order enumeration.<\/li>\n<\/ul>\n\n<p><strong>For merchants<\/strong><\/p>\n\n<ul>\n<li>A React admin screen to review requests, filter by status, search by order, name or email, view\nthe audit timeline, view\/regenerate the durable receipt and mark requests refunded or rejected.<\/li>\n<li>A menu badge counting the requests awaiting action.<\/li>\n<li>A conservative, configurable eligibility engine (withdrawal window, start trigger, eligible order\nstatuses, per-product and per-category exclusions) that fails closed when configuration is missing.<\/li>\n<li>Article 16 checkout consents \u2014 digital content (art. 16(m)) and early-started services\n(art. 14(4)(a)) \u2014 in both the classic checkout and the WooCommerce Checkout block, shown either on\nevery checkout or only for the carts that actually call for them.<\/li>\n<li>Role-based access to the requests screen, so the personal data each request holds is visible to\nthe people you choose rather than to everyone who can edit the shop.<\/li>\n<li>Optional WooCommerce Subscriptions support: a confirmed withdrawal cancels the subscription\n(status transition only \u2014 subscription data is never deleted).<\/li>\n<li>An append-only audit trail and tamper-evident receipts (SHA-256 of the receipt payload).<\/li>\n<\/ul>\n\n<p><strong>Built to standard<\/strong><\/p>\n\n<ul>\n<li>Security-first: capability + nonce\/REST permission checks and input sanitisation \/ output\nescaping on every privileged path; signed, rate-limited guest access.<\/li>\n<li>Accessibility: WCAG 2.2 AA, verified with automated axe checks.<\/li>\n<li>Fully translatable; ships a complete Italian (it_IT) translation.<\/li>\n<\/ul>\n\n<p>This plugin encodes legal and security intent; it is not legal advice. The mapping of the art. 59\nexceptions to your catalogue and the durable-medium content must be validated by a qualified legal\nprofessional before relying on them.<\/p>\n\n<h3>Source code and build process<\/h3>\n\n<p>This plugin ships its complete, human-readable source. The compiled assets in <code>build\/<\/code> are\ngenerated from the React\/JS\/CSS source in <code>assets\/<\/code> with @wordpress\/scripts.<\/p>\n\n<ul>\n<li>JS\/CSS source: <code>assets\/admin\/<\/code> and <code>assets\/frontend\/<\/code><\/li>\n<li>Generated bundles: <code>build\/admin\/<\/code> and <code>build\/frontend\/<\/code><\/li>\n<li>Rebuild the bundles: <code>composer install &amp;&amp; npm ci &amp;&amp; npm run build<\/code><\/li>\n<li>Runtime PHP dependencies (Dompdf) are managed with Composer.<\/li>\n<\/ul>\n\n<p>Development repository: https:\/\/github.com\/erred74\/ErreD-EU-Order-Withdrawal-for-WooCommerce<\/p>\n\n<h3>Hooks for developers<\/h3>\n\n<p>All hooks are prefixed <code>recesso_dig_<\/code>. Names and signatures are stable within a major version.<\/p>\n\n<p>Filters:<\/p>\n\n<ul>\n<li><code>recesso_dig_is_eligible<\/code> \u2014 <code>( EligibilityResult $result, WC_Order $order )<\/code>. The last word on\nwhether an order can be withdrawn from. Use it to refine the decision for your catalogue.<\/li>\n<li><code>recesso_dig_withdrawable_statuses<\/code> \u2014 <code>( string[] $statuses )<\/code>. Which order statuses a withdrawal\nmay be started from, after the setting has been applied.<\/li>\n<li><code>recesso_dig_entry_token_ttl<\/code> \u2014 <code>( int $seconds )<\/code>. Lifetime of the signed link emailed to\nguest-checkout customers. Default 60 days, floor of one day.<\/li>\n<li><code>recesso_dig_consent_applies<\/code> \u2014 <code>( bool $applies, string $consent )<\/code> where <code>$consent<\/code> is <code>digital<\/code>\nor <code>service<\/code>. Decides per cart whether a consent is asked for. Both checkouts read this same\ndecision, so the classic checkout and the Checkout block cannot disagree.<\/li>\n<li><code>recesso_dig_consent_required<\/code> \u2014 <code>( bool $required, string $consent )<\/code>. Makes a consent blocking or\noptional. Must not depend on the cart: the Checkout block registers its fields once per request,\nbefore any cart is known.<\/li>\n<li><code>recesso_dig_consent_render_hook<\/code> \u2014 <code>( string $hook )<\/code>. Moves the consent checkboxes to another\ncheckout hook; return an empty string to suppress the render and place them yourself. Classic\ncheckout only \u2014 in the Checkout block, WooCommerce decides placement.<\/li>\n<li><code>recesso_dig_consent_render_priority<\/code> \u2014 <code>( int $priority, string $hook )<\/code>. Classic checkout only.<\/li>\n<\/ul>\n\n<p>Actions:<\/p>\n\n<ul>\n<li><code>recesso_dig_request_created<\/code> \u2014 <code>( WithdrawalRequest $request )<\/code>. After step one is stored, before\nthe consumer has confirmed. Not yet a legal record.<\/li>\n<li><code>recesso_dig_request_confirmed<\/code> \u2014 <code>( WithdrawalRequest $request )<\/code>. After step two. This is the\nmoment of communication; <code>confirmed_at_gmt<\/code> is set and never changes.<\/li>\n<li><code>recesso_dig_request_processed<\/code> \u2014 <code>( int $request_id, string $action )<\/code>. After a merchant decision.<\/li>\n<li><code>recesso_dig_after_declaration_form<\/code> \u2014 fires inside the flow container, below the declaration form.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin to the <code>\/wp-content\/plugins\/<\/code> directory, or install it through the WordPress\nplugins screen.<\/li>\n<li>Activate the plugin through the 'Plugins' screen in WordPress.<\/li>\n<li>WooCommerce 8.2 or newer (with High-Performance Order Storage) is required.<\/li>\n<li>Visit WooCommerce \u2192 Recesso digitale: settings to configure the withdrawal window, the window\nstart trigger and your product\/category exclusions.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20decide%20whether%20an%20order%20can%20be%20withdrawn%3F\"><h3>Does this plugin decide whether an order can be withdrawn?<\/h3><\/dt>\n<dd><p>No. The plugin provides the channel and records the request; the merchant accepts or rejects each\none. The ordinary 14-day period is shown as advisory information (it does not hide the function),\nand the merchant can pre-exclude specific products or categories (art. 59). Rejecting a request\nrequires a reason, which is recorded and emailed to the consumer. The mapping of the art. 59\nexceptions to your catalogue must still be validated by a legal professional.<\/p><\/dd>\n<dt id=\"does%20it%20work%20for%20guest-checkout%20orders%3F\"><h3>Does it work for guest-checkout orders?<\/h3><\/dt>\n<dd><p>Yes. Guests receive a per-order, single-purpose signed link (HMAC, verified in constant time and\nrate-limited). A bare order id or order key is never sufficient to submit a withdrawal, and\nresponses are uniform to prevent order enumeration.<\/p><\/dd>\n<dt id=\"does%20the%20withdrawal%20flow%20require%20javascript%3F\"><h3>Does the withdrawal flow require JavaScript?<\/h3><\/dt>\n<dd><p>No. The two-step flow is server-rendered and works with JavaScript disabled; JavaScript only\nenhances the admin experience.<\/p><\/dd>\n<dt id=\"what%20is%20the%20%22durable%20medium%22%3F\"><h3>What is the \"durable medium\"?<\/h3><\/dt>\n<dd><p>A withdrawal acknowledgement sent by email together with a stored PDF receipt, kept in a protected\nlocation and downloadable only through a capability- or token-checked endpoint. The receipt records\nthe content of the request and the exact date and time of transmission.<\/p><\/dd>\n<dt id=\"do%20the%20checkout%20consents%20work%20with%20the%20checkout%20block%3F\"><h3>Do the checkout consents work with the Checkout block?<\/h3><\/dt>\n<dd><p>Yes. They are registered through WooCommerce's Additional Checkout Fields API, so WooCommerce renders,\nvalidates and stores them natively in the block checkout \u2014 no extra JavaScript is loaded. That API\narrived in WooCommerce 8.9: on older versions the block checkout simply shows no consents, and the\nclassic <code>[woocommerce_checkout]<\/code> shortcode keeps working on every supported version.<\/p><\/dd>\n<dt id=\"can%20a%20consent%20appear%20only%20for%20the%20products%20that%20need%20it%3F\"><h3>Can a consent appear only for the products that need it?<\/h3><\/dt>\n<dd><p>Yes. Enable \"Show each consent only when the cart contains a product classified for it\" under Checkout\nconsents. Each consent then follows the \"Withdrawal status\" you set on the product or its category:\nthe digital-content box appears only with art. 16(m) items in the cart, the service box only with\nart. 14(4)(a) items. The option is off by default, so updating the plugin never changes what your\ncheckout shows.<\/p>\n\n<p>Either consent can also be made a condition of placing the order, and both are off by default. For the\nArticle 14(4)(a) service-start consent that default is deliberate: asking for the service to begin\ninside the withdrawal period is the customer's request to make, and it only entitles you to a\nproportionate payment if they later withdraw. Require it only where your service always begins inside\nthat window \u2014 a live session, a booking for the next few days \u2014 so an order without the request is one\nyou cannot fulfil.<\/p><\/dd>\n<dt id=\"can%20customers%20see%20the%20requests%20they%20have%20sent%3F\"><h3>Can customers see the requests they have sent?<\/h3><\/dt>\n<dd><p>Yes. The My Account \"Right of withdrawal\" tab lists them with the date they were sent, the order, the\nscope, the current status, any note you wrote when deciding, the receipt verification code and a link\nto the receipt PDF that keeps working for as long as the account does. Orders they can still withdraw\nfrom are listed in the same table. The tab is on by default and can be turned off under Withdrawal\nlink visibility. Guest-checkout customers have no account, so their route stays the signed link in\ntheir emails.<\/p><\/dd>\n<dt id=\"my%20withdrawal%20links%20stopped%20working.%20what%20happened%3F\"><h3>My withdrawal links stopped working. What happened?<\/h3><\/dt>\n<dd><p>Most likely the page hosting the withdrawal form was deleted, moved to the trash or unpublished. When\nthat happens the plugin stops showing withdrawal links rather than pointing them somewhere useless,\nand tells you so on the settings screen and in an admin notice. Select or restore the page under\nGeneral and the links come back.<\/p><\/dd>\n<dt id=\"does%20it%20support%20woocommerce%20subscriptions%3F\"><h3>Does it support WooCommerce Subscriptions?<\/h3><\/dt>\n<dd><p>Optionally. If WooCommerce Subscriptions is active, a confirmed withdrawal cancels the related\nsubscription by transitioning its status \u2014 it never deletes subscription data. With Subscriptions\nabsent, the plugin is unaffected.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20make%20external%20network%20calls%3F\"><h3>Does the plugin make external network calls?<\/h3><\/dt>\n<dd><p>No. It functions fully offline and loads no third-party scripts, fonts or assets.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20my%20data%20on%20uninstall%3F\"><h3>What happens to my data on uninstall?<\/h3><\/dt>\n<dd><p>Nothing is removed unless you opt in via the \"Delete all data on uninstall\" setting. When enabled,\nthe plugin removes its tables, options and the flow page on uninstall.<\/p><\/dd>\n<dt id=\"can%20i%20change%20the%20wording%20on%20the%20withdrawal%20page%3F\"><h3>Can I change the wording on the withdrawal page?<\/h3><\/dt>\n<dd><p>Yes, in three ways, and you will usually only need the first. The four texts on the order lookup screen \u2014 the page title, the intro paragraph, the hint under the email field and the submit button label \u2014 are settings, under WooCommerce \u2192 Order Withdrawal: settings \u2192 Order lookup screen. The intro of the declaration form, the consumer self-declaration, the excluded-product notices and the status emails have their own fields on the same screen. Leave any of them empty to keep the bundled wording, which follows the language of each visitor; your own text is shown exactly as written, in every language, and can be translated per language with WPML or Polylang.<\/p>\n\n<p>For anything else \u2014 field labels, the confirmation step, the acknowledgement screen \u2014 use a translation editor such as Loco Translate, which edits the plugin's strings and stores your version outside the plugin so updates do not overwrite it. For full control of the markup, copy any file from the plugin's <code>templates\/frontend\/<\/code> into a <code>recesso-digitale\/<\/code> folder in your theme (for example <code>wp-content\/themes\/your-child-theme\/recesso-digitale\/lookup.php<\/code>) and edit it there; the plugin uses your copy automatically. A template copied before 0.8.0 keeps its own hardcoded wording and will ignore the settings above \u2014 re-copy it if you want both.<\/p><\/dd>\n<dt id=\"can%20i%20change%20the%20colour%20of%20the%20withdrawal%20button%3F\"><h3>Can I change the colour of the withdrawal button?<\/h3><\/dt>\n<dd><p>Yes, under WooCommerce \u2192 Order Withdrawal: settings \u2192 Withdrawal page appearance. Pick any colour and the plugin works out the hover shade and the label colour from it, so the label keeps a WCAG AA contrast ratio whatever you choose. Leave it empty for the bundled colour. If your theme styles its buttons the way you want them everywhere, choose \"Inherit my theme's button style\" instead and the plugin stops styling them at all. The \u00abrecedere dal contratto qui\u00bb link in My Account and in your order emails is not affected: it sits inside your theme's own pages and has always used your theme's button style.<\/p><\/dd>\n<dt id=\"why%20does%20the%20customer%20receive%20a%20link%20instead%20of%20sending%20the%20request%20straight%20away%3F\"><h3>Why does the customer receive a link instead of sending the request straight away?<\/h3><\/dt>\n<dd><p>Because the withdrawal function must work for guest-checkout customers, who have no account to log into. If the lookup screen simply accepted \"order number plus email\" and recorded a withdrawal, anyone could file withdrawals against orders that are not theirs, and could discover which order numbers exist by trying them. That matters more here than on an ordinary form: the moment a withdrawal is confirmed is a legal fact \u2014 the date from which your refund deadline runs \u2014 so a request you cannot attribute is a bad record, not just a nuisance.<\/p>\n\n<p>So the plugin checks that the order number and the email match, then emails a cryptographically signed, expiring link to the address on the order itself, never to the address typed in the form. Opening that link proves the person has the order's mailbox, and the request is bound to a verified order. The screen answers identically whether or not an order matched, so it reveals nothing. Customers who arrive from the link in their order emails, or from the My Account tab, already hold a signed link and never see this step.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.8.0<\/h4>\n\n<p>The withdrawal page is now yours to word and to colour, without touching code or waiting for a translation.<\/p>\n\n<ul>\n<li><strong>New:<\/strong> the four texts on the order lookup screen \u2014 page title, intro paragraph, the hint under the email field, and the submit button label \u2014 are settings, under WooCommerce \u2192 Order Withdrawal: settings \u2192 Order lookup screen. Until now they were the only customer-facing copy in the plugin with no field of its own, which meant the first screen many customers see was the one screen a merchant could not reword. Leave a field empty to keep the bundled sentence, which follows each customer's language; your own wording can be translated per language with WPML or Polylang.<\/li>\n<li><strong>New:<\/strong> a colour for the withdrawal page's buttons, under Withdrawal page appearance. Pick any colour and the plugin works out the hover shade and the label colour from it, so the label keeps a WCAG AA contrast ratio whatever you choose \u2014 a pale brand colour cannot leave you with white text nobody can read.<\/li>\n<li><strong>New:<\/strong> \"Inherit my theme's button style\", in the same section, for stores whose theme already styles its buttons the way they want them everywhere. The plugin then stops styling those buttons entirely. It stays off by default: the withdrawal page is an ordinary page, where a theme's button rules are not guaranteed to load, and the shipped styling is what keeps the control from rendering as bare text.<\/li>\n<li><strong>Fix:<\/strong> with \"Delete all data on uninstall\" enabled, the wording you had written for the dated-service exclusion notice (Art. 16(l)) was left behind in the database instead of being removed. Two rows, no effect on how the site ran, but the setting promises a clean removal and did not deliver one. The plugin's own version marker was left behind for the same reason. Present since 0.6.0, and now covered by a test that checks every setting the plugin writes against the list of what it deletes.<\/li>\n<\/ul>\n\n<h4>0.7.0<\/h4>\n\n<p>Customers can now follow their withdrawal requests from their account, and a withdrawal page that has\nbeen deleted or unpublished no longer fails silently.<\/p>\n\n<ul>\n<li><strong>New:<\/strong> the My Account \"Right of withdrawal\" tab lists the requests the customer has sent \u2014 when it\nwas sent, the order, the scope, the current status, the note you wrote when you decided it, and the\nreceipt verification code \u2014 alongside the orders they can still withdraw from. Previously the tab\nlisted eligible orders only, so sending a request made the order disappear from it and left the\ncustomer reading \"None of your orders is currently eligible for withdrawal\". The acknowledgement and\nstatus emails link to the same screen.<\/li>\n<li><strong>New:<\/strong> the receipt PDF is reachable from that tab for as long as the account exists. The link in\nthe acknowledgement email is signed with a token that expires after 60 days, and until now that was\nthe only route to it \u2014 a durable medium the consumer can no longer open is not durable.<\/li>\n<li><strong>New:<\/strong> the My Account orders list shows the withdrawal control on an eligible order, and the\nrequest's status on an order already withdrawn from. It showed neither before.<\/li>\n<li><strong>New:<\/strong> the Article 14(4)(a) service-start consent can be made mandatory (Withdrawals \u2192 Settings \u2192\nCheckout consents). Off by default, because asking for the service to start inside the withdrawal\nperiod is the customer's choice to make; useful where the service always begins inside that window,\nsuch as live sessions or bookings.<\/li>\n<li><strong>New:<\/strong> four developer filters for the checkout consents \u2014 <code>recesso_dig_consent_render_hook<\/code> and\n  recesso_dig_consent_render_priority move the checkboxes on the classic checkout (an empty hook\nsuppresses the render), <code>recesso_dig_consent_applies<\/code> decides per cart whether each consent is\nasked for, and <code>recesso_dig_consent_required<\/code> makes either one blocking or optional. All hooks are\nnow documented under \"Hooks for developers\" below.<\/li>\n<li><strong>New:<\/strong> an \"Edit your details\" link on the confirmation step, back to the form. Re-submitting\nreplaces the unconfirmed request rather than adding a second one.<\/li>\n<li><strong>Fix:<\/strong> a withdrawal page that was deleted, trashed or unpublished sent every withdrawal link to\nthe shop front page instead \u2014 customers arrived with a valid link, no form and no explanation. Links\nare now suppressed rather than misdirected, and the settings screen and an admin notice say what is\nwrong with the page. The settings screen also stops describing your home page as the withdrawal form\nwhen no page is selected.<\/li>\n<li><strong>Fix:<\/strong> an expired or already-used link submitted from a stale form produced an unstyled \"You are\nnot authorized to perform this action\" page outside your theme, with no way back. It now explains\nwhat happened on the withdrawal page and offers the form that sends a fresh link.<\/li>\n<li><strong>Fix:<\/strong> returning to the confirmation step for a request already sent re-showed the success screen\nas though the withdrawal had just been recorded. It now says the request is already on record and\nwhen it was sent. Reaching the form again for an order already withdrawn from says the same, instead\nof a bare \"a request is already in progress\".<\/li>\n<li><strong>Fix:<\/strong> the message screen printed whatever text the address bar carried. It was correctly escaped,\nso it was never a scripting hole, but it did let a crafted link display wording of someone else's\nchoosing inside your withdrawal page. Only messages this plugin defines can be shown now.<\/li>\n<li><strong>Fix:<\/strong> accessibility of the public form \u2014 the consumer declaration told screen readers to announce\nits own label twice, the order-lookup fields had no description attached, and a validation error was\nnot moved to on re-render.<\/li>\n<li>Two links in the requests screen were built with a helper that HTML-escapes the URL it returns. That\nis correct when printing a link into a page, and wrong for a URL handed to the admin app as data and\nset straight onto a button: the browser then sent <code>amp;request<\/code> instead of <code>request<\/code>, so the server\nnever saw the parameters and refused. Both are fixed and covered by tests that fail against the old\nform.<\/li>\n<li><strong>Fix:<\/strong> <strong>Export CSV<\/strong> failed with \"The link you followed has expired\". The export nonce never\nreached the server. Present since 0.3.0.<\/li>\n<li><strong>Fix:<\/strong> opening a durable-medium <strong>receipt<\/strong> from the request detail panel failed with \"You are not\nauthorized to perform this action\". Present since 0.5.1, and it affected every receipt opened from\nthat panel, whatever the age of the withdrawal. The Download link in the no-JavaScript requests\ntable was never affected by either bug.<\/li>\n<li>A receipt link that cannot be matched to a withdrawal record no longer reports an authorisation\nfailure. Merchants are told the record could not be read and pointed at the requests screen, where\na pending database upgrade finishes; everyone else still gets the same generic refusal, so the\nendpoint cannot be used to discover which requests exist.<\/li>\n<li>A merchant following an old receipt link \u2014 from an acknowledgement email, or a bookmark, whose\nsigned token has since expired \u2014 is now taken to that request in the admin instead of a permissions\nerror. The file itself still requires a freshly signed link.<\/li>\n<\/ul>\n\n<h4>0.6.1<\/h4>\n\n<p>Superseded by 0.7.0, which contains these fixes. Never released separately.<\/p>\n\n<p>Two links in the requests screen were built with a helper that HTML-escapes the URL it returns. That\nis correct when printing a link into a page, and wrong for a URL handed to the admin app as data and\nset straight onto a button: the browser then sent <code>amp;request<\/code> instead of <code>request<\/code>, so the server\nnever saw the parameters and refused. Both are fixed, and both are now covered by tests that fail\nagainst the old form. These are the only two places where the plugin builds a URL server-side and\nhands it to JavaScript.<\/p>\n\n<ul>\n<li>Fix: <strong>Export CSV<\/strong> failed with \"The link you followed has expired\". The export nonce never reached\nthe server. Present since 0.3.0.<\/li>\n<li>Fix: opening a durable-medium <strong>receipt<\/strong> from the request detail panel failed with \"You are not\nauthorized to perform this action\". Present since 0.5.1, and it affected every receipt opened from\nthat panel, whatever the age of the withdrawal. The Download link in the no-JavaScript requests\ntable was never affected by either bug.<\/li>\n<li>A receipt link that cannot be matched to a withdrawal record no longer reports an authorisation\nfailure. Merchants are told the record could not be read and pointed at the requests screen, where\na pending database upgrade finishes; everyone else still gets the same generic refusal, so the\nendpoint cannot be used to discover which requests exist.<\/li>\n<li>A merchant following an old receipt link \u2014 from an acknowledgement email, or a bookmark, whose\nsigned token has since expired \u2014 is now taken to that request in the admin instead of a permissions\nerror. The file itself still requires a freshly signed link.<\/li>\n<\/ul>\n\n<h4>0.6.0<\/h4>\n\n<ul>\n<li>Checkout consents now work in the <strong>WooCommerce Checkout block<\/strong>, not only the classic shortcode\ncheckout. They are registered through WooCommerce's Additional Checkout Fields API, so the\ncheckboxes are rendered, validated and stored by WooCommerce itself \u2014 accessible markup and\nblock-theme styling included. Requires WooCommerce 8.9 or newer for the block checkout; the\nclassic checkout is unchanged and works on every supported version.<\/li>\n<li>New option: show each consent <strong>only when the cart contains a product classified for it<\/strong> (the\ndigital-content box with art. 16(m) items, the service box with art. 14(4)(a) items), using the\n\"Withdrawal status\" already set on the product or category. Off by default, so nothing changes on\nupdate; turn it on under Checkout consents.<\/li>\n<li>New \"Right of withdrawal\" tab in My Account, listing the customer's currently eligible orders with\nthe \u00abrecedere dal contratto qui\u00bb control for each. Can be switched off under Withdrawal link\nvisibility.<\/li>\n<li>New <code>[recesso_digitale_link]<\/code> shortcode (attributes: <code>text<\/code>, <code>class<\/code>) for footers, widgets and\nmenus, and <code>[recesso_digitale_avviso_esclusione]<\/code> for product templates built with a page builder\n(Divi, Elementor, Bricks and similar) whose layouts do not fire the usual WooCommerce hook.<\/li>\n<li>The settings screen is considerably more configurable, and every field now says whether it is\nmandatory, recommended or optional:\n\n<ul>\n<li>which <strong>order statuses<\/strong> offer the withdrawal function (a checkbox list of every registered\nstatus, previously fixed to Processing and Completed);<\/li>\n<li>which <strong>roles<\/strong>, besides the administrator, may view and manage requests \u2014 access is granted and\nrevoked the moment you save, and is never offered to customer-facing roles;<\/li>\n<li>a <strong>From name<\/strong> and <strong>From address<\/strong> for the plugin's own emails only;<\/li>\n<li>the wording of the <strong>accepted, rejected and completed<\/strong> customer emails;<\/li>\n<li>the <strong>intro paragraph<\/strong> above the public form (text and on\/off);<\/li>\n<li>an optional <strong>\"bought as a consumer\" self-declaration<\/strong> on the form, recorded verbatim in the\ndurable-medium receipt for B2B disputes;<\/li>\n<li>separate <strong>title and body for each exclusion notice<\/strong> \u2014 digital content (art. 16(m)), dated\nservices (art. 16(l)) and the other art. 16 exceptions \u2014 with a <code>{withdrawal_page_link}<\/code>\nplaceholder.<\/li>\n<\/ul><\/li>\n<li>The requests screen now lists <strong>recent unmatched lookups<\/strong>: attempts to request a withdrawal link\nwhose order number and email matched no order, so a mistyped reference is visible instead of\nvanishing silently. No withdrawal record is created for them, and the submitted address is stored\nmasked.<\/li>\n<li>Fix: a decision taken through the request detail panel's \"Set status\" dropdown \u2014 the main path\nsince 0.5.0 \u2014 wrote no order note. Accepting, rejecting, completing and resetting a decision now\nall appear in the order timeline.<\/li>\n<li>Fix: the \"default policy for unconfigured products\" setting declared one default and applied\nanother. Both are now \"Allow withdrawal\", which is what running sites have always used.<\/li>\n<li>Fix: the settings screen and the CSV export required <code>manage_woocommerce<\/code> while the requests list\nrequired the plugin's own capability. All three now use the plugin capability, which the new roles\nsetting controls.<\/li>\n<li>Fix: an opted-in \"delete all data on uninstall\" left two options behind.<\/li>\n<li>Hardening: an in-place upgrade whose table can no longer take another column (InnoDB \"row size too\nlarge\", possible after several upgrades) now rebuilds the table and completes, instead of leaving\na half-applied schema that breaks the requests screen until a manual re-activation.<\/li>\n<li>Every merchant-editable text is now exposed to WPML and Polylang String Translation; the previous\nconfiguration file covered only five of them.<\/li>\n<li>Database: one new optional column (<code>consumer_declaration<\/code>), applied automatically. Receipts issued\nbefore this release keep verifying against their stored hash \u2014 the receipt payload is versioned,\nand a request without a self-declaration hashes exactly as it did before.<\/li>\n<\/ul>\n\n<h4>0.5.10<\/h4>\n\n<ul>\n<li>Compatibility with WordPress 7.1 and WooCommerce 11. Verified against the WordPress 7.1 release\ncandidate with WooCommerce 11.0.1: full integration and end-to-end suites, including the\naccessibility checks, pass unchanged.<\/li>\n<li>Admin: the requests screen now opts in explicitly to the 40px control size that WordPress 7.1\nmakes the default, so the status filter, the search field and the action buttons keep their\nintended alignment on every supported WordPress version instead of changing height silently.<\/li>\n<li>Security: the bundled Dompdf library, used to render the durable-medium receipt, is updated from\n3.1.5 to 3.1.6. That release fixes six reported issues, including a local file read and a\nfile-existence disclosure through SVG images embedded as data URIs, and two denial-of-service\npaths through oversized image bitmaps. This plugin never enabled remote resource loading and its\nreceipt template contains no images, SVG or custom fonts, so exposure was limited; the library is\nupdated regardless.<\/li>\n<li>Admin: the requests bundle is now loaded with the deferred script strategy.<\/li>\n<li>The minimum supported WordPress version is now 6.9, matching the minimum required by the\nWooCommerce releases this plugin is built against. Nothing in the plugin itself required the\nchange: WooCommerce 11 already refuses to run below WordPress 6.9, so the previous floor of 6.7\ncould not be satisfied in practice.<\/li>\n<li>No database migration and no changes to the withdrawal flow, the durable-medium receipt or the\nlegal timestamps.<\/li>\n<\/ul>\n\n<h4>0.5.9<\/h4>\n\n<ul>\n<li>Fix: the order-lookup form never actually sent the withdrawal-link email. WooCommerce does not\nautoload its WC_Email base class, so on the front-end request the send bailed out before the email\nwas built. The mailer is now initialised first, so the link is delivered.<\/li>\n<li>Order-lookup: the link is emailed whenever the submitted order number and email match, regardless\nof the order's current eligibility \u2014 a legitimate consumer always gets a response on their own\naddress, and the declaration screen explains any ineligibility (e.g. an expired window) when the\nlink is opened.<\/li>\n<\/ul>\n\n<h4>0.5.5<\/h4>\n\n<ul>\n<li>Withdrawal page: visiting the page without a signed link (e.g. via the persistent footer link) now\nshows an order-lookup form instead of a blank page. The consumer enters their order number and the\nemail used on the order, and the plugin emails a secure, signed withdrawal link to that order's\naddress. The link is never rendered inline and the response is always uniform, so orders cannot be\nenumerated; requests are rate-limited per IP and protected by a honeypot.<\/li>\n<li>New \"Withdrawal link request\" email (WooCommerce \u2192 Settings \u2192 Emails) carries the requested link.<\/li>\n<\/ul>\n\n<h4>0.5.4<\/h4>\n\n<ul>\n<li>Admin: the WooCommerce menu entries and the requests-page heading now default to English\n(\"Order Withdrawal\", \"Order Withdrawal: settings\"); Italian sites keep the previous\n\u00abRecesso digitale\u00bb labels via the bundled it_IT translation.<\/li>\n<\/ul>\n\n<h4>0.5.3<\/h4>\n\n<ul>\n<li>Uninstall: only the withdrawal page auto-created by the plugin is removed. The page is now\nidentified by a created-by-plugin marker (and must still host the withdrawal shortcode), so a\npre-existing page the merchant selected in settings is never deleted.<\/li>\n<\/ul>\n\n<h4>0.5.2<\/h4>\n\n<ul>\n<li>The withdrawal function is now a single \u00abrecedere dal contratto qui\u00bb button shown below the order\ndetails, available to both guest-checkout customers (order-received page) and logged-in members\n(My Account order view); the previous duplicate button is gone and the link no longer reports\n\"this withdrawal link is not valid or has expired\".<\/li>\n<li>Confirmation step: removed the (unnecessary) product thumbnail and gave the \u00abconferma recesso\u00bb\nbutton a proper, accessible button style that no longer depends on the theme.<\/li>\n<li>Admin: unconfirmed (abandoned) declarations no longer appear in the requests list or its counts,\nand a consumer who closed the page before confirming can start a fresh request.<\/li>\n<li>Admin: the menu badge counts all open requests awaiting action (confirmed and acknowledged) and\nuses the standard WooCommerce\/WordPress menu-counter styling.<\/li>\n<\/ul>\n\n<h4>0.5.1<\/h4>\n\n<ul>\n<li>Packaging: the distribution now bundles the full, human-readable JS\/CSS source (<code>assets\/<\/code>) and\nthe build manifests (<code>package.json<\/code>, <code>package-lock.json<\/code>) alongside the compiled <code>build\/<\/code>\nassets, and the readme documents how to rebuild them and links the public development repository.<\/li>\n<li>Dependency: the bundled Dompdf library is updated from 3.0.0 to 3.1.5.<\/li>\n<li>Hardening: the admin receipt download link now carries a nonce that the download endpoint\nverifies for the admin path (the consumer link continues to use its signed, rate-limited token).<\/li>\n<li>Hardening: saving a product's withdrawal status now verifies the WooCommerce editor nonce and\nthe <code>edit_product<\/code> capability explicitly.<\/li>\n<\/ul>\n\n<h4>0.5.0<\/h4>\n\n<ul>\n<li>New \"Withdrawal\" column on the WooCommerce orders screen (HPOS and the legacy list) showing each\norder's current withdrawal decision as a colour-coded badge.<\/li>\n<li>The request detail panel now sets the decision through a single \"Set status\" dropdown (Pending,\nAccepted, Rejected, Completed) with a \"Save status\" button next to \"Regenerate receipt\". The reason\nfield appears only when rejecting (and stays required); the orders column updates to match.<\/li>\n<li>Hardening: the contract reference stored for a withdrawal is now always derived server-side from\nthe order number, ignoring any client-supplied value on the REST create endpoint.<\/li>\n<li>Hardening: the receipt download endpoint now validates the stored path against an exact directory\nboundary, preventing a similarly named sibling directory from being treated as the protected store.<\/li>\n<li>Packaging: reproducible production builds (installed from composer.lock) and a direct-access guard\nadded to the generated PHP asset files in the distribution.<\/li>\n<\/ul>\n\n<h4>0.4.0<\/h4>\n\n<ul>\n<li>Product\/category \"Withdrawal status\" now offers the specific art. 59 \/ Directive classifications\n(standard, digital content art. 16(m), service started early art. 14(4)(a), dated accommodation \/\ntransport art. 16(l), other art. 16 exception) instead of a plain allow\/exclude, and each maps to\nthe right eligibility outcome. Statuses saved by earlier versions keep working.<\/li>\n<li>A one-time welcome notice after activation links straight to the settings and the auto-created\nwithdrawal page.<\/li>\n<li>Reorganised the settings screen into clear sections (General, Withdrawal deadline, Article 16\nexclusions, Checkout consents, Model withdrawal form, Excluded products notice, Withdrawal link\nvisibility, Data), added a notification email and a withdrawal-page selector, a \"show model form\"\ntoggle and an optional trader phone number.<\/li>\n<li>The Annex I.B model withdrawal form was redesigned to match the statutory layout (header block with\nthe trader's details, fillable lines, source attribution and an optional printable view).<\/li>\n<\/ul>\n\n<h4>0.3.1<\/h4>\n\n<ul>\n<li>Fix: an in-place update now reliably adds the v4 optional columns \u2014 the installed schema version is\nonly advanced once the columns actually exist, so the requests admin list and the withdrawal form no\nlonger break until a manual re-activation.<\/li>\n<li>Hardening: the withdrawal declaration never white-screens \u2014 a transient persistence failure degrades\nto a friendly message instead of a fatal error (the legally-required function stays usable).<\/li>\n<\/ul>\n\n<h4>0.3.0<\/h4>\n\n<ul>\n<li>Art. 59 configuration: per-product and per-category \"Right of withdrawal\" status (allow \/ exclude \/\ninherit) in the product and category editors, plus an opt-in \"excluded from withdrawal\" notice on\nthe product page.<\/li>\n<li>Checkout consents: optional, configurable digital-content (art. 16(m)) and service-start\n(art. 14(4)(a)) consents, recorded on the order with timestamps and an order note.<\/li>\n<li>Annex I.B model withdrawal form (printable), populated with configurable trader contact details,\nshown below the public form and via the [recesso_digitale_modulo] shortcode.<\/li>\n<li>Order notes mirror the withdrawal lifecycle; new customer emails on accept\/refund\/complete and an\nadmin notification (multiple recipients) when a withdrawal is confirmed.<\/li>\n<li>Admin: Accept \/ Mark completed \/ Mark refunded actions, an at-a-glance stats summary and a CSV\nexport of requests.<\/li>\n<li>GDPR: personal-data exporter and eraser (anonymises personal data while retaining the legal\nacknowledgement) and a suggested privacy-policy snippet.<\/li>\n<li>Optional refund IBAN and reason fields on the declaration (carried into the durable receipt),\nhoneypot anti-spam, an optional persistent footer link, an optional strict deadline-enforcement\nmode with grace days, and a wpml-config.xml for WPML\/Polylang.<\/li>\n<\/ul>\n\n<h4>0.2.0<\/h4>\n\n<ul>\n<li>Redesigned the consumer withdrawal page: products are chosen with checkboxes, each shown with its\nthumbnail, and a per-product quantity selector appears only when more than one unit was purchased.<\/li>\n<li>The durable-medium acknowledgement email now lists every selected product with its quantity, along\nwith the confirmation email and the declaration timestamp, matching the PDF receipt.<\/li>\n<li>The two-step confirmation (\u00abconferma recesso\u00bb) and the completion screen now itemise exactly which\nproducts and quantities are being withdrawn.<\/li>\n<li>Internal: item resolution unified in one shared component used by the receipt, email and on-screen\nsummaries; the tamper-evident receipt hash is unchanged.<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Initial development release.<\/li>\n<li>Security-first, HPOS-native withdrawal channel: continuously available function, two-step\nserver-rendered declaration\/confirmation flow, signed rate-limited guest access.<\/li>\n<li>Durable medium: acknowledgement email plus a protected, tamper-evident PDF receipt with a\nwrite-once legal timestamp (dies a quo), generated asynchronously via Action Scheduler.<\/li>\n<li>Conservative, configurable, fail-closed eligibility engine (window, start trigger, art. 59\nexclusions) with filters for integrators.<\/li>\n<li>React admin: list, status filter, free-text search, audit timeline, receipt view\/regenerate,\nprocess actions, and a menu badge for requests awaiting action.<\/li>\n<li>Optional WooCommerce Subscriptions adapter (withdrawal cancels the subscription).<\/li>\n<li>Merchant-decides model: the 14-day period is advisory (shown to the merchant), the withdrawal\nfunction stays available, and the merchant accepts or rejects each request. Rejection requires a\nreason, recorded in the audit trail and emailed to the consumer.<\/li>\n<li>Accessibility to WCAG 2.2 AA (axe-verified) and a complete it_IT translation.<\/li>\n<\/ul>","raw_excerpt":"Digital withdrawal function for WooCommerce \u2014 the EU &quot;easy withdrawal&quot; duty (Directive 2023\/2673), in force from 19 June 2026.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/330627","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=330627"}],"author":[{"embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/draison"}],"wp:attachment":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=330627"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=330627"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=330627"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=330627"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=330627"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=330627"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}