BuddyPilot Withdrawal (Easy Returns)

Changelog

1.0.17

  • Improved: The My Account order page now lists every item with its withdrawal status, eligible, already withdrawn, or not eligible, above the withdrawal button. Digital items the customer consented to receive immediately (Article 16(m)) are shown with a “not eligible for withdrawal” badge instead of being silently omitted, and orders where no item is eligible now show the item list with that explanation instead of a generic message.
  • Improved: The withdrawal form shows the same read-only item list with badges when an order has no items eligible for withdrawal.
  • Improved: Bundled translations now fill any strings the translate.wordpress.org language pack is still missing, so strings added in a release appear in the site language immediately without waiting for the language pack to be updated. Community translations from the language pack keep priority.
  • Fixed: The rejection / partial-resolution email no longer shows two near-identical ADR / EU Online Dispute Resolution notices. The notice with the clickable link is kept; the duplicate default text was removed.

1.0.16

  • Fixed: The “right of withdrawal” link in the WooCommerce email footer and the My Account call-to-action now resolve to the correct language version of the information page on Polylang and WPML sites. Previously the stored page ID was used verbatim, so on multilingual stores the link could be missing or point to the wrong language.
  • Fixed: The withdrawal period and the refund deadline are now shown consistently across all screens. The My Account order button now reflects the configured withdrawal period instead of a hardcoded 14 days, the declaration preview and the post-submission confirmation now reflect the configured refund deadline instead of a hardcoded value or the wrong setting.
  • Fixed: The guest withdrawal flow now stays in the language the visitor is using on multilingual sites. Previously, after requesting an access link on a non-default language page, the form action, every following step and the e-mails fell back to the site default language. The form now recognises translated page variants, keeps each step on the current-language page, and sends both the magic-link e-mail and the withdrawal-confirmation e-mail in the visitor’s language (Polylang, WPML). The confirmation e-mail now also follows the customer’s language for logged-in My Account submissions; operator-registered declarations keep the site language.
  • Improved: The refund deadline option is now seeded on activation, so fresh installations report a consistent value before the operator visits the settings screen.

1.0.15

  • Feature: Guest magic-link emails now point to the correct language version of the withdrawal form on multilingual sites. Polylang, WPML, TranslatePress, Weglot, and qTranslate-XT are all supported automatically; the order language meta stored by each plugin is used to resolve the translated page URL.
  • Improved: Translation .mo files for all 24 EU official languages are now bundled in the plugin ZIP as a fallback. Users on sites where translate.wordpress.org has not yet published a language pack receive translated strings from the bundled .mo files instead of falling back to English.
  • Improved: Czech (cs_CZ), Croatian (hr), Dutch Belgium (nl_BE), Dutch Netherlands (nl_NL), and Romanian (ro_RO) translations synchronised with GlotPress (translate.wordpress.org); GlotPress-approved strings are now authoritative.

1.0.14

  • Feature: New buddypilot_withdrawal_has_consent filter allows third-party plugins to integrate their own Article 16(m) consent checkbox. Return true from the filter to record consent for all digital items in the order; the plugin handles the internal storage. No knowledge of internal meta keys is required.
  • Improved: When the plugin’s own consent checkbox is set to “Hidden” in settings, the new filter still fires. External consent can therefore be recorded even when the built-in checkbox is disabled.

1.0.13

  • Feature: Operators can now close a declaration as “Reject all items” or “Partial resolution” directly from the declaration detail page. Previously only full acceptance was available from that screen.
  • Feature: Partial resolution mode allows a per-item accept/reject decision with a mandatory rejection reason for each rejected item, so the customer receives an itemised outcome rather than a single blanket decision.
  • Feature: Rejection and partial resolution emails now include the EU ODR (Online Dispute Resolution) platform link (ec.europa.eu/consumers/odr) as required for cross-border dispute notifications under Article 11a.
  • Feature: The customer-facing withdrawal form now shows per-item resolution badges for fully-resolved declarations: accepted items display a confirmation badge, rejected items display the rejection reason and an ODR platform link. Previously the form showed a generic “order not eligible” message.
  • Improved: Reopening a declaration now resets the resolution type and operator note to null, so the operator starts with a clean slate when correcting an erroneous decision.
  • Security: Financial snapshot fields in the declaration record (item total, subtotal, tax) are immutable; they cannot be overwritten by POST manipulation during the resolution step.
  • Security: Resolution type is validated against a strict server-side whitelist (accepted / rejected / partial); arbitrary values are rejected before reaching the database.
  • Security: Already-closed declarations reject stale resolution attempts with an explicit error, preventing accidental overwrites in concurrent operator sessions.

