Aller au contenu
Québec Studio

Package pour Laravel

Cookie Consent Kit

Le consentement aux témoins, fait correctement : aucun témoin tiers avant l’accord du visiteur, et des pages qui restent en cache. Pensé pour la Loi 25.

Laravel 11–13
v1.1.0
Aussi pour
Craft CMS, Statamic

La documentation technique est rédigée en anglais, comme dans le dépôt.

Guide

Cookie consent banner for Laravel 11 to 13, built for Quebec's Law 25 and usable under the GDPR. Built on quebecstudio-mods/consent-kit-core, shared with the Craft CMS plugin.

  • No third-party cookie is set before consent.
  • The HTML is the same for every visitor; pages stay cacheable.
  • English and French included; an application adds any language with one file.
  • YouTube videos load on click, with the thumbnail served by the application.

Installation

Requires PHP 8.2. Declare the private repositories in the application's composer.json:

"repositories": [
    { "type": "vcs", "url": "[email protected]:quebecstudio-mods/laravel-consent-kit.git" },
    { "type": "vcs", "url": "[email protected]:quebecstudio-mods/consent-kit-core.git" }
]
composer require quebecstudio-mods/laravel-consent-kit
php artisan vendor:publish --tag=cookie-consent-assets
php artisan vendor:publish --tag=cookie-consent-config

The service provider is discovered automatically. The banner is added to every HTML page served through the web middleware group.

How it works

InjectConsent, appended to the web group, edits HTML responses:

PositionMarkup
first in <head>the inline bootstrap: reads the consent cookie, primes Matomo and Google Consent Mode in a refused state
end of <head>consent.css
end of <body>the <qsm-consent-kit> banner (when autoInject is on) and consent.js

JSON, redirects, file and streamed responses are left untouched.

Configuration

config/cookie-consent.php. The keys follow the core's settings; the Craft-only ones (policySource, policyEntry, templateRoot) do not apply.

KeyDefaultWhat it does
cookieNamecookie_consentCookie that stores the decision
cookieMaxAge15552000Its lifetime, in seconds
version1Increase to ask every visitor again
policyUrl/privacy-policyPolicy link in the banner; empty shows none
defaultLanguageenLanguage when the locale has no wording file
autoInjecttrueAdds the banner to every HTML page the middleware sees
colorSchemeautoauto, light, dark
backdropStyleblurblur, dim, none
displayModefullfull, floating, corner-left, corner-right; full width under 40rem
reopenButtontrueTab that reopens the banner
reopenPositionautoIts side: left, right, or auto, right for corner-right
gpcHidesBannertrueSkips the banner under Global Privacy Control
analyticsCategorystatisticsCategory granting Matomo and analytics_storage
marketingCategorymarketingCategory granting the Google ad signals
videoFacadetrueYouTube videos load on click
videoThumbnailstrueThe facade shows the YouTube thumbnail
videoConsentCategory''Category whose consent skips the facade
inventoryFramework''Cookie table classes: '', bootstrap, bulma, tailwind, custom
inventoryClasses[]Classes per table element, with custom
categoriesnullCategories and cookies; null uses the shipped ones

Categories

null ships three categories: necessary, declaring the session cookie (config('session.cookie')), XSRF-TOKEN and the consent cookie; statistics and marketing, empty. A category with no declared cookie is not shown.

Wording in categories is a string, or keyed by locale:

'categories' => [
    'necessary' => [
        'required' => true,
        'label' => ['en' => 'Necessary', 'fr' => 'Nécessaires'],
        'cookies' => [
            'session' => ['name' => 'laravel_session', 'purpose' => ['en' => 'Keeps your session.'], 'duration' => ['en' => 'Session']],
        ],
    ],
    'statistics' => [
        'label' => ['en' => 'Statistics', 'fr' => 'Statistiques'],
        'cookies' => [
            'ga' => ['name' => '_ga', 'provider' => 'Google', 'purpose' => ['en' => 'Distinguishes visitors.'], 'duration' => ['en' => '2 years']],
        ],
    ],
],

