Changelog
Current version: 1.1.0
One section per suite version, newest first. Each module that shipped changes in a version has its own subsection, carried from that module's own changelog; modules without changes in a version are simply absent.
1.1.0 — 2026-07-26
GdprCore
Changed
- Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release, which introduces the EU Right of Withdrawal (Directive (EU) 2023/2673 — mandatory online withdrawal function from 19 June 2026). No functional changes to this module.
GdprAdmin
Changed
- Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release, which introduces the EU Right of Withdrawal (Directive (EU) 2023/2673 — mandatory online withdrawal function from 19 June 2026). No functional changes to this module.
GdprConsent
Changed
- Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release, which introduces the EU Right of Withdrawal (Directive (EU) 2023/2673 — mandatory online withdrawal function from 19 June 2026). No functional changes to this module.
GdprConsentHyva
Changed
- Restructured the Tailwind sources: extracted
tailwind-source.cssintomodule.css+ component partials and refreshed thetailwind.config.jssafelist so the module's classes survive purge. Frontend Tailwind build only — no PHP or behavioural changes. - Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release (adds EU Right of Withdrawal, Directive (EU) 2023/2673).
GdprCookie
Changed
- Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release, which introduces the EU Right of Withdrawal (Directive (EU) 2023/2673 — mandatory online withdrawal function from 19 June 2026). No functional changes to this module.
GdprCookieHyva
Changed
- Restructured the Tailwind sources: extracted
tailwind-source.cssintomodule.css+ component partials and refreshed thetailwind.config.jssafelist so the module's classes survive purge. Frontend Tailwind build only — no PHP or behavioural changes. - Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release (adds EU Right of Withdrawal, Directive (EU) 2023/2673).
GdprCookieTemplates
Changed
- Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release, which introduces the EU Right of Withdrawal (Directive (EU) 2023/2673 — mandatory online withdrawal function from 19 June 2026). No functional changes to this module.
GdprDataSubject
Changed
- Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release, which introduces the EU Right of Withdrawal (Directive (EU) 2023/2673 — mandatory online withdrawal function from 19 June 2026). No functional changes to this module.
GdprDataSubjectHyva
Changed
- Updated the
tailwind.config.jssafelist for the GDPR Suite 1.1.0 build. Frontend Tailwind build only — no PHP or behavioural changes. - Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release (adds EU Right of Withdrawal, Directive (EU) 2023/2673).
GdprDemo
Changed
- Updated the
tailwind.config.jssafelist for the GDPR Suite 1.1.0 build. Frontend Tailwind build only — no PHP or behavioural changes. - Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release (adds EU Right of Withdrawal, Directive (EU) 2023/2673).
GdprFrontend
Changed
- Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release, which introduces the EU Right of Withdrawal (Directive (EU) 2023/2673 — mandatory online withdrawal function from 19 June 2026). No functional changes to this module.
GdprFrontendHyva
Changed
- Updated the
tailwind.config.jssafelist for the GDPR Suite 1.1.0 build. Frontend Tailwind build only — no PHP or behavioural changes. - Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release (adds EU Right of Withdrawal, Directive (EU) 2023/2673).
GdprGtm
Changed
- Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release, which introduces the EU Right of Withdrawal (Directive (EU) 2023/2673 — mandatory online withdrawal function from 19 June 2026). No functional changes to this module.
GdprPolicy
Changed
- Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release, which introduces the EU Right of Withdrawal (Directive (EU) 2023/2673 — mandatory online withdrawal function from 19 June 2026). No functional changes to this module.
GdprPolicyHyva
Changed
- Updated the
tailwind.config.jssafelist for the GDPR Suite 1.1.0 build. Frontend Tailwind build only — no PHP or behavioural changes. - Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release (adds EU Right of Withdrawal, Directive (EU) 2023/2673).
GdprPrivacyCenter
Changed
- Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release, which introduces the EU Right of Withdrawal (Directive (EU) 2023/2673 — mandatory online withdrawal function from 19 June 2026). No functional changes to this module.
GdprPrivacyCenterHyva
Changed
- Restructured the Tailwind sources: extracted
tailwind-source.cssintomodule.css+ component partials and refreshed thetailwind.config.jssafelist so the module's classes survive purge. Frontend Tailwind build only — no PHP or behavioural changes. - Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release (adds EU Right of Withdrawal, Directive (EU) 2023/2673).
GdprWithdrawal
Initial release. Introduces the EU Right of Withdrawal for online sales contracts (Directive (EU) 2023/2673, amending Directive 2011/83/EU), which mandates a clearly visible online withdrawal function from 19 June 2026.
Added
- Withdrawal lifecycle — customer & guest storefront withdrawal forms, an admin grid + detail view, and an observer-driven state machine (new → submitted → confirmed → processing → processed / rejected / expired) with illegal-transition guards.
- Tamper-evident audit trail — every status transition is recorded with a hash-chained history for durable, verifiable proof.
- Eligibility engine — configurable 14-day window with
start_basis(delivery / last shipment / order date), delivery-date resolution, and statutory exclusions (Directive 2011/83/EU Art. 16). - Guarded order actions — cancel / credit-memo via
OrderActionService, gated on a goods-returned check. The standard outbound-shipping refund (Art. 13) is applied on a full withdrawal and zeroed on a genuine partial, keyed on anis_full_requestflag; refund via the same payment means. - Durable-medium acknowledgement — a confirmation email queued on every confirmation, plus request-received and admin-notification templates.
- Art. 11a confirmation block — consumer name, order reference and confirmation email shown before the Confirm button; the authenticated path uses the account email, not the order snapshot.
- Email queue admin surface (grid + status source) and a cron that auto-processes confirmed requests.
- Multi-store aware configuration throughout — all scope reads are keyed to the order's store.
- Quantity-aware over-withdrawal guard and reference generation hardened against concurrent inserts.
Setup\Patch\Data\BackfillIsFullRequest— backfills theis_full_requestflag on pre-existing full rows.- Comprehensive unit + integration test coverage; merchant documentation under
docs/withdrawal/.
Dependencies
qoliber/gdpr-core(^1.0),magento/module-customer,magento/module-sales- PHP 8.1 – 8.5
GdprWithdrawalGraphQl
Initial release. GraphQL API for Qoliber_GdprWithdrawal, shipped as part of
the GDPR Suite 1.1.0 release that introduces the EU Right of Withdrawal
(Directive (EU) 2023/2673).
Added
- Queries/mutations to create a withdrawal, list a customer's withdrawable orders, and read withdrawal status — with authenticated-customer and guest (verify + rate-limited, generic-error) parity to the storefront.
- Store-scoped eligibility resolved from the order's store; the authenticated create path persists and sends the durable acknowledgement to the account email.
Dependencies
qoliber/gdpr-withdrawal(^1.0),magento/module-graph-ql,magento/module-sales- PHP 8.1 – 8.5
GdprWithdrawalHyva
Initial release. Hyvä (strict-CSP) storefront companion for
Qoliber_GdprWithdrawal, shipped as part of the GDPR Suite 1.1.0 release
that introduces the EU Right of Withdrawal (Directive (EU) 2023/2673).
Added
- Hyvä Tailwind/Alpine templates for the customer & guest withdrawal forms, guest lookup, and the order-view withdrawal button — including the Art. 11a confirmation block.
- Strict-CSP-safe Alpine registration via an external
withdrawal-form.js(no inline handlers), guarded against the Alpine init-timing race. - Store-scoped order-view button label/visibility (resolved from the order's store).
- Tailwind config and i18n (en / de / pl).
Dependencies
qoliber/gdpr-withdrawal(^1.0),qoliber/hyva-module-registration- PHP 8.1 – 8.5
GdprYireoGtm
Changed
- Version aligned to 1.1.0 for the GDPR Suite 1.1.0 release, which introduces the EU Right of Withdrawal (Directive (EU) 2023/2673 — mandatory online withdrawal function from 19 June 2026). No functional changes to this module.
1.0.5 — 2026-06-11
GdprConsent
Added
- Configurable "Link Text" on consent definitions (REAC-7). New nullable
link_textcolumn + admin form field: the{link}placeholder in the checkbox label now renders the merchant's text instead of the hardcoded "Privacy Policy" (which remains the fallback when empty). Honoured by the text and CMS-page renderers and the checkout consent config.
GdprCookie
Fixed
- Hyvä cookie banner showed categories with no cookies (REAC-10).
ViewModel\CookieConsent::getCategoriesWithCookies()now drops categories that have no cookie details — there is nothing for the visitor to allow or deny. Luma's Knockout banner already filtered these client-side; the shared server-side filter makes both themes consistent.
GdprPolicy
Changed
- The privacy-policy consent renderers (Luma + Hyvä) honour the consent definition's new "Link Text" (
link_text, see Qoliber_GdprConsent 1.0.5) for the{link}placeholder, falling back to the policy title / "Privacy Policy".
1.0.4 — 2026-06-11
GdprConsentHyva
Fixed
- Strict-CSP Hyvä Checkout froze on "Proceed to payment" (critical; missed in the 1.0.3 release sync). The checkout consent template appended an inline
<script>after the Magewire component's root element; on every Magewire morphdom re-render the script is re-executed viaeval(), which a strict checkout CSP (nounsafe-eval) blocks — the step transition rejected and checkout never advanced (plus a "Multiple root elements" Livewire warning). ThegdprCheckoutConsentsAlpine component is now registered in the static, CSP-hashedbefore.body.endblock and the inline script is gone; the Magewire template ends at its single root element.
GdprDataSubject
Fixed
- Luma delete-account confirmation was still case-sensitive. The 1.0.3 case-insensitive "type DELETE" fix shipped for Hyvä but this module's Luma template was missed in the release sync — lowercase
deletestill flagged the field red and failedvalid()(re-triggering the all-fields-red wash). The Luma validator, submit guard and live-feedback handler now compare case-insensitively, matching Hyvä.
1.0.3 — 2026-06-11
GdprCore
Added
Api\TagTypeInterfaceandModel\TagType\TagTypePool(moved here from GdprFrontend, which keeps deprecated BC shims). Hosting the tag-type contract in the shared core module breaks the GdprCookie ⇄ GdprFrontend package dependency cycle; GdprFrontend/GdprGtm/GdprYireoGtm now wire their tag types into the GdprCore pool.
GdprAdmin — 2026-06-09
Fixed (marketplace-hardening review, 2026-06-10)
- Packaging: composer now declares the module's real dependencies (
gdpr-consent,gdpr-cookie,gdpr-data-subject,gdpr-policy) and the module sequence includes GdprCookie/GdprPolicy — the dashboards, readiness auditor and audit export query those modules' tables/classes, so a partial install produced fatal admin pages.
Fixed
- "Data Subject Requests" overview grid actions 404'd. The GDPR Dashboard "View all requests" grid exposed Process/Reject/Delete mass actions, a "Create New Request" button and inline edit — none of which have controllers in this module (it has only
Requests/Index), so every one 404'd. Removed them; the grid is now a read-only overview. Manage requests via GDPR → GDPR Requests.
GdprConsent
Fixed
- Admin hardening: consent Delete/Save and all mass actions (Delete/Enable/Disable) are now HttpPost-only; Edit/Index/New declare HttpGet. The grid's row Delete action POSTs with a form key, and the edit form's Delete button was replaced with a
DeleteButtonblock that POSTs viadeleteConfirm(..., {"data": {}})(the previous plain XML button emitted a GET, which the POST-only controller would reject). - Packaging: composer now declares the module's real dependencies (
module-checkout,module-contact,module-newsletter,module-quote,module-store— plugin/extension-attribute targets that previously brokesetup:di:compileon partial installs); removed the no-opMagento_Cookiesequence entry.
GdprConsentHyva — 2026-06-10
Fixed
setup:di:compilefailed on Hyvä-theme-without-Hyvä-Checkout installs. The checkout consent Magewire component extends Magewire/Hyvä-Checkout classes that composer never required. Declaredhyva-themes/magento2-hyva-checkoutas a dependency; splitting the component into a dedicatedGdprConsentHyvaCheckoutmodule is scheduled for 1.1 (ROADMAP F18.3).- CSP cleanup: removed leftover
hyva-csp-helpergenerator comments (no functional change).
GdprCookie — 2026-06-09
Fixed (review round 2, 2026-06-11)
- Cookie-detail edit form's Delete button now POSTs with a form key (
deleteConfirm(..., {"data": {}})) — the Delete controller is HttpPost-only since the previous round.DetectedCookie\MassDeleteis now HttpPost-only too. - Package cycle with GdprFrontend broken:
ViewModel\CookieConsentnow consumes the TagType pool from GdprCore (see GdprCore 1.0.3); theqoliber/gdpr-frontendcomposer requirement is gone.
Fixed (marketplace-hardening review, 2026-06-10)
- Admin hardening: cookie-category delete now requires POST (was GET), cookie-detail delete/save/edit/new/index and category save now declare granular
ADMIN_RESOURCEACL (previously any admin role could execute them; cookie-detail delete carried a deadisAllowed()override the framework never calls). Grid Delete actions now POST with a form key. - Packaging: declared the real
qoliber/gdpr-frontendcomposer dependency (ViewModel\CookieConsentimports its TagType pool); a standalone install no longer breaks compilation. The proper decoupling is scheduled for 1.1 (ROADMAP F18.2).
Fixed
- Luma cookie-consent theme/colours had no effect on the storefront. The banner's
data-themeattribute was applied by a fragile one-shot JS that raced KnockoutJS rendering, so the[data-theme="…"]CSS variables/rules never matched the rendered element (Dark/Light/Custom all looked identical). The four KO banner templates (popup, bottom, sidebar-left, sidebar-right) now binddata-themetosettings.themedirectly, so the theme and Custom colour palette apply reliably. (Hyvä already server-rendereddata-themeand was unaffected.)
GdprCookieHyva — 2026-06-10
Fixed
- CSP cleanup: removed leftover
hyva-csp-helpergenerator comments from the Hyvä templates (per AGENTS.md; no functional change).
GdprCookieTemplates — 2026-06-10
Fixed
- Admin hardening: the template-picker JSON controller now declares a granular
ADMIN_RESOURCE(Qoliber_GdprAdmin::gdpr_cookies_manage); its previousisAllowed()override used a method name the framework never calls, so any admin role could query it.
GdprDataSubject — 2026-06-09
Fixed (review round 2, 2026-06-11)
- Guest anonymization state machine was inconsistent. (a) Requesting anonymization now immediately moves the original fetch request to
anonymization_requested, so the data link stops serving personal data while erasure is pending. (b) The guest view located the anonymization request by the original fetch token — which can never match the anonymize row's own token — so the pending/complete banner never rendered; it is now matched viaoriginal_request_id. (c) The terminalanonymization_completed/anonymization_failedstatuses (new interface constants, also used by the cron) are accepted by the guest view/controller whitelists as status-only states, so the guest's link shows the erasure outcome instead of "invalid link" — without ever serving data again. - PII log hygiene (round 2): removed remaining raw subject emails from DSAR logs (anonymization request/cron, guest submit, restriction/objection crons, customer lookup) — request IDs are the correlator.
Fixed (marketplace-hardening review, 2026-06-10)
- Guest data-ready links were dead on arrival.
Cron\ProcessDataFetchRequestsmarked a requestcompletedright after emailing the download link, but the download/view gates only acceptnotified/accessed— so every emailed link was rejected. The cron now setsnotified(matchingProcessDataAccessNotifications); completion follows access/expiry. - Admin hardening: request Block/Unblock/Mark-Reviewed are now POST-only (grid actions and the detail-page buttons submit with a form key; previously plain GET links).
- PII log hygiene: DSAR/export paths no longer write raw subject emails or full stack traces to application logs — request IDs or truncated email hashes are used as correlators, exceptions log
class @ file:line.
Fixed
- Admin request "Process" / "Delete" actions 404'd. The request grid's row actions (perform/resend/export/archive) and mass "Delete", and the detail page's "Process/Approve" buttons, all pointed at controllers that never existed (
gdpr/request/{perform,resend,export,archive,massDelete}). Removed them. Request fulfilment is performed automatically by the per-type cron once a request is pending — honouring the right to erasure/access without undue delay — so admin approval is not a gate; the admin's controls are View, Notes, Block/Unblock (legal hold) and Review. - A denied request left the customer account locked out permanently. The account is locked when a deletion/anonymization request is submitted, but nothing released the lock on denial. Added
Service\CustomerLookupService::unlockCustomerAccount()and call it fromDenyDelete/DenyAnonymize, so a denied request re-enables the customer's login.
GdprDataSubjectHyva — 2026-06-09
Fixed (review round 2, 2026-06-11)
- Guest invalid-link branch rendered malformed Alpine markup — it opened
<div x-data="gdprGuestViewData">(a component only registered in the data branch) and returned without closing the wrapper. The error box is now static, complete markup. The anonymization branches also key on the new terminal statuses, with a status belt that never renders data while erasure is pending/failed.
Fixed (marketplace-hardening review, 2026-06-10)
- CSP cleanup: removed leftover
hyva-csp-helpergenerator comments from the Hyvä templates (per AGENTS.md; no functional change).
Fixed
- Delete-account form was confusing and could not be submitted with valid data. The "type DELETE" confirmation is now case-insensitive (lowercase
deleteis accepted; the uppercased display no longer mismatches a case-sensitive check), live validation uses@inputinstead of@change, and the acknowledgement checkbox now reads.checkedinstead of the string"on". A fully and validly filled form now enables the submit button instead of staying disabled/red.
GdprFrontend — 2026-06-10
Changed (review round 2, 2026-06-11)
Api\TagTypeInterfaceandModel\TagType\TagTypePoolmoved to GdprCore (deprecated BC shims remain); di.xml tag-type wiring now targets the GdprCore pool. This breaks the GdprCookie ⇄ GdprFrontend package cycle: the dependency is now one-way (GdprFrontend → GdprCookie).- Removed the unused
Qoliber_GdprConsent/Qoliber_GdprDataSubjectsoft sequence entries (no code, layout or config references); sequence now declares the real dependencies (GdprCookie, Magento_GoogleGtag).
Fixed
- Packaging: declared the module's real composer dependencies —
qoliber/gdpr-cookie(the storefrontViewModel\CookieConsent, instantiated on every page, extends GdprCookie's view model: a standalone install fataled the whole storefront) andmagento/module-google-gtag(di.xml plugsMagento\GoogleGtag\Block\Ga). The structural decoupling is scheduled for 1.1 (ROADMAP F18.2).
GdprGtm
Changed
- Tag type now implements the GdprCore
TagTypeInterfaceand registers in the GdprCoreTagTypePool(moved from GdprFrontend). - Packaging: declared the real
qoliber/gdpr-cookiedependency (the frontend layout instantiates its CookieConsent view model); removed the no-opMagento_GoogleGtagsequence entry (no code, layout or block interaction).
GdprPolicy — 2026-06-09
Fixed (marketplace-hardening review, 2026-06-10)
- REST policy-consent endpoints could never authorize.
etc/webapi.xmlreferenced the ACL resourcepolicy_consent_view, butacl.xmldefinespolicy_consents_view— every token was rejected. Fixed the reference. - Undeclared hard dependency on Qoliber_GdprCookie. Data patches inject GdprCookie repositories and
di.xmlplugs its CookieConsent view model, so a partial install fataledsetup:upgrade/di:compile. Declared the dependency (composer + module sequence) and pointed both cookie-seeding patches'getDependencies()atInstallDefaultCookiesso patch ordering can no longer silently skip seeding.
Fixed
- "Privacy Policy" consent link 404'd (e.g. on the registration form).
Block\Consent\Renderer\PrivacyPolicy::getPolicyUrl()fell back to agdpr/policy/viewroute that does not exist. Repointed it to the realgdpr/policy/renderendpoint so the consent link / policy modal never resolves to a 404.
GdprPolicyHyva — 2026-06-10
Fixed
- CSP cleanup (per AGENTS.md): the privacy-policy modal now binds
x-datadirectly to the canonicalQoliberGdprPrivacyPolicycomponent; removed the redundant generatedgdprPrivacyPolicyalias wrapper script and leftoverhyva-csp-helpergenerator comments.
GdprYireoGtm
Changed
- Tag type now implements the GdprCore
TagTypeInterfaceand registers in the GdprCoreTagTypePool(moved from GdprFrontend).
1.0.2 — 2026-06-07
GdprAdmin
Fixed
- "Data Subject Requests" details page led to a 404. The requests grid action column (
Ui\Component\Listing\Column\RequestActions) built the View link asqoliber_gdpr/request/view, butQoliber_GdprAdminhas no such controller — the data-subject request detail view is owned byQoliber_GdprDataSubjecton thegdpradmin route. Reachable from the GDPR Dashboard's "View All Requests" button, clicking a row's View therefore hit a non-existent route and 404'd. Repointed the link to the real controllergdpr/request/view(sameidparameter). Covered by a unit test.
GdprConsent — 2026-06-06
Fixed
- Guest checkout failed with a TypeError (critical).
PaymentInformationManagementPluginwas bound to both the logged-inMagento\Checkout\Model\PaymentInformationManagementand the guestMagento\Checkout\Model\GuestPaymentInformationManagement, but the guest interface inserts$emailas the second argument — so on every guest order the$emailstring was passed into thePaymentInterface $paymentMethodparameter and threw aTypeError, blocking the order. AdditionallysaveConsentData(int $cartId, …)type-hinted the cart id asint, which a masked-string guest cart id also broke. Split the logic into a dedicatedPlugin\Checkout\Model\GuestPaymentInformationManagementPluginwith the correct guest signature, keptPaymentInformationManagementPluginfor the logged-in flow, moved the shared consent extraction intoService\Checkout\PaymentConsentSaver, and dropped the unused/incorrectly-typed$cartId. Covered by unit tests. - Privacy-policy consent link stale on installs upgraded from 1.0.0-RC. In 1.0.0 the
privacy_policyconsent's routing changed (display_typecms_page_link→privacy_policy_link,link_url/privacy-policy-cookie-restriction-mode→gdpr/policy/render), butInstallDefaultConsentsis run-once and insert-only, so RC-upgraded stores kept the stale values and the consent's policy link routed to the CMS renderer (which has no page id) and failed. Added an idempotentSetup/Patch/Data/ReconcilePrivacyPolicyConsentLinkthat corrects the row only when it is still at the exact RC defaults (fresh installs and merchant-customised rows are left untouched).
Removed
- Dead, redundant quote-based checkout consent path.
Observer\CheckoutSubmitAllAfter(read consent off the quote) was never registered in anyevents.xml, so theShippingInformationManagementPluginthat wrote consent to the quote on every checkout shipping step fed nothing — a wasted quote save and a latent double-recording landmine (had the observer ever been registered,ConsentTrackerhas no per-order dedup, so every Luma order would have logged its consents twice). Consent is captured via the payment/Magewire → checkout-session path and persisted by the unifiedObserver\PersistCheckoutConsents(see Changed). Removed the orphaned observer,Plugin\Checkout\Model\ShippingInformationManagementPluginand its two di bindings, and theshipping-save-processorJS mixin. TheCartInterface/ShippingInformationInterfaceconsent extension attributes are now unused and will be removed in a future minor.
Changed
- Unified checkout consent capture across Luma and Hyvä. The two storefronts stashed checkout consent under different checkout-session keys (
qoliber_gdpr_consentvsqoliber_gdpr_consents), each consumed by its own observer on overlapping events — a divergence that risked silent misses and, if ever naively aligned, double-recording (ConsentTrackerhas no per-order dedup). Introduced a single shared key,Model\Checkout\ConsentSession::KEY, used by both writers, and one base-module observerObserver\PersistCheckoutConsentson the universalcheckout_submit_all_afterevent that records consent for every storefront (accepting both the serialized-string and raw-array payload shapes). Removed the Luma-onlyObserver\CheckoutOnepageSuccess; the redundantQoliber_GdprConsentHyvaobserver is removed too (see its changelog).
GdprConsentHyva
Changed
- Unified checkout consent capture with the Luma stack. The Hyvä consent Magewire component now stashes consent under the shared
Qoliber\GdprConsent\Model\Checkout\ConsentSession::KEYinstead of its own private session key, and recording is handled by the single base-module observerQoliber\GdprConsent\Observer\PersistCheckoutConsents(oncheckout_submit_all_after). Removed this module's now-redundantObserver\CheckoutSubmitAllAfterObserverand itsetc/events.xml. No behavioural change for Hyvä checkout — consent is still recorded once per order; the two storefronts simply no longer use divergent session keys/observers. SeeQoliber_GdprConsent1.0.2.
GdprCookie — 2026-06-06
Fixed
- "Cookie Type" select rendered blank for some cookies. The Cookie Detail form and listing offered only
HTTP/local_storage/session_storage, but the seed data storespersistent(×13) andsession(×1) too. With no matching option,Magento_Ui/js/form/element/selectresolved the value toundefined, so admins saw a blank Type and re-saving could silently clear it. Added a canonicalModel\Source\CookieTypesource (covering all five values) used by the form; the listing column carries the matching inline option set (grid select columns need an inline array, not a source object). Covered by a unit test.
Added
Setup/Patch/Data/ReconcileFunctionalityCookies— idempotent patch that movesproduct_data_storageandsection_data_idsto the Functionality category on stores upgraded from 1.0.0-RC. The 1.0.0InstallDefaultCookiesreclassified these two cookies (Essential → Functionality) but, being run-once and insert-only, never moved them on existing installs, leaving them wrongly flagged as required/essential. No-op on fresh installs where they are already correct.
GdprPolicy — 2026-06-06
Fixed
- "Cookie Consent Mode Text" was ignored when Privacy Policy Type = CMS Page.
Plugin\ViewModel\CookieConsentPluginrendered the merchant-configured consent text only for the version-based policy type; in CMS-page mode it emitted a hardcoded, untranslatable English sentence ("For more information about how we handle your data…") and ignored the configured text. The configured text is now authoritative for both policy types, with the hardcoded link kept only as a fallback when no consent text is set. Covered by an e2e test. - Hardened the privacy-policy render path against opaque "Error loading privacy policy".
Controller\Policy\Renderand both renderers (VersionBasedRenderer,CmsPageRenderer) now catch\Throwable(not just\Exception) and log the exception class + file:line, so a PHPErrorreturns clean JSON and a diagnosable log line instead of a 500 HTML page that the storefront surfaced as a generic failure. The effective-date placeholder replacement now degrades to today's date on a malformed stored date instead of failing the whole policy load. Covered by an e2e test.
1.0.1 — 2026-06-02
GdprAdmin
Fixed
- GDPR Consent Logs admin grid failed to load — it showed "0 records found" with an "Something went wrong with processing the default view and we have restored the default view" error and a Something went wrong modal.
etc/di.xmlregistered theqoliber_gdpr_consent_log_listing_data_sourcecollection a second time (virtualTypeQoliberGdprConsentSearchResult→ tableqoliber_gdpr_consent_log), overriding the correct binding declared inQoliber_GdprConsent(→qoliber_gdpr_consent_customer_log). BecauseQoliber_GdprAdminis<sequence>d afterQoliber_GdprConsent, its di.xml merged last and the wrong mapping won. The grid's listing XML targets theqoliber_gdpr_consent_customer_logschema (PKlog_id, columnsconsent_code,form_location,is_accepted,accepted_at), none of which exist inqoliber_gdpr_consent_log— so the first render threwSQLSTATE Unknown column 'log_id'. Removed the stray binding and the now-orphanedQoliberGdprConsentGridDataProvider/QoliberGdprConsentSearchResultvirtualTypes so the correctQoliber_GdprConsentdata source takes effect. Verified by resolving the live grid collection: it now queriesqoliber_gdpr_consent_customer_logand returns rows without error.
GdprCookie
Fixed
- Cookie Detail form "Cookie Category" dropdown could hide categories —
Ui/Component/Form/Element/CategoryOptionsonly listed categories withis_enabled = 1, while the cookie listing grid shows all categories. A cookie saved against a category that was later disabled lost its value on edit, because a<select>cannot render an option that is not in its option list (this matches the "category doesn't appear on edit" report). Removed theis_enabledfilter so the form lists every category, consistent with the listing grid. Note: an entirely empty dropdown on a fresh install means no cookie categories have been seeded — runbin/magento setup:upgradeto apply theInstallDefaultCookies/InstallGoogleConsentCategorydata patches.
1.0.0 — 2026-05-22
GdprCore
Added
- Initial release of the shared GDPR domain kernel module.
Qoliber\GdprCore\Model\Enum\LawfulBasis— GDPR Art. 6 lawful-basis backed string enum (Consent, Contract, Legal Obligation, Legitimate Interests).Qoliber\GdprCore\Model\Source\LawfulBasisSource—OptionSourceInterfaceadapter for admin forms/grids.Qoliber\GdprCore\Service\AgeGateService— GDPR Art. 8 age-of-digital-consent helper. Computes age from DOB, exposescanGiveConsent()/canGiveConsentStrict()/requiresParentalConsent(). Threshold configurable (13–18, default 16) underqoliber_gdpr/age_gate/threshold; gate toggle atqoliber_gdpr/age_gate/enabled(disabled by default).- Domain enums (PHP 8.1 modernisation, WS5):
RequestStatus(backed string, 13 cases) withisTerminal()/isActive()helpers.RequestType(backed string, 10 cases) witharticleReference()mapping each right to its GDPR Art. 15–21 citation.PolicyStatus(backed int, 4 cases — draft/active/published/archived) withisPublic()/isEditable()helpers.ConsentAction(backed string, 2 cases — granted/revoked) withisPositive().- Legacy class-constants in consuming modules remain for back-compat; new code should prefer the enums.
GdprAdmin
Added (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
Setup/Patch/Data/SeedDefaultRopa— idempotent data patch that seeds six baseline Art. 30 processing activities (Order Fulfilment, Customer Account Management, Marketing Communications, Website Analytics, Customer Support, Fraud Prevention & Security Monitoring) on a fresh install. Lawful basis values use theQoliber\GdprCore\Model\Enum\LawfulBasisbacking strings so the Readiness Auditor's "all activities have a lawful basis" check recognises them. Seed-only-when-empty: a merchant who edited or deleted rows does not see them revived on the nextsetup:upgrade.Service/ReadinessAuditor/Check/EmailQueueScrubbedCheck— new auditor check that FAILs when anyqoliber_gdpr_email_queuerow isstatus = sentbut still carriestemplate_vars(which holds the verification URL with the plaintext bearer token). SEC-4 Item 1 extension. Wired intoetc/di.xmlunderemail_queue_scrubbed.
Added
- GDPR compliance dashboard with compliance score
- Request statistics, consent overview, compliance checklist
- Missing RequestActions UI column class for request grid
- 4 dashboard block classes (Stats, RecentRequests, ConsentOverview, ComplianceStatus) with templates
- Audit export controller for regulator-ready CSV export of DSR requests + consent logs + policy consents
- Missing ACL resources for cookie management (gdpr_cookies_manage, gdpr_cookie_details)
- GDPR Art. 6 lawful-basis integration (2026-04-20):
lawful_basisvarchar(50) nullable column + btree index onqoliber_gdpr_processing_activities.legal_basiscolumn relaxed to nullable and marked DEPRECATED (removed in the next minor release).RenameLegalBasisToLawfulBasisdata patch normalises free-textlegal_basisvalues (e.g. "Consent", "Legitimate Interests", "Art. 6(1)(a)") into theLawfulBasisenum backing strings; unknown values stay NULL and are logged for manual reclassification.- "Lawful Basis Review" dashboard widget counts unreviewed consent definitions and cookie categories with deep-links to filtered admin listings.
- Audit export extended with three configuration sections (CONSENT DEFINITIONS, COOKIE CATEGORIES, PROCESSING ACTIVITIES) each carrying lawful-basis + review-stamp columns; the POLICY CONSENT LOG section also gains a
Lawful Basiscolumn. - Module now depends on
Qoliber_GdprCore(via<sequence>inmodule.xml+ composer).
- Processing Activities admin CRUD (2026-04-20):
- Full admin CRUD: listing grid (
qoliber_gdpr/processingactivity/index), edit/new form, delete action. ProcessingActivityInterface+ model/resource/collection/repository wired through UI component DataProvider.- Per-row Edit/Delete actions via
ProcessingActivityActionscolumn class. - Menu entry under GDPR → Processing Activities; ACL:
gdpr_processing(view),gdpr_processing_save,gdpr_processing_delete.
- Full admin CRUD: listing grid (
- GDPR Readiness Auditor (2026-04-22):
- New admin dashboard at GDPR → Readiness Auditor (
qoliber_gdpr/readiness/index) showing pass / warn / fail for each compliance surface with deep-links to fix pages. Service\ReadinessAuditororchestrates checks via DI (di.xml→ReadinessAuditor.checks) so other modules can register their own checks without touching GdprAdmin.- Five checks shipped:
DpoConfiguredCheck(Art. 37–39),ConsentDefinitionsCheck(Art. 7(1)),CookieCategoriesCheck(ePrivacy Art. 5(3)),ProcessingActivitiesCheck(Art. 30 ROPA),TokenHashingHealthyCheck(SEC-4 health). - ACL:
Qoliber_GdprAdmin::gdpr_readiness. ReadinessAuditorTest(5 tests) covers aggregation, isGreen() semantics, broken-check resilience, non-Check ignored entries.
- New admin dashboard at GDPR → Readiness Auditor (
Deprecated
legal_basiscolumn onqoliber_gdpr_processing_activities— kept for one release; removed in the next minor. Uselawful_basis(enum-backed) instead.
Fixed
- DataRequestInterface namespace in RequestStatus/RequestType source models (was referencing GdprAdmin, now GdprDataSubject)
- Module dependencies on Qoliber_GdprDataSubject and Qoliber_GdprConsent
Changed
- Version bump from 1.0.0-rc1 to 1.0.0, PHP 8.4 support added
GdprConsent
Fixed (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
Plugin/Newsletter/Controller/Manage/SavePlugin— newsletter "Manage" Save plugin was registered against the wrong type and never executed; now correctly firesaroundExecuteso the consent checkbox state on/newsletter/manage/actually persists.Block/Consent/ConsentList+view/frontend/templates/newsletter/account/manage.phtml— consent checkbox on newsletter-preferences page now pre-ticks based on the customer's existing consent record AND can be un-ticked (revocation flow). Previously the checkbox was always rendered unchecked and toggling it off had no observable effect.Block/Customer/ConsentHistory+view/frontend/templates/customer/consent-history.phtml— consent-history rows now render the actual{link}placeholder via the realConsentRendererPool(instead of the bogus literal "1.0" version string), and the "details" expander now displays the exact text the customer accepted at the time of acceptance.Block/Customer/ConsentHistory::getFormLocationLabel— castsPhrase→stringso the fallback branch no longer fatals the customer consent-history page.- Customer-account guest fatal:
Controller/Consent/SaveandController/Customer/Index(now deleted, see below) no longer 500 for guests; they consistently 302 to login. Companion fix inQoliber_GdprDataSubjectcontrollers.
Removed (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
Controller/Customer/Index.php,view/frontend/layout/gdpr_consent_customer_index.xml,view/frontend/templates/customer/consent-history.phtml,Block/Customer/ConsentHistory.php, and the matching unit test were retired in favour of the canonical/customer/consent/preferencessurface (seeQoliber_GdprPrivacyCenter). No redirect — the route is gone and the customer-journey spec asserts a 404.
Added
- CsrfAwareActionInterface on LogConsent AJAX controller
- SerializerInterface injected in ConsentDefinition constructor (replaces ObjectManager)
- Age-gate plugin (Art. 8, 2026-04-20):
BlockMinorConsentbefore-plugin onConsentTracker::trackConsentsstrips non-essential consent entries (marketing/analytics/etc.) for logged-in customers who (a) have a DOB below the configured threshold AND (b) lack agdpr_parental_consent_verifiedcustomer attribute. Essentials (privacy_policy,terms_conditions) remain because they're contract/legal basis, not consent basis. Guests and customers with no DOB pass through unchanged; merchants opt in viaqoliber_gdpr/age_gate/enabled.- 6 unit tests cover passthroughs (disabled, guest, adult, load-failure) and minor-with/without parental verification.
- GDPR Art. 6 lawful-basis integration (2026-04-20):
lawful_basis,lawful_basis_reviewed_at,lawful_basis_reviewed_bycolumns onqoliber_gdpr_consent_definition(+ btree index onlawful_basis).- Three field constants and six accessor methods on
ConsentDefinitionInterface/ConsentDefinition. BackfillLawfulBasisdata patch classifies existing consent definitions bycode(privacy_policy / terms_conditions → CONTRACT, everything else → CONSENT pending admin review).StampLawfulBasisReviewsave-before observer recordsreviewed_at+reviewed_bywhen an admin sets or changes the basis (idempotent: does not re-stamp unchanged rows).- Event prefix
qoliber_gdpr_consent_definitionregistered on the model so save events fire. - Admin form exposes a "GDPR Lawful Basis (Art. 6)" required-entry select backed by
Qoliber\GdprCore\Model\Source\LawfulBasisSource; listing grid gains "Lawful Basis" + "Basis Reviewed" columns. - Module now depends on
Qoliber_GdprCore(via<sequence>inmodule.xml) for the shared enum.
Fixed
- Guest email fallback removed -- returns null instead of fake '[email protected]'
- Newsletter consent save -- plugin uses getPostValue() instead of getPost()->get()
- User agent string no longer collected in consent logs (data minimization)
Block/Adminhtml/Customer/Tab/Consents.php: injectedStoreManagerInterface,SerializerInterfaceandLoggerInterface; addedgetStoreName()andgetConsentSnapshotData()helpers so the admin template no longer reaches forObjectManager::getInstance()or rawjson_decode()view/adminhtml/templates/customer/tab/consents.phtml: store name + snapshot decoding delegated to the Block — removes finalObjectManager::getInstance()usage and last rawjson_decode()in the admin consent history UIBlock/Adminhtml/Order/View/ConsentInfo.php: consent snapshot now decoded via injectedSerializerInterfaceinstead of rawjson_decode(); runs on every admin order viewObserver/CheckoutSubmitAllAfter.php: quote consent payload now decoded viaSerializerInterface(was rawjson_decode()); runs on every order placementObserver/CheckoutOnepageSuccess.php: session consent payload now decoded viaSerializerInterface(was rawjson_decode()); runs on every checkout successUi/Component/Listing/Column/FormLocations.php: admin grid column now decodesform_locationsviaSerializerInterface(was rawjson_decode())
Changed
- Version bump from 1.0.0-rc1 to 1.0.0, PHP 8.4 support added
GdprConsentHyva
Fixed (strict CSP — review finding #2, QLB_GDPR_V2.1, 2026-05-20)
- Strict-CSP safety:
customer/consent/preferences/hyva_current-status.phtml+checkout/gdpr-consents.phtmlconverted via Hyvä'shyva-csp-helpertool. One PHP-conditional inline:class="{...}"(the required-consent error ring) the tool couldn't auto-reach was hand-converted to a CSP-safe method (...ErrorRingreadingdata-consent-error-id). Fixes review finding #2. Verified under theHyva/default-csptheme.
Changed
- Version bump from 1.0.0-rc1 to 1.0.0
- PHP 8.4 support added
- All localStorage keys unified to
qoliber_gdpr_*prefix - Dependency on
qoliber/gdpr-consentbumped to stable^1.0
Fixed
- Magewire consent component aligned with base module server-side consent tracking
- Alpine.js modal visibility regression when toggling checkout consents
- Required-consent validation error state cleared correctly on successful acceptance
- Added
@themeblock toview/frontend/tailwind/tailwind-source.cssdeclaring custom color tokens (--color-gdpr-primary,--color-gdpr-primary-dark,--color-gdpr-error,--color-privacy-primary,--color-privacy-success,--color-privacy-accent) — required for Tailwind v4 / Hyvä 1.4+ builds, which no longer carrytailwind.config.js theme.extend.colors - Removed unused
ObjectManager::getInstance()fallback forViewModelRegistryinview/frontend/templates/checkout/gdpr-consents.phtml— Hyvä auto-injects$viewModelsinto every template, the fallback was dead code
GdprCookie
Added (US privacy laws — QLB_GDPR_V2.1, 2026-05-20)
- US state-law (CCPA/CPRA + VA/CO/CT) opt-out support, layered on the existing GDPR opt-in model:
ViewModel/ComplianceMode+Service/GpcSignal— resolve the active compliance model and detect the Global Privacy Control opt-out signal (Sec-GPCheader server-side;navigator.globalPrivacyControlclient-side, which is authoritative since it is not full-page-cached).CookieConsentview model now publishes acomplianceblock into both the Hyvä config and Luma settings JSON.view/frontend/web/js/model/cookie-manager.js— inus_optoutmode non-essential cookies default to allowed; a GPC signal auto-records an opt-out (keep essentials, purge sale/sharing cookies) without a click; newoptOut()method.view/frontend/web/js/view/do-not-sell-link.js+templates/do-not-sell-link.phtml— "Do Not Sell or Share My Personal Information" footer link (US opt-out mode only) that records an opt-out and lets the consent-updated event flip Google Consent Modead_*signals to denied.templates/compliance-config.phtml— publisheswindow.qoliberGdprCompliancefor both Luma and Hyvä.- Tests:
Test/Unit/ViewModel/ComplianceModeTest(8) +Test/Unit/Service/GpcSignalTest(6 cases) + Playwrightfrontend/us-compliance.spec.ts(5 E2E: opt-in vs opt-out config, default-allow, GPC auto-opt-out, Do Not Sell opt-out). - Merchant guide:
docs/US-PRIVACY-LAWS.md.
Fixed (theming — QLB_GDPR_V2.1, 2026-05-20)
- Full-page-cache staleness on cookie config save (pre-existing, affected texts / display style / theme alike): added
Qoliber\GdprFrontend\Observer\FlushPageCacheOnConfigChange, wired toadmin_system_config_changed_section_qoliber_gdpr_cookie. A system-config save only invalidates theconfigcache type, notfull_page, so the cookie banner — baked into every cached page — kept rendering the old text/theme until a manual flush. The observercleanType()s the page cache on save, so admin changes show on the storefront immediately. Verified end-to-end: cache HIT → config change → cache MISS → next request reflects the new palette with no manual flush. (Lives in Qoliber_GdprFrontend since that module owns theqoliber_gdpr_cookieconfig section; see its CHANGELOG.)
Added (theming — QLB_GDPR_V2.1, 2026-04-29)
ViewModel/Theme— new view model that resolves the active colour scheme (light / dark / custom) into a CSS-variable map. Custom values overlay on top of the Light preset, so a partially-configured Custom theme is never visually broken.view/frontend/templates/luma/theme-vars.phtml— emits an inline<style>block of CSS custom properties scoped to.gdpr-cookie-consent[data-theme="custom"]. No-op for light/dark (the static_light.less/_dark.lessfiles already handle those).view/frontend/layout/default.xml— wires the new theme-vars block after the cookie banner, gated byqoliber_gdpr_cookie/consent/enabled.view/frontend/web/js/view/privacy-preferences.js::applyTheme— fix: stampdata-themeon.qoliber-gdpr-cookie-consent(the actual KO-rendered element) in addition to the legacy.gdpr-cookie-consentselector, so the variable scope is hit on the rendered banner. Without this the existing_light/_dark.lessselectors silently no-op.view/frontend/web/css/source/components/_privacy-preferences.less—.action.primarybutton background + hover + border now go throughvar(--gdpr-btn-primary-bg, …)/var(--gdpr-btn-primary-hover, …)(was hardcoded@color-blue1+darken(@color-blue1, 10%)). Same for__privacy-linkcolour + hover. Category-toggle ON state now usesvar(--gdpr-toggle-on, @color-blue1). LESS-computed values stay as the compile-time fallback so Light/Dark presets that don't define the variable still render correctly. The Custom theme palette now flows end-to-end through all primary buttons and links.Test/Unit/ViewModel/ThemeTest— 8 cases / 52 assertions covering scheme resolution (light / dark / custom / unknown), Custom overrides with admin-set + partial + whitespace values falling back to Light, and CSS-property rendering (underscores translated to dashes).
Added (release prep — QLB_GDPR_V2.1, 2026-04-29)
Plugin/Response/Http— server-side cookie suppression registered againstMagento\Framework\App\Response\Http::sendResponse. On every storefront response the plugin:- Reads the visitor's
gdpr_consentcookie (categories list) - Queries every cookie registered under a non-consented, non-required category in admin
- Emits
Set-Cookie: name=; expires=Thu, 01 Jan 1970headers viaCookieManagerInterface::deleteCookie()for every match present on the request - Honours a hard-coded
NEVER_DELETEallow-list (mirrors the JS allow-list incookie-manager.js) so an admin misconfig cannot strip session essentials - Closes the HttpOnly cookie gap that the JS-side interceptor in
cookie-manager.jsstructurally cannot reach — JS cannot see HttpOnly cookies viadocument.cookie, but the server controls the Set-Cookie header so the browser deletes them anyway. - Layered on top of the JS interceptor for belt-and-suspenders coverage: JS prevents writes synchronously; this plugin cleans up one response later, including HttpOnly and server-set cookies.
- Reads the visitor's
Test/Unit/Plugin/Response/HttpTest— 8 cases, 15 assertions covering: no-consent / malformed-consent / consent-without-categories no-ops, required category never contributing to the rejection set, non-consented cookies deleted when present,NEVER_DELETEoverrides admin misconfig, cookies absent from the request not redundantly deleted, consent to all categories produces no deletions.
Fixed (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
view/frontend/web/js/view/cookie-settings-link.js— module now returns a constructor (function (config, element) {...}) instead of a plain object literal{ initialize: ... }. UnderMagento_Ui/js/core/appthenew Constr(config, element)instantiation threwConstr is not a constructorand wedged knockout bindings for the rest of the page (privacy-policy KO component never bound, etc.).view/frontend/templates/luma/cookie-settings-link.phtml— footer-link initialisation switched fromMagento_Ui/js/core/appto a plaintext/x-magento-initmapping ({"#qoliber-gdpr-footer-link": {"Qoliber_GdprCookie/js/view/cookie-settings-link": {}}}). The new init pattern matches the JS module's signature and avoids the constructor-cast issue altogether. Net effect: clicking the footer "Cookie Settings" link reliably reopens the consent banner on every page.
Added
- 3 mass action controllers for CookieDetail (MassDelete, MassEnable, MassDisable)
- GDPR Art. 6 lawful-basis integration (2026-04-20):
lawful_basis,lawful_basis_reviewed_at,lawful_basis_reviewed_bycolumns onqoliber_gdpr_cookie_categories(+ btree index onlawful_basis).- Three field constants and six accessor methods on
CookieCategoryInterface/CookieCategory. BackfillLawfulBasisdata patch maps existing categories byis_required(essential → LEGAL_OBLIGATION, others → CONSENT pending admin review).StampLawfulBasisReviewsave-before observer recordsreviewed_at+reviewed_by(idempotent: does not re-stamp unchanged rows).- Event prefix
qoliber_gdpr_cookie_categoryregistered on the model. - Admin form exposes a required-entry "GDPR Lawful Basis (Art. 6)" select backed by
Qoliber\GdprCore\Model\Source\LawfulBasisSource; listing grid gains "Lawful Basis" + "Basis Reviewed" columns. - Module now depends on
Qoliber_GdprCore(via<sequence>inmodule.xml).
Fixed
- DataPersistor key mismatch in CookieCategory DataProvider
- ObjectManager replaced with DI in CategoryOptions.php
- Redundant acl.xml removed (ACL managed by GdprAdmin)
- Close button (X) now calls decline() instead of closeWithoutSaving() in all templates
- Clicking entire category row toggles the switch (not just toggle element)
- Empty categories without cookies are hidden from consent banner
- Allow Selection button now visible on all tabs including About
- Cookie consent banner ifconfig path corrected to qoliber_gdpr_cookie/consent/enabled
- Unknown cookies always blocked (removed permissive mode branch)
- checkConsentStatus() reads consent cookie properly (was always showing banner)
- toggleScripts() implements deny-by-default script activation
Changed
- All localStorage keys unified to qoliber_gdpr_* prefix
- Version bump from 1.0.0-rc1 to 1.0.0, PHP 8.4 support added
GdprCookieHyva
Fixed (Hyvä cookie banner UI — QLB_GDPR_V2.1, 2026-05-22)
- Category toggles never turned green when on.
view/frontend/templates/hyva/theme-vars.phtmlstyled the "on" track with.peer-checked\:bg-green-600:has(:checked), but the track<span>does not contain the checkbox (it is a sibling), so:has(:checked)never matched — while.bg-gray-300 { … !important }forced the track to the off colour unconditionally. Corrected the selector to the peer-sibling form.peer:checked ~ .peer-checked\:bg-green-600. Also fixed the Details-tab track markup (peer-checked peer-disabled→peer-checked:bg-green-600 peer-disabled:bg-gray-400) incookie-consent.phtml. - Banner animation under strict-CSP.
x-transitionkeyframes used inline ternary expressions, which the Alpine CSP build cannot evaluate (and which it applies as literal class names), so the popup never animated. Replaced with static opacity-fade keyframes; the layout position class is now emitted server-side (fromgetDisplayStyle()) instead of via:class, because binding:classon the same element asx-transitionlets the reactive update clobber the transition. - Backdrop blur popped in after the popup. The
backdrop-bluroverlay lived inside the popup wrapper, whose animatingopacityforms a "backdrop root" — so the nestedbackdrop-filtercould not blur the page until the wrapper settled. Moved the backdrop to a sibling of the popup (direct child of the non-animating root) with its own opacity fade matched to the popup; the wrapper ispointer-events-noneand the contentpointer-events-autoso click-outside-to-close still reaches the backdrop. Blur now fades in/out in lockstep with the popup. view/frontend/tailwind/tailwind.config.js—safelistfor the toggle peer-state classes, fade keyframes, and the backdrop layering/click-through utilities so they are always emitted.
Added (US privacy laws — QLB_GDPR_V2.1, 2026-05-20)
view/frontend/layout/hyva_default.xml— wires two new Hyvä blocks for US state-law support:compliance-config.phtml(publisheswindow.qoliberGdprComplianceso the Alpine/JS layer knows the opt-in vs opt-out model + GPC state) and the "Do Not Sell or Share" link block (US opt-out mode only, placed inbefore.body.endfor theme-agnostic safety — relocatable to a footer container via theme override). Runtime + ViewModels live inQoliber_GdprCookie; seedocs/US-PRIVACY-LAWS.md.
Added (theming — QLB_GDPR_V2.1, 2026-04-29)
view/frontend/templates/hyva/theme-vars.phtml— emits an inline<style>block of CSS custom properties under#qoliber-gdpr-cookie-consent[data-theme="..."]for all three schemes (Hyvä has no.lessof its own, so this is the only output path). The same block layers specificity-tied overrides on top of Tailwind colour utilities used inside the cookie banner template, so the existing markup is re-skinned without touching it.view/frontend/layout/hyva_default.xml— wires the new theme-vars block after the cookie banner block.view/frontend/templates/hyva/cookie-consent.phtml— addsid="qoliber-gdpr-cookie-consent"anddata-theme="<scheme>"to the outer Alpine wrapper so the theme-vars selector matches. The Theme ViewModel resolves the scheme.
Fixed (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
view/frontend/templates/hyva/privacy/cookie-card.phtml— "Manage Cookies" button on the Hyvä Privacy Center now actually reopens the cookie banner. Replaced the broken inlineonclick(CSP-incompatible, used a malformed[ x-data="..." *=gdprCookieConsent]selector that matched nothing) with a proper Alpinex-on:clickthat dispatchesgdpr-reopen-settings. The cookie-consent component already listens for that event, so the existingreopenSettings()flow runs end-to-end.view/frontend/templates/hyva/cookie-consent.phtml— inline policy modal now fetches/gdpr/policy/render(the real JSON endpoint) instead of/gdpr/policy/view(404). The fetch is escaped via$block->getUrl(...)so it picks up the correct frontName and store base URL.
Changed
- Version bump from 1.0.0-rc1 to 1.0.0
- PHP 8.4 support added
- Dependency on
qoliber/gdpr-cookiebumped to stable^1.0 - All localStorage keys unified to
qoliber_gdpr_*prefix
Fixed
- Close button (X) triggers decline flow instead of closing without saving
- Clicking full category row now toggles the switch (not just the toggle element)
- Empty categories (no cookies) are hidden from the consent banner
- "Allow Selection" button visible on all tabs including About
- Unknown cookies always blocked (permissive mode branch removed)
- Consent cookie state restored correctly on subsequent page loads
- Template name validated against whitelist to prevent template injection
TypeError: Cannot read properties of undefined (reading 'classList')inview/frontend/templates/hyva/cookie-consent.phtml— replacedthis.el.classList.add(...)withel.classList.add(...)in the Alpine$nextTickcallbacks that style.gdpr-policy strong/.gdpr-policy aelements inside the consent banner- Google Consent Mode v2 bypass (High):
view/frontend/layout/hyva_default.xmlremoved the block registration forhyva/google-consent-init.phtml, which was loadinggtag.js/gtm.jsunconditionally regardless of consent state. The correct, lazy-loading path inqoliber/gdpr-frontend-hyva(consent/google-tag.phtml) now handles Google Consent Mode v2 on Hyvä — scripts load only after the user grantsanalytics_storageorad_storage.
GdprCookieTemplates
Fixed
- Namespace corrected from Qoliber\CookieDetailsTemplates to Qoliber\GdprCookieTemplates in controller
Changed
- Version bump from 1.0.0-rc1 to 1.0.0, PHP 8.4 support added
GdprDataSubject
Fixed (review findings — QLB_GDPR_V2.1, 2026-05-20)
- Guest DSAR postback broken after SEC-4 token hardening. The guest data-view templates submitted
$dataRequest->getToken()for export / anonymization POSTs, but the plaintexttokencolumn is scrubbed post-notification (SEC-4), so those posts sent an empty token and failed. They now submit$token— the bearer token from the URL the guest actually arrived with (the page already loads/validates against it). Fixed inview/frontend/templates/guest/view-data.phtmlandGdprDataSubjectHyva .../hyva/datasubject/guest/view-data.phtml. - Stale plaintext-token assumption in anonymization cron.
Cron/ProcessAnonymizationRequestspassed$request->getToken()(now empty) into the original fetch-data request'sresponse_dataasanonymization_token, andController/Guest/ViewDataredirected using it. Both are stale and an at-rest leak risk if a legacy plaintext token ever reappears. Removed the token fromresponse_dataentirely;ViewDatano longer stitches one request's bearer token into another's URL — it renders the current page (already authenticated by the guest's valid URL token) with ananonymization_completedflag instead. Cron/ProcessEmailQueue— after a successful send, the cron now nulls outtemplate_varson theqoliber_gdpr_email_queuerow. That blob holds the verification URL with the plaintext bearer token, so leaving it on disk after the email has been delivered violates SEC-4 ("zero plaintext bearer token at rest").Setup/Patch/Data/ScrubSentEmailTemplateVars— one-shot data patch for existing rows:UPDATE qoliber_gdpr_email_queue SET template_vars = NULL WHERE status = 'sent' AND template_vars IS NOT NULL. Runs once onsetup:upgrade, idempotent on re-run.Test/Unit/Regression/TokenLeakRegressionTest::testEmailQueueProcessorScrubsTemplateVarsAfterSend— greps the cron source for the literalsetTemplateVars(null)call so a future refactor that drops the scrub fails this test rather than silently regrowing the at-rest leak.
Removed (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
Controller/Request/Index.phpand the matchingview/frontend/layout/gdprds_request_index.xml— the/gdprds/request/indexroute was a duplicate of the Privacy Center surface (/customer/account/privacy) and shipped with its own (drift-prone) UI. Retired with no redirect; the customer-journey spec asserts a 404 response so a future re-add fails CI.Controller/Customer/{Anonymize,Delete,Rectification}*standalone controllers (the mutating endpoints*Postare kept; only the standalone GET render controllers were removed). All flows now live inside the Privacy Center page.
Fixed (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
- Customer-account guest 500:
Controller/Account/Privacy,Controller/Customer/AnonymizePost,Controller/Customer/DeletePost,Controller/Customer/Objection,Controller/Customer/RectificationPost,Controller/Customer/Restrictionnow consistently 302 to login for guests instead of fataling. The fix uses Magento'sCustomer\Controller\Plugin\AccountaroundExecute pattern.
Added
- GDPR Art. 18 / Art. 21 DSAR integration + status-transition audit log (2026-04-20):
- New table
qoliber_gdpr_request_historyrecords every DSAR status transition (from/to status, changed_by, change_source, note, timestamp); CASCADE FK toqoliber_gdpr_requests. - New table
qoliber_gdpr_marketing_suppression(unique on email+scope) holds Art. 21 / Art. 18 suppression entries;MarketingSuppressionServiceexposesisSuppressed()+add(). StageStatusTransition+PersistStatusTransitionobserver pair onqoliber_gdpr_request_save_before/_save_aftercaptures every status change (admin / cron / api / customer source inferred).- Event prefix
qoliber_gdpr_requestregistered on the model so save events fire. ProcessRestrictionRequestscron (every 15 min) processes Art. 18 DSARs: adds suppression scope=all (marketing freeze; transactional processing remains permitted per Art. 18(2)); transitions DSAR to completed.ProcessObjectionRequestscron (every 15 min) processes Art. 21 DSARs: adds suppression scope=marketing; transitions DSAR to completed.Block/Adminhtml/Request/View/Historynow renders real history rows (repo query, newest-first); admin template updated to show from/to status, source, admin user, note.
- New table
- SEC-4 at-rest token hashing (2026-04-20):
- New
token_hashvarchar(64) column + index onqoliber_gdpr_requests; plaintexttokenretained for one transition release. TokenHasherservice (HMAC-SHA256 keyed onenv.phpcrypt.key; encryptor fallback) — never logs the plaintext.BackfillTokenHashdata patch hashes every pre-existing token in chunks of 2000 rows (idempotent, NULL-guarded).StampTokenHashobserver (model_save_before) stamps the hash whenever the plaintext token is set or changed, so all write paths are covered.DataRequestRepository::getByToken()looks up by hash first, falls back to plaintext only while the transition column exists.
- New
- SEC-4 hardening (2026-04-21):
DataRequestRepository::getByToken()is now hash-only — the plaintext fallback is gone.- Every guest-flow call site (
Anonymization/Request,Anonymization/Confirm,Anonymization/Status,Export/Download,Guest/ViewData,GuestDataViewModel,AnonymizationStatusViewModel) switched from directaddFieldToFilter('token', ...)/load($model, $token, 'token')torepository->getByToken(), so plaintext reads on thetokencolumn no longer occur at runtime. - Removed
original_token/parent_tokenkeys from serializedrequest_data/response_dataJSON — these turned the hashed column into a plaintext leak via audit trail. Replaced withoriginal_request_id/parent_request_id. - Removed the
setToken($token . '_download_' . time())mutation hack inExport/Download; the audit row now records the download event with stable integer linkage only. - Single-use verification.
Request/Verifyrotates the token on successful verification (UUID v4) — any replay of the verification URL hashes to a value no row carries and lands in the "invalid" branch. Guest/ViewDatanow enforces status-whitelist (CONFIRMED / PROCESSING / NOTIFIED / ACCESSED / ANONYMIZATION_REQUESTED) and a non-null futureexpires_at; previously a pending_confirmation row with a valid token could render personal data.- New tests:
VerifyRotatesTokenTest(3),ViewDataValidationTest(5),CleanupExpiredRequestsNestedTest(2),TokenLeakRegressionTest(3). Full suite 176/176 green.
- SEC-4 closure push (2026-04-21):
- Fail-closed on missing expiry everywhere.
Verify,Anonymization/Confirm,Anonymization/Status, andDataRequestViewModel::assertViewable()now reject rows withexpires_at = NULLthe same as already-expired rows. NULL is treated as misconfiguration, never "valid forever". - Plaintext token scrubbed post-notification. Both notification crons (
ProcessDataFetchRequests,ProcessDataAccessNotifications) now blank the plaintexttokencolumn after the email is sent.token_hashstays intact so the recipient's click still resolves. - Observer semantics updated.
StampTokenHashno longer clearstoken_hashwhen the plaintext is cleared — caller (typically the cron scrub path) drives that now. Full hash-reset requires both columns to be nulled explicitly. - Export path hardened (Finding 1).
ProcessDataFetchRequests::generateDataFiles()now derives the on-disk export directory + filename from the stable integerrequest_id, not the bearer token. The token remains the encryption key but never appears inresponse_data['data_files'][*]['file_path']. - Historical scrub. New
ScrubPostNotificationTokensdata patch blanks plaintext for every existing row already past the notification stage (NOTIFIED / ACCESSED / COMPLETED / EXPIRED). Idempotent; depends onBackfillTokenHash. - New tests:
DataRequestViewModelExpiryTest(4),CronWipesPlaintextTokenTest(2),DsarLifecycleScenarioTest(1 end-to-end scenario),TokenLeakRegressionTestexpanded by 1. Full suite 184/184 green.
- Fail-closed on missing expiry everywhere.
- Logger/Handler.php and Logger/Logger.php classes
- queueVerificationEmail() method in EmailService
- Verification email template registration
- Tax retention period config (7 years default) to prevent anonymization of recent financial records
- Legal hold constants in DataRequestInterface (STATUS_LEGAL_HOLD, block reason types)
- Article 15 metadata in DataFetcherService for GDPR-compliant exports
- Data retention admin config group (consent_log_days, verification_token_hours, export_file_hours, expired_request_days)
- Legal hold documentation section in admin config
- Production readiness validator -- blocks enablement without DPO email/name and notification template
Fixed
- Removed legacy DataAccessRequest model, resource model, and collection (wrong table name)
- Rewritten Submit, GuestSubmit, Verify controllers on DataRequestRepository
- Cron wired to ProcessDataFetchRequests (was ProcessDataAccessNotifications)
- Cron fetches confirmed requests (was filtering for pending)
- Store ID type mismatch in fetch cron (scalar to array)
- QuoteDataAnonymizer config path (was checking creditmemo config)
- ProcessAnonymizationRequests status overwrite + DatarequestInterface typo
- DataAnonymizationService record totaling
- Customer account locked after anonymization (is_active=0, failures_num=999)
- AccountManagementPlugin checks both is_active and failures_num for login blocking
- Export writes temporary files instead of storing payloads in response_data
- Download marks request as ACCESSED status
Removed
- DataAccessRequest legacy model and collection
- Privacy.php.bak file
- PDF from default export formats (txt,csv,json only)
- PDF translation entries from all i18n files
- Placeholder DPO defaults ([email protected], John Doe, +1-555-123-4567)
- Non-existent Cron\ProcessDataRequests reference from di.xml
Changed
- Version bump from 1.0.0-rc1 to 1.0.0, PHP 8.4 support added
GdprDataSubjectHyva
Fixed (strict CSP — review finding #2, QLB_GDPR_V2.1, 2026-05-20)
- Strict-CSP (Alpine CSP build) safety: all Hyvä templates converted via Hyvä's
hyva-csp-helpermigration tool — inlinex-dataobject literals,x-model,x-init,x-effect,@change/@click/x-on:submithandlers, and:classobject/ternary expressions extracted into registered Alpine.data components +$hyvaCsp->registerInlineScript(). Fixes review finding #2 (export form, data-request, guest view-data, customer anonymize/delete/rectification, quick-actions). Verified: guest data-request page renders under theHyva/default-csptheme with 0 console errors.
Fixed (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
view/frontend/templates/customer/privacy/cards/export.phtml— "Export Now" button on the Hyvä Privacy Center now scrolls to the actual export form. The button targeted#export-section(legacy id from the Luma layout) but the real anchor on the Hyvä page is#export-form, so the click resolved to no element and did nothing. Both thehrefand the@click.preventscrollIntoViewcall now use#export-form.
Changed
- Version bump from 1.0.0-rc1 to 1.0.0
- PHP 8.4 support added
- Dependency on
qoliber/gdpr-data-subjectbumped to stable^1.0 - Terminology aligned with base module: "deletion" → "account closure & anonymization"
Fixed
- Privacy dashboard quick-action card labels match base module naming
- Guest data request form correctly submits via Hyvä's Alpine.js AJAX helpers
- Data export download link opens fresh request against rate-limited endpoint
Hyvä 1.4 / Tailwind v4 compatibility
- Verified against Hyvä theme
^1.4with Tailwind v4 JIT build - No code changes required — module uses only core Tailwind utilities present in the default theme
GdprDemo
Fixed (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
ViewModel/DemoLinks::getCustomerRequestUrl— "Request My Data" demo link now points at the canonical Privacy Center surface (customer/account/privacy) instead of the retiredgdprds/request/indexroute. The old route was deleted in this release (seeQoliber_GdprDataSubjectCHANGELOG); the demo bar would have surfaced a 404 otherwise.
Added
- Production-mode gate (2026-04-21): the demo bar is automatically hidden
when Magento runs in production mode (
bin/magento deploy:mode:show==production). Merchants can override per-store viaqoliber_gdpr_demo/settings/force_enabled(default: 0) for demo/staging instances that deliberately run in production mode.DemoLinks::isEnabled()is the single source of truth, exercised by both Luma and Hyvä templates. - Initial release — storefront demo helper bar
- Top-of-page ribbon with a
DEMObadge and quick links to every public GDPR flow:- Guest Data Request (
gdprds/guest/datarequest) - Privacy Center (
customer/account/privacy, login required) - Request My Data (
gdprds/request/index, login required) - Consent History (
gdpr-consent/customer/index, login required) - Privacy Policy (
gdpr/policy/render) - Cookie Preferences — re-opens the cookie consent banner by clearing stored consent + reloading
- Guest Data Request (
- Two styled variants:
- Luma: purple/indigo gradient + Less stylesheet (
view/frontend/web/css/source/_module.less) - Hyvä: Tailwind v4 utilities with Alpine.js cookie-reopen handler and Hyvä CSP registration
- Luma: purple/indigo gradient + Less stylesheet (
ViewModel\DemoLinkssupplies all URLs + aisCustomerLoggedIn()helper so links that require authentication are flagged with a "(login required)" hint
Non-goals
- Not intended for production merchants. The bar is meant to help demo visitors (and partners evaluating the suite) discover every GDPR flow without hunting for URLs.
- Module sequences after all core Qoliber GDPR modules so its layout handles apply last.
Requirements
- PHP 8.1, 8.2, 8.3, or 8.4
qoliber/gdpr-data-subject: ^1.0qoliber/gdpr-privacy-center: ^1.0qoliber/gdpr-policy: ^1.0qoliber/gdpr-cookie: ^1.0
GdprFrontend
Fixed (cookie theme colour defaults — QLB_GDPR_V2.1, 2026-05-22)
etc/config.xml— the custom-theme colour group seeded only 6 of the 32 admin colour fields, so the other 26 pickers rendered empty even thoughQoliber\GdprCookie\ViewModel\Theme::LIGHT_DEFAULTSdefines the full palette. Seeded all 32 fields fromLIGHT_DEFAULTSso every colour picker is pre-filled out of the box.Model/Config/Backend/ConsentEnabledValidator— the "cannot enable Cookie Consent" DPO errors pointed to a non-existent section ("Stores > Config > Data Subject Requests > DPO"). Corrected to the real path: "Stores > Config > GDPR Compliance > Data Subject Rights > Data Protection Officer".
Added (US privacy laws — QLB_GDPR_V2.1, 2026-05-20)
Model/Config/Source/ComplianceMode+etc/adminhtml/system.xmlcompliancegroup: a store-view-scoped Compliance Mode (gdpr_optindefault /us_optout), plus "Honour GPC", "Show Do Not Sell link", and link-text fields.etc/config.xmlseeds the defaults. Lets a merchant run EU store views opt-in and US store views opt-out (CCPA/CPRA, Virginia, Colorado, Connecticut, …).- See
Qoliber_GdprCookiefor the runtime (GPC detection, opt-out cookie behaviour, Do Not Sell link) anddocs/US-PRIVACY-LAWS.mdfor the merchant guide.
Added (theming — QLB_GDPR_V2.1, 2026-05-20)
Model/Config/Source/ConsentTheme—Custom (admin-defined colours)option added alongside Light / Dark.etc/adminhtml/system.xml— newtheme_customgroup with 6 "basics" colour pickers + ~24 "advanced" fields, gated by<depends>onconsent/theme = custom.etc/config.xml—theme_customdefaults (the six basics) seeded from the Light preset.Block/Adminhtml/System/Config/Field/Color— HTML5 colour-picker field renderer paired with a hex text input (sorgba()/ box-shadow strings can be pasted for the advanced fields).Observer/FlushPageCacheOnConfigChange+etc/adminhtml/events.xml— purges the full-page cache when theqoliber_gdpr_cookieconfig section is saved (eventadmin_system_config_changed_section_qoliber_gdpr_cookie). Fixes pre-existing FPC staleness affecting the cookie banner texts / display style / theme — admin changes now show on the storefront immediately, no manual flush. 1 unit test (Test/Unit/Observer/FlushPageCacheOnConfigChangeTest).
Added
- acl.xml for Qoliber_GdprFrontend::config ACL resource
- Production readiness validator -- blocks cookie consent enablement without DPO + privacy policy
Fixed
- Google Tag script loads dynamically only after consent (deny-by-default)
- Missing strict_types declarations
Removed
- Hard Hyva dependency from composer.json
Changed
- Version bump from 1.0.0-rc1 to 1.0.0, PHP 8.4 support added
GdprFrontendHyva
Changed
- Version bump from 1.0.0-rc1 to 1.0.0
- PHP 8.4 support added
- Dependency on
qoliber/gdpr-frontendbumped to stable^1.0
Fixed
- GTM noscript tag now respects consent state (only rendered when analytics/marketing consent granted)
- Google Consent Mode v2 default-state handling aligned with base module
- Hyvä CSP registration applied to all inline consent scripts
Hyvä 1.4 / Tailwind v4 compatibility
- Verified against Hyvä theme
^1.4with Tailwind v4 JIT build - No code changes required — module uses only core Tailwind utilities present in the default theme
GdprGtm
Fixed
- Empty google-tag-manager-noscript.phtml populated with GTM noscript iframe fallback
Changed
- Version bump from 1.0.0-rc1 to 1.0.0, PHP 8.4 support added
GdprPolicy
Security (review findings — QLB_GDPR_V2.1, 2026-05-20)
- Removed the anonymous
POST /V1/gdpr/policy/consent/logREST route. It exposedPolicyConsentRepository::logConsent()— which accepts a caller-suppliedcustomerId— to unauthenticated callers, letting anyone forge policy-consent evidence against arbitrary customer IDs. All legitimate consent logging goes through the session-aware frontend controllers (Controller/Consent/Log,Controller/Policy/Accept), which derivecustomerIdfrom the customer session and never trust client input; the storefront JS posts to those, not this route. The authenticated read routes (selfwith forced%customer_id%, ACL-gated views) are unchanged.
Added
- PolicySection model, resource model, and collection classes
- CsrfAwareActionInterface on Consent/Log controller
- Policy re-consent wiring (2026-04-20):
ReconsentCheckerservice determines whether a customer must re-accept the active policy: returns true on version bump, false on contract/legal-obligation basis (compulsory acceptances don't re-prompt), true on legitimate-interests basis (allows objection prompt).Reconsentstorefront ViewModel — templates callneedsReconsent(); guests short-circuit to false, logged-in customers get a server-side check againsthasAcceptedCurrentVersion+ lawful-basis gate.- Fully unit-tested (8 tests covering version match, version change, all four bases, invalid inputs, repo-exception handling).
- GDPR Art. 6 lawful-basis integration (2026-04-20):
lawful_basisvarchar(50) nullable column + btree index onqoliber_gdpr_policy_consent.PolicyConsentInterface::LAWFUL_BASISconstant,getLawfulBasis()/setLawfulBasis()accessors on interface andPolicyConsentmodel.PolicyConsentRepository::save()stampsLawfulBasis::CONSENTon every new row that arrives without a basis — every policy acceptance is Art. 6(1)(a) CONSENT by definition; stamping at write time keeps evidence travelling with the row.BackfillPolicyConsentLawfulBasischunked data patch (5000 rows/pass) classifies historical rows as CONSENT; idempotent.- Module now depends on
Qoliber_GdprCore(via<sequence>inmodule.xml+ composer).
- Server-side policy acceptance evidence in Accept.php via policyConsentRepository->logConsent()
- Server-side evidence in privacy-policy.js modal flow
- Server-side evidence in privacy-policy-manager.js setAcceptance() -- ALL acceptance paths now log to DB
- Server-side evidence in Hyva privacy-policy.phtml
- needsReconsent() method in PrivacyPolicy ViewModel
Fixed
- Removed extra $policyType parameter from logConsent() call
- Removed undefined $policyType variable in PolicyConsentRepository
- Guarded getCmsPageId() with method_exists check
- Effective date "Today" replaced with actual formatted date
- h2 headers now bold in privacy policy content
- Effective date text color contrast improved
- Privacy policy consent link uses gdpr/policy/render route instead of generic Magento URL
- Default consent display_type changed to privacy_policy_link
Changed
- All localStorage keys unified to qoliber_gdpr_* prefix
- Version bump from 1.0.0-rc1 to 1.0.0, PHP 8.4 support added
GdprPolicyHyva
Fixed (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
view/frontend/templates/hyva/privacy/policy-card.phtml— "View Policy" card on the Hyvä Privacy Center now renders a self-contained Alpine modal that fetches/gdpr/policy/renderand displays the policy content inline. Previously, whendisplay_locationwas anything other thanmodal/cookie_consent, the card linked directly to/gdpr/policy/render— which is a JSON endpoint, so customers landed on a raw JSON page instead of formatted policy text. The new modal works regardless of admin display-location config.
Added
- Initial stable release of Hyvä theme compatibility for Qoliber GDPR Policy
- Hyvä-native privacy policy rendering templates using Tailwind CSS and Alpine.js
CookieConsentPluginfor Hyvä-specific integration with cookie consent flow- Hyvä layout integration via
etc/frontendconfiguration - Server-side policy acceptance evidence logged through the base
GdprPolicyrepository
Changed
- Version bump from 1.0.0-rc1 to 1.0.0
- PHP 8.4 support added
Hyvä 1.4 / Tailwind v4 compatibility
- Verified against Hyvä theme
^1.4with Tailwind v4 JIT build - No code changes required — module uses only core Tailwind utilities present in the default theme
Requirements
- PHP 8.1, 8.2, 8.3, or 8.4
hyva-themes/magento2-theme-module: ^1.3.11qoliber/gdpr-policy: ^1.0- Magento Framework
GdprPrivacyCenter
Changed (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
view/frontend/layout/customer_account.xml— sub-navigation entry under Privacy Center renamed from "My Consent History" to "Consent Preferences" (URLcustomer/consent/preferencesis unchanged). The page actually lets the customer accept / reject each consent AND shows the history of those decisions; the old label implied a read-only view.- Removed the duplicate Privacy Center sidebar entry that
Qoliber_GdprDataSubjectwas registering (itsview/frontend/layout/customer_account.xmlwas deleted). Two modules adding the same nav link is a real bug: the customer-journey spec now assertstoHaveCount(1)so a future re-introduction fails CI.
Fixed (release prep — QLB_GDPR_V2.1, 2026-04-27 → 2026-04-28)
Controller/Center/Index— guest visits to/customer/account/privacynow consistently 302 to login instead of fataling. The fix uses the standard MagentoCustomer\Controller\Plugin\AccountaroundExecute pattern.
Fixed
- Removed non-existent Qoliber_Core dependency from module.xml
- Controller/Center/Index.php missing parent::__construct() call
- Privacy Center nav link path (customer/account/privacy)
- Consent History nav link path (gdpr-consent/customer/index)
Changed
- Version bump from 1.0.0-rc1 to 1.0.0, PHP 8.4 support added
GdprPrivacyCenterHyva
Added
- Initial stable release of Hyvä theme compatibility for Qoliber GDPR Privacy Center
- Hyvä-native customer account privacy dashboard templates
- Quick action cards for data export, rectification, anonymization, and account closure
- Tailwind CSS styling consistent with Hyvä design system
- Responsive mobile-first layout for privacy center pages
- Customer account navigation integration in Hyvä layouts
Changed
- Version bump from 1.0.0-rc1 to 1.0.0
- PHP 8.4 support added
Fixed
- EOF normalization in
view/frontend/tailwind/tailwind-source.css(trailing newline) applied by Hyvä source scanner during Tailwind v4 build — confirms the file is picked up bynpx hyva-sources
Requirements
- PHP 8.1, 8.2, 8.3, or 8.4
hyva-themes/magento2-theme-module: any versionqoliber/gdpr-privacy-center: any version- Magento Framework
GdprYireoGtm
Changed
- Version bump from 1.0.0-rc1 to 1.0.0, PHP 8.4 support added
1.0.0-rc1 — 2025-08-27
GdprAdmin
Added
- Created administrative GDPR dashboard with compliance score calculation based on active policies, cookie categories, processing activities, and pending requests
- Implemented unified admin menu structure for centralized GDPR management
- Added Data Processing Activities tracking system with legal basis documentation (GDPR Article 30 record of processing activities)
- Developed processing activities database schema with support for activity name, description, legal basis, data categories, retention periods, and recipients
- Created admin grid for viewing and managing GDPR data subject requests across all modules
- Implemented RequestsDataProvider for UI component listing with filtering and sorting capabilities
- Added Dashboard block with real-time statistics including request counts by status, recent consent logs, and consent statistics by type and action
- Developed compliance score metric that evaluates: active privacy policies (25%), configured cookie categories (25%), documented processing activities (25%), and timely request handling (25%)
- Created ACL resources for role-based access control to GDPR administrative functions
- Implemented admin routing configuration for dashboard and requests management pages
- Added admin layout XML files for dashboard and requests listing views
- Created UI component XML configuration for GDPR requests listing grid with custom columns
- Implemented source models for request types (fetch_data, anonymize, delete, rectification, objection, restriction) and request statuses (pending, processing, completed, failed, expired)
- Added ProcessingActivity model, resource model, and collection for ROPA (Record of Processing Activities) management
- Developed database indexes for efficient querying of processing activities
- Created system configuration section for GDPR admin settings under Stores > Configuration
- Implemented admin menu items under Privacy & GDPR section with access to Dashboard and Data Subject Requests
- Added support for tracking customer consent history and GDPR request lifecycle
- Created comprehensive database schema with timestamped audit trails for all processing activities
Technical Details
- Database table:
qoliber_gdpr_processing_activitieswith fields for activity tracking, legal basis, data categories, retention periods, and recipients - Admin controllers for dashboard display and request management interface
- Integration with Magento Backend, UI components, and admin routing system
- Support for multi-store environments with store-scoped configurations
GdprConsent
Added
- Created comprehensive consent management system with support for explicit user consent tracking
- Implemented ConsentDefinition entity for managing different types of consent (marketing, analytics, terms, privacy policy)
- Developed ConsentTracker service for recording consent acceptance with IP address and user agent logging
- Added consent snapshot functionality to preserve exact consent text version at time of acceptance (GDPR Article 7 proof of consent)
- Created multi-store consent label support with store-view-specific translations
- Implemented consent log database schema with customer consent history tracking including order association
- Developed ConsentDefinitionRepository and ConsentLogRepository for consent data management
- Added form location tracking for consents across registration, checkout, contact, and newsletter forms
- Created renderer pool system with Text and CMS Page renderers for flexible consent display
- Implemented consent checkbox integration for customer registration forms
- Added consent collection during checkout process with PaymentInformationManagement and ShippingInformationManagement plugins
- Developed newsletter subscription consent tracking with dedicated plugins
- Created contact form consent integration with PostPlugin
- Implemented customer account consent history view with revocation capability
- Added admin consent management interface with create, edit, delete, and mass operations
- Developed consent log viewer in admin with customer email lookup and filtering
- Created consent information display in admin order view showing accepted consents per order
- Implemented customer consent tab in admin customer edit page
- Added ConsentConfigProvider for checkout page consent rendering via Knockout.js
- Developed consent preferences page for customers to view and manage their consent choices
- Created consent link service for generating privacy policy and terms links
- Implemented consent validation rules system with JSON-based configuration
- Added support for required vs optional consents with frontend validation
- Developed consent display types: text, CMS page link, external URL with configurable link targets (_self, _blank, modal)
- Created InstallDefaultConsents data patch installing pre-configured consent definitions for terms, privacy policy, marketing, and newsletter
- Implemented UpdateConsentTextLinks data patch for consent link management
- Added console command for listing all configured consents (gdpr:consent:list)
- Developed ConsentList block for frontend consent display with renderer support
- Created checkout GdprConsents block for consent collection during order placement
- Implemented customer consent history block showing granted/revoked consent timeline
- Added order view consent information block for admin
- Developed Ajax consent logging endpoint for asynchronous consent tracking
- Created consent save controller for customer preference updates
- Implemented mass enable/disable operations for admin consent management
- Added ACL resources for granular consent management permissions
- Developed admin routing for consent CRUD operations and consent log viewing
- Created UI components for consent listing and form editing with custom columns
- Implemented consent status column renderer for admin grids
- Added customer email column renderer with customer account linking
- Created form locations multi-select column renderer
- Developed event observers for checkout success, customer registration, and order placement
- Implemented frontend events configuration for consent tracking on key customer actions
- Added WebAPI configuration for REST endpoint exposure
- Created extension attributes for order consent data attachment
- Implemented system configuration for consent module settings
- Added frontend routes for consent preferences and customer consent management
- Developed consent snapshot serialization with full consent text preservation
- Created IP address and user agent tracking for consent audit trail
- Implemented guest email consent tracking separate from customer consent
- Added consent revocation timestamp tracking
- Developed additional data field for consent-specific metadata storage
- Created database indexes for efficient consent lookup by customer ID, email, consent code, and acceptance date
- Implemented foreign key constraints for data integrity across consent tables
- Added store ID tracking for multi-store consent management
- Developed order entity association for checkout consent linking
Technical Details
- Database tables:
qoliber_gdpr_consent_definition,qoliber_gdpr_consent_store_label,qoliber_gdpr_consent_customer_log,qoliber_gdpr_consent_log - ConsentTracker service captures consent with IP, user agent, store context, and full consent snapshot
- Consent snapshot stored as JSON with consent ID, code, title, description, checkbox text, required flag, timestamp, and store ID
- Support for multiple form locations: registration, contact, newsletter, checkout, custom
- Renderer pool architecture allows extensible consent display formats
- Plugin-based integration ensures consent collection across Magento checkout flow
- Multi-language support via store-specific consent labels
- Granular ACL permissions for consent administration
- API interfaces for programmatic consent management
- Frontend layout integration across customer account, checkout, registration, contact, and newsletter pages
- Observer pattern for automated consent logging on customer lifecycle events
GdprConsentHyva — 2024
Added
- Initial Hyva theme compatibility module for Qoliber GDPR Consent
- Magewire Component Integration: Implemented
GdprConsentsMagewire component for Hyva Checkout integration- Real-time consent state management using Magewire reactive properties
- Implements
EvaluationInterfacefor Hyva Checkout validation workflow - Live consent synchronization with checkout session
- Component lifecycle methods (mount, acceptAll, rejectAll, clearConsents)
- Protected methods from frontend calls via uncallables configuration
- Full-screen loading indicators for consent actions
- Alpine.js Component: Created
qoliberGdprConsentAlpine.js component following Hyva patterns- Boolean object pattern for modal visibility management
- Error state handling with visual feedback (red text on invalid required consents)
- Real-time error message updates via custom events
- Integration with Hyva's createBooleanObject helper
- Hyva Checkout Templates: Purpose-built templates for Hyva Checkout
- Magewire-powered checkout consents template with wire:model bindings
- Modal slide-out panel for consent details with Tailwind transitions
- Accept All / Required Only action buttons
- Responsive design with mobile-first approach
- Heroicons Solid integration for UI consistency
- Layout Integration: Comprehensive Hyva layout support
hyva_checkout_components.xml: Magewire component registration in checkout flowhyva_default.xml: Global Hyva theme integrationhyva_contact_index_index.xml: Contact form consent integrationhyva_customer_account_create.xml: Registration form consentshyva_newsletter_manage_index.xml: Newsletter subscription consentshyva_customer_account_privacy.xml: Privacy dashboard integrationhyva_customer_consent_preferences.xml: Consent preference managementdefault_hyva.xml: Fallback layout for Hyva detection
- Customer Privacy Dashboard: Hyva-styled templates for consent management
hyva_hero.phtml: Hero section with gradient backgroundshyva_history.phtml: Consent history timeline viewhyva_current-status.phtml: Current consent status cards- Privacy center card integration with Tailwind styling
- Newsletter Integration: Enhanced newsletter subscription with consent handling
- Subscribe template with inline consent checkboxes
- Proper consent validation before subscription
- Consent Rendering System: ConsentRendererPool integration
- Dynamic checkbox text rendering with privacy policy links
- HTML content support with proper escaping
- Fallback mechanisms for renderer failures
- Event Handling: Observer pattern for checkout workflow
CheckoutSubmitAllAfterObserver: Persists consents after order placement- Event-driven architecture for consent state changes
- Dependency Injection: Proper DI configuration
- Frontend DI configuration for Hyva-specific services
- Plugin system integration
- Tailwind CSS Configuration: Custom Tailwind config for GDPR styling
- GDPR-specific color palette (primary: #006bb4, error: #ef4444)
- Template scanning configuration for JIT compilation
- CSP Compliance: Content Security Policy support via Hyva CSP helper
- Inline script registration for CSP compatibility
- Proper nonce handling for Alpine.js components
Technical Details
- Magewire Features:
- Component state persistence in checkout session (
qoliber_gdpr_consentssession key) - Checksum-safe data structures (simplified IDs to prevent encoding issues)
- Limited to 5 consents for performance (configurable page size)
- Event emission for consent updates (
gdpr-consents-updated) - Payment method integration via event emitting
- Component state persistence in checkout session (
- Validation System:
- Required consent validation in
evaluateCompletionmethod - Custom error events with consent details (
gdpr-consents:details:error) - Success events for completed validation
- User-friendly error messages with missing consent titles
- Required consent validation in
- Alpine.js Architecture:
- Error tracking per consent item via dataset attributes
- Dynamic error class binding (text-red-600 on error)
- Modal visibility management with transitions
- Event-driven error state updates
- Template Features:
- Wire model bindings for real-time updates (
wire:model="consent.{id}") - Conditional rendering based on consent requirements
- Slide-out modal with backdrop overlay
- Accessible markup with ARIA attributes
- Heroicons integration for consistent iconography
- Wire model bindings for real-time updates (
Dependencies
- PHP 8.1, 8.2, or 8.3
- Magento Framework
- qoliber/gdpr-consent: 1.0.0-rc1 || ^1.0
- hyva-themes/magento2-theme-module: ^1.3.11
- qoliber/hyva-module-registration
Compatibility
- Magento 2.4.x
- Hyva Theme 1.3.11+
- Hyva Checkout (Magewire-based)
GdprCookie
Added
- Created comprehensive cookie management system for GDPR compliance with cookie categorization
- Implemented CookieCategory entity with support for essential, marketing, and analytics cookie types
- Developed CookieDetail entity for individual cookie documentation with provider information
- Added cookie category translation system supporting multi-language cookie descriptions per store view
- Created cookie detail translation tables for localized cookie explanations
- Implemented cookie provider registry with IAB TCF (Transparency and Consent Framework) vendor support
- Developed detected cookies tracking system for automatic cookie discovery and classification
- Added cookie scanner detection with first/last detected timestamps and detection count
- Created regex pattern matching for cookie names supporting wildcard cookie detection (e.g., ga, cto_)
- Implemented cookie duration tracking with session/persistent/days format
- Added cookie type classification: HTTP cookies, Local Storage, Session Storage
- Developed cookie domain and path tracking for cross-domain cookie management
- Created InstallDefaultCookies data patch with pre-configured essential, marketing, and analytics categories
- Implemented essential cookies setup including Magento session, form_key, and security cookies
- Added marketing cookies configuration for advertising and tracking services
- Developed analytics cookies setup for Google Analytics and user behavior tracking
- Created InstallGoogleConsentCategory data patch for Google Consent Mode v2 compliance
- Implemented MigrateGoogleCookiesToNewCategory data patch for cookie recategorization
- Added cookie category admin interface with create, edit, delete, and mass operations
- Developed cookie detail admin management with import functionality
- Created cookie category repository with search capabilities
- Implemented cookie detail repository with filtering and sorting
- Added CookieDetailDataProvider for admin UI component forms
- Developed category options UI component for category selection dropdowns
- Created cookie category name column renderer for admin grids
- Implemented cookie detail actions column with edit/delete operations
- Added cookie category actions column with admin action buttons
- Developed cookie category options component for filtering
- Created cookie consent ViewModel for frontend cookie banner integration
- Implemented admin routing for cookie category and detail management
- Added ACL resources for cookie management permissions
- Developed UI component XML for cookie detail listing grid with provider, type, duration, and category columns
- Created UI component forms for cookie category editing with translation support
- Implemented cookie detail form with category assignment, provider URL, and technical specifications
- Added cookie provider management with privacy policy URL tracking
- Developed IAB vendor integration with vendor ID and purposes JSON storage
- Created detected cookies table for unclassified cookie tracking with classification workflow
- Implemented cookie classification linking between detected and categorized cookies
- Added frontend layout integration for customer privacy center cookie preferences
- Developed default layout integration for cookie consent banner display
- Created cookie import functionality for bulk cookie addition from templates
- Implemented save and continue button for cookie detail editing
- Added delete button with confirmation for cookie removal
- Developed back button for admin navigation consistency
- Created generic button base class for admin form actions
- Implemented cookie detail save controller with validation
- Added cookie category save controller with translation support
- Developed mass delete operation for cookie categories
- Created mass enable/disable operations for bulk cookie category management
- Implemented cookie category edit controller with form data loading
- Added new action controllers for cookie category and detail creation
- Developed cookie category index controller for listing view
- Created admin menu items under Privacy & GDPR > Cookie Management section
- Implemented system configuration support for cookie management settings
- Added database indexes for efficient cookie lookup by name, provider, and classification status
- Developed foreign key constraints ensuring referential integrity across cookie tables
- Created unique constraints for cookie category codes and provider names
- Implemented timestamp tracking for cookie creation and updates
- Added sort order support for cookie category display ordering
- Developed is_active flag for cookie detail enabling/disabling
- Created is_required flag for essential vs optional cookie categorization
- Implemented is_enabled flag for cookie category activation
- Added is_regex flag for pattern-based cookie matching
- Developed is_classified flag for detected cookie processing status
- Created is_iab_vendor flag for IAB TCF vendor identification
Technical Details
- Database tables:
qoliber_gdpr_cookie_categories,qoliber_gdpr_cookie_categories_translation,qoliber_gdpr_cookie_details,qoliber_gdpr_cookie_details_translation,qoliber_gdpr_cookie_providers,qoliber_gdpr_detected_cookies - Cookie categories support multi-language descriptions via translation table with locale and store ID
- Cookie details include technical specifications: name, provider, type, duration, domain, description
- Regex pattern matching enables wildcard cookie detection for dynamic cookie names
- Detected cookies table tracks unclassified cookies with automatic detection counting
- IAB TCF vendor support enables Transparency and Consent Framework compliance
- Cookie providers table maintains centralized provider information with privacy policy URLs
- Translation tables use unique constraints on (entity_id, store_id, locale) for data integrity
- Admin UI components use DataProvider pattern for form population
- Frontend ViewModel pattern for cookie consent banner data exposure
- Repository pattern for cookie CRUD operations with search criteria support
- Mass action support for bulk cookie category operations
- Import functionality enables quick cookie setup from predefined templates
GdprCookieHyva — 2024
Added
- Initial Hyva theme compatibility module for Qoliber GDPR Cookie
- Advanced Cookie Consent Modal: Full-featured Alpine.js-powered cookie consent interface
- Multi-layout support: center popup, left sidebar, right sidebar, bottom banner
- Responsive design with mobile-first approach and adaptive layouts
- Three-tab interface: Consent, Details, About
- Smooth transitions and animations using Tailwind CSS
- Backdrop blur and overlay effects for center popup mode
- Category-Based Cookie Management: Granular cookie control system
- Dynamic category loading from backend configuration
- Toggle switches for optional cookie categories
- Always-enabled essential/necessary cookies
- Visual distinction for required vs optional categories (disabled state styling)
- Cookie count display per category
- Detailed Cookie Information Display: Expandable accordion interface
- Individual cookie details (name, description, provider, duration, type)
- Collapsible category sections with smooth transitions
- Provider and technical metadata display
- Search-friendly cookie documentation
- Multiple Consent Actions: Flexible consent management
- Accept All: Enable all cookie categories
- Deny All: Keep only essential/necessary cookies
- Allow Selection: Save custom category preferences
- Cookie Settings: Expand full configuration interface
- Privacy Policy Integration: Inline privacy policy modal
- AJAX-loaded privacy policy content via
/gdpr/policy/view - Loading and error states with visual feedback
- Modal-within-modal architecture
- Clickable privacy policy links with custom styling
- Title and content dynamic loading
- AJAX-loaded privacy policy content via
- Google Consent Mode v2 Integration: Advanced Google consent management
- Default consent state configuration (granted/denied)
- Dynamic consent updates based on user preferences
- Category mapping: marketing → ad_storage/ad_personalization, analytics → analytics_storage
- Always-granted categories: functionality_storage, security_storage
- URL passthrough support for ad click tracking
- Ads data redaction when consent denied
- Wait for update configuration (default 500ms)
- Debug mode with console logging
- Consent state persistence in localStorage (
qoliber_google_consent)
- Hyva Cookie System Integration: Seamless Hyva theme compatibility
window.cookie_consent_groupsintegrationwindow.cookie_consent_configmapping- Essential/necessary category synchronization (dual mapping for compatibility)
- Critical Magento cookie protection (PHPSESSID, form_key, etc.)
- Event-driven cookie consent updates (
user-allowed-save-cookie) - Custom event emission (
qoliber-gdpr-consent-updated) - Cookie restriction mode enablement
- Temporary cookie storage handling
- Local Storage Persistence: Client-side consent management
- Consent data structure: accepted, categories, timestamp, version
- Cookie lifetime configuration (default 365 days)
- Dual persistence: localStorage + Hyva cookie system
- Consent restoration on page load
- Reopener Button: Persistent consent management access
- Floating action button (bottom-left)
- Appears after initial consent given
- Hover effects and scale animations
- Restores saved selections when reopened
- Z-index management for proper layering
- Tab Navigation System: Organized information architecture
- Active tab highlighting with bottom border
- Smooth content transitions
- Default consent tab on open
- Persistent tab state during modal interactions
- Theme Configuration: Customizable Hyva theme integration
- Theme config template for backend-driven styling
- Display style detection and class management
- Computed properties for layout adaptation
- Responsive height constraints per layout
- Privacy Center Integration: Customer account privacy dashboard
- Cookie management card in privacy center
- Reopen settings from privacy dashboard
- Global event listener for settings reopening (
gdpr-reopen-settings)
- CSP (Content Security Policy) Support: Security-compliant inline scripts
- Hyva CSP helper integration
- Proper script registration for CSP nonce support
- Generated obfuscated function names for CSP compatibility
- Data attribute-based translations for CSP-safe text injection
- Checkout Integration: Cookie consent in checkout flow
- Dedicated checkout layout (
hyva_checkout_index_index.xml) - Non-blocking consent collection during checkout
- Dedicated checkout layout (
- Tailwind CSS Configuration: Custom Tailwind config for cookie consent
- Template scanning for JIT compilation
- Prose styling for policy content
- Transition utilities configuration
Technical Details
- Alpine.js Architecture:
- Main component:
gdprCookieConsent()with reactive properties - CSP-safe wrapper:
qoliberGdprCookieHyvaHyvaCookieConsent()with obfuscated methods - Computed properties: displayStyle, categories, texts, googleConsent
- Layout-specific class getters:
getContainerClass(),getContentClass()
- Main component:
- State Management:
isVisible: Modal visibility controlshowSettings: Expanded settings view toggleshowReopener: Floating button visibilityactiveTab: Current tab selection (consent/details/about)selectedCategories: User-selected cookie categories arrayexpandedCategories: Accordion expansion state objectshowPrivacyModal: Privacy policy modal visibility
- Cookie Mapping System:
- Backend-driven cookie-to-category mapping
- Pattern-based cookie matching support
- Magento critical cookie automatic inclusion
- Essential/necessary dual-category mapping for Hyva compatibility
- Cookie consent groups initialization from saved data
- Event System:
qoliber-gdpr-consent-updated: Fired on consent changes with category detailsuser-allowed-save-cookie: Hyva integration eventgdpr-reopen-settings: External reopen triggerqoliberGoogleConsentUpdated: Google consent update notification (debug mode)
- Google Consent Configuration:
ad_storage: Marketing consent mappingad_user_data: Marketing consent mappingad_personalization: Marketing consent mappinganalytics_storage: Analytics consent mappingfunctionality_storage: Always grantedpersonalization_storage: Marketing consent mappingsecurity_storage: Always granted
- Layout Variations:
- Center: Full-screen overlay with centered modal (max-w-4xl)
- Bottom: Banner at bottom with horizontal layout option
- Left: Sidebar from left edge (max-w-md)
- Right: Sidebar from right edge (max-w-md)
- Responsive Behavior:
- Mobile-first design with
md:breakpoint adaptations - Flexible header layout in bottom mode
- Adaptive height constraints per display style
- Touch-friendly toggle switches and buttons
- Mobile-first design with
Dependencies
- Magento Framework
- hyva-themes/magento2-theme-module: ^1.3
- qoliber/gdpr-cookie
- qoliber/hyva-module-registration
Compatibility
- Magento 2.4.x
- Hyva Theme 1.3+
- Google Tag Manager (optional, for Consent Mode v2)
- Alpine.js 3.x (included in Hyva)
- Tailwind CSS 3.x (Hyva default)
GdprCookieTemplates
Added
- Created pre-configured cookie template library for common third-party services
- Implemented CookieTemplateService providing standardized cookie definitions for popular platforms
- Added Google Analytics cookie templates including _ga, _gid, _gat, and ga* pattern cookies with accurate durations
- Developed Facebook Pixel cookie templates for _fbp, _fbc, and fr cookies with Meta privacy policy links
- Created Criteo advertising cookie templates with cto_* pattern and criteo cookies
- Implemented PayPal payment cookie templates including paypal, PYPF, and ts security cookies
- Added Hotjar analytics cookie templates for _hjid, hjSessionUser*, and _hjIncludedInSessionSample
- Developed Mailchimp email marketing cookie templates for landing site and user email tracking
- Created Klaviyo marketing automation cookie templates including __kla_id and klaviyo cookies
- Implemented Trustpilot review widget cookie templates with trustpilot and tp_* patterns
- Added Yotpo reviews and loyalty cookie templates with yotpo_* pattern and yotpo_site_uid
- Developed Bing Ads conversion tracking cookie templates for _uetmsclkid and uetmsclkid* patterns
- Created template structure with cookie name, description, type (HTTP/Local Storage/Session), duration, provider, and privacy URL
- Implemented regex pattern support in templates for wildcard cookie matching (ga, cto_, tp_, yotpo_, etc.)
- Added getTemplate() method for retrieving individual service templates by key
- Developed getTemplateNames() method returning dropdown-formatted template list for admin UI
- Created comprehensive provider privacy policy URL mappings for GDPR transparency requirements
- Implemented accurate cookie duration specifications (session, minutes, hours, days, months, years)
- Added cookie type classification (HTTP, Local Storage, Session Storage) for each template entry
- Developed template keys: google_analytics, facebook_pixel, criteo, paypal, hotjar, mailchimp, klaviyo, trustpilot, yotpo, bing_ads
- Created detailed cookie descriptions explaining purpose and data collection for user transparency
- Implemented admin template index controller for template browsing interface
- Added admin routing configuration for cookie template management
- Developed integration with Qoliber_GdprAdmin for centralized GDPR administration
Cookie Templates Included
Google Analytics (4 cookies)
- _ga: 2-year user identification cookie
- _gid: 24-hour user distinction cookie
- _gat: 1-minute rate throttling cookie
- ga* (regex): 2-year session state persistence
Facebook Pixel (3 cookies)
- _fbp: 3-month advertisement delivery cookie
- _fbc: 2-year conversion tracking cookie
- fr: 3-month advertisement products cookie
Criteo (2 cookies)
- cto_* (regex): 13-month advertising and retargeting
- criteo: 13-month retargeting cookie
PayPal (3 cookies)
- paypal: Session payment processing cookie
- PYPF: 2-year fraud prevention cookie
- ts: 3-year security and fraud prevention
Hotjar (3 cookies)
- _hjid: 1-year user identification cookie
- hjSessionUser* (regex): 1-year session tracking
- _hjIncludedInSessionSample: 2-minute session sampling
Mailchimp (2 cookies)
- mailchimp_landing_site: 1-month landing page tracking
- mailchimp_user_email: 1-year user identification
Klaviyo (2 cookies)
- __kla_id: 2-year email marketing identification
- klaviyo: 2-year behavior tracking cookie
Trustpilot (2 cookies)
- trustpilot: 1-year review widget tracking
- tp_* (regex): 1-year functionality tracking
Yotpo (2 cookies)
- yotpo_* (regex): 1-year reviews and loyalty
- yotpo_site_uid: 1-year user identification
Bing Ads (2 cookies)
- _uetmsclkid: 1-year conversion tracking
- uetmsclkid* (regex): 1-year tracking and analytics
Technical Details
- CookieTemplateService returns structured arrays with name, description, type, duration, provider, provider_url, and is_regex flag
- Templates designed for one-click import into GdprCookie module
- Privacy policy URLs reference official provider documentation
- Regex patterns enable flexible cookie name matching for dynamic cookies
- Template structure compatible with CookieDetail entity model
- Service methods support both bulk template retrieval and individual template access
- Dropdown formatting for seamless admin UI integration
GdprDataSubject
Added
- Created comprehensive data subject rights management system implementing GDPR Articles 15-21
- Implemented DataRequest entity supporting fetch_data, anonymize, delete, rectification, objection, and restriction request types
- Developed unified GDPR requests database schema tracking customer ID, email, request type, status, source, and audit trail
- Added request status workflow: pending, processing, confirmed, completed, rejected, failed, expired, partially_completed
- Created request source tracking: customer, guest, admin for accountability
- Implemented token-based verification system for guest data access and email confirmation
- Developed request blocking mechanism with admin controls for reason, timestamp, and blocking user
- Added DataAnonymizationService orchestrating anonymization across multiple data anonymizers
- Created modular anonymizer architecture with interfaces: CustomerDataAnonymizer, OrderDataAnonymizer, QuoteDataAnonymizer, InvoiceDataAnonymizer, ShipmentDataAnonymizer, CreditMemoDataAnonymizer, NewsletterDataAnonymizer, DataRequestAnonymizer
- Implemented AbstractDataAnonymizer base class with faker integration for realistic fake data generation
- Developed CustomerDataAnonymizer replacing customer names, emails, phone numbers, addresses with anonymized values
- Created OrderDataAnonymizer for sales order data anonymization with configurable order status filtering
- Implemented QuoteDataAnonymizer for cart and quote data erasure
- Added InvoiceDataAnonymizer for invoice billing/shipping address anonymization
- Developed ShipmentDataAnonymizer for shipment address data replacement
- Created CreditMemoDataAnonymizer for credit memo address anonymization
- Implemented NewsletterDataAnonymizer for newsletter subscription data removal
- Added DataRequestAnonymizer for GDPR request history anonymization
- Developed data fetcher system with interfaces for extracting customer data across entities
- Created CustomerDataFetcher extracting customer profile, addresses, and account information
- Implemented OrderDataFetcher gathering order history with items, addresses, and payment data
- Added QuoteDataFetcher for active cart data retrieval
- Developed InvoiceDataFetcher for invoice records extraction
- Created ShipmentDataFetcher for shipment history compilation
- Implemented CreditMemoDataFetcher for credit memo data export
- Added NewsletterDataFetcher for subscription status extraction
- Developed CustomerAddressDataFetcher for address book data collection
- Created DataFetcherService orchestrating all fetchers for complete customer data export
- Implemented DataConversionService supporting CSV, JSON, and TXT export formats
- Developed CsvConverter generating CSV files from customer data arrays
- Created JsonConverter producing formatted JSON exports
- Implemented TxtConverter generating human-readable text file exports
- Added DynamicExportFormat source model with pluggable converter architecture
- Developed cron job ProcessAnonymizationRequests executing every 15 minutes with batch processing (250 requests per run)
- Created cron job ProcessDeletionRequests for automated customer account deletion
- Implemented cron job ProcessDataFetchRequests for data export generation
- Added cron job ProcessDataAccessNotifications for email notification delivery
- Developed cron job CleanupExpiredRequests removing expired tokens daily at 2 AM
- Created ProcessEmailQueue cron job for asynchronous email delivery with retry logic
- Implemented email queue system with pending, processing, sent, failed statuses and retry counting
- Added DataRequestRepository with search capabilities and status filtering
- Developed request notes system with internal, customer, system, and compliance note types
- Created admin request view interface with details, history, and notes tabs
- Implemented admin request management with approve, deny, block, unblock, mark reviewed actions
- Added customer privacy center interface for data access, rectification, deletion, and objection requests
- Developed guest request submission system with email verification
- Created view data controller for guest access to exported data via secure token
- Implemented data request verification with token validation and expiration checking
- Added customer account privacy page with request history and status tracking
- Developed customer deletion confirmation workflow with email verification
- Created anonymization request submission with preservation options
- Implemented rectification request interface for data correction
- Added objection and restriction request types for marketing and processing objections
- Developed admin view for request details with comprehensive request information display
- Created request history tracking with created_at, updated_at, completed_at, verified_at, reviewed_at, accessed_at timestamps
- Implemented IP address and user agent logging for request audit trail
- Added store ID tracking for multi-store request management
- Developed admin user tracking for admin-initiated actions
- Created request data and response data JSON fields for flexible metadata storage
- Implemented expires_at timestamp for automatic request expiration
- Added email_sent_at tracking for notification delivery confirmation
- Developed blocked_at, blocked_by, blocked_reason fields for request blocking workflow
- Created reviewed_at, reviewed_by fields for admin review tracking
- Implemented FakerInterface for generating realistic anonymized data
- Added partial email anonymization (j***@example.com format) for privacy
- Developed DataSubjectConfigInterface for configuration management
- Created Config source models for OrderStatus, ExportFormat, DynamicExportFormat
- Implemented RequestType, RequestSource, RequestStatus source models for admin UI
- Added email templates for verification, confirmation, completion, and notifications
- Developed ViewData block for guest data access interface
- Created GuestForm block for guest request submission
- Implemented admin View block with request details, notes, and history
- Added Notes block for admin request note management
- Developed Details block displaying comprehensive request information
- Created History block showing request lifecycle events
- Implemented frontend controllers for guest data request, verification, and access
- Added export download controller with secure token validation
- Developed customer privacy controller integrating all data subject rights
- Created customer deletion, anonymization, rectification, objection, restriction controllers
- Implemented admin controllers for request view, approve, deny, block, unblock, add notes, mark reviewed
- Added anonymization status tracking with confirm endpoint
- Developed anonymization request creation linking to original fetch_data request
- Created frontend routes for gdpr/request, gdpr/guest, gdpr/export, gdpr/account/privacy
- Implemented admin routes for request management under qoliber_gdpr namespace
- Added ACL resources for data subject request management permissions
- Developed admin menu items under Privacy & GDPR > Data Subject Requests
- Created system configuration section for data subject settings
- Implemented configurable allowed order statuses for anonymization (complete, closed, canceled)
- Added configurable request expiration periods
- Developed configurable export format selection
- Created email queue with scheduled_at, sent_at timestamps and error tracking
- Implemented retry mechanism with retry_count and error_message logging
- Added foreign key from email queue to requests table with cascade delete
- Developed indexes for efficient request lookup by customer_id, email, type, status, token, dates
- Created indexes for email queue status and scheduled_at for cron optimization
- Implemented request notes indexes by request_id, note_type, created_at
- Added ramsey/uuid dependency for secure token generation
- Developed comprehensive logging throughout anonymization and data fetching processes
- Created area emulation for admin context execution in cron jobs
- Implemented preserveEmail option allowing email retention during anonymization
- Added original_request_id linking for anonymization request tracking
- Developed anonymization_status updates on original fetch_data requests
- Created website store ID aggregation for multi-store data processing
- Implemented batch processing limits preventing timeout on large datasets
- Added error handling with partial completion support
- Developed anonymization result tracking with total_anonymized count
- Created success/failure status reporting with detailed error arrays
GDPR Rights Implemented
Right to Access (Article 15)
- Complete customer data export in CSV, JSON, or TXT format
- Fetchers extract data from customers, orders, quotes, invoices, shipments, credit memos, newsletters, addresses
- Secure token-based guest access to exported data
- Email notification with download link
- Configurable data retention and expiration
Right to Rectification (Article 16)
- Customer-initiated data correction requests
- Admin review and approval workflow
- Request tracking with status updates
Right to Erasure / Right to be Forgotten (Article 17)
- Automated customer account deletion with data removal
- Configurable order status filtering (only delete when orders complete/closed/canceled)
- Multi-store data removal across website stores
- Admin approval workflow for deletion requests
- Preservation options for legal/financial record retention
Right to Data Portability (Article 20)
- Machine-readable data export (JSON, CSV)
- Structured data format for transfer to other services
- Complete data extraction across all customer touchpoints
Right to Object (Article 21)
- Marketing objection request type
- Processing objection tracking
- Customer-initiated objection submission
Right to Restriction of Processing (Article 21)
- Processing restriction request type
- Temporary data processing suspension tracking
Data Anonymization Features
- Multi-entity anonymization: customers, orders, quotes, invoices, shipments, credit memos, newsletters, GDPR requests
- Faker-generated realistic replacement data maintaining data format integrity
- Configurable anonymization scope with entity-specific anonymizers
- Order status filtering preventing premature order data anonymization
- Email preservation option for legal compliance scenarios
- Comprehensive anonymization logging with success/failure tracking
- Partial completion support for error resilience
- Website-wide store aggregation ensuring complete multi-store anonymization
Cron Job Schedule
- ProcessDataAccessNotifications: Every 15 minutes
- ProcessAnonymizationRequests: Every 15 minutes (250 batch limit)
- ProcessDeletionRequests: Every 15 minutes
- CleanupExpiredRequests: Daily at 2:00 AM
- Email queue processing with retry logic
Technical Details
- Database tables:
qoliber_gdpr_requests,qoliber_gdpr_request_notes,qoliber_gdpr_email_queue - Request token generation using ramsey/uuid for cryptographic security
- Email queue system with status tracking, retry counting, and error logging
- Modular anonymizer architecture via dependency injection
- DataFetcherService aggregates all fetchers via DI array
- DataConversionService supports pluggable format converters
- Cron jobs use area emulation for proper admin context
- Foreign key constraints ensure referential integrity
- Comprehensive indexes optimize query performance for high-volume request handling
- Request lifecycle tracking with multiple timestamp fields for complete audit trail
- Multi-store support via store ID tracking and website store aggregation
- Guest verification via secure token with expiration
- Admin blocking mechanism for fraud prevention
- Request notes system for compliance documentation
- Configurable export formats via system configuration
- Batch processing prevents timeout on large anonymization operations
GdprDataSubjectHyva — 2024
Added
- Initial Hyva theme compatibility module for Qoliber GDPR Data Subject Rights
- Privacy Dashboard Templates: Comprehensive Hyva-styled privacy center
- Hero section with gradient backgrounds and modern card design
- GDPR rights overview with icon-based navigation
- Data types information display
- DPO (Data Protection Officer) contact information
- Quick actions section with action cards
- Quick Actions Cards: Modern card-based UI for GDPR rights
- Export Your Data: Purple gradient card with download icon
- Rectify Your Data: Cyan gradient card with edit icon
- Anonymize Your Data: Pink gradient card with lock icon (conditionally displayed)
- Delete Your Account: Red gradient card with trash icon (conditionally displayed)
- Hover effects: shadow elevation, border highlighting, vertical translation
- Smooth scroll navigation to export form via Alpine.js click handler
- Responsive grid layout (1 column mobile, 2 tablet, 3 desktop)
- Data Export Interface: Hyva-styled data export functionality
- Guest data export form with modern styling
- Format selection interface
- Export form template integration
- Guest User Templates: Dedicated templates for non-authenticated users
- Guest data request form (
hyva/datasubject/guest/data-request.phtml) - View data interface (
hyva/datasubject/guest/view-data.phtml) - Anonymization confirmation (
hyva/datasubject/guest/anonymization-confirm.phtml)
- Guest data request form (
- Customer Account Templates: Authenticated user data subject rights
- Account deletion request form (
hyva/datasubject/customer/delete.phtml) - Anonymization request form (
hyva/datasubject/customer/anonymize.phtml) - Rectification request form (
hyva/datasubject/customer/rectification.phtml)
- Account deletion request form (
- Anonymization Workflow: Multi-step anonymization process
- Status tracking interface (
hyva/anonymization/status.phtml) - Confirmation step template
- Status-based UI updates
- Status tracking interface (
- Privacy Center Integration: Seamless integration with GDPR Privacy Center
- Privacy dashboard template (
hyva/datasubject/privacy-dashboard.phtml) - Rights overview cards
- Data types information display
- DPO contact integration
- Quick actions grid with conditional rendering
- Privacy dashboard template (
- Privacy Account Cards: Modular privacy action cards
- Delete card (
customer/privacy/cards/delete.phtml) - Export card (
customer/privacy/cards/export.phtml) - Rectify card (
customer/privacy/cards/rectify.phtml) - Anonymize card (
customer/privacy/cards/anonymize.phtml)
- Delete card (
- Layout Integration: Comprehensive Hyva layout support
hyva_gdprds_guest_viewdata.xml: Guest data view layouthyva_gdprds_customer_delete.xml: Customer deletion layouthyva_customer_account_privacy.xml: Privacy center layouthyva_gdprds_guest_datarequest.xml: Guest data request layouthyva_gdprds_customer_anonymize.xml: Anonymization request layouthyva_gdprds_anonymization_status.xml: Anonymization status layouthyva_gdprds_anonymization_confirm.xml: Confirmation layouthyva_gdprds_customer_rectification.xml: Rectification layout
- Conditional Feature Display: Backend configuration-driven UI
- Anonymization card shown only if enabled via
$configViewModel->isAnonymizationEnabled() - Deletion card shown only if enabled via
$configViewModel->isDeletionEnabled() - Dynamic grid adaptation based on enabled features
- Anonymization card shown only if enabled via
- ViewModel Integration: Proper data layer separation
- Privacy ViewModel integration (
Qoliber\GdprDataSubject\ViewModel\Privacy) - Config ViewModel integration (
Qoliber\GdprDataSubject\ViewModel\Config) - Template-level data access via view models
- Privacy ViewModel integration (
- Tailwind CSS Styling: Modern, responsive design system
- Gradient backgrounds (purple-to-indigo, cyan-to-blue, pink-to-rose, red-to-orange)
- Shadow utilities (shadow-lg, shadow-xl, shadow-2xl)
- Transition effects (duration-300, ease-in-out)
- Hover states with transform utilities
- Border utilities with hover effects
- Responsive spacing and typography
- Icon System: SVG-based iconography
- Download icon for data export
- Edit/pencil icon for rectification
- Lock icon for anonymization
- Trash icon for deletion
- Arrow icons for navigation
- Consistent sizing (w-8 h-8 for card icons, w-4 h-4 for inline)
- Smooth Scroll Navigation: Enhanced UX for in-page navigation
- Alpine.js @click.prevent handlers
- ScrollIntoView with smooth behavior
- Anchor-based navigation with scroll offset
- Tailwind Configuration: Custom Tailwind config for data subject features
- Template scanning configuration
- JIT compilation support
Technical Details
- Card Component Architecture:
- Base card:
bg-white rounded-xl p-8 shadow-lg hover:shadow-xl - Hover transformation:
hover:-translate-y-1 - Border animation:
border-2 border-transparent hover:border-{color}-500 - Icon container:
w-14 h-14 bg-gradient-to-br rounded-xl flex items-center justify-center
- Base card:
- Gradient Color Palette:
- Export:
from-purple-500 to-indigo-600 - Rectify:
from-cyan-500 to-blue-600 - Anonymize:
from-pink-500 to-rose-600 - Delete:
from-red-500 to-orange-600
- Export:
- Responsive Grid System:
- Mobile:
grid-cols-1(single column) - Tablet:
md:grid-cols-2(two columns) - Desktop:
lg:grid-cols-3(three columns) - Gap:
gap-6(1.5rem spacing)
- Mobile:
- Typography Hierarchy:
- Section headings:
text-2xl font-bold text-gray-800 - Card titles:
text-xl font-semibold text-gray-800 - Card descriptions:
text-gray-600 - Links:
font-semiboldwith color-specific classes
- Section headings:
- Alpine.js Integration:
- Smooth scroll handler:
@click.prevent="document.getElementById('export-form').scrollIntoView({ behavior: 'smooth', block: 'start' })" - Event-driven navigation
- Progressive enhancement approach
- Smooth scroll handler:
- Conditional Rendering Logic:
- PHP-based:
<?php if ($configViewModel && $configViewModel->isAnonymizationEnabled()): ?> - Backend-driven feature flags
- Clean template architecture
- PHP-based:
- Action URLs:
- Rectification:
/gdprds/customer/rectification - Anonymization:
/gdprds/customer/anonymize - Deletion:
/gdprds/customer/delete - Export: In-page anchor
#export-form
- Rectification:
Dependencies
- Magento Framework
- hyva-themes/magento2-theme-module
- qoliber/gdpr-data-subject
- qoliber/hyva-module-registration
Compatibility
- Magento 2.4.x
- Hyva Theme 1.3+
- Alpine.js 3.x (included in Hyva)
- Tailwind CSS 3.x (Hyva default)
User Experience Enhancements
- Visual Hierarchy: Clear distinction between action types via color-coded gradients
- Interactive Feedback: Hover states provide immediate visual feedback
- Accessibility: Semantic HTML with proper heading structure
- Mobile Optimization: Touch-friendly card sizes and responsive layouts
- Progressive Disclosure: Smooth scroll to detailed forms from quick actions
- Information Architecture: Logical grouping of related privacy functions
GdprFrontend — 2024
Added
- Cookie Consent UI Framework: Comprehensive frontend cookie consent banner implementation with customizable display styles (popup, banner, overlay) and visual themes
- Google Consent Mode v2 Integration: Full support for Google Consent Mode v2 API with configurable consent states (granted/denied) for analytics_storage, ad_storage, ad_user_data, and ad_personalization
- Tag Type System: Extensible tag type architecture via
TagTypeInterfaceallowing multiple tracking implementations:GoogleTagimplementation for native Google Analytics 4 (GA4) with G-XXXXXXXXXX ID format validationTagTypePoolfor managing multiple tag type providers
- Plugin System:
DisableNativeGoogleGtagPluginto prevent conflicts by disabling Magento's nativeMagento_GoogleGtagmodule when Google Consent Mode is enabled - Advanced Consent Configuration:
- Default consent state configuration (granted/denied)
- URL passthrough for ad click information when cookies are denied
- Ads data redaction when ad_storage is denied
- Configurable wait time for consent updates (0-10000ms)
- Debug mode for console logging of consent events
- Consent Popup Customization:
- Multiple display styles: popup, banner, overlay
- Theme selection for visual appearance
- Configurable to show on first visit
- Cookie settings reopener options (icon, link, both)
- Customizable icon position (bottom-left, bottom-right, top-left, top-right)
- Comprehensive Content Management:
- WYSIWYG editor support for consent message and policy content
- Configurable consent title and message
- "About Cookie Policy" section with custom title and HTML content
- "What Are Cookies" educational section
- "How We Use Cookies" explanation section
- Translation Support:
Translationhelper for multi-language cookie consent interfaces - ViewModel Architecture:
CookieConsentViewModel extending baseGdprCookiefunctionality for frontend-specific implementations - Template System:
google-consent-head.phtmlfor injecting Google Consent Mode v2 script in document headconsent/google-tag.phtmlfor Google Tag (GA4) implementation
- Hyva Theme Compatibility: Built-in support for Hyva themes (requires hyva-themes/magento2-theme-module ^1.3.11)
- Admin Configuration: Comprehensive system.xml with organized sections:
- Cookie Consent Settings (qoliber_gdpr_cookie/consent)
- Cookie Content Settings (qoliber_gdpr_cookie/texts)
- Google Consent Mode v2 (qoliber_gdpr_cookie/google_consent)
Dependencies
- Requires
Qoliber_GdprConsentmodule for core consent management functionality - Requires
Qoliber_GdprDataSubjectmodule for data subject rights handling - Requires
Magento_GoogleGtagmodule (can be disabled via configuration) - PHP 8.1, 8.2, or 8.3 compatibility
Technical Implementation
- Frontend layout integration via
default.xmlanddefault_head_blocks.xml - ACL resources for admin configuration access under
Qoliber_GdprFrontend::config - Tag ID validation with regex patterns (
G-[A-Z0-9]{10}for Google Tag) - Strict typing and modern PHP 8.1+ features throughout codebase
GdprFrontendHyva — 2024
Added
- Initial Hyva theme compatibility module for Qoliber GDPR Frontend
- Google Consent Mode v2 Implementation: Advanced Google Tag Manager integration
- Pre-initialization consent defaults before GTM script loads
- Default consent state configuration (granted/denied per category)
- Wait for update mechanism (configurable delay, default 500ms)
- Post-load consent restoration from localStorage
- Dynamic consent updates via gtag API
- Google Tag Manager Integration: Proper GTM initialization sequence
- Async GTM script loading after consent defaults set
- gtag.js initialization with proper timing
- dataLayer initialization and gtag function declaration
- GTM tag configuration with merchant-specific Tag ID
- Consent State Management: Comprehensive consent tracking
- Default consent state for 7 consent types:
ad_user_data: User data for advertisingad_personalization: Personalized advertisingad_storage: Advertising cookiesanalytics_storage: Analytics cookiesfunctionality_storage: Always granted for necessary functionalitypersonalization_storage: Personalization cookiessecurity_storage: Always granted for security
- localStorage persistence (
qoliber_google_consent) - Automatic consent restoration on page load
- JSON-encoded consent state with proper escaping
- Default consent state for 7 consent types:
- URL Passthrough Support: Ad click tracking preservation
- Optional URL passthrough for ad click information
- gtag 'url_passthrough' configuration
- Backend-controlled enablement
- Ads Data Redaction: Privacy-enhanced advertising
- Optional ads data redaction when consent denied
- gtag 'ads_data_redaction' configuration
- PII protection for denied consent states
- Debug Mode: Development and troubleshooting support
- Console logging of consent state changes
- Consent restoration logging
- Custom event logging (
qoliberGoogleConsentUpdated) - Conditional debug output based on backend configuration
- CSP (Content Security Policy) Support: Security-compliant script injection
- Hyva CSP helper integration (
$hyvaCsp->registerInlineScript()) - Proper inline script registration for CSP nonce support
- Separated script blocks for CSP compliance
- Hyva CSP helper integration (
- ViewModel Integration: Clean data layer architecture
CookieConsentViewModel integration- Configuration array access via
getCookieConsentConfigArray() - Google Consent config extraction from main config
- Conditional rendering based on feature enablement
- Configuration-Driven Behavior: Backend-controlled features
- Enable/disable toggle via
$googleConsent['enabled'] - GTM Tag ID validation (must not be empty)
- Default state configuration (granted/denied)
- Wait for update timing configuration
- URL passthrough toggle
- Ads data redaction toggle
- Debug mode toggle
- Enable/disable toggle via
- Google Consent Head Template: Proper head section integration
google-consent-head.phtml: Head section consent initialization- Placement before GTM script load
- Critical consent defaults set early in page lifecycle
- Layout Integration: Hyva theme layout support
hyva_default.xml: Global Hyva theme integration- Head section script injection
- Before body end script placement
- Consent Tag Template: Google Tag implementation
consent/google-tag.phtml: Main GTM integration template- Conditional rendering based on feature flags
- Proper script ordering and timing
- Event listener for consent updates
- JSON Encoding Security: XSS prevention
- JSON_HEX_TAG flag for script tag escaping
- JSON_HEX_APOS flag for apostrophe escaping
- JSON_HEX_QUOT flag for quote escaping
- JSON_HEX_AMP flag for ampersand escaping
- Proper JSON encoding in script contexts
- Event-Driven Architecture: Custom event system
qoliberGoogleConsentUpdatedcustom event- Event detail with consent state payload
- Window-level event dispatching
- Event listener registration in debug mode
- Immediate Consent Check: Fast consent restoration
- IIFE (Immediately Invoked Function Expression) for consent restoration
- Try-catch for localStorage access failures
- Silent failure handling for localStorage unavailable
- JSON parsing with error handling
- Tailwind Configuration: Hyva theme styling support
- Custom Tailwind config for frontend templates
- Template scanning configuration
- JIT compilation support
Technical Details
- GTM Initialization Sequence:
- Initialize dataLayer array
- Declare gtag function
- Set default consent state
- Configure URL passthrough (if enabled)
- Configure ads data redaction (if enabled)
- Load GTM script asynchronously
- Configure GTM with Tag ID
- Restore saved consent from localStorage
- Consent Restoration Logic:
javascript
(function() { try { var storedConsent = localStorage.getItem('qoliber_google_consent'); if (storedConsent) { var consent = JSON.parse(storedConsent); gtag('consent', 'update', consent); } } catch (e) { // Silent failure } })(); - Default Consent Configuration:
- All consent types default to backend-configured state (granted/denied)
- Functionality and security storage always granted
- Wait for update prevents premature tag firing
- Debug Logging:
- Restoration log:
[Qoliber GDPR] Restored consent from storage: {consent} - Update log:
[Qoliber GDPR] Google Consent Updated: {detail} - Conditional output based on
debugModeconfiguration
- Restoration log:
- Configuration Array Structure:
PHP
$googleConsent = [ 'enabled' => bool, 'gtagId' => string, 'defaultState' => 'granted'|'denied', 'waitForUpdate' => int (milliseconds), 'urlPassthrough' => bool, 'adsDataRedaction' => bool, 'debugMode' => bool ] - GTM Script Loading:
- Async attribute for non-blocking load
- Source:
https://www.googletagmanager.com/gtag/js?id={TAG_ID} - Loaded after consent defaults set
- CSP Script Blocks:
- Three separate script blocks for proper CSP handling
- Each block registered with Hyva CSP helper
- Nonce support for inline scripts
Dependencies
- PHP 8.1, 8.2, or 8.3
- Magento Framework
- Magento Theme module
- Magento CMS module
- hyva-themes/magento2-theme-module: ^1.3.11
- qoliber/gdpr-frontend: ^1.0
- qoliber/hyva-module-registration
Compatibility
- Magento 2.4.x
- Hyva Theme 1.3.11+
- Google Tag Manager
- Google Consent Mode v2 API
- Modern browsers with localStorage support
Integration Points
- Works with GdprCookieHyva for consent updates
- Listens for consent change events from cookie module
- Updates Google Consent Mode dynamically based on user preferences
- Integrates with Hyva CSP system for security compliance
Performance Considerations
- Async GTM script loading prevents blocking
- Minimal JavaScript footprint
- localStorage caching reduces consent API calls
- Wait for update mechanism prevents premature tag firing
- Efficient IIFE for consent restoration
GdprGtm
Added
- Initial release candidate with Google Tag Manager GDPR integration
GdprPolicy — 2024
Added
- Privacy Policy Management System: Comprehensive privacy policy creation, versioning, and publishing system with full CRUD operations
- Policy Versioning: Advanced version control for privacy policies with semantic versioning support
- Track policy versions (e.g., 1.0.0, 1.1.0, 2.0.0)
- Effective date tracking for each policy version
- Archive historical policy versions
- Automatic version management on policy updates
- Policy Status Management: Four-state workflow system:
- Draft (0): Policies in development
- Active (1): Currently in effect but not requiring new consent
- Archived (2): Historical policies for record-keeping
- Published (3): Active policies requiring user consent
- Consent Tracking System: Complete audit trail of policy consent:
PolicyConsentmodel with comprehensive consent metadata- Customer ID and email tracking (registered users)
- Guest email tracking (anonymous visitors)
- IP address recording for legal compliance
- Country code from geolocation
- User agent string for device tracking
- Session ID for consent attribution
- Context field for consent scenario tracking
- Consent method tracking (popup, checkbox, modal, etc.)
- Store ID for multi-store consent management
- Acceptance/rejection flag with timestamps
- Consent timestamp (
consented_at) - Withdrawal timestamp (
withdrawn_at) for consent revocation - Additional data JSON field for extensibility
- Database Schema: Robust database structure with three main tables:
qoliber_gdpr_privacy_policy: Privacy policy storageqoliber_gdpr_policy_version: Version history trackingqoliber_gdpr_policy_consent: Consent logs
- Admin Interface:
- Privacy policy grid listing (
Controller/Adminhtml/PrivacyPolicy/Index.php) - Policy creation form (
Controller/Adminhtml/PrivacyPolicy/NewAction.php) - Policy editing interface (
Controller/Adminhtml/PrivacyPolicy/Edit.php) - Policy save action with validation (
Controller/Adminhtml/PrivacyPolicy/Save.php) - Policy deletion (
Controller/Adminhtml/PrivacyPolicy/Delete.php) - Policy publishing workflow (
Controller/Adminhtml/PrivacyPolicy/Publish.php) - Consent log viewer (
Controller/Adminhtml/Consent/Index.php) - UI components with action column (
Ui/Component/Listing/Column/PrivacyPolicyActions.php) - Status label rendering (
Ui/Component/Listing/Column/StatusLabel.php) - Generic button architecture for form actions
- Privacy policy grid listing (
- Frontend Controllers:
- Policy acceptance endpoint (
Controller/Policy/Accept.php) - AJAX-based consent recording - Policy rendering endpoint (
Controller/Policy/Render.php) - Dynamic policy display - Consent logging endpoint (
Controller/Consent/Log.php) - Privacy-first consent tracking
- Policy acceptance endpoint (
- Rendering System:
CmsPageRenderer: Render policies from CMS pagesVersionBasedRenderer: Render version-specific policy contentPrivacyPolicyRendererAPI interface for extensible rendering
- Configuration System:
- Policy source selection (CMS page vs. version-based)
- Display mode options (modal, inline, popup)
- Display location configuration (checkout, registration, newsletter)
- Link style customization
- Opening mode (new tab, same window, modal)
- Policy status configuration
- Cookie Integration:
Cookiehelper for privacy policy acceptance trackingAddPrivacyPolicyCookiedata patch - Registers privacy policy cookieAddPolicyVersionCookiedata patch - Tracks accepted policy version- Cookie-based consent state management
- Integration with Magento's cookie restriction system
- Default Content:
InstallDefaultPrivacyPolicydata patch providing:- Comprehensive 9-section privacy policy template
- GDPR-compliant policy content covering:
- Information We Collect (Personal and Non-Personal)
- How We Use Your Information
- How We Share Your Information
- Your Choices and Rights
- Security measures
- Children's Privacy
- International Transfers
- Third-Party Websites
- Changes to Privacy Policy
- HTML-formatted content with proper structure
- Automatic installation only if no published policy exists
- Version 1.0.0 baseline
- Default consent text: "I have read and agree to the Privacy Policy"
- Repository Pattern: Full repository implementation with SearchResults
PrivacyPolicyRepository: CRUD operations with search criteria supportPrivacyPolicySearchResults: Collection results with paginationPolicyConsentRepository: Consent log management- Clean API layer separation from models
- ViewModel Architecture:
PrivacyPolicyViewModel for frontend policy display- Configuration access methods
- Policy version retrieval
- Enable/disable state management
- Plugin System:
CookieConsentPlugin: Integrates privacy policy with cookie consentLinkTargetPlugin: Controls policy link opening behavior
- Multi-Store Support:
- Store-specific privacy policies
- Language code tracking for localization
- Store ID in consent records for multi-tenant compliance
- ACL Resources: Admin permission system for policy management
- System Configuration: Modal notice for admin guidance
Technical Implementation
- API Contracts: Comprehensive interface definitions:
PrivacyPolicyInterface: Policy entity contractPrivacyPolicyRepositoryInterface: Repository contractPrivacyPolicySearchResultsInterface: Search results contractPolicyConsentInterface: Consent entity contractPolicyConsentSearchResultsInterface: Consent search resultsConfigInterface: Configuration contractPrivacyPolicyRendererInterface: Renderer contract
- Resource Models: Optimized database operations
ResourceModel/PrivacyPolicywith collection supportResourceModel/PolicyVersionwith collection supportResourceModel/PolicyConsentwith collection support
- Data Providers: Admin form data population
PrivacyPolicy/DataProviderfor UI forms
- Cache Integration: IdentityInterface implementation for policy caching
- Event System: Event prefix and object for observers
- Frontend Integration:
- Layout XML for policy display
- Block architecture for policy rendering
- JavaScript for AJAX consent submission
- Template system for various display modes
GDPR Compliance Features
- Article 13/14 Transparency: Complete privacy notice system
- Article 7 Consent Conditions: Valid consent recording with audit trail
- Article 12 Accessibility: Clear, intelligible policy presentation
- Right to Information: Version tracking for transparency
- Accountability (Article 5): Comprehensive consent audit logs
- Consent Withdrawal: Timestamp tracking for consent revocation
- Data Minimization: Only essential consent metadata collected
- Lawfulness of Processing: Documented legal basis via consent
Dependencies
- Requires
Qoliber_GdprFrontendfor cookie consent integration - Requires
Qoliber_GdprConsentfor consent framework - Requires
Magento_Cmsfor CMS page rendering - Requires
Magento_Cookiefor cookie management - PHP 8.1, 8.2, or 8.3 compatibility
Database Fields
qoliber_gdpr_privacy_policy table:
- policy_id, title, content, version, status, consent_text, requires_consent, effective_date, store_id, language_code, created_at, updated_at
qoliber_gdpr_policy_consent table:
- consent_id, customer_id, customer_email, guest_email, policy_id, policy_version, policy_type, ip_address, country_code, user_agent, session_id, context, consent_method, store_id, is_accepted, consented_at, withdrawn_at, additional_data
Admin Routes
qoliber_gdpr_policy/privacypolicy/index- Policy gridqoliber_gdpr_policy/privacypolicy/new- Create policyqoliber_gdpr_policy/privacypolicy/edit- Edit policyqoliber_gdpr_policy/privacypolicy/save- Save policyqoliber_gdpr_policy/privacypolicy/delete- Delete policyqoliber_gdpr_policy/privacypolicy/publish- Publish policyqoliber_gdpr_policy/consent/index- View consent logs
Frontend Routes
qoliber_gdpr/policy/accept- Accept/decline policy (POST)qoliber_gdpr/policy/render- Render policy contentqoliber_gdpr/consent/log- Log consent event
GdprPolicyHyva — 2024
Added
- Initial Hyvä compatibility module for Qoliber GDPR Policy
- Hyvä privacy policy display templates with Tailwind CSS styling
- Modal and inline display modes for privacy policy
- Server-side policy consent logging integration
- Policy version tracking and re-consent flow
- Accept/decline flow compatible with Hyvä's Alpine.js patterns
Technical Details
- Hyvä theme module registration via
registration.php - Layout XML for Hyvä storefront integration
- Plugin configuration for cookie consent coordination
GdprPrivacyCenter
Added
- Initial release candidate with Privacy Center customer account integration
GdprPrivacyCenterHyva — 2024
Added
- Initial Hyvä compatibility module for Qoliber GDPR Privacy Center
- Customer account privacy dashboard using Hyvä's Alpine.js + Tailwind stack
- Action card grid with four primary rights flows:
- Export My Data
- Update My Data (rectification)
- Anonymize Data
- Delete Account
- Hyvä layout XML for customer account privacy integration
- Navigation menu integration under customer account area
Technical Details
- Hyvä theme module registration via
registration.php - Layout XML for Hyvä storefront integration
- No controllers or models required — purely presentational overlay on base module
GdprYireoGtm — 2024
Added
- Yireo GTM Integration: Specialized integration module for Yireo's Google Tag Manager extension with GDPR cookie consent
- TagType Implementation:
YireoGtmclass implementingTagTypeInterfacefor seamless integration with GdprFrontend tag system - Dynamic Module Detection: Automatic availability detection based on
Yireo_GoogleTagManager2module status- Uses
ModuleManagerto check if Yireo GTM is installed and enabled - Only appears in tag type selection when Yireo module is active
- Prevents configuration errors when Yireo GTM is not available
- Uses
- Configuration Reuse: Leverages existing Yireo GTM configuration
- No duplicate Container ID entry required
- Reads container ID from Yireo's configuration path
- Reduces configuration complexity
- Eliminates sync issues between configurations
- Template System:
consent/yireo-gtm.phtmltemplate for rendering Yireo GTM with consent awareness - Admin Guidance: Informational notice field explaining:
- Yireo GoogleTagManager2 module requirement
- Configuration location (Stores > Configuration > Yireo > GoogleTagManager)
- Container ID source from Yireo's settings
- Validation Bypass: Smart validation that skips tag ID format checking since Yireo manages its own configuration
- Help Documentation: Context-aware help text explaining configuration-free setup
Technical Implementation
- Implements
Qoliber\GdprFrontend\Api\TagTypeInterfacefor tag type system integration - Code identifier:
yireo_gtm - Label: "Yireo Google Tag Manager"
- Conditional availability via
isAvailable()method checking module status - Constructor dependency injection of
ModuleManagerfor module detection - PHP 8.1, 8.2, and 8.3 compatibility with strict typing
Yireo GTM Version Support
- Compatible with Yireo GoogleTagManager2 version 3.0 and 4.0
- Requires
yireo/magento2-googletagmanager2: ^3.0||^4.0 - Forward-compatible version constraint for future updates
Dependencies
- Requires
Qoliber_GdprFrontendfor base cookie consent and tag type framework - Requires
Yireo_GoogleTagManager2module (v3.0 or v4.0) - PHP 8.1, 8.2, or 8.3 compatibility
Integration Benefits
- No Duplicate Configuration: Uses Yireo's existing GTM container ID
- Seamless Integration: Works with Yireo's advanced GTM features
- Consent Compliance: Adds cookie consent layer to Yireo GTM
- Automatic Detection: Only shows when Yireo GTM is installed
- DataLayer Compatibility: Preserves Yireo's dataLayer structure and events
Use Cases
- Sites already using Yireo GTM wanting to add GDPR cookie consent
- E-commerce stores with Yireo's enhanced e-commerce tracking
- Businesses requiring advanced GTM features with consent compliance
- Multi-store setups leveraging Yireo's GTM configuration
Configuration
- No tag ID field required (uses Yireo's configuration)
- Automatically integrates with Yireo's GTM settings
- Tag type selection available in
qoliber_gdpr_cookie/google_consent/tag_type - Only visible when both GdprFrontend and Yireo GTM are enabled
Notes
- This is a bridge module between Qoliber GDPR and Yireo GTM
- Does not replace Yireo GTM, but enhances it with consent management
- Maintains compatibility with Yireo's future updates via version constraint
- Listed as suggested (not required) in GdprMetapackage
1.0.0-beta2 — 2024
GdprFrontend
Changed
- Enhanced stability and bug fixes for beta release
GdprPolicy
Changed
- Enhanced stability and bug fixes for beta release
1.0.0-beta1 — 2024
GdprFrontend
Added
- Initial beta release with core cookie consent functionality
GdprPolicy
Added
- Initial beta release with core privacy policy management