1.0.12

  • Fixed: Article 16(m) consent checkbox was not displayed at checkout on stores using WooCommerce 8.6 or later with a classic shortcode-based checkout (e.g. Blocksy theme). The plugin now correctly detects whether the block checkout is in use before routing consent collection through the Additional Checkout Fields API.
  • Improved: Guest withdrawal session is now time-limited to 15 minutes after clicking the magic link, reducing the window in which a shared or inactive browser session could be misused.
  • Improved: Magic link redemption endpoint now applies rate limiting per order per IP, consistent with the email verification endpoint.
  • Improved: Declaration detail and status toggle in the admin panel now verify that the current user has access to the linked order, providing correct access control on multi-vendor setups.
  • Improved: Operator-customised consent label text is sanitised when saved, so stored option value is always clean HTML.
  • Improved: Plugin no longer collects or stores the browser user-agent string with withdrawal declarations. The field served no active purpose and its removal reduces the personal data footprint. Existing installations will have the column dropped automatically on first load after updating (no data loss; the legal declaration record is preserved in full).

1.0.11

  • Fixed: Plugin email class registration is now isolated per class. A constructor failure in one class no longer propagates into WooCommerce’s email dispatch and no longer blocks all WooCommerce transactional emails (new order, customer processing, etc.).

1.0.10

  • Fixed: Attempting to bulk-change orders in withdrawal status to Completed or Processing now triggers an admin notice informing the operator how many orders were skipped because the status change is not permitted for them, and that those orders must be handled individually.

1.0.9

  • Feature: Guest verification form now accepts custom order numbers from third-party renumbering plugins (e.g. WebToffee Advanced Order Numbers, Custom Order Numbers for WooCommerce by Tyche Softwares). Guests can enter the formatted number shown in their confirmation email instead of the internal numeric order ID.
  • Feature: Order number input on the guest verification form no longer forces a numeric-only keyboard on mobile devices, allowing guests to type prefixed order numbers such as ORD-2024-1042.
  • Security: Input length on the guest verification form is now capped before order resolution, preventing crafted requests from triggering full-table database scans on stores with custom order number plugins installed.

1.0.8

  • Feature: Withdrawal information page is now created as native WordPress blocks, allowing the operator to freely edit the legal wording directly in the block editor.
  • Feature: New [buddypilot_withdrawal_info_block] shortcode renders the dynamic sections (trader contact details, return address, CTA button) independently so they always reflect current settings, even after manual edits to the surrounding text.
  • Feature: New “Overwrite information page content” button in WooCommerce > Settings > Withdrawal > Customer refreshes the page with the latest model notice wording at any time.
  • Fixed: Orders imported via the WooCommerce REST API (e.g. BaseLinker) were being re-imported in a loop because the plugin was writing unnecessary consent meta to every new order. The plugin no longer writes any meta to API-created orders that contain no digital items.

1.0.7

  • Improved: Delivery tracking now uses a dedicated database table instead of order meta, preventing third-party order-sync integrations (e.g. BaseLinker) from re-importing orders on every delivery status update.
  • Improved: Confirmation screen now reads the configured withdrawal period dynamically instead of using a hardcoded value.
  • Improved: Rate limiting is now handled with a single atomic database operation.
  • Improved: Reduced database queries on the withdrawals list page.
  • Fixed: Several coding standards issues and minor security hardening.

1.0.6

  • Feature: guest (non-logged-in) customers can now submit a withdrawal declaration directly from a dedicated form page. After entering their order number and billing email, a secure one-time magic-link is sent to the billing address; clicking it opens the full interactive withdrawal form with no account required.
  • Feature: new [buddypilot_withdrawal_guest_form] shortcode for the guest withdrawal form page. The page and shortcode can be created with a single click from WooCommerce > Settings > Withdrawal > Customer.
  • Feature: [buddypilot_withdrawal_information] shortcode now shows an optional “Submit withdrawal form online” call-to-action button linking to the guest form page when the form page is configured. Existing information pages are not modified.
  • Feature: new “Withdrawal form access link (guest)” transactional email containing the magic-link; configurable under WooCommerce > Settings > Emails.

