| 开发者 | artprojectgroup |
|---|---|
| 更新时间 | 2026年6月23日 17:39 |
| 捐献地址: | 去捐款 |
| PHP版本: | 7.4 及以上 |
| WordPress版本: | 7.1 |
| 版权: | GNU General Public License v3 or later |
| 版权网址: | 版权信息 |
[apg_withdrawal_form] shortcode._apg_withdrawal_type = digital), on every order, or on selected categories and/or selected products. The customer's choice is persisted to order meta as legal evidence.apg-withdrawal-for-woocommerce folder to the /wp-content/plugins/ directory via FTP.[apg_withdrawal_form] shortcode to the page configured as the withdrawal page in the settings.In the plugin settings you can configure the notification email, the withdrawal page, the withdrawal window in days, the deadline source (completed or created date), the extra grace days and which data to store (IP address, browser identifier).
Yes. The plugin is fully compatible with WooCommerce High-Performance Order Storage.
Yes. The form supports both logged-in customers (with pre-filled data and order selector) and guests (with email lookup of their orders).
The withdrawal form page is auto-created on activation and contains the [apg_withdrawal_form] shortcode. To comply with Article 11a of Directive 2011/83/EU (added by Directive 2023/2673), the link to that page should be prominently visible and easy to find on the storefront. The plugin gives you several tools to place it; deciding where to place it is the merchant's (or their web designer's) responsibility:
[apg_withdrawal_link] shortcode, with optional label, class and target attributes, to drop the link inside any post, page, footer widget or HTML block.woocommerce_email_after_order_table).The plugin does not delete withdrawal request records automatically. As a general recommendation, keep them for at least 5 years after their creation — the typical statute of limitations for consumer and contractual actions in many EU jurisdictions. Always check the applicable retention period in your country before deleting old records or running the plugin's CSV export + uninstall flow.
APG Withdrawal for WooCommerce is a free plugin. Art Project Group does not provide free technical support, but offers a paid technical support service for installation and configuration.
/languages) was not being loaded on sites where translate.wordpress.org had not yet generated a language pack. WordPress's just-in-time loader only inspects wp-content/languages/plugins/, so the .mo file shipped inside the plugin was ignored. The plugin now hooks the WordPress 6.6+ lang_dir_for_domain filter to return the bundled /languages folder when no language pack is available, without resorting to the WP.org-discouraged load_plugin_textdomain() call. On WordPress 6.5 and below the bundled translation will still not load until a language pack is published, but the plugin keeps working in the source language.WC_Email classes shipped by the plugin (customer acknowledgement, admin notification, status update) are picked up automatically by the new built-in EmailLogger. Each log entry is enriched via woocommerce_email_log_context with the withdrawal request id, scope and the SHA-256 receipt hash plus its UTC timestamp, so the log entry can be cross-checked against the email actually delivered to the customer. The filter is silently ignored on older WooCommerce versions.apg_withdrawal_label_is_ambiguous()) flags withdrawal labels that fail the "unambiguous wording" requirement of Article 11a of Directive 2011/83/EU. Used in two places: (a) the configurable confirmation button label (Settings → Button text) now surfaces an admin warning if the merchant saves an ambiguous wording (e.g. "Contáctanos", "Gestionar pedido", "Volver"); the choice is not blocked, only flagged; (b) the [apg_withdrawal_link] shortcode and the matching apg-withdrawal/link Gutenberg block emit a _doing_it_wrong() notice (visible with WP_DEBUG) when an ambiguous custom label attribute is used. Lists of "passes" and "blacklist" terms are filterable via apg_withdrawal_label_unambiguous_terms and apg_withdrawal_label_ambiguous_terms.?print=1 to the Annex I.B URL so the browser print dialog opens automatically on page load (the existing on-page Print button still works for users who reach the URL directly).WC()->countries->get_countries() and get_states()) instead of the raw XX:YY ISO code stored in woocommerce_default_country, each on its own paragraph. Every paragraph in the addressee block ends with a period, as expected in formal correspondence.wpml_register_single_string action) on init. When neither plugin is active the registration is a no-op and the original value is rendered unchanged.apg_withdrawal_is_rate_limited() helper throttles repeated submissions by IP + email pair (default policy: 5 attempts per 10 minutes, both filterable via apg_withdrawal_rate_limit_max and apg_withdrawal_rate_limit_window). A hidden honeypot field is rendered in both steps of the form and silently swallows automated submissions before any persistence happens. Client IP detection respects common reverse-proxy headers and is filterable via apg_withdrawal_client_ip.completed_date to created_date for orders that have not yet been marked complete. No code change required.product_cat, with automatic inheritance for products that keep the "Withdrawal allowed (default)" value. When a product belongs to several categories with conflicting types, the most restrictive type wins (priority order: excluded > personalized > digital > manual > allowed).[apg_withdrawal_notice] shortcode, matching apg-withdrawal/notice Gutenberg block and woocommerce_single_product_summary injection (priority 20, between the price and the Add to Cart button) that automatically displays the exclusion notice on the product page when the effective withdrawal type is not allowed.excluded, digital, personalized, manual) and a translated default text per type. Optional per-product override field on the Withdrawal product data tab to customise the notice for a single product.Never (disabled), On products classified as digital content, On every order — driven exclusively by the per-product / per-category withdrawal type. Legacy installations with mode virtual are migrated to digital; mode specific is migrated to digital and the previously selected categories / products are automatically marked with _apg_withdrawal_type = digital to preserve their behaviour. The legacy digital_waiver_categories / digital_waiver_products settings stop being honoured at the UI level (a one-time silent migration runs on init, flagged by the apg_withdrawal_migrated_to_0_5 option).?apg_withdrawal_model_form=1 with @media print styling, pre-populated with the store name, address, email (from WooCommerce settings) and an optional merchant phone (new Merchant phone (optional) plugin setting). The public withdrawal request form links to it as "Download the official model withdrawal form (Annex I.B)".[apg_withdrawal_link] shortcode and apg-withdrawal/link Gutenberg block to render a link to the public withdrawal form with optional label, class and target attributes. The default label uses the literal wording suggested by Article 11a(1) ("Withdraw from the contract here"). The My Account per-order action label has been updated to the same default for new installs._apg_withdrawal_receipt_hash, _apg_withdrawal_receipt_hash_timestamp) and exposed in the CSV export._apg_withdrawal_digital_waiver_log order meta) that includes the exact label shown to the customer, UTC timestamp, IP, user agent and checkout type (classic or block). The legacy _apg_withdrawal_digital_waiver boolean meta is also written for backwards compatibility.wp_mail() was invoked, whether it returned success (= "accepted by the mailer", not actual recipient delivery), the UTC timestamp and any error captured through wp_mail_failed. The information is surfaced in the request detail screen and exported as two additional CSV columns.[redacted]) and keeps the record itself plus the _apg_withdrawal_wc_order_id reference for legal evidence, in line with the burden of proof in Article 16 bis(8). The same anonymisation is also triggered automatically when a WordPress user is deleted (via Users → Delete, a customer-facing "Delete my account" button shipped by third-party plugins such as apg-gdpr-texts-for-forms, or any other path), so the withdrawal records never outlive the user account with personal data attached.=, +, -, @, tab or carriage return is prefixed with an apostrophe before being written via fputcsv.disabled, virtual, all, specific) so the values now match the actual mode selector.woocommerce_checkout_before_terms_and_conditions with priority 999) and block-based (via JavaScript that reinserts itself with a MutationObserver to remain right before the native terms checkbox, after any other custom one)..wp-block-woocommerce-checkout-terms-block .wc-block-components-checkbox plus jQuery .after()), avoiding duplicated privacy or marketing notices._apg_withdrawal_digital_waiver ('1' or '0') on both checkouts: the classic checkout reads the POST value on woocommerce_checkout_create_order, the block checkout injects the value into the StoreAPI request body under extensions['apg-withdrawal']['digital_waiver'] and the server hook woocommerce_store_api_checkout_update_order_from_request writes the same meta.apg_withdrawal_check_cart_waiver), re-checks server-side whether the current cart still qualifies, inserting or removing the checkbox without a full page reload._apg_withdrawal_type = digital setting, so virtual flag and explicit digital classification are treated as equivalent triggers.wc_print_notice() so they pick up the correct WooCommerce template for both block themes (block-notices/*.php) and classic themes (notices/*.php).wc_print_notice() and toggled by JavaScript, instead of being built by hand with legacy markup that breaks on block themes.woocommerce-invalid class on the email field.wc_wp_theme_get_element_class_name( 'button' ) for theme and block-theme compatibility.