| 开发者 | pay4all |
|---|---|
| 更新时间 | 2026年8月25日 00:10 |
| PHP版本: | 7.4 及以上 |
| WordPress版本: | 7.1 |
| 版权: | GPL-2.0-or-later |
| 版权网址: | 版权信息 |
Pay4All AGE > Settings) manages both integrations. A merchant using both Pay4All Shop and WooCommerce therefore only needs to configure the verification process once and will benefit from consistent behaviour across both platforms.
Identity document photos and/or video selfie
The merchant can choose to require either verification method or both, depending on the applicable legislation.
WooCommerce support
Simply select the Requires age verification option on the product page to trigger QR-code age verification during checkout. The customer's age verification status can be reviewed directly from the order.
Pay4All Pro provides the WooCommerce integration. Pay4All Age remains completely free when used with Pay4All Shop.
How it works
edit_users capability./wp-content/plugins/pay4all-age-verification/ or install via Plugins > Add New.Yes. Pay4All Age Verification is a companion plugin — it plugs into either Pay4All Shop (free, ships the form-based checkout) or WooCommerce (via the paid Pay4All Pro add-on). On a bare WordPress install without either, the plugin stays dormant and shows an admin notice on the Plugins screen.
AES-256-GCM with a per-order (or per-user) subkey derived via HMAC-SHA256 from a master key. The master key is generated once and stored in wp-content/uploads/p4all-age-secure/age.key (mode 0600). Ciphertexts live in the same private folder, guarded by .htaccess, index.php and web.config so they are never web-servable — a direct URL always returns 403 / 404. See the Security section above for the full threat model.
Outside the database, in wp-content/uploads/p4all-age-secure/age.key. This means a stolen SQL dump alone is not enough to decrypt the photos — the attacker would also need read access to that specific file. Please make sure your backup strategy either encrypts wp-content/uploads/p4all-age-secure/ or excludes it entirely from the backup archive.
They are auto-purged. Both the WooCommerce order lifecycle (woocommerce_delete_order hook) and Pay4All Shop order deletion trigger KycStorage::purge_order(), which removes every encrypted blob and the order-scoped directory. A daily cron also purges session-scoped buckets older than the configured TTL (default 24 h).
The delete_user hook fires KycStorage::purge_user() — every stored user photo (recto / verso / selfie_1 / selfie_2) is removed together with the user record. GDPR-friendly by default.
The page uses the native <input type="file" accept="image/*" capture="…"> API — supported by Safari (iOS 6+), Chrome, Firefox, Edge on both Android and iOS. On the desktop side, the QR code is generated with a pure-JS library (no external service call) and the pairing is polled every 4 seconds via a REST endpoint scoped to the session token.
Yes. When a product's Requires age verification flag is ticked on a source-language product, every translation is treated as age-restricted too — even if the flag hasn't been mirrored to the translation post. Same behaviour on WooCommerce products via Pay4All Pro.
French (fr_FR), German (de_DE), Italian (it_IT) and English (en_US). Every customer-facing string is also overridable per-language from the settings page — merchants can rewrite the KYC panel copy without touching a .po file.
No. Photo capture, encryption, storage and admin decryption are all local — nothing leaves the site. The QR code is generated client-side ; the mobile page polls only your own WordPress REST API.
msgid = English source, msgstr = translation). Full translation packs are bundled and validated for French (fr_FR), German (de_DE) and Italian (it_IT) under /languages/.TEXT_DEFAULTS / ADMIN_STRINGS inline catalogs (~600 lines of hardcoded fr/de/it/en strings) are replaced by a single English source array feeding through gettext. The merchant per-language text override (Pay4All AGE > Settings > Texts) still wins over the shipped translation, so custom copy is preserved on upgrade.MediaRecorder, with a random 4-digit challenge code (minted by the server) burned into the top-right of the recorded pixels as a real-time proof. The head-motion prompt (« Tournez lentement la tête ») shows as an HTML overlay to guide the customer but doesn't pollute the recorded file. Video is compressed client-side (VP8 or H.264, ~500 kbps, ~325 KB for 5 s), encrypted AES-256-GCM before storage, and played back inline in the admin lightbox with the same shield button. Legacy orders that stored the two-photo variant remain readable and decryptable - no data migration needed.post_meta at upload time (checkout + resend flows). The video autoplays and loops muted for at-a-glance review.Pay4All AGE > Paramètres > Textes exposing every customer-facing string of the video capture flow (pre-recording notice, single head-motion prompt, statuses, Démarrer / Valider / Refaire / Recommencer buttons, camera-denied / unsupported-browser errors), overridable per language. Default text is now shown as an input placeholder (empty field = « use built-in translation »).$_POST['slots'] via array_map('sanitize_key', wp_unslash(...)) in the admin resend handler ; mt_rand() replaced by wp_rand() in the challenge-code fallback.get_edit_post_link() returns an empty string when called from the customer's public REST upload (no edit_post cap). URL is now built manually.Pay4All AGE > Paramètres > Textes > Renvoi, with placeholders {customer_firstname}, {customer_lastname}, {order_number}, {slots_list}, {link}, {admin_order_url}, {site_name}, {shop_name}. Sensible FR / DE / IT / EN defaults ship out of the box.Pay4All AGE > Paramètres > Documents à demander > Ordre d'affichage. The chosen order applies to both Pay4All Shop and WooCommerce checkouts (single source of truth). Keyboard fallback (up/down arrows) included for accessibility.<details> markup.