Wording

The banner speaks the application locale (app()->getLocale()): the exact locale, then its base language, then defaultLanguage.

lang/vendor/cookie-consent/<language>.php replaces strings or adds a language. A file holds only the keys it changes:

<?php

return [
    'texts' => ['accept' => 'J’accepte'],
];
php artisan vendor:publish --tag=cookie-consent-lang

copies the shipped files there as a starting point. A published file keeps every key, so shipped wording updates no longer reach it; keep only the keys you change.

In templates

@cookieConsentBanner                               {{-- with autoInject off --}}
{{ CookieConsent::cookieTable() }}
{{ CookieConsent::cookieTable(['category' => 'statistics', 'headingLevel' => 2]) }}
@withCookieTable($page->body)
@withCookieTable($page->body, ['heading' => false])
{{ CookieConsent::videoFacade($youtubeId, $title) }}

@withCookieTable outputs its content as HTML with the [cookie-table] markers replaced; like {!! !!}, use it only for HTML you trust. CookieConsent::withCookieTable() escapes content that is not Htmlable.

MethodReturns
banner()the banner, once per request
cookieTable(options)the declared cookies; options classes, category, heading, headingLevel
withCookieTable(content, options)content with its [cookie-table] markers replaced; content that is not Htmlable is escaped
videoFacade(id, title, poster)a YouTube facade
categories()visible categories and their cookies
config()the resolved configuration

YouTube posters are served by the route cookie-consent.thumbnail (/cookie-consent/thumbnail?v=<id>), outside the web group, and cached in storage/app/cookie-consent-thumbnails/.

Overriding templates

resources/views/vendor/cookie-consent/<name>.blade.php replaces a shipped template: banner, cookie-table, video-facade, video-embed.

php artisan vendor:publish --tag=cookie-consent-views

The variables each template receives are listed in the core package's README. Keep the data-qsm-ck-* attributes: the script finds every control through them.

Assets

vendor:publish --tag=cookie-consent-assets copies consent.js and consent.css to public/vendor/cookie-consent/. They are also published with the laravel-assets tag, which the Laravel application skeleton republishes on composer update.

Front end

Styling, the JavaScript API, conditional tags and integration recipes are the same as for the Craft plugin; see its documentation.

Recording consents

The package does not keep a register of decisions, but everything needed to build one is there: an event, a beacon script, and the server-side fingerprint of what the banner was showing. Recording consents walks through it.

Tests

composer install
vendor/bin/pest

Licence

Proprietary. See LICENSE.md.

Une extension qui n’existe pas encore?

Si Craft CMS, Statamic ou Laravel ne fait pas encore ce dont vous avez besoin, on peut le développer pour vous.

Parlons-en

Nous utilisons des témoins

Ce site utilise des témoins (« cookies ») nécessaires à son fonctionnement. Avec votre accord, nous en utilisons aussi pour mesurer la fréquentation. Vous pouvez changer d'avis en tout temps. Politique de confidentialité

Vos préférences de témoins

Toujours actif

Indispensables au fonctionnement du site et à la sécurité des formulaires. Ils ne peuvent pas être désactivés.

Nécessaires
Témoin Déposé par Finalité Conservation
CraftSessionId Ce site Maintient votre session de navigation. Session
CRAFT_CSRF_TOKEN Ce site Protège les formulaires contre la falsification de requête. Session
cookie_consent Ce site Mémorise vos choix en matière de témoins. 6 mois

Nous aident à comprendre comment le site est utilisé, afin de l’améliorer. Mesurées avec Matomo.

Statistiques
Témoin Déposé par Finalité Conservation
_pk_id.* Ce site Reconnaît le navigateur d’une visite à l’autre, sans vous identifier. 13 mois
_pk_ses.* Ce site Regroupe les pages vues pendant une même visite. 30 minutes