{"id":341237,"date":"2026-07-16T13:45:18","date_gmt":"2026-07-16T13:45:18","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/pay4all-age-verification\/"},"modified":"2026-07-29T08:22:52","modified_gmt":"2026-07-29T08:22:52","slug":"pay4all-age-verification","status":"publish","type":"plugin","link":"https:\/\/haz.wordpress.org\/plugins\/pay4all-age-verification\/","author":23516902,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.5.0","stable_tag":"1.5.0","tested":"7.0.2","requires":"5.9","requires_php":"7.4","requires_plugins":null,"header_name":"Pay4All Age Verification","header_author":"Pay4All","header_description":"Age verification and legal-age gate for Pay4All Shop via ID + selfie capture, cross-device QR flow, AES-256-GCM encryption at rest. Ideal for alcohol, tobacco, or any adult-only product.","assets_banners_color":"9185c0","last_updated":"2026-07-29 08:22:52","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/pay4all.ch\/","rating":0,"author_block_rating":0,"active_installs":50,"downloads":414,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"pay4all","date":"2026-07-16 13:44:57"},"1.1.0":{"tag":"1.1.0","author":"pay4all","date":"2026-07-17 10:54:42"},"1.1.1":{"tag":"1.1.1","author":"pay4all","date":"2026-07-17 14:41:56"},"1.1.2":{"tag":"1.1.2","author":"pay4all","date":"2026-07-18 17:52:53"},"1.3.1":{"tag":"1.3.1","author":"pay4all","date":"2026-07-22 16:56:08"},"1.4.0":{"tag":"1.4.0","author":"pay4all","date":"2026-07-27 10:12:04"},"1.4.1":{"tag":"1.4.1","author":"pay4all","date":"2026-07-27 11:33:17"},"1.4.2":{"tag":"1.4.2","author":"pay4all","date":"2026-07-28 17:05:14"},"1.5.0":{"tag":"1.5.0","author":"pay4all","date":"2026-07-29 08:22:52"}},"upgrade_notice":{"1.5.0":"<p>i18n refactor: plugin source strings now in English (WordPress convention). Full translation packs bundled and validated for French, German and Italian. Merchant text overrides preserved. No configuration change, no manual action.<\/p>","1.4.2":"<p>Readme rewrite only - no behaviour change. Safe upgrade.<\/p>","1.0.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3610333,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3610333,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3611581,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3611581,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0","1.1.0","1.1.1","1.1.2","1.3.1","1.4.0","1.4.1","1.4.2","1.5.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3611581,"resolution":"1","location":"assets","locale":"","width":1062,"height":416},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3611581,"resolution":"2","location":"assets","locale":"","width":1200,"height":1565},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3611581,"resolution":"3","location":"assets","locale":"","width":2500,"height":2500},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3611581,"resolution":"4","location":"assets","locale":"","width":1089,"height":190},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3611581,"resolution":"5","location":"assets","locale":"","width":1035,"height":3251}},"screenshots":{"1":"Product edit screen : the <em>Requires age verification<\/em> checkbox, added right next to the price row on Pay4All Shop products.","2":"Customer checkout with an age-restricted product in the cart : the KYC panel appears in the \u00ab V\u00e9rification d'\u00e2ge \u00bb step with the QR code + status of each photo slot.","3":"Mobile capture page (loaded from the QR) : native camera capture for ID recto \/ verso and selfies, live upload progress, encrypted at rest before storage.","4":"Admin lightbox : merchant clicks the shield icon on the order edit screen \u2014 the encrypted photos are streamed, decrypted on-the-fly, and displayed side-by-side without being written back to disk.","5":"Settings page : merchant chooses required documents (ID \/ selfies \/ both), OR \/ AND mode, purge delay, and can override the customer-facing texts in each activated language."}},"plugin_section":[],"plugin_tags":[70877,5616,5240,30944,273626],"plugin_category":[],"plugin_contributors":[268195],"plugin_business_model":[],"class_list":["post-341237","plugin","type-plugin","status-publish","hentry","plugin_tags-age-gate","plugin_tags-age-verification","plugin_tags-id-verification","plugin_tags-selfie","plugin_tags-woocommerece","plugin_contributors-pay4all","plugin_committers-pay4all"],"banners":{"banner":"https:\/\/ps.w.org\/pay4all-age-verification\/assets\/banner-772x250.png?rev=3611581","banner_2x":"https:\/\/ps.w.org\/pay4all-age-verification\/assets\/banner-1544x500.png?rev=3611581","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/pay4all-age-verification\/assets\/icon-128x128.png?rev=3610333","icon_2x":"https:\/\/ps.w.org\/pay4all-age-verification\/assets\/icon-256x256.png?rev=3610333","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/pay4all-age-verification\/assets\/screenshot-1.png?rev=3611581","caption":"Product edit screen : the <em>Requires age verification<\/em> checkbox, added right next to the price row on Pay4All Shop products."},{"src":"https:\/\/ps.w.org\/pay4all-age-verification\/assets\/screenshot-2.png?rev=3611581","caption":"Customer checkout with an age-restricted product in the cart : the KYC panel appears in the \u00ab V\u00e9rification d'\u00e2ge \u00bb step with the QR code + status of each photo slot."},{"src":"https:\/\/ps.w.org\/pay4all-age-verification\/assets\/screenshot-3.png?rev=3611581","caption":"Mobile capture page (loaded from the QR) : native camera capture for ID recto \/ verso and selfies, live upload progress, encrypted at rest before storage."},{"src":"https:\/\/ps.w.org\/pay4all-age-verification\/assets\/screenshot-4.png?rev=3611581","caption":"Admin lightbox : merchant clicks the shield icon on the order edit screen \u2014 the encrypted photos are streamed, decrypted on-the-fly, and displayed side-by-side without being written back to disk."},{"src":"https:\/\/ps.w.org\/pay4all-age-verification\/assets\/screenshot-5.png?rev=3611581","caption":"Settings page : merchant chooses required documents (ID \/ selfies \/ both), OR \/ AND mode, purge delay, and can override the customer-facing texts in each activated language."}],"raw_content":"<!--section=description-->\n<p><strong>Pay4All Age Verification<\/strong> blocks any order containing age-restricted products until the customer has submitted a 5-second video selfie and\/or valid proof of identity, including the front and back of the document. The video selfie and identity document photos are captured by scanning a QR code, allowing the customer to continue the verification process on their smartphone.<\/p>\n\n<p>The plugin integrates with <strong>WooCommerce<\/strong> and <strong>Pay4All Shop<\/strong> (pay4all-form). Install it alongside either e-commerce solution, and it will only appear when a product is marked as requiring age verification. The same settings page (<code>Pay4All AGE &gt; Settings<\/code>) 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.<\/p>\n\n<h4>Identity document photos and\/or video selfie<\/h4>\n\n<p>The merchant can choose to require either verification method or both, depending on the applicable legislation.<\/p>\n\n<h4>WooCommerce support<\/h4>\n\n<p>Simply select the <em>Requires age verification<\/em> 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.<\/p>\n\n<p><strong>Pay4All Pro<\/strong> provides the WooCommerce integration. Pay4All Age remains completely free when used with Pay4All Shop.<\/p>\n\n<h4>How it works<\/h4>\n\n<ol>\n<li>The merchant selects the <em>Requires age verification<\/em> option on the product edit screen.<\/li>\n<li>When a customer adds the product to their order form, a panel containing a QR code appears.<\/li>\n<li>The customer scans the QR code with their smartphone. The mobile capture page opens and allows them to take the required identity document photos or record the video selfie using their phone's camera.<\/li>\n<li>The form displayed on the customer's computer automatically unlocks once all required photos and\/or the video selfie have been submitted.<\/li>\n<li>When the order is submitted, the encrypted photos and videos are stored with the order. They are only decrypted on demand by an administrator from the order edit screen.<\/li>\n<\/ol>\n\n<h4>Security<\/h4>\n\n<ul>\n<li>Photos are encrypted with <strong>AES-256-GCM<\/strong> using a per-order (or per-user) subkey derived via HMAC-SHA256 from a master key.<\/li>\n<li>Ciphertexts live in a private folder guarded, so they are never web-servable.<\/li>\n<li>Admin decryption endpoint is nonce-protected and requires the <code>edit_users<\/code> capability.<\/li>\n<li>Photos are auto-purged when the order (or user) is permanently deleted.<\/li>\n<\/ul>\n\n<h4>WPML \/ Polylang<\/h4>\n\n<p>Multilingual-aware : when the <em>Requires age verification<\/em> flag is set on a source product, every translation is treated as age-restricted too \u2014 even if the flag hasn't been mirrored to the translation.<\/p>\n\n<h4>Available languages<\/h4>\n\n<p>Fran\u00e7ais (fr_FR), Deutsch (de_DE), Italiano (it_IT), English (en_US).<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin does not connect to any external service. Everything runs on the site: photo capture, encryption, storage and admin decryption are all local. No data is sent to any third-party server.<\/p>\n\n<h3>Source code<\/h3>\n\n<p>The complete, non-minified source of this plugin is bundled inside the ZIP itself. Every PHP, CSS and JavaScript file is human-readable and directly editable. No compiler, transpiler or bundler is required to work on this plugin.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin to <code>\/wp-content\/plugins\/pay4all-age-verification\/<\/code> or install via <em>Plugins &gt; Add New<\/em>.<\/li>\n<li>Activate it from the <em>Plugins<\/em> menu.<\/li>\n<li>Open <em>Pay4All AGE &gt; Param\u00e8tres<\/em> to tune what documents you require and to override the customer-facing texts if needed.<\/li>\n<li>On each product that requires an age check, tick the <em>Requires age verification<\/em> checkbox on the product edit screen (Pay4All Shop product).<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20i%20need%20pay4all%20shop%20or%20woocommerce%3F\"><h3>Do I need Pay4All Shop or WooCommerce?<\/h3><\/dt>\n<dd><p>Yes. Pay4All Age Verification is a companion plugin \u2014 it plugs into either <strong>Pay4All Shop<\/strong> (free, ships the form-based checkout) or <strong>WooCommerce<\/strong> (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.<\/p><\/dd>\n<dt id=\"how%20are%20photos%20encrypted%3F\"><h3>How are photos encrypted?<\/h3><\/dt>\n<dd><p><strong>AES-256-GCM<\/strong> 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 <code>wp-content\/uploads\/p4all-age-secure\/age.key<\/code> (mode 0600). Ciphertexts live in the same private folder, guarded by <code>.htaccess<\/code>, <code>index.php<\/code> and <code>web.config<\/code> so they are never web-servable \u2014 a direct URL always returns 403 \/ 404. See the <em>Security<\/em> section above for the full threat model.<\/p><\/dd>\n<dt id=\"where%20is%20the%20master%20encryption%20key%20stored%3F\"><h3>Where is the master encryption key stored?<\/h3><\/dt>\n<dd><p>Outside the database, in <code>wp-content\/uploads\/p4all-age-secure\/age.key<\/code>. This means a stolen SQL dump alone is not enough to decrypt the photos \u2014 the attacker would also need read access to that specific file. Please make sure your backup strategy either encrypts <code>wp-content\/uploads\/p4all-age-secure\/<\/code> or excludes it entirely from the backup archive.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20the%20photos%20when%20an%20order%20is%20deleted%3F\"><h3>What happens to the photos when an order is deleted?<\/h3><\/dt>\n<dd><p>They are auto-purged. Both the WooCommerce order lifecycle (<code>woocommerce_delete_order<\/code> hook) and Pay4All Shop order deletion trigger <code>KycStorage::purge_order()<\/code>, 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).<\/p><\/dd>\n<dt id=\"what%20happens%20if%20a%20user%20account%20is%20deleted%3F\"><h3>What happens if a user account is deleted?<\/h3><\/dt>\n<dd><p>The <code>delete_user<\/code> hook fires <code>KycStorage::purge_user()<\/code> \u2014 every stored user photo (recto \/ verso \/ selfie_1 \/ selfie_2) is removed together with the user record. GDPR-friendly by default.<\/p><\/dd>\n<dt id=\"does%20the%20mobile%20capture%20page%20work%20on%20all%20phones%3F\"><h3>Does the mobile capture page work on all phones?<\/h3><\/dt>\n<dd><p>The page uses the native <code>&lt;input type=\"file\" accept=\"image\/*\" capture=\"\u2026\"&gt;<\/code> API \u2014 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.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20wpml%20%2F%20polylang%3F\"><h3>Does it work with WPML \/ Polylang?<\/h3><\/dt>\n<dd><p>Yes. When a product's <em>Requires age verification<\/em> flag is ticked on a source-language product, every translation is treated as age-restricted too \u2014 even if the flag hasn't been mirrored to the translation post. Same behaviour on WooCommerce products via Pay4All Pro.<\/p><\/dd>\n<dt id=\"which%20languages%20ship%20out%20of%20the%20box%3F\"><h3>Which languages ship out of the box?<\/h3><\/dt>\n<dd><p>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 \u2014 merchants can rewrite the KYC panel copy without touching a <code>.po<\/code> file.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20contact%20any%20external%20service%3F\"><h3>Does the plugin contact any external service?<\/h3><\/dt>\n<dd><p>No. Photo capture, encryption, storage and admin decryption are all local \u2014 nothing leaves the site. The QR code is generated client-side ; the mobile page polls only your own WordPress REST API.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.5.0<\/h4>\n\n<ul>\n<li><strong>i18n refactor - source strings converted to English.<\/strong> All user-facing strings in the plugin code are now in English, matching the WordPress i18n convention (<code>msgid<\/code> = English source, <code>msgstr<\/code> = translation). Full translation packs are bundled and validated for French (fr_FR), German (de_DE) and Italian (it_IT) under <code>\/languages\/<\/code>.<\/li>\n<li><strong>Config.php cleanup.<\/strong> The historic per-locale <code>TEXT_DEFAULTS<\/code> \/ <code>ADMIN_STRINGS<\/code> 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 (<code>Pay4All AGE &gt; Settings &gt; Texts<\/code>) still wins over the shipped translation, so custom copy is preserved on upgrade.<\/li>\n<li>No behaviour change, no configuration change, no manual action required.<\/li>\n<\/ul>\n\n<h4>1.4.2<\/h4>\n\n<ul>\n<li>Readme rewrite: Description, WooCommerce support and How it works sections rewritten in clearer English to better reflect the current feature set (video selfie, QR-code capture, choice between ID document and\/or video selfie). No behaviour change.<\/li>\n<\/ul>\n\n<h4>1.4.1<\/h4>\n\n<ul>\n<li>Anti-fraude \u00e9tendu aux photos : le code d\u00e9fi 4 chiffres est d\u00e9sormais aussi incrust\u00e9 sur les photos de pi\u00e8ce d'identit\u00e9 (recto + verso), pas seulement sur la vid\u00e9o. Compos\u00e9 c\u00f4t\u00e9 client via un canvas dans le coin haut-droit avant l'upload. Le code n'est jamais affich\u00e9 au client (ni pendant la vid\u00e9o, ni avant la photo) - il appara\u00eet uniquement dans les fichiers finaux, et l'admin le voit dans la lightbox au-dessus de chaque item pour cross-check visuel.<\/li>\n<li>UX desktop : sur les \u00e9crans \u2265 901 px, les boutons \u00ab Prendre la photo \u00bb \/ capture vid\u00e9o directe sont masqu\u00e9s - le client est forc\u00e9 \u00e0 scanner le QR code pour capturer depuis son smartphone. Garantit que chaque fichier passe bien par la cam\u00e9ra du t\u00e9l\u00e9phone (o\u00f9 le code d\u00e9fi est burned par le canvas). Mobile \/ tablette portrait garde les boutons.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>New <strong>liveness selfie video<\/strong> replaces the two static selfie photos. When the merchant asks for a selfie, the mobile capture page now records a single 5 s clip via <code>MediaRecorder<\/code>, 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 (\u00ab Tournez lentement la t\u00eate \u00bb) 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.<\/li>\n<li>No third-party service : the challenge code is minted by the plugin, the recording, overlay compositing and compression all run in the customer's browser, and the encrypted bytes never leave the merchant's server. Matches the plugin's \u00ab 100 % local \u00bb promise as before.<\/li>\n<li>UX customer : \u00ab Vous aurez 5 secondes pour tourner lentement la t\u00eate \u00bb notice shown before the recording starts ; the customer then previews the recorded clip and clicks \u00ab Valider et envoyer \u00bb (or \u00ab Refaire la vid\u00e9o \u00bb) BEFORE the upload begins. \u00ab Recommencer la vid\u00e9o \u00bb button only surfaces after a successful upload.<\/li>\n<li>UX admin : the lightbox displays the \u00ab Code attendu dans la vid\u00e9o : #XXXX \u00bb banner above the video player so the merchant can visually cross-check the digits burned into the video pixels against the reference code - proof the clip is a real-time recording, not a stale replay. The code is persisted on the order as <code>post_meta<\/code> at upload time (checkout + resend flows). The video autoplays and loops muted for at-a-glance review.<\/li>\n<li>UX admin resend : a single \u00ab Demander au client de renvoyer les photos et la vid\u00e9o \u00bb button now resends the whole KYC bundle at once ; no more per-photo checkboxes. The default OR-choice option at checkout now follows the merchant's drag-drop order (was always \u00ab pi\u00e8ce d'identit\u00e9 \u00bb before, even when moved to 2nd position).<\/li>\n<li>R\u00e9glages admin : new \u00ab Vid\u00e9o \u00bb text-override section under <code>Pay4All AGE &gt; Param\u00e8tres &gt; Textes<\/code> exposing every customer-facing string of the video capture flow (pre-recording notice, single head-motion prompt, statuses, D\u00e9marrer \/ Valider \/ Refaire \/ Recommencer buttons, camera-denied \/ unsupported-browser errors), overridable per language. Default text is now shown as an input placeholder (empty field = \u00ab use built-in translation \u00bb).<\/li>\n<li>Cleanup : dropped the now-obsolete admin fields \u00ab Libell\u00e9 - Selfie 1 \/ 2 (historique) \u00bb and \u00ab Bouton - Prendre le selfie \u00bb. Renamed the drag-drop step \u00ab Selfies \u00bb to \u00ab Vid\u00e9o selfie \u00bb (FR \/ EN \/ IT) \/ \u00ab Selfie-Video \u00bb (DE) and the metabox hint on the order screen to mention the video alongside the photos.<\/li>\n<li>Plugin Check : sanitisation of <code>$_POST['slots']<\/code> via <code>array_map('sanitize_key', wp_unslash(...))<\/code> in the admin resend handler ; <code>mt_rand()<\/code> replaced by <code>wp_rand()<\/code> in the challenge-code fallback.<\/li>\n<\/ul>\n\n<h4>1.3.1<\/h4>\n\n<ul>\n<li>Fix : the resend \u00ab Documents received \u00bb screen didn't paint on the desktop copy of the mobile page after the customer uploaded from their phone. Root cause : the resend token was cleared the instant the last photo landed, so the desktop poll got 410 and never observed the \u00ab satisfied \u00bb state. The token now stays alive for a 15-minute grace window after completion and the admin notification is idempotent (no double e-mail on re-uploads).<\/li>\n<li>Fix : admin resend e-mail on Pay4All Shop orders was missing the order link because <code>get_edit_post_link()<\/code> returns an empty string when called from the customer's public REST upload (no <code>edit_post<\/code> cap). URL is now built manually.<\/li>\n<li>Fix : \u00ab Ask to resend \u00bb checkboxes now appear on WooCommerce orders even when the photos live in the customer's account bucket rather than the order bucket.<\/li>\n<li>UX : the resend mobile page now shows both a QR code AND the clickable URL below it so a customer who opened the e-mail on their desktop can either scan or copy-paste to their phone. Polls the status endpoint every 4 s so the desktop copy flips to \u00ab Documents received \u00bb once the phone finishes.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>New <strong>\u00ab Ask the customer to resend the photos \u00bb<\/strong> admin action. On any order screen (Pay4All Shop AND WooCommerce - via Pay4All Pro), the age-verification lightbox now shows a checkbox next to each photo. The admin ticks the ones to retake and clicks the new button - the customer receives an e-mail with a secure 30-day link that opens the same mobile capture page, this time restricted to the requested photos. New photos overwrite the old encrypted files (same order id, so admin decryption keeps working).<\/li>\n<li>Once every requested photo has been re-uploaded, the admin gets a single \u00ab new photos received \u00bb notification e-mail - never one per photo.<\/li>\n<li>Customer + admin e-mails have their own <strong>subject + body per locale<\/strong> in <code>Pay4All AGE &gt; Param\u00e8tres &gt; Textes &gt; Renvoi<\/code>, with placeholders <code>{customer_firstname}<\/code>, <code>{customer_lastname}<\/code>, <code>{order_number}<\/code>, <code>{slots_list}<\/code>, <code>{link}<\/code>, <code>{admin_order_url}<\/code>, <code>{site_name}<\/code>, <code>{shop_name}<\/code>. Sensible FR \/ DE \/ IT \/ EN defaults ship out of the box.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>New <strong>drag-and-drop reorder<\/strong> of the ID card and selfies steps from <code>Pay4All AGE &gt; Param\u00e8tres &gt; Documents \u00e0 demander &gt; Ordre d'affichage<\/code>. The chosen order applies to both Pay4All Shop and WooCommerce checkouts (single source of truth). Keyboard fallback (up\/down arrows) included for accessibility.<\/li>\n<li>Plugin renamed to \u00ab Pay4All Age Verification for WooCommerce &amp; Pay4All Shop \u00bb to reflect the dual-storefront support already provided when paired with Pay4All Pro.<\/li>\n<li>Full FR \/ DE \/ IT \/ EN translations for the new \u00ab Ordre d'affichage \u00bb UI strings.<\/li>\n<\/ul>\n\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>Fix : the KYC text-override form is now correctly styled when embedded inside Pay4All Shop's \u00ab R\u00e9glages \u203a V\u00e9rification d'\u00e2ge \u00bb tab. The settings-page CSS was only enqueued on the plugin's own page, so labels overlapped with inputs and the language accordions rendered as bare <code>&lt;details&gt;<\/code> markup.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Renamed the settings page title from \u00ab Pay4All \u2014 Age verification \u00bb to \u00ab Pay4All Age verification \u00bb in the four bundled languages.<\/li>\n<li>Added FR\/EN\/DE\/IT translations for the \u00ab Important reminder \u00bb box on the settings page (previously French-only).<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Fix bug security.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Product-level <em>Requires age verification<\/em> checkbox (Pay4All Shop).<\/li>\n<li>Cross-device QR flow (desktop QR -&gt; mobile capture page).<\/li>\n<li>AES-256-GCM encryption at rest, per-order and per-user derived subkeys.<\/li>\n<li>Metabox on the Pay4All Shop order edit screen with nonce-protected decrypted-photo streaming and a lightbox to view every document side-by-side.<\/li>\n<li>Shield column on the WordPress users list \u2014 one click opens the customer's verified documents.<\/li>\n<li>Settings page with OR \/ AND mode, purge delay, per-locale text overrides.<\/li>\n<li>FR \/ DE \/ IT \/ EN built-in translations, with 4-language text override per string from the settings page.<\/li>\n<li>WPML \/ Polylang aware : translated products inherit the <em>Requires age verification<\/em> flag from their source.<\/li>\n<\/ul>","raw_excerpt":"Age verification by scanning a QR code (ID document and\/or video selfie) when ordering products subject to a legal age restriction from WooCommerce.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/haz.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/341237","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/haz.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/haz.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/haz.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=341237"}],"author":[{"embeddable":true,"href":"https:\/\/haz.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/pay4all"}],"wp:attachment":[{"href":"https:\/\/haz.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=341237"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/haz.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=341237"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/haz.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=341237"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/haz.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=341237"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/haz.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=341237"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/haz.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=341237"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}