75 min readAug 19, 2026by jakub

Changelog

Current version: 1.2.0

The suite is released as one version across all 22 modules. A module only appears under a version if it actually changed in that release.

1.2.0 — 2026-08-19

Qoliber_GdprAdmin

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.

Fixed

  • The Hyvä cookie banner was absent on a fresh install. qoliber_gdpr/general/enabled had no config.xml default, and Qoliber_GdprCookieHyva gates all six of its storefront blocks on it via ifconfig. Magento resolves an unset path as false, so a clean install rendered no banner, no consent UI and no blocker until an admin opened the config section and pressed Save — which is what wrote the row, and why it looked correct on every developer machine.

Removed

  • Dead settings that rendered, saved, and were read by nothing: general/data_retention_period, the entire requests group (auto_approve_access, request_expiry_days, deletion_grace_period), the entire automation group (auto_delete_inactive, inactive_period_days, auto_anonymize_orders, order_anonymize_days) and the entire notifications group (notify_admin_requests, admin_notification_email). The automation group is the one worth calling out: it offered "Auto-delete Inactive Accounts / after N days", an Art. 5(1)(e) storage-limitation control with no implementation behind it, and its two config.xml defaults sat under a data_retention node that system.xml calls automation, so they never bound either.
  • The orphaned cookie-detail form assets (cookie-detail-form.js, its template and LESS), left behind when the cookie-template picker was deferred.

Qoliber_GdprConsent

Changed

  • The consent-list block now declares its customer session and log-collection factory as dependencies. Both were fetched from the ObjectManager service locator inside methods, which hid them from DI: no other module or test could substitute them, and the block could not be constructed without the global object manager. They are now optional trailing constructor arguments, which keeps appending them backward compatible for any theme subclass that does not forward them — those still fall back to the locator. The session is wired as a Proxy in etc/frontend/di.xml on purpose: the block is attached in default.xml and so renders on cacheable pages, and constructing the real session eagerly would start a session on every render and defeat full page cache for anonymous visitors.
  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.

Added

  • qoliber_gdpr_consent/retention/consent_log_days and the nightly purge that makes it real. The consent evidence tables hold a guest email, an IP and a full user agent per row, and nothing ever deleted them — so a subject who exercised Art. 17 still had their address in the GDPR module's own tables afterwards, indefinitely. A setting of this name was removed earlier in 1.2.0 precisely because it was declared, saved and read by nothing; it returns with Cron\PurgeConsentLogs behind it and unit tests that fail if it becomes dead again. It defaults to 0 (keep indefinitely): an entry is simultaneously personal data and the proof that consent was given, so the retention period is the controller's decision, not a default this extension should pick. The newest entry per customer and consent is never purged.
  • qoliber_gdpr/consent/checkout_enabled now has an admin field. Model\Checkout\ConsentConfigProvider has always read this path, but no system.xml declared it, so its value came from config.xml and no merchant could change it. Declared with a config_path override so the stored path is unchanged and existing installs do not reset.
  • Integration coverage for the registration boundary: consent evidence is asserted through the real CustomerRegisterSuccess observer payload, so a registration form that dropped the consent field entirely now fails a test.

Fixed

  • Full page cache served one customer's consent state to every other customer. The consent list is attached to form.subscribe in default.xml — the newsletter form in the footer of every storefront page — and pre-ticked its boxes from the logged-in customer's own consent history. FPC varies only on customer_logged_in and customer_group, never on customer id, so the first shopper to warm a page baked their ticked box into the cached HTML for everyone else in that group. Submitting that form then wrote a consent-log row recording an acceptance they never gave: a fabricated consent record, produced by the module whose purpose is proving consent. Pre-filling is now opt-in per placement and enabled only on newsletter_manage_index, which core marks cacheable="false". cacheable="false" was deliberately NOT used on the footer placement — that block is on every page, so it would have disabled full page cache store-wide.
  • Consent IP minimisation now delegates to the shared Qoliber\GdprCore\Api\IpMinimizerInterface, so the Art. 5(1)(c) truncation policy cannot drift between modules — this module and GdprPolicy each carried a private copy.
  • A customer whose email is null no longer aborts account creation. CustomerInterface::getEmail() is nullable while ConsentLinkService is strict-typed, so the raw value raised a TypeError — an \Error, which the observer's catch (\Exception) cannot catch.

Removed

  • The duplicate qoliber_gdpr_consent/consent/checkout_enabled default, which no code read.

Qoliber_GdprConsentHyva

Fixed

  • Checkout consent was recorded against the wrong definitions. Consents were keyed by loop position, and those keys travel to ConsentTracker, which treats a numeric identifier as a database primary key — so ticking the first checkout consent recorded consent against whichever definition happened to hold id 1. Now keyed by the definition's own code, as Luma does.
  • Ticking a checkout consent persisted nothing. Only "accept all" and "reject all" wrote the checkout session, and the method meant to emit the data built its payload and then discarded it — so a shopper who ticked the boxes and placed the order produced no consent rows. Every change now persists.
  • A sixth required checkout consent was invisible on Hyvä. The query carried a setPageSize(5) "for safety"; the Luma path has no cap. Removed.
  • Consent boxes were pre-ticked from a previous form. The checked state was overridden from localStorage, carried across unrelated forms, so a consent ticked once on the newsletter arrived pre-ticked on registration. It could only ever tick: the writer stored '1' for true but removed the key for false, so '0' was never written and the loader could never pre-untick. A pre-ticked box is not consent under Art. 4(11), so the override is gone rather than corrected — the server-rendered state is authoritative. Luma never had this behaviour.

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprCookie

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.

