Appearance
Cookie Consent
A consent banner: analytics and ads wait for the visitor's yes.
kitloom/cookie-consent · admins: kitloom/cookie-consent-filament, kitloom/cookie-consent-nova
Video lessons
Recorded in the Filament admin; the Nova admin works the same way.
A cookie consent banner for the site. Visitors decide which cookies they allow, and analytics, tag managers and ad pixels added by other modules wait until they say yes. It does what Complianz or CookieYes did on the WordPress site, and their banner settings can be imported. The admin page is the Cookie Consent section (kitloom/cookie-consent-filament or kitloom/cookie-consent-nova).
What visitors see
On a visitor's first visit, a banner asks them about cookies. It has three buttons:
- Accept all
- Deny — only functional cookies, which the site needs to work.
- Preferences — the visitor ticks categories one by one.
| Category | What it covers |
|---|---|
| Functional | What the site needs to work. Always on; the visitor cannot refuse it. |
| Preferences | Remembered choices: the language, the region. |
| Statistics | Counting visits: Google Analytics, Plausible, Matomo. |
| Marketing | Ads and their measurement: Meta, TikTok, Google Ads pixels, embedded videos that track. |
The choice is kept in the visitor's browser, in the kitloom_consent cookie, for as long as the settings say (365 days by default). After that the banner asks again. Once a visitor has chosen, a small Manage consent button stays in the corner so they can change their mind. A visitor who takes back a category gets the page reloaded, so whatever that category had loaded is gone.
The banner is the same for every visitor: pages stay in the page cache, and the visitor's browser decides whether to show it.
Setting it up
- Install the module. The banner appears at once, with default texts in the site's language, and every tracker from other modules waits for consent.
- Open Cookie Consent → Settings:
- Texts — leave a field empty to keep the text shown in grey. The message may contain HTML: a link, bold text.
- Categories — untick the ones the site does not use. A site without ads does not need to offer Marketing. Each category's name and description can be rewritten.
- Cookie policy — a page of the site, or an address. The banner links to it.
- Colours and Position — a corner, across the bottom, or in the middle of the screen.
- Keep the choice for — how many days before the banner asks again.
- On the cookie policy page, put
[cookie-consent]. It shows a button that opens the visitor's preferences. Data-protection rules want visitors to be able to change their mind, so keep this button or the floating Manage consent button.
Coming from Complianz or CookieYes
If the WordPress site ran Complianz or CookieYes, the settings page has an Import button. The console command does the same:
bash
php artisan cookie-consent:import
php artisan cookie-consent:import --from=cookieyesThe import takes:
- the texts (CookieYes: in the site's default language);
- the position and the colours;
- which categories were shown;
- how long consent is kept;
- the cookie policy page or address;
- whether Google Consent Mode was on.
What the plugin left empty stays as it is. The plugin's own tables and options are not touched.
Visitors' choices cannot be carried over: they were in the plugin's cookies, so every visitor sees the new banner once. Pages that contain Complianz's [cmplz-manage-consent] keep working: it is the same button as [cookie-consent].
Google Consent Mode v2
Off by default. In that case, Google Analytics and Google Tag Manager wait for consent like every other tracker: nothing loads before the visitor says yes.
Turned on, Google's tags load right away with every signal denied: no analytics or ad cookies, only cookieless pings. When the visitor chooses, the banner tells Google which signals are now granted:
| Category | Consent Mode signals |
|---|---|
| Preferences | personalization_storage |
| Statistics | analytics_storage |
| Marketing | ad_storage, ad_user_data, ad_personalization |
functionality_storage and security_storage are always granted. Google Ads in the EEA requires Consent Mode, and Google Analytics models the visits of visitors who said no.
The theme
The banner goes where the theme put @siteHead and @siteFooter in its layout; every kitloom theme has them. A theme of your own adds @siteHead, @siteBodyOpen and @siteFooter to its root layout.
To change the banner's markup, publish its view and edit it, keeping the ids and the data-kitloom-consent-* attributes:
bash
php artisan vendor:publish --tag=kitloom-cookie-consent-viewsThe theme's own scripts can ask about consent too:
js
if (window.kitloomConsent && kitloomConsent.has('statistics')) { /* … */ }
document.addEventListener('kitloom:consent', (event) => console.log(event.detail)); // {functional: true, preferences: false, statistics: true, marketing: false}kitloomConsent.open() opens the preferences. kitloomConsent.choice() is the visitor's choice, or null before they choose.
A script in the theme can also be held back without any code: write it as <script type="text/plain" data-kitloom-consent="statistics">…</script>, and the banner runs it once the category is granted.
For developers
A module that adds a tracker hands its markup to kitloom/site's
ScriptConsentwith the category it needs. It does not need this package:phppublic function __construct(private ScriptConsent $consent) {} yield $this->consent->gate(ScriptConsent::STATISTICS, $snippet, googleConsentMode: true);- Without this module, the markup goes out as it is.
- With it, every
<script>becomestype="text/plain" data-kitloom-consent="statistics". An iframe's or an image'ssrcmoves todata-kitloom-src, and<noscript>is dropped: without JavaScript there is nobody to ask. googleConsentMode: trueis for Google tags only. When Consent Mode is on, the tag is not held back; the denied defaults are put in front of it.- Functional markup is never held back.
Settings:
cookie_consent_*, declared byConsentOptionsand written throughSettingWriter. The texts have no stored default: empty means the translated default.Classes:
HeldScripts— theScriptConsentimplementation.ConsentScripts— thePageScriptsProvider: style and script in the head, banner view before</body>.GoogleConsentMode— the defaults snippet.Import\BannerImport— the import.
The browser script is
resources/js/consent.js, inlined into the page with no build step and no dependencies. A Content Security Policy nonce set withVite::useCspNonce()goes on its tags.Config:
php artisan vendor:publish --tag=kitloom-cookie-consent-configpublisheskitloom-cookie-consent.php. It sets the cookie's name, the shortcodes switch and the admin sections (filament.register,nova.register).Tests, from the application that installs the package:
php vendor/bin/phpunit --testsuite CookieConsent.