Appearance
Are you an LLM? You can read better optimized documentation at /flows/customer/CF-30-cookie-consent.md for this page in Markdown format
Cookie Consent / GDPR
Flow ID: CF-30 | Module(s): cookies, eshop (front controller), Cms/Cookie domain | Complexity: Medium
Business Overview
The Cookie Consent system provides GDPR-compliant cookie management for the storefront. It combines a client-side consent modal (Vue 2) with a server-side cookie registry (database-backed catalog of all cookies the shop uses). The consent mechanism integrates with Google Tag Manager's Consent Mode v2 to gate analytics, advertising, and personalization tracking based on visitor choices.
What visitors experience:
- On first visit, a cookie consent banner appears at the bottom of the page
- Three quick actions: "Accept Essentials", "Accept All", or "More Settings"
- The details panel (lazy-loaded) shows a categorized table of all cookies the shop uses
- The settings modal offers per-category toggles (required, analytics, advertising, personalization, ad user data, ad personalization)
- Partial consent saves only the categories the visitor explicitly enabled
- Consent persists for 365 days via first-party cookies; returning visitors skip the banner
What administrators do:
- Enable/disable the cookie details feature via global settings (
COOKIES.ENABLEDregistry key) - Manage the cookie catalog: add, edit, delete cookie entries with platforms, categories, data controllers, key names, domains, descriptions, retention periods, and privacy links
- Configure which data controllers and categories are active (multi-select filters)
- Assign CMS pages that should display an inline cookie declaration table (PAGES_TO_SHOW)
Key business behaviors:
- Feature-gated: entire flow is disabled when
COOKIES.ENABLEDis false - Consent state is stored client-side only (browser cookies) -- no server-side consent record per visitor
- Google Consent Mode v2 integration pushes
consent defaultandconsent updateevents to the dataLayer - Functionality storage is always granted by default; all other categories default to denied
- Legacy session-based cookie tracking (
session_cookies) coexists for backward compatibility with older tracking helpers - No MUI: cookie catalog is single-language (no
cookies_muitable)
API Reference
REST Endpoints (Modern)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /rest/cms/cookie | Guest | List cookie catalog entries (paginated, filterable) |
| GET | /rest/cms/cookie/item | Guest | Get single cookie entry by filter |
| GET | /rest/cms/cookie/{id} | Guest | Get single cookie entry by ID |
| POST | /rest/cms/cookie | Backend (Admin) | Create cookie entry |
| POST | /rest/cms/cookie/{id} | Backend (Admin) | Update cookie entry |
| DELETE | /rest/cms/cookie/{id} | Backend (Admin) | Delete cookie entry |
Filters: id (exact), categories (partial), dataControllers (partial), dataKeyNames (partial) Sorts: id, categories
Legacy JSON API (Storefront)
| Method | Path | Description |
|---|---|---|
| GET | /cookies | Returns cookie catalog grouped by category (JSON) |
Legacy Admin
| Method | Path | Description |
|---|---|---|
| GET | /cookies_admin | Admin listing + filter config form |
| GET | /cookies_admin/add | Add cookie entry form |
| PUT | /cookies_admin/update | Update cookie entry (AJAX, JSON response) |
| POST | /cookies_admin/delete | Delete cookie entry (AJAX, JSON response) |
Legacy Session Cookie Endpoint
| Method | Path | Description |
|---|---|---|
| POST | /customer/set_cookies | Saves session-level cookie consent (legacy) |
Code Flow
Storefront Consent Banner Flow
- Page load (
Adv_front_controller): PassescookieDetailsEnabledandcookiePagesToShowto the Vue app viajsonState.config - Vue mount (
cookiesModalMixin.js): Checksconsent_statuscookie- No consent cookie: Calls
initializeDefaultState()-- sets all consent cookies to defaults, pushesgtag('consent', 'default', ...), opens the cookie modal - Has consent cookie: Calls
initializeStateFromCookies()-- reads each consent cookie value, pushesgtag('consent', 'default', ...)with stored values
- No consent cookie: Calls
- User action: One of three paths:
- Accept Essentials: Sets
consent_status=true, denies ad/analytics/personalization/ad_user_data/ad_personalization, grants functionality only - Accept All: Sets
consent_status=true, grants all categories, persists to cookies, pushesgtag('consent', 'update', ...)with all granted - More Settings: Switches to
CookieSettingsview with per-category toggles, then "Partial Consent" or "Full Consent"
- Accept Essentials: Sets
- Cookie persistence: Each consent category is stored as a separate first-party cookie (365-day expiry) using
cookie-access.js - Details table (lazy-loaded): When user clicks "Details",
CookieNoticefetchesGET /cookiesand renders a sortable, filterable table of all registered cookies
Admin Cookie Catalog Management
File: ecommercen/cookies/controllers/Adv_cookies_admin.php
- Feature gate: Every action checks
$this->registry->value('COOKIES', 'ENABLED')-- returns 404 if disabled - List (
index): Loads active data_controllers and categories from registry, queries cookies filtered by those values, renders the admin table with inline edit and delete buttons - Add (
add): Form validation requires all 8 fields (platforms, categories, data_controllers, data_key_names, domains, description, retention_period, links), inserts via model - Update (
update): JSON response, validates id + description + links, updates via model - Delete (
delete): JSON response, validates numeric ID, deletes via model - Registry config: Saves active DATA_CONTROLLERS, CATEGORIES, and PAGES_TO_SHOW arrays to the registry table
CMS Page Cookie Table Integration
File: ecommercen/category/controllers/Adv_category.php (line ~125)
When rendering a CMS page, checks if the current category_id is in the PAGES_TO_SHOW registry array. If matched, loads the cookie catalog and renders the cookies_table component inline within the page content.
View: application/views/main/cms/page.php -- conditionally includes cookiesTable component when $cookies is non-empty and COOKIES.ENABLED is true.
Legacy Session Cookie Flow
File: ecommercen/eshop/controllers/Adv_customer.php (setCookies method)
Stores a session-level session_cookies array with keys SESS_COOKIE_REQUIRED (1) and SESS_COOKIE_ADVERTISING (2). This is a legacy mechanism used by the tracking helper (tracking_helper.php) to conditionally include promotion tracking data attributes.
Domain Layer
| Component | Path |
|---|---|
| Entity | src/Domains/Cms/Cookie/Repository/Entity.php |
| Repository | src/Domains/Cms/Cookie/Repository/Repository.php |
| RepositoryConfigurator | src/Domains/Cms/Cookie/Repository/RepositoryConfigurator.php |
| WriteRepository | src/Domains/Cms/Cookie/Repository/WriteRepository.php |
| Service (read) | src/Domains/Cms/Cookie/Service.php |
| WriteService | src/Domains/Cms/Cookie/WriteService.php |
| WriteData | src/Domains/Cms/Cookie/WriteData.php |
| Validator | src/Domains/Cms/Cookie/Validator.php |
| ListRequest | src/Domains/Cms/Cookie/ListRequest.php |
| DI Registration | src/Domains/Cms/container.php (Cookie section) |
REST Layer
| Component | Path |
|---|---|
| Controller | src/Rest/Cms/Controllers/Cookie.php |
| Resource | src/Rest/Cms/Resources/Cookie/Resource.php |
| Collection | src/Rest/Cms/Resources/Cookie/Collection.php |
| DI Registration | src/Rest/Cms/container.php |
Legacy Layer
| Component | Path |
|---|---|
| Front controller | ecommercen/cookies/controllers/Adv_cookies.php |
| Admin controller | ecommercen/cookies/controllers/Adv_cookies_admin.php |
| Model | ecommercen/cookies/models/Adv_cookies_model.php |
| App overrides | application/modules/cookies/controllers/Cookies.php, Cookies_admin.php, models/Cookies_model.php |
Architecture
Frontend Component Tree
CookieModal (GenericModal wrapper)
├── CookieNotice (banner view)
│ ├── Accept Essentials button
│ ├── Accept All button
│ ├── More Settings button → opens CookieSettings
│ └── Details panel (lazy-loaded cookie table via SimpleTable)
└── CookieSettings (per-category toggles)
├── Required (always on, disabled checkbox)
├── Analytics toggle
├── Advertising toggle
├── Personalization toggle
├── Ad User Data toggle
├── Ad Personalization toggle
├── Partial Consent button
└── Full Consent buttonAdditionally, CookieSettingsButton is a standalone component that re-opens the modal from anywhere (e.g., footer link).
Vuex Store
Module: cookies (namespaced) -- registered in assets/vue/store/index.jsFile: assets/vue/cookies/store/cookiesModule.js
State: Six consent categories, each with { defaultValue, validForDays, value }:
adStorage(default: denied)analyticsStorage(default: denied)functionalityStorage(default: granted)personalizationStorage(default: denied)adUserData(default: denied)adPersonalization(default: denied)
Plus cookieNoticeVisible and cookieSettingsVisible for UI state.
Google Consent Mode v2 Integration
The cookiesModalMixin.js handles dataLayer integration:
- On mount: pushes
gtag('consent', 'default', { ... })with either default values or previously stored cookie values - On consent update: pushes
gtag('consent', 'update', { ... })with the new values viaupdateGtagConsentFromState
Mapped consent signals: ad_storage, analytics_storage, functionality_storage, personalization_storage, ad_user_data, ad_personalization. Note: security_storage is explicitly not supported.
Theme Variants
- Main theme:
assets/main/vue/cookies/components/-- full implementations - Design theme:
assets/design/vue/cookies/components/-- extends main theme components with no overrides (extends: CookieNotice,extends: CookieModal) - SCSS:
assets/main/scss/_cookies.scss,assets/design/scss/_cookies.scss - Default library theme:
application/views/default/components/library/footer/scss/_footer_cookie_notice.scss,modals/footer/scss/_cookie_settings.scss
Data Model
cookies Table
| Column | Type | Description |
|---|---|---|
id | int (PK, AI) | Primary key |
platforms | varchar(255) | Platform(s) using this cookie (e.g., "web") |
categories | varchar(255) | Consent category (e.g., "analytics", "advertising") |
data_controllers | varchar(255) | Organization responsible (e.g., "Google LLC") |
data_key_names | varchar(255) | Cookie identifiers (e.g., "_ga, _gid") |
description | varchar(255) | Purpose description |
domains | varchar(255) | Domains where cookie is set |
retention_period | varchar(255) | Duration (e.g., "2 years") |
links | varchar(255) | Privacy policy URL |
No MUI companion table -- cookie catalog is single-language.
Registry Keys (registry table)
| Group | Key | Description |
|---|---|---|
COOKIES | ENABLED | Feature toggle (boolean) |
COOKIES | DATA_CONTROLLERS | Active data controllers filter (serialized array) |
COOKIES | CATEGORIES | Active categories filter (serialized array) |
COOKIES | PAGES_TO_SHOW | CMS page IDs that display the cookie declaration table (serialized array) |
Client-Side Consent Cookies
| Cookie Name | Values | Expiry | Purpose |
|---|---|---|---|
consent_status | true | 365 days | Whether consent banner has been dismissed |
consent_ad_storage | granted / denied | 365 days | Advertising cookie consent |
consent_analytics_storage | granted / denied | 365 days | Analytics cookie consent |
consent_functionality_storage | granted / denied | 365 days | Functionality cookie consent (default: granted) |
consent_personalization_storage | granted / denied | 365 days | Personalization cookie consent |
consent_ad_user_data | granted / denied | 365 days | Ad user data consent |
consent_ad_personalization | granted / denied | 365 days | Ad personalization consent |
Cookies are set with domain= (root domain, no www prefix) and path=/.
Session Data (Legacy)
| Session Key | Structure | Purpose |
|---|---|---|
session_cookies | { 1: bool, 2: bool } | Required (1) and Advertising (2) consent. Used by tracking_helper.php for promotion data attributes. |
Configuration
Feature Toggle
Enabled via admin settings panel (ecommercen/settings/controllers/Adv_settings.php):
Registry: COOKIES.ENABLED = true/false
Admin view: application/views/admin/settings/only_advisable.php (enableCookies checkbox)Constants
php
// application/config/constants.php
define('SESS_COOKIE_REQUIRED', 1);
define('SESS_COOKIE_ADVERTISING', 2);Routes
php
// application/config/routes.php
$route['cookies'] = 'cookies/cookies/index';
$route['cookies_admin'] = 'cookies/cookies_admin/index';
// + language-prefixed variantsphp
// application/config/rest_routes.php
$route['rest/cms/cookie']['GET'] = [Cookie::class, 'index'];
$route['rest/cms/cookie/item']['GET'] = [Cookie::class, 'item'];
$route['rest/cms/cookie/(:num)']['GET'] = [Cookie::class, 'show'];
$route['rest/cms/cookie']['POST'] = [Cookie::class, 'store'];
$route['rest/cms/cookie/(:num)']['POST'] = [Cookie::class, 'update'];
$route['rest/cms/cookie/(:num)']['DELETE'] = [Cookie::class, 'destroy'];
// + language-prefixed variantsREST Policies
php
// application/config/rest_policies.php
Cookie::class => [
'defaults' => ['auth' => 'backend', 'roles' => [AUTH_ROLE_ADMIN]],
'methods' => [
'index' => ['auth' => 'guest'],
'show' => ['auth' => 'guest'],
'item' => ['auth' => 'guest'],
],
],Read operations are public (guest); write operations require backend auth with ADMIN role.
Admin Menu
php
// application/config/admin_menu.php
[
'route' => 'cookies_admin',
'icon' => t('admin.menu.gdpr.icon'), // fa-shield-halved
'label' => t('admin.menu.gdpr.label'), // "GDPR"
'roles' => [AUTH_ROLE_ADVISABLE, AUTH_ROLE_DEVELOPER, AUTH_ROLE_ADMIN],
'group' => 'SETTINGS'
]Template Component
json
// application/config/mainTemplate.json
"cookiesTable": {
"view": "components/cookies/cookies_table",
"scss": ""
}Frontend Localization
The following translation key groups are used:
cookies.*-- banner text, button labels, table headerscms.cookies.*-- CMS page inline table labelseshop.admin.cookies.*-- admin panel labelscookies.settings.*-- settings modal labels and descriptions
Client Extension Points
Controller Overrides
The application/modules/cookies/ directory contains empty subclasses of the upstream controllers and model:
Cookies extends Adv_cookies-- override for custom storefront JSON behaviorCookies_admin extends Adv_cookies_admin-- overrideafterAdd()/afterUpdate()hooksCookies_model extends Adv_cookies_model-- override query logic
Domain Layer Override
In a client repo, create Custom\Domains\Cms\Cookie\ classes and register DI aliases:
php
$services->alias(
\Advisable\Domains\Cms\Cookie\WriteService::class,
\Custom\Domains\Cms\Cookie\WriteService::class
);Frontend Customization
- Override
CookieNotice.vueorCookieSettings.vuein the design theme (assets/design/vue/cookies/components/) - Override SCSS variables in
assets/design/scss/_cookies.scss - The default library theme provides alternative styling in
application/views/default/components/library/
Admin Hooks
afterAdd($result)-- empty hook inAdv_cookies_admin, override for post-creation logicafterUpdate($result)-- empty hook inAdv_cookies_admin, override for post-update logic
CMS Page Integration
Add category page IDs to the PAGES_TO_SHOW registry array to display the cookie declaration table on specific CMS pages. The table renders via the cookiesTable template component.
Business Rules
- Feature gate: All cookie admin and storefront endpoints return 404 / empty array when
COOKIES.ENABLEDis false - Default consent: Functionality storage is always
granted; all other categories default todenied - Required cookies: The "Required Cookies" toggle in settings is always on and disabled -- visitors cannot opt out of essential cookies
- Cookie domain: Consent cookies are set on the root domain (strips
www.prefix) to work across subdomains - No server-side consent record: Consent is stored entirely in browser cookies. There is no per-visitor consent audit trail in the database
- 365-day expiry: All consent cookies expire after one year; the banner reappears when
consent_statusexpires - Lazy-load details: The cookie catalog table is only fetched when the visitor clicks the "Details" button, avoiding unnecessary API calls
- Cache: The legacy
GET /cookiesendpoint usespscache(page-scoped cache) with the front controller's TTL - Admin roles: Cookie catalog management requires ADVISABLE, DEVELOPER, or ADMIN roles (admin menu); REST write operations require ADMIN role
- Admin validation: Add requires all 8 fields; update requires only id, description, and links (other fields are not editable after creation via the admin UI)
- CSV seed data: Initial cookie entries are seeded from
assets/patches/cookies/updatedCookies.csvvia theInitialSeedseeder, with a defaultGoogledata controller registry entry
Related Flows
- CF-01 Product Browsing -- consent state determines whether analytics/advertising tracking fires
- CF-10 Customer Auth --
customer/set_cookiesendpoint sets legacy session-level consent - CF-26 Home Page -- cookie modal renders on every storefront page via
Adv_front_controllerbase class - CF-29 Contact Forms -- shared CAPTCHA trait hierarchy via front controller