Fixed

  • composer require qoliber/gdpr-cookie on its own returned HTTP 500 on every storefront page. getReopenerType(), getDisplayStyle() and getTheme() are declared : string under strict_types and returned scopeConfig->getValue() with no fallback, while those defaults ship only in Qoliber_GdprFrontend — which this module does not require. The footer link block has no ifconfig, so it renders on every page: getValue() returned null, null from a : string is a TypeError, and Layout::renderNonCachedElement() catches \Exception rather than \Error. All three now cast with a real default.
  • The banner rendered with no copy on that same install. Every qoliber_gdpr_cookie/texts/* value was read with no fallback, so a store without Qoliber_GdprFrontend got a banner with no title, no message and no policy text, silently. The copy now falls back to the translated defaults getTexts() already held.
  • Scripts the merchant deferred pending consent were never activated. The documented way to gate a third-party script in this suite is to author its tag with type="text/plain" and a data-consent-category, and let the consent component swap it for a live script once that category is allowed. That swap lived only in js/view/cookie-consent.js, which carries a requirejs alias but is initialised by no template — the Luma banner mounts js/view/privacy-preferences.js, whose own toggleScripts() only fired jQuery events. So the swap was dead code: the shopper consented and the merchant's script still never ran. This is a functional break rather than a privacy gap. The activation now lives in the component that is actually mounted; the published qoliberGdpr*Enabled jQuery events are kept alongside it, since a merchant may already listen to them.
  • The Luma cookie banner was absent on a standalone install. This module gates its banner on qoliber_gdpr_cookie/consent/enabled and its detector on detection/client_side_enabled, but both defaults shipped only in Qoliber_GdprFrontend, which this module does not require and deliberately does not sequence (the reverse direction would be circular). composer require qoliber/gdpr-cookie on its own therefore produced a store with no cookie banner at all, silently. Both defaults, plus qoliber_gdpr/general/enabled, now ship here.

Added

  • The Luma consent component now listens for qoliberGdprEmbedAllowCategory, so the "Always allow <provider>" button on a blocked third-party embed (see Qoliber_GdprEmbed) grants that provider's cookie category through this module's existing consent path. Embed consent and banner consent therefore share one writer rather than diverging.

Removed

  • The orphaned Import Cookie button from the cookie-detail form. It emitted an importCookie event with no handler, so pressing it did nothing; the feature is deferred rather than half-present.

Qoliber_GdprCookieHyva

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.

Fixed

  • Google Consent Mode never loaded on Hyvä, so analytics and ads stayed dark after consent. The signal the tag loaders consume — qoliber_gdpr_google_consent in localStorage plus the qoliberGoogleConsentUpdated event — was written only by a RequireJS module the Luma banner pulls in, and Hyvä layouts remove that banner. Nothing emitted it, so Qoliber_GdprFrontendHyva, Qoliber_GdprGtm and Qoliber_GdprYireoGtm all waited forever. It failed silently, because the Hyvä template defines a gtag() dataLayer stub: consent updates were pushed to an array no library ever read. The call was also guarded on gtag already existing, which was circular — the loaders wait for this signal before loading gtag. Fixing that exposed a second divergence: Hyvä hardcoded only analytics and marketing and ignored the google_services category, so the same "Allow All" granted analytics_storage on Luma and denied it on Hyvä. The Luma category mapping is now mirrored exactly, and a spec asserts the two themes' payloads are identical to each other.
  • "Do Not Sell or Share My Personal Information" was inert on Hyvä. The layout mounted the Luma template, whose only handler wiring is text/x-magento-init — RequireJS, which Hyvä does not ship. The CCPA/CPRA control rendered and did nothing: clicking it jumped to the top of the page and recorded no opt-out. Hyvä now has its own template that dispatches to the consent component, which owns the decision.
  • A Global Privacy Control signal was ignored on Hyvä. window.qoliberGdprCompliance is emitted on both themes but was read only by the Luma cookie-manager, so the US opt-out model was not implemented on Hyvä at all — a legal requirement in California, Colorado and Connecticut. applyGpcIfPresent() now runs before the banner decision, treating navigator.globalPrivacyControl as authoritative (it is never page-cached) and never overriding a choice the shopper already made.
  • Banner decisions left no server-side record on Hyvä. Luma POSTs every save to the consent-log endpoint, which allow-lists the cookie_categories scope for exactly that. The Hyvä component wrote browser storage only, so a Hyvä store had zero Art. 7(1) evidence for banner decisions. It now posts the same payload, fire-and-forget so a failed audit write can never block or reverse the shopper's choice.
  • The consent cookie was never written on Hyvä, and the server-side cookie blocker was therefore dead there. This module forces COOKIE_CONFIG.cookie_restriction_enabled = true, which arms Hyvä's own gate: hyva.setCookie() silently drops any name absent from cookie_consent_config, parks it in temp storage and returns as though it had written. gdpr_consent was never registered — gdpr_policy_version was, so the mechanism was understood — so the cookie never reached document.cookie. That is not only a storage inconsistency with Luma: Qoliber_GdprCookie's response-level blocker early-returns when that cookie is absent, so on a Hyvä store view it could never expire a single rejected cookie, leaving the entire HttpOnly / server-set / proxy-set layer unenforced. gdpr_consent is now registered in essential and necessary — recording that a shopper refused cookies cannot itself require consent.
  • Deferred scripts are now activated on Hyvä. The Hyvä consent component had no equivalent of the Luma script activation at all, so a script correctly deferred with type="text/plain" and a data-consent-category stayed inert on a Hyvä store view even after the shopper granted its category. applyConsent() now performs the same swap, so it fires on init, accept-all, accept-selected, decline and the embed "always allow" path. Note for anyone editing this template: the method's documentation deliberately does not spell out a literal script tag, because the comment lives inside an inline script that Hyvä hashes for CSP via registerInlineScript() — a literal tag in the body corrupts the content that is hashed, the hash stops matching, and the browser blocks the entire cookie banner.
  • The compliance model (qoliber_gdpr_cookie/compliance/*) is now emitted on the Hyvä storefront through a dedicated compliance-config.phtml, so US opt-out mode, the Global Privacy Control signal and the Do-Not-Sell link behave on Hyvä as they do on Luma.

Added

  • The Hyvä consent component now listens for qoliberGdprEmbedAllowCategory, so the "Always allow <provider>" button on a blocked third-party embed (see Qoliber_GdprEmbed) grants that provider's cookie category through this module's own Alpine consent path. Without it the button was a silent no-op on Hyvä, because the Luma component that previously carried the listener is removed from Hyvä layouts entirely.

Qoliber_GdprCookieTemplates

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprCore

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.

Added

  • TESTS.md — one page describing every automated check that guards the suite: the 693 unit, 63 integration and 537 end-to-end tests, the three gating scripts, and how the PHP floor and ceiling are proven. It also records the traps that cost real debugging time — that unit and integration must not share a process, that the integration sandbox keeps its own generated/, why the Playwright project order is load-bearing, and which skips and flakes are expected rather than symptoms.
  • Api\IpMinimizerInterface and Model\IpMinimizer — the canonical Art. 5(1)(c) IP-minimisation implementation, shared by the consent and policy modules. IPv4 is truncated to /24 and IPv6 to /48, masked in packed form so the output is canonical RFC 5952; an unparseable address yields null rather than an empty string, because "no address recorded" and "an empty address was recorded" are different facts.

Fixed

  • getRemoteAddress() returns false despite its @return string docblock, which raised a TypeError — an \Error that escapes catch (\Exception) — and broke registration. Cast at every call site, with a regression guard.
  • A SearchResultsInterface return-type incompatibility that made setup:di:compile fatal. Covered by a subprocess test that loads the generated classes, since the failure only appears in a fresh compile.

Qoliber_GdprDataSubject

Fixed

  • Stored XSS reaching an authenticated administrator. request_type came straight off a storefront POST with no allowlist — the guest controller had one, the logged-in customer controller did not — and was persisted verbatim. The admin grid then rendered it through <bodyTmpl>ui/grid/cells/html</bodyTmpl>, a Knockout html binding that inserts unescaped, and Magento ships the admin CSP report-only so nothing downstream stopped it. Any registered customer could therefore run script in an admin session. Submit now allowlists the type against every DataRequestInterface::TYPE_* constant, and the grid column escapes an unrecognised type as a second layer, because rows written before the allowlist existed are still in the table.
  • Erasure left most of the request row identifying the subject. The data-request anonymiser replaced customer_email alone, leaving ip_address, user_agent, response_data, admin_user, blocked_reason — and request_data, which is not metadata: a rectification request stores the shopper's own free text, i.e. the names, addresses and phone numbers they asked to have corrected. All are now cleared.
  • Order addresses kept the subject's real email after erasure. anonymizeOrderAddress() replaced twelve fields but never called setEmail(), so the address survived on every order, invoice, shipment and credit-memo row. The sibling quote anonymiser always did this; the order path simply missed it.
  • The admin sales grids kept the postal address after erasure. sales_order_grid had neither address column written, and the invoice and credit-memo grids were missing shipping_address — only the shipment grid was complete. Street, city and postcode therefore stayed visible and searchable in Sales grids indefinitely. The order's customer_note — the checkout comment box, which routinely contains an address or a phone number — is now cleared too.
  • Quote addresses kept city, postcode and region. Both sibling methods replaced them; this one did not.
  • Withheld orders were excluded from an erasure silently. Orders whose status is outside the configured set are skipped, which is correct — they still have to be fulfilled — but nothing recorded it, so the subject was told their data was erased while those orders stayed fully identifiable and the erasure record showed no trace. The withheld increment ids are now listed in the result, matching how unanonymisable quotes were already reported.
  • The credit-memo section of a subject-access export ignored store scope. The invoice and shipment fetchers filter on store_id; this one did not, so it returned rows from every website and disclosed more than the merchant had configured to release.
  • The export error shown to the shopper quoted the raw exception. Exception text routinely contains the offending value (Duplicate entry '[email protected]' …), and this string is displayed and stored in the session flash bag. The visitor now gets a neutral message; the scrubbed detail still goes to the log.
  • Order and newsletter data were exported regardless of configuration. OrderDataFetcher::isEnabled() and NewsletterDataFetcher::isEnabled() returned an unconditional true, so export_settings/include_order_data and include_newsletter_data had no effect and every row was still disclosed in a subject-access export — more personal data than the merchant had configured to release under Art. 15. Both now consult their setting, as the invoice, shipment, credit-memo and address fetchers already did.
  • Customer addresses were never anonymised. CustomerAddressDataAnonymizer gated on anonymization_settings/anonymize_customer_addresses, a path with no admin field and no config.xml default, so isSetFlag() returned false on every install and the anonymizer never ran — while the admin comment claimed customer data "and addresses" were covered. The field and its default now exist.
  • The Privacy Center advertised disabled actions. The Luma dashboard rendered the Anonymize and Delete cards regardless of account_actions/enable_anonymization and enable_deletion, while the Hyvä dashboard gated both. The controllers always enforced the flags, so this was a misleading UI rather than an open door; both card blocks now carry ifconfig.
  • The admin was never notified of rectification requests. gdpr_admin_notification was set as a template identifier and registered in no email_templates.xml, so getTransport() threw and the caller swallowed it. Registered — in the frontend area, because an adminhtml registration cannot resolve design/email/header_template and the mail arrived with "Error filtering template" as its entire body.
  • The data subject was never acknowledged. notification/rectification_confirmation_template, its registered template and its default all existed for a mail nothing sent. RectificationPost now sends it, in its own try/catch so a merchant-notification failure cannot suppress the subject's acknowledgement.
  • Notification settings resolved at the wrong store. Both data-ready crons read the template with SCOPE_STORE and no store id and hardcoded trans_email/ident_support, ignoring notification/sender_identity entirely. In a cron the scope resolves to the CLI default, so on a multi-brand install one store's subject-access mail rendered with another's template and sender. Both now take the request's store id.
  • Personal data reached logs and outlived them. The recipient address and the data subject's address were written raw into EmailService log calls beside a scrubbed exception; and ProcessEmailQueue persisted $e->getMessage() into email_queue.error_message. Mail failures routinely quote the recipient, so that stored addresses in a table no retention job clears. Logs are scrubbed; the row now takes a stable QUEUE_PROCESSING_FAILED:<exception-class> code.

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • The subject-access CSV export now passes an explicit $escape to fputcsv(). PHP 8.4 deprecated calling it without one because the default is changing, and this package's composer constraint claims support up to 8.5 — an Art. 15 export is the last path that should depend on a default shifting underneath it. The value passed is '', which is both the value the default is moving to and the RFC 4180 behaviour: a backslash in a name or an address is now treated as data rather than as an escape character, so exported personal data is no longer mangled.

Removed

  • Dead settings that rendered, saved, and were read by nothing: data_protection_officer/office_hours (its only accessor sat on an interface nothing implements) and retention/consent_log_days (whose group comment promised a nightly cron that never touched consent logs).

Added

  • anonymization_settings/anonymize_customer_addresses — postal addresses are personal data under Art. 4(1) and are now erasable independently of the account record.

Deprecated

  • Api\ConfigInterface — restored unchanged after being removed in error during 1.2.0 development. Nothing implements it; DataSubjectConfigInterface is the maintained contract. Scheduled for removal in 2.0.0.

Qoliber_GdprDataSubjectHyva

Fixed

  • Guest data anonymisation was impossible on Hyvä. The confirm handler called .then() on dataset.hyvacsp10, which is a string (a Hyvä modal's show-JS, stored in an attribute because Alpine's CSP-friendly build cannot evaluate it), so the click threw a TypeError before anything ran — and the method it chained to, submitAnonymizationRequest, was defined nowhere in the codebase. The component also declared none of the four state properties the template binds to, so the button looked enabled and no error banner could render. A guest therefore could not exercise Art. 17 on Hyvä at all, silently. The component now carries its state and a real POST mirroring the Luma flow; confirmation uses the browser's own dialog, which is what the CSP build allows.

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprDemo

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprEmbed

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.

Fixed

  • The embed consent log stored the full page URL including its query string. The value arrives from window.location.href, so search terms and campaign parameters were kept verbatim beside a customer id and a timestamp with no retention job — an indefinitely retained slice of browsing history, and more than Art. 5(1)(c) allows for proving one embed was consented to. Scheme, host and path are now stored; a URL that will not parse is stored empty rather than raw, since the field is written from an untrusted request.
  • Google reCAPTCHA is no longer mistaken for a Google Maps embed. The Maps provider owns the bare google.com host — deliberately, since a google.com iframe is a transfer to Google whatever the path — and host matching strips a leading www., so it also claimed https://www.google.com/recaptcha/.... On any form protected by reCAPTCHA that replaced the captcha with a "Load this content" placeholder, and on a login or checkout form it stopped the customer completing the order. reCAPTCHA is a security and fraud control rather than the marketing transfer this module exists to gate, so google.com paths under /recaptcha/ are now exempt. The exemption is boundary-anchored and case-sensitive against Google's own lowercase path, and a URL carrying a .. dot-segment is refused an exemption outright, because the browser resolves the segment away before it sends the request — /recaptcha/../maps/embed reads as exempt but fetches the map. No other provider is affected: the hook it uses defaults to exempting nothing. Payment iframes were never at risk and are unchanged. The module matches an allowlist of seven media providers on exact host, so Adyen, Stripe, PayPal, Braintree, Klarna, Amazon Pay, Przelewy24, PayU, Google Pay and 3-D Secure all pass through untouched, and checkout needs no exclusion.

Added

  • Script-based embeds are now blocked too, not just iframes. X and Instagram publish no iframe: their embed code is a visible <blockquote> plus a loader <script> that builds the iframe in the browser. An iframe-only rewriter never saw that transfer, so both providers reached the shopper unblocked despite being configured and enabled. Provider <script src> tags are now rewritten into the same placeholder, and data-embed-tag records which element was removed so consent rebuilds a script rather than pointing an iframe at a .js file (it defaults to iframe, so a placeholder already sitting in full page cache still restores correctly). Matching uses the SAME provider allowlist as iframes and resolves the tag's own src attribute, never the text of the markup: a payment SDK, reCAPTCHA, a CDN, an inline script and a JSON-LD block naming a provider are all left byte-identical. That containment is load-bearing rather than cosmetic — a wrongly deferred payment SDK does not degrade to a placeholder, it breaks the checkout — so it is pinned by unit tests and asserted again on a real rendered page, where exactly one of 38 scripts (Luma) and one of 48 (Hyvä) is deferred.
  • Third-party embed blocking. A YouTube, Vimeo, Google Maps, Spotify, SoundCloud, X (Twitter) or Instagram iframe sets its own cookies and hands the visitor's IP address to the provider the moment it loads — before any click, and before the cookie banner has been answered. Blocking on the play button is too late: the privacy-relevant request already happened when the page rendered. This module intercepts earlier, on the server, rewriting the iframe out of the rendered HTML before it ever reaches the browser. This covers every embed already present in the server-rendered page, including PageBuilder's video content type. It does not cover an iframe a storefront constructs itself in client-side JavaScript after the page has loaded — for example Magento's own product-video gallery (Magento_ProductVideo), which still reaches YouTube before consent, since there is no HTML for a server-side rewriter to see.
  • Provider iframes are rewritten server-side into an inert placeholder before the page reaches the browser — on every response, cache hit or miss alike, so a page cached before this module was enabled is still safe. The placeholder shows the provider name and a "Load this content" action instead of the live embed.
  • The shopper controls consent at two levels: loading one placeholder restores just that embed for the current session, while allowing the provider's cookie category (via the existing cookie banner) restores every embed from that provider going forward.
  • A one-off "Load this content" click is recorded as evidence — with a minimised IP address — satisfying the Art. 7(1) obligation to demonstrate that consent was given. Recorded entries are visible to admins in a new GDPR > Logs & Reports > Embed Consent Log grid.
  • Ships with blocking enabled out of the box for YouTube, Vimeo, Google Maps, Spotify, SoundCloud, X (Twitter) and Instagram. Any provider can be excluded from blocking individually under Stores > Configuration > GDPR Compliance > Cookie Consent > Third-Party Embed Blocking, e.g. where another consent tool already manages it.
  • "Always allow" now leaves the same demonstrable evidence as a one-off click, on both Luma and Hyvä. Previously only the one-off "Load this content" path wrote an evidence row; the durable "Always allow <provider>" grant left no server-side trace at all — its only record was localStorage on the shopper's own device, which cannot serve as Art. 7(1) evidence on request. embed-blocker.js now posts to the exact same evidence endpoint for that click too, before dispatching the event the cookie banner listens for, so both clicks go through one code path on both themes. A new consent_scope column (one_off / always, validated server-side) distinguishes the two in the Embed Consent Log grid, which gained a Scope column to show it.
  • The "Always allow" button is no longer offered when it would be a silent no-op. qoliber_gdpr_cookie/embeds/enabled had no relationship to the cookie banner's own master switch (qoliber_gdpr_cookie/consent/enabled): a merchant running this suite for its DSR/policy features alongside a third-party CMP, with the banner disabled, saw a working "Load this content" button next to an "Always allow" button that nothing on the page could ever act on. The placeholder now omits "Always allow" server-side whenever the banner is disabled and keeps "Load this content" either way; the admin config for Third-Party Embed Blocking now also declares a <depends> on the banner's master switch so the coupling is visible rather than folklore.
  • The placeholder's consent copy is now translatable. The notice text and both button labels were hardcoded English with no __(), no template override point and no admin field — a real defect for a store that also provisions de and fr views, since Art. 7(2) expects a data subject to be told what they are consenting to in a language they understand. A new Api\PlaceholderCopyInterface, injected into EmbedRewriter, now supplies the four strings; the Magento-backed implementation runs them through __(), with source keys shipped in i18n/en_US.csv. EmbedRewriter itself stays framework-free and unit-testable with a plain stub of the interface. The provider's own label (e.g. "YouTube") is still interpolated, not translated.

Qoliber_GdprFrontend

Fixed

  • The dependency on Qoliber_GdprCore was never declared. This module's Api\TagTypeInterface and Model\TagType\TagTypePool are BC shims that extends the GdprCore classes of the same name, and etc/di.xml configures Qoliber\GdprCore\Model\TagType\TagTypePool directly, so composer require could resolve it without qoliber/gdpr-core present and the module would fatal on a class that is simply not there. Installing the full suite hid it, because something else pulled the package in. Now required explicitly at ^1.2.

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprFrontendHyva

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprGtm

Fixed

  • The dependency on Qoliber_GdprCore was never declared. This module's GoogleTagManager tag type implements Qoliber\GdprCore\Api\TagTypeInterface and etc/di.xml registers itself on GdprCore's pool, so composer require could resolve it without qoliber/gdpr-core present and the module would fatal on a class that is simply not there. Installing the full suite hid it, because something else pulled the package in. Now required explicitly at ^1.2.

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprPolicy

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.

Fixed

  • Cross-customer authorisation hole in the policy-consent REST API. GET /V1/gdpr/policy/consent/check accepted a caller-supplied customerId and answered for it, so an authenticated customer could ask about another subject's policy consent. The endpoint now answers only for the token's own customer.
  • A broken :policyType route in webapi.xml that made one endpoint unreachable.
  • Policy IP minimisation now delegates to the shared GdprCore implementation instead of a private copy.

Added

  • Model\PolicyConsentSearchResults with explicit typed overrides, fixing a di:compile incompatibility.

Qoliber_GdprPolicyHyva

Fixed

  • The dependency on Qoliber_GdprConsent was never declared. Plugin\Model\Consent\Renderer\PrivacyPolicyRendererPlugin type-hints Qoliber\GdprConsent\Api\Data\ConsentDefinitionInterface, so the plugin fatals if that package is absent. Now required explicitly at ^1.2.

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprPrivacyCenter

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprPrivacyCenterHyva

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprWithdrawal

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.

Fixed

  • Withdrawal notification templates are now resolved from configuration at send time. The confirmation, approved and rejected templates were selected by hardcoded identifiers, so the admin fields were saved and never consulted.
  • Guest withdrawal controllers no longer pass a raw Throwable in the Monolog context. The message was scrubbed, but NormalizerFormatter re-serialises the exception object, putting the original text — which routinely quotes the subject's email — straight back into the log.
  • The mail-send exception text is no longer persisted to the withdrawal record's error_message.

Removed

  • guest/lookup_fields — declared, saved, and read by nothing; its Model\Source\LookupFields source model is removed with it.

Qoliber_GdprWithdrawalGraphQl

Fixed

  • confirmWithdrawal returned the raw exception message to the caller. Exception text routinely quotes the offending value, and this resolver answers unauthenticated clients. It now returns a neutral message.

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprWithdrawalHyva

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

Qoliber_GdprYireoGtm

Fixed

  • The dependency on Qoliber_GdprCore was never declared. This module's YireoGtm tag type implements Qoliber\GdprCore\Api\TagTypeInterface and etc/di.xml registers itself on GdprCore's pool, so composer require could resolve it without qoliber/gdpr-core present and the module would fatal on a class that is simply not there. Installing the full suite hid it, because something else pulled the package in. Now required explicitly at ^1.2.

Changed

  • Dependency constraints are now pinned. Every magento/* requirement was an unbound "*", which let Composer resolve a Magento version this code was never tested against, and sibling qoliber/gdpr-* requirements sat at ^1.0 or "*" even where a 1.2.0 sibling is required — Qoliber_GdprEmbed's "Always allow" button, for instance, needs the listener added to Qoliber_GdprCookie in 1.2.0, so resolving 1.0.0 gave a silently dead button. Magento packages now carry their major.minor floor and suite siblings require ^1.2, matching how the suite is built and released.
  • Version aligned to 1.2.0 for the GDPR Suite 1.2.0 release. No functional changes to this module.

1.1.0 — 2026-07-26

Qoliber_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.

Qoliber_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.

Qoliber_GdprConsentHyva

Changed

  • Restructured the Tailwind sources: extracted tailwind-source.css into module.css + component partials and refreshed the tailwind.config.js safelist 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).

Qoliber_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.

Qoliber_GdprCookieHyva

Changed

  • Restructured the Tailwind sources: extracted tailwind-source.css into module.css + component partials and refreshed the tailwind.config.js safelist 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).

Qoliber_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.

Qoliber_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.

Qoliber_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.

Qoliber_GdprDataSubjectHyva

Changed

  • Updated the tailwind.config.js safelist 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).

Qoliber_GdprDemo

Changed

  • Updated the tailwind.config.js safelist 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).

Qoliber_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.

Qoliber_GdprFrontendHyva

Changed

  • Updated the tailwind.config.js safelist 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).

Qoliber_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.

Qoliber_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.

Qoliber_GdprPolicyHyva

Changed

  • Updated the tailwind.config.js safelist 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).

Qoliber_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.

Qoliber_GdprPrivacyCenterHyva

Changed

  • Restructured the Tailwind sources: extracted tailwind-source.css into module.css + component partials and refreshed the tailwind.config.js safelist 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).

Qoliber_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 an is_full_request flag; 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 the is_full_request flag 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

Qoliber_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

Qoliber_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

Qoliber_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

Qoliber_GdprConsent

Added

  • Configurable "Link Text" on consent definitions (REAC-7). New nullable link_text column + 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.

Qoliber_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.

Qoliber_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

Qoliber_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 via eval(), which a strict checkout CSP (no unsafe-eval) blocks — the step transition rejected and checkout never advanced (plus a "Multiple root elements" Livewire warning). The gdprCheckoutConsents Alpine component is now registered in the static, CSP-hashed before.body.end block and the inline script is gone; the Magewire template ends at its single root element.

Qoliber_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 delete still flagged the field red and failed valid() (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

Qoliber_GdprAdmin (module date: 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.

Qoliber_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 DeleteButton block that POSTs via deleteConfirm(..., {"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 broke setup:di:compile on partial installs); removed the no-op Magento_Cookie sequence entry.

Qoliber_GdprConsentHyva (module date: 2026-06-10)

Fixed

  • setup:di:compile failed on Hyvä-theme-without-Hyvä-Checkout installs. The checkout consent Magewire component extends Magewire/Hyvä-Checkout classes that composer never required. Declared hyva-themes/magento2-hyva-checkout as a dependency; splitting the component into a dedicated GdprConsentHyvaCheckout module is scheduled for 1.1 (ROADMAP F18.3).
  • CSP cleanup: removed leftover hyva-csp-helper generator comments (no functional change).

Qoliber_GdprCookie (module date: 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\MassDelete is now HttpPost-only too.
  • Package cycle with GdprFrontend broken: ViewModel\CookieConsent now consumes the TagType pool from GdprCore (see GdprCore 1.0.3); the qoliber/gdpr-frontend composer 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_RESOURCE ACL (previously any admin role could execute them; cookie-detail delete carried a dead isAllowed() override the framework never calls). Grid Delete actions now POST with a form key.
  • Packaging: declared the real qoliber/gdpr-frontend composer dependency (ViewModel\CookieConsent imports 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-theme attribute 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 bind data-theme to settings.theme directly, so the theme and Custom colour palette apply reliably. (Hyvä already server-rendered data-theme and was unaffected.)

Qoliber_GdprCookieHyva (module date: 2026-06-10)

Fixed

  • CSP cleanup: removed leftover hyva-csp-helper generator comments from the Hyvä templates (per AGENTS.md; no functional change).

Qoliber_GdprCookieTemplates (module date: 2026-06-10)

Fixed

  • Admin hardening: the template-picker JSON controller now declares a granular ADMIN_RESOURCE (Qoliber_GdprAdmin::gdpr_cookies_manage); its previous isAllowed() override used a method name the framework never calls, so any admin role could query it.

Qoliber_GdprCore

Added

  • Api\TagTypeInterface and Model\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.

Qoliber_GdprDataSubject (module date: 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 via original_request_id. (c) The terminal anonymization_completed/anonymization_failed statuses (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\ProcessDataFetchRequests marked a request completed right after emailing the download link, but the download/view gates only accept notified/accessed — so every emailed link was rejected. The cron now sets notified (matching ProcessDataAccessNotifications); 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 from DenyDelete / DenyAnonymize, so a denied request re-enables the customer's login.

Qoliber_GdprDataSubjectHyva (module date: 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-helper generator 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 delete is accepted; the uppercased display no longer mismatches a case-sensitive check), live validation uses @input instead of @change, and the acknowledgement checkbox now reads .checked instead of the string "on". A fully and validly filled form now enables the submit button instead of staying disabled/red.

Qoliber_GdprFrontend (module date: 2026-06-10)

Changed (review round 2, 2026-06-11)

  • Api\TagTypeInterface and Model\TagType\TagTypePool moved 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_GdprDataSubject soft 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 storefront ViewModel\CookieConsent, instantiated on every page, extends GdprCookie's view model: a standalone install fataled the whole storefront) and magento/module-google-gtag (di.xml plugs Magento\GoogleGtag\Block\Ga). The structural decoupling is scheduled for 1.1 (ROADMAP F18.2).

Qoliber_GdprGtm

Changed

  • Tag type now implements the GdprCore TagTypeInterface and registers in the GdprCore TagTypePool (moved from GdprFrontend).
  • Packaging: declared the real qoliber/gdpr-cookie dependency (the frontend layout instantiates its CookieConsent view model); removed the no-op Magento_GoogleGtag sequence entry (no code, layout or block interaction).

Qoliber_GdprPolicy (module date: 2026-06-09)

Fixed (marketplace-hardening review, 2026-06-10)

  • REST policy-consent endpoints could never authorize. etc/webapi.xml referenced the ACL resource policy_consent_view, but acl.xml defines policy_consents_view — every token was rejected. Fixed the reference.
  • Undeclared hard dependency on Qoliber_GdprCookie. Data patches inject GdprCookie repositories and di.xml plugs its CookieConsent view model, so a partial install fataled setup:upgrade/di:compile. Declared the dependency (composer + module sequence) and pointed both cookie-seeding patches' getDependencies() at InstallDefaultCookies so 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 a gdpr/policy/view route that does not exist. Repointed it to the real gdpr/policy/render endpoint so the consent link / policy modal never resolves to a 404.

Qoliber_GdprPolicyHyva (module date: 2026-06-10)

Fixed

  • CSP cleanup (per AGENTS.md): the privacy-policy modal now binds x-data directly to the canonical QoliberGdprPrivacyPolicy component; removed the redundant generated gdprPrivacyPolicy alias wrapper script and leftover hyva-csp-helper generator comments.

Qoliber_GdprYireoGtm

Changed

  • Tag type now implements the GdprCore TagTypeInterface and registers in the GdprCore TagTypePool (moved from GdprFrontend).

1.0.2 — 2026-06-07

Qoliber_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 as qoliber_gdpr/request/view, but Qoliber_GdprAdmin has no such controller — the data-subject request detail view is owned by Qoliber_GdprDataSubject on the gdpr admin 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 controller gdpr/request/view (same id parameter). Covered by a unit test.

Qoliber_GdprConsent (module date: 2026-06-06)

Fixed

  • Guest checkout failed with a TypeError (critical). PaymentInformationManagementPlugin was bound to both the logged-in Magento\Checkout\Model\PaymentInformationManagement and the guest Magento\Checkout\Model\GuestPaymentInformationManagement, but the guest interface inserts $email as the second argument — so on every guest order the $email string was passed into the PaymentInterface $paymentMethod parameter and threw a TypeError, blocking the order. Additionally saveConsentData(int $cartId, …) type-hinted the cart id as int, which a masked-string guest cart id also broke. Split the logic into a dedicated Plugin\Checkout\Model\GuestPaymentInformationManagementPlugin with the correct guest signature, kept PaymentInformationManagementPlugin for the logged-in flow, moved the shared consent extraction into Service\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_policy consent's routing changed (display_type cms_page_linkprivacy_policy_link, link_url /privacy-policy-cookie-restriction-modegdpr/policy/render), but InstallDefaultConsents is 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 idempotent Setup/Patch/Data/ReconcilePrivacyPolicyConsentLink that 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 any events.xml, so the ShippingInformationManagementPlugin that 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, ConsentTracker has 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 unified Observer\PersistCheckoutConsents (see Changed). Removed the orphaned observer, Plugin\Checkout\Model\ShippingInformationManagementPlugin and its two di bindings, and the shipping-save-processor JS mixin. The CartInterface/ShippingInformationInterface consent 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_consent vs qoliber_gdpr_consents), each consumed by its own observer on overlapping events — a divergence that risked silent misses and, if ever naively aligned, double-recording (ConsentTracker has no per-order dedup). Introduced a single shared key, Model\Checkout\ConsentSession::KEY, used by both writers, and one base-module observer Observer\PersistCheckoutConsents on the universal checkout_submit_all_after event that records consent for every storefront (accepting both the serialized-string and raw-array payload shapes). Removed the Luma-only Observer\CheckoutOnepageSuccess; the redundant Qoliber_GdprConsentHyva observer is removed too (see its changelog).

Qoliber_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::KEY instead of its own private session key, and recording is handled by the single base-module observer Qoliber\GdprConsent\Observer\PersistCheckoutConsents (on checkout_submit_all_after). Removed this module's now-redundant Observer\CheckoutSubmitAllAfterObserver and its etc/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. See Qoliber_GdprConsent 1.0.2.

Qoliber_GdprCookie (module date: 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 stores persistent (×13) and session (×1) too. With no matching option, Magento_Ui/js/form/element/select resolved the value to undefined, so admins saw a blank Type and re-saving could silently clear it. Added a canonical Model\Source\CookieType source (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 moves product_data_storage and section_data_ids to the Functionality category on stores upgraded from 1.0.0-RC. The 1.0.0 InstallDefaultCookies reclassified 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.

Qoliber_GdprPolicy (module date: 2026-06-06)

Fixed

  • "Cookie Consent Mode Text" was ignored when Privacy Policy Type = CMS Page. Plugin\ViewModel\CookieConsentPlugin rendered 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\Render and both renderers (VersionBasedRenderer, CmsPageRenderer) now catch \Throwable (not just \Exception) and log the exception class + file:line, so a PHP Error returns 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

Qoliber_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.xml registered the qoliber_gdpr_consent_log_listing_data_source collection a second time (virtualType QoliberGdprConsentSearchResult → table qoliber_gdpr_consent_log), overriding the correct binding declared in Qoliber_GdprConsent (→ qoliber_gdpr_consent_customer_log). Because Qoliber_GdprAdmin is <sequence>d after Qoliber_GdprConsent, its di.xml merged last and the wrong mapping won. The grid's listing XML targets the qoliber_gdpr_consent_customer_log schema (PK log_id, columns consent_code, form_location, is_accepted, accepted_at), none of which exist in qoliber_gdpr_consent_log — so the first render threw SQLSTATE Unknown column 'log_id'. Removed the stray binding and the now-orphaned QoliberGdprConsentGridDataProvider / QoliberGdprConsentSearchResult virtualTypes so the correct Qoliber_GdprConsent data source takes effect. Verified by resolving the live grid collection: it now queries qoliber_gdpr_consent_customer_log and returns rows without error.

Qoliber_GdprCookie

Fixed

  • Cookie Detail form "Cookie Category" dropdown could hide categoriesUi/Component/Form/Element/CategoryOptions only listed categories with is_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 the is_enabled filter 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 — run bin/magento setup:upgrade to apply the InstallDefaultCookies / InstallGoogleConsentCategory data patches.

1.0.0 — 2026-05-22

Qoliber_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_activities with 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

Qoliber_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

Qoliber_GdprConsentHyva

Added

  • Initial Hyva theme compatibility module for Qoliber GDPR Consent
  • Magewire Component Integration: Implemented GdprConsents Magewire component for Hyva Checkout integration
    • Real-time consent state management using Magewire reactive properties
    • Implements EvaluationInterface for 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 qoliberGdprConsent Alpine.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 flow
    • hyva_default.xml: Global Hyva theme integration
    • hyva_contact_index_index.xml: Contact form consent integration
    • hyva_customer_account_create.xml: Registration form consents
    • hyva_newsletter_manage_index.xml: Newsletter subscription consents
    • hyva_customer_account_privacy.xml: Privacy dashboard integration
    • hyva_customer_consent_preferences.xml: Consent preference management
    • default_hyva.xml: Fallback layout for Hyva detection
  • Customer Privacy Dashboard: Hyva-styled templates for consent management
    • hyva_hero.phtml: Hero section with gradient backgrounds
    • hyva_history.phtml: Consent history timeline view
    • hyva_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_consents session 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
  • Validation System:
    • Required consent validation in evaluateCompletion method
    • Custom error events with consent details (gdpr-consents:details:error)
    • Success events for completed validation
    • User-friendly error messages with missing consent titles
  • 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

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)

Qoliber_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

Qoliber_GdprCookieHyva

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
  • 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_groups integration
    • window.cookie_consent_config mapping
    • 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
  • 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()
  • State Management:
    • isVisible: Modal visibility control
    • showSettings: Expanded settings view toggle
    • showReopener: Floating button visibility
    • activeTab: Current tab selection (consent/details/about)
    • selectedCategories: User-selected cookie categories array
    • expandedCategories: Accordion expansion state object
    • showPrivacyModal: 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 details
    • user-allowed-save-cookie: Hyva integration event
    • gdpr-reopen-settings: External reopen trigger
    • qoliberGoogleConsentUpdated: Google consent update notification (debug mode)
  • Google Consent Configuration:
    • ad_storage: Marketing consent mapping
    • ad_user_data: Marketing consent mapping
    • ad_personalization: Marketing consent mapping
    • analytics_storage: Analytics consent mapping
    • functionality_storage: Always granted
    • personalization_storage: Marketing consent mapping
    • security_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

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)

Qoliber_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

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

Qoliber_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\LawfulBasisSourceOptionSourceInterface adapter for admin forms/grids.
  • Qoliber\GdprCore\Service\AgeGateService — GDPR Art. 8 age-of-digital-consent helper. Computes age from DOB, exposes canGiveConsent() / canGiveConsentStrict() / requiresParentalConsent(). Threshold configurable (13–18, default 16) under qoliber_gdpr/age_gate/threshold; gate toggle at qoliber_gdpr/age_gate/enabled (disabled by default).
  • Domain enums (PHP 8.1 modernisation, WS5):
    • RequestStatus (backed string, 13 cases) with isTerminal() / isActive() helpers.
    • RequestType (backed string, 10 cases) with articleReference() mapping each right to its GDPR Art. 15–21 citation.
    • PolicyStatus (backed int, 4 cases — draft/active/published/archived) with isPublic() / isEditable() helpers.
    • ConsentAction (backed string, 2 cases — granted/revoked) with isPositive().
    • Legacy class-constants in consuming modules remain for back-compat; new code should prefer the enums.

Qoliber_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

Qoliber_GdprDataSubjectHyva

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)
  • 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)
  • Anonymization Workflow: Multi-step anonymization process
    • Status tracking interface (hyva/anonymization/status.phtml)
    • Confirmation step template
    • Status-based UI updates
  • 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 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)
  • Layout Integration: Comprehensive Hyva layout support
    • hyva_gdprds_guest_viewdata.xml: Guest data view layout
    • hyva_gdprds_customer_delete.xml: Customer deletion layout
    • hyva_customer_account_privacy.xml: Privacy center layout
    • hyva_gdprds_guest_datarequest.xml: Guest data request layout
    • hyva_gdprds_customer_anonymize.xml: Anonymization request layout
    • hyva_gdprds_anonymization_status.xml: Anonymization status layout
    • hyva_gdprds_anonymization_confirm.xml: Confirmation layout
    • hyva_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
  • 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
  • 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
  • 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
  • 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)
  • 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-semibold with color-specific classes
  • Alpine.js Integration:
    • Smooth scroll handler: @click.prevent="document.getElementById('export-form').scrollIntoView({ behavior: 'smooth', block: 'start' })"
    • Event-driven navigation
    • Progressive enhancement approach
  • Conditional Rendering Logic:
    • PHP-based: <?php if ($configViewModel && $configViewModel->isAnonymizationEnabled()): ?>
    • Backend-driven feature flags
    • Clean template architecture
  • Action URLs:
    • Rectification: /gdprds/customer/rectification
    • Anonymization: /gdprds/customer/anonymize
    • Deletion: /gdprds/customer/delete
    • Export: In-page anchor #export-form

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

Qoliber_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 retired gdprds/request/index route. The old route was deleted in this release (see Qoliber_GdprDataSubject CHANGELOG); 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 via qoliber_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 DEMO badge 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
  • 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
  • ViewModel\DemoLinks supplies all URLs + a isCustomerLoggedIn() 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.0
  • qoliber/gdpr-privacy-center: ^1.0
  • qoliber/gdpr-policy: ^1.0
  • qoliber/gdpr-cookie: ^1.0

Qoliber_GdprFrontend

Added

  • Initial beta release with core cookie consent functionality

Qoliber_GdprFrontendHyva

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 advertising
      • ad_personalization: Personalized advertising
      • ad_storage: Advertising cookies
      • analytics_storage: Analytics cookies
      • functionality_storage: Always granted for necessary functionality
      • personalization_storage: Personalization cookies
      • security_storage: Always granted for security
    • localStorage persistence (qoliber_google_consent)
    • Automatic consent restoration on page load
    • JSON-encoded consent state with proper escaping
  • 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
  • ViewModel Integration: Clean data layer architecture
    • CookieConsent ViewModel 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
  • 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
    • qoliberGoogleConsentUpdated custom 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:
    1. Initialize dataLayer array
    2. Declare gtag function
    3. Set default consent state
    4. Configure URL passthrough (if enabled)
    5. Configure ads data redaction (if enabled)
    6. Load GTM script asynchronously
    7. Configure GTM with Tag ID
    8. 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 debugMode configuration
  • 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

Qoliber_GdprGtm

Added

  • Initial release candidate with Google Tag Manager GDPR integration

Qoliber_GdprPolicy

Added

  • Initial beta release with core privacy policy management

Qoliber_GdprPolicyHyva

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

Qoliber_GdprPrivacyCenter

Added

  • Initial release candidate with Privacy Center customer account integration

Qoliber_GdprPrivacyCenterHyva

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

Qoliber_GdprYireoGtm

Added

  • Yireo GTM Integration: Specialized integration module for Yireo's Google Tag Manager extension with GDPR cookie consent
  • TagType Implementation: YireoGtm class implementing TagTypeInterface for seamless integration with GdprFrontend tag system
  • Dynamic Module Detection: Automatic availability detection based on Yireo_GoogleTagManager2 module status
    • Uses ModuleManager to 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
  • 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.phtml template 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\TagTypeInterface for 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 ModuleManager for 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_GdprFrontend for base cookie consent and tag type framework
  • Requires Yireo_GoogleTagManager2 module (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
Changelog — GDPR Compliance Suite — Compliance & Legal — Extensions | qoliber Docs