1.0.5

  • Plugin renamed to BuddyPilot Withdrawal (Easy Returns) for better discoverability.
  • Added full translations for all 24 EU official languages: bg, cs, da, de (de_DE, de_AT, de_CH), el, es, et, fi, fr (fr_FR, fr_BE, fr_CH), ga, hr, hu, it, lt, lv, mt, nl (nl_NL, nl_BE), pl, pt, ro, sk, sl, sv.
  • Translation quality: all 24 EU language files audited across three rounds; legal terminology verified against official national gazettes (EU Directive 2011/83/EU Annex I), diacritical marks restored, formal register enforced throughout, plural forms corrected, and internal consistency improved.

1.0.4

  • Feature: fractional product quantities are now detected and reported in the withdrawal declaration. Full handling of fractional quantities (correct proration, refund calculation) is available in BuddyPilot Withdrawal Pro.
  • Feature: added “Upgrade to Pro” action link in the Plugins list, shown only when the Pro version is not active.

1.0.3

  • Tested and confirmed compatible with WordPress 7.0.
  • Security: nonce is now verified before consuming a rate-limit slot, preventing CSRF probes from exhausting a user’s hourly budget.
  • Security: anonymous (guest) rate-limit buckets are now scoped per hashed IP instead of a shared user_id=0 bucket.
  • Security: sealed_map and GET presealed IDs are validated against the order before use, preventing crafted requests from attaching sealed confirmations to ordinary items.
  • Security: apply_filters(‘buddypilot_withdrawal_declaration_items_payload’) output is re-validated: entries with item_id=0, negative quantities or non-array values are stripped.
  • Security: PermissionChecker now explicitly blocks user_id=0 regardless of order customer_id.
  • Security: OperatorRegistration checks EXCLUDED_STATUSES at handler entry and flushes the permission cache after order save.
  • Security: DeclarationRepository validates filing_date format and rejects zero-date strings.
  • Security: RateLimit::tally() returns PHP_INT_MAX when the rate-limit table is missing, preventing the limiter from silently becoming a no-op.
  • Fix: round(qty, 10) in get_declared_quantities() prevents IEEE-754 epsilon accumulation on fractional product quantities.
  • Fix: removed spurious user_register hook from Privacy Manager; only woocommerce_created_customer is used.

1.0.2

  • Code: renamed all short bpw_ / bpw- identifiers to the full buddypilot_withdrawal_ / buddypilot-withdrawal- prefix throughout (affects AJAX/admin-post action names, script handles, localized JS object, metabox ID, WooCommerce field type, nonce field names, lock keys and GET parameters). Resolves WordPress.org unique-prefix review requirement.

1.0.1

  • Security: all admin and AJAX request handlers now verify user permissions before nonce verification, consistent with WordPress security guidelines.
  • Security: the AJAX path in the operator registration handler now uses check_ajax_referer() instead of check_admin_referer(), returning a proper AJAX error response on nonce failure.
  • Security: added current_user_can() gate to the admin notice handler for info-page creation status.
  • Security: currency symbol and separator values from localized price format data are now escaped on the JavaScript side before insertion into the DOM.
  • Code: moved inline JavaScript from the operator registration template to an enqueued file (assets/js/admin/operator-registration.js); strings passed via wp_localize_script().
  • Code: removed load_plugin_textdomain() call; WordPress 4.6 and later loads translations automatically for plugins hosted on WordPress.org.

1.0.0

  • First stable release. Full implementation of the Article 11a withdrawal function: two-step form, guest verification, operator manual registration, declarations admin list, configurable period and delivered statuses, Article 16(m) consent capture, Annex I(A)/(B) page generator, customer and admin emails, My Account withdrawal history, HPOS support, GDPR hooks, WCAG 2.2 AA compliance, Polish and English translations.

Plugin Website
Visit website

Author
BuddyPilot
Version:
1.0.17
Last Updated
June 17, 2026
Active Installs
60
Requires
WordPress 5.8
Tested Up To
WordPress 7.0
Requires PHP
7.4

Share Post

Join our newsletter.

Get insights into what’s happening at ChangelogWP right in your inbox. We don’t believe in spam.