Skip to content

feat: add GDPR cookie consent banner#1216

Merged
CaiJimmy merged 18 commits into
CaiJimmy:masterfrom
delize:GDPR-cookie-consent
Feb 19, 2026
Merged

feat: add GDPR cookie consent banner#1216
CaiJimmy merged 18 commits into
CaiJimmy:masterfrom
delize:GDPR-cookie-consent

Conversation

@delize
Copy link
Copy Markdown
Contributor

@delize delize commented Dec 24, 2025

Add a GDPR-compliant cookie consent banner that gates analytics (Google Analytics) and functional cookies (comments) until user consent is given.

Features:

  • Theme-consistent styling using CSS variables (light/dark mode)
  • Settings panel with category toggles (necessary, analytics, functional)
  • Consent stored in cookie for 365 days
  • Google Analytics only loads after analytics consent
  • Comments only load after functional consent
  • Translations for all 32 supported languages
  • Accessible with proper ARIA attributes and focus management

Configuration in hugo.yaml:
params: cookies: enabled: true categories: analytics: true functional: true

When cookies.enabled is false, scripts load normally without consent gating.

Closes #412

@delize
Copy link
Copy Markdown
Contributor Author

delize commented Dec 24, 2025

I took note of the previous PR that was attempted with Cookie Consent, and you mentiond that it "wasn't fitting into the style".

This should match similar styling as much as possible. Some demos of it below (without having to visit the netlify site, you still can 😄 )

Banner (Dark Theme)

cookie-banner-dark-mode

Banner (Light Theme)

Screenshot 2025-12-24 at 16 43 30

Preferences (Dark Theme)

Screenshot 2025-12-24 at 16 44 42

Preferences (Light Theme)

Screenshot 2025-12-24 at 16 44 05

Functional Cookies Disabled - Comments Section (Dark Theme)

Screenshot 2025-12-24 at 16 45 27

Functional Cookies Disabled - Comments Section (Light Theme)

comments-consent-disabled-light

@delize delize marked this pull request as draft December 24, 2025 22:58
@delize delize marked this pull request as ready for review December 24, 2025 23:06
@delize delize force-pushed the GDPR-cookie-consent branch from 46d9727 to d16f29c Compare December 24, 2025 23:14
@AiratTop
Copy link
Copy Markdown
Contributor

Waiting for merge

Add a GDPR-compliant cookie consent banner that gates analytics (Google
Analytics) and functional cookies (comments) until user consent is given.

Features:
- Theme-consistent styling using CSS variables (light/dark mode)
- Settings panel with category toggles (necessary, analytics, functional)
- Consent stored in cookie for 365 days
- Google Analytics only loads after analytics consent
- Comments only load after functional consent
- Translations for all 32 supported languages
- Accessible with proper ARIA attributes and focus management

Configuration in hugo.yaml:
  params:
    cookies:
      enabled: true
      categories:
        analytics: true
        functional: true

When cookies.enabled is false, scripts load normally without consent gating.

Closes CaiJimmy#412
Move Google Analytics consent logic to avoid shadowing Hugo's internal
`_internal/google_analytics.html` template.

Changes:
- Rename google_analytics.html → cookies/analytics.html
- Update head.html to conditionally load:
  - cookies.enabled=true: cookies/analytics.html (consent-gated)
  - cookies.enabled=false: Hugo's _internal/google_analytics.html
- Align cookies/analytics.html with Hugo's internal template:
  - Support Privacy.GoogleAnalytics.Disable setting
  - Support Privacy.GoogleAnalytics.RespectDoNotTrack setting
  - Add UA- prefix deprecation warning

Note: Custom JS is required for consent-gated GA because Hugo templates
render at build time, but consent happens at runtime. We cannot call
Hugo's internal template after the user grants consent - we must
dynamically inject the GA script via JavaScript.
@delize delize force-pushed the GDPR-cookie-consent branch from d16f29c to 29e082b Compare February 2, 2026 20:21
@delize
Copy link
Copy Markdown
Contributor Author

delize commented Feb 2, 2026

Have rebased on the v4 changes from the past week

@CaiJimmy
Copy link
Copy Markdown
Owner

CaiJimmy commented Feb 2, 2026

Have rebased on the v4 changes from the past week

Thanks! Sorry but I can't give you an ETA for reviewing this pull request as it contains a lot of changes, and currently I'm a bit busy with academic stuffs.

Did you use an AI tool for this by the way? Sorry if I'm wrong.

@delize
Copy link
Copy Markdown
Contributor Author

delize commented Feb 2, 2026

Hey,

No worries.

Yeah. Typescript & design is not something I am good at, I can easily diagnose and troubleshoot general issues or templating / html, but creating a whole display element for example - not something I am a pro at. If you would prefer to not PR merge it on that alone - I am perfectly okay with that. I did actually review the code being generated - not just yolo it away - and made several changes based on either bad ui, bad general issues, and ensuring 0 console errors/warnings for the code itself.

I will say, a lot of the changes are just appended languages based on the il8n and the cookie banner info.

@CaiJimmy CaiJimmy merged commit 4ad88a3 into CaiJimmy:master Feb 19, 2026
5 of 6 checks passed
@CaiJimmy
Copy link
Copy Markdown
Owner

Thanks!

@delize
Copy link
Copy Markdown
Contributor Author

delize commented Feb 19, 2026

No worries that was a lot more revisions than I was expecting 🙈

jin-li added a commit to jin-li/hugo-theme-stack that referenced this pull request Mar 4, 2026
* refactor: create a generic `taxonomy` widget (CaiJimmy#1268)

* refactor: introduce a generic taxonomy widget and refactor existing category and tag cloud widgets to use it.

* feat: Implement optional title linking for taxonomy widgets and enable parameter customization for taxonomy partials.

* refactor: remove fallback to taxonomy page title for widget display

Because this field always exists. I think it's better to let user customize via widget params

* Update layouts/_partials/widget/taxonomy.html

* refactor: check for .Params.taxonomy existence before accessing

* feat: add markdown alerts support (CaiJimmy#1221)

* Markdown alerts

* refactor(alert): move alert color to variable.scss and simplify the style

* style: fix indent in render-blockquote

* feat(alert): add customizable alert icons for different alert types

* doc: add example usage of markdown alert

---------

Co-authored-by: Jimmy Cai <jimmy@cai.im>

* feat(i18n): add i18n support for Markdown alert (CaiJimmy#1269)

* docs: add blockquote with custom alert title

* feat: add alert types to i18n and update blockquote rendering

* fix: wrong translation key

* feat: add alert title translation for all supported languages

Done by AI

* feat: add GDPR cookie consent banner (CaiJimmy#1216)

* feat: add GDPR cookie consent banner

Add a GDPR-compliant cookie consent banner that gates analytics (Google
Analytics) and functional cookies (comments) until user consent is given.

Features:
- Theme-consistent styling using CSS variables (light/dark mode)
- Settings panel with category toggles (necessary, analytics, functional)
- Consent stored in cookie for 365 days
- Google Analytics only loads after analytics consent
- Comments only load after functional consent
- Translations for all 32 supported languages
- Accessible with proper ARIA attributes and focus management

Configuration in hugo.yaml:
  params:
    cookies:
      enabled: true
      categories:
        analytics: true
        functional: true

When cookies.enabled is false, scripts load normally without consent gating.

Closes CaiJimmy#412

* refactor: move consent-gated GA to cookies/analytics.html

Move Google Analytics consent logic to avoid shadowing Hugo's internal
`_internal/google_analytics.html` template.

Changes:
- Rename google_analytics.html → cookies/analytics.html
- Update head.html to conditionally load:
  - cookies.enabled=true: cookies/analytics.html (consent-gated)
  - cookies.enabled=false: Hugo's _internal/google_analytics.html
- Align cookies/analytics.html with Hugo's internal template:
  - Support Privacy.GoogleAnalytics.Disable setting
  - Support Privacy.GoogleAnalytics.RespectDoNotTrack setting
  - Add UA- prefix deprecation warning

Note: Custom JS is required for consent-gated GA because Hugo templates
render at build time, but consent happens at runtime. We cannot call
Hugo's internal template after the user grants consent - we must
dynamically inject the GA script via JavaScript.

* style: indent cookies/analytics.html

* refactor: don't use default, put default configurations in params.toml

* fix: don't use `description` as translation key because it's reserved and will throw error

* fix: remove footer/components/custom-font.html call

* fix: banner showSettings key

* style: indent comments/include

* Add missing article.alert translation back

* style: format i18n toml files

* style: indent head/head.html

* style adjustment

* style: add missing -

* style: format demo/config/params.toml

* style: remove redundant comments from cookies.scss

* style: update box-shadow for cookie banner content

---------

Co-authored-by: delize <4028612+delize@users.noreply.github.com>
Co-authored-by: Jimmy Cai <jimmy@cai.im>

* feat(list): ability to show article tags on homepage (CaiJimmy#1270)

* feat(list): ability to show article tags on homepage

closes CaiJimmy#880

* Disable showTags by default

* refactor(sidebar): drop support for .Pre and remove old codes (CaiJimmy#1271)

* refactor(sidebar): drop support for .Pre and remove old codes

* Simplify

* doc(demo): disable cookie consent

* ci: update Hugo version to 0.156.0

---------

Co-authored-by: Jimmy <jimmy@cai.im>
Co-authored-by: Bigstool <20697772+Bigstool@users.noreply.github.com>
Co-authored-by: Andrew Doering <delize@users.noreply.github.com>
Co-authored-by: delize <4028612+delize@users.noreply.github.com>
jin-li pushed a commit to jin-li/hugo-theme-stack that referenced this pull request Mar 5, 2026
* feat: add GDPR cookie consent banner

Add a GDPR-compliant cookie consent banner that gates analytics (Google
Analytics) and functional cookies (comments) until user consent is given.

Features:
- Theme-consistent styling using CSS variables (light/dark mode)
- Settings panel with category toggles (necessary, analytics, functional)
- Consent stored in cookie for 365 days
- Google Analytics only loads after analytics consent
- Comments only load after functional consent
- Translations for all 32 supported languages
- Accessible with proper ARIA attributes and focus management

Configuration in hugo.yaml:
  params:
    cookies:
      enabled: true
      categories:
        analytics: true
        functional: true

When cookies.enabled is false, scripts load normally without consent gating.

Closes CaiJimmy#412

* refactor: move consent-gated GA to cookies/analytics.html

Move Google Analytics consent logic to avoid shadowing Hugo's internal
`_internal/google_analytics.html` template.

Changes:
- Rename google_analytics.html → cookies/analytics.html
- Update head.html to conditionally load:
  - cookies.enabled=true: cookies/analytics.html (consent-gated)
  - cookies.enabled=false: Hugo's _internal/google_analytics.html
- Align cookies/analytics.html with Hugo's internal template:
  - Support Privacy.GoogleAnalytics.Disable setting
  - Support Privacy.GoogleAnalytics.RespectDoNotTrack setting
  - Add UA- prefix deprecation warning

Note: Custom JS is required for consent-gated GA because Hugo templates
render at build time, but consent happens at runtime. We cannot call
Hugo's internal template after the user grants consent - we must
dynamically inject the GA script via JavaScript.

* style: indent cookies/analytics.html

* refactor: don't use default, put default configurations in params.toml

* fix: don't use `description` as translation key because it's reserved and will throw error

* fix: remove footer/components/custom-font.html call

* fix: banner showSettings key

* style: indent comments/include

* Add missing article.alert translation back

* style: format i18n toml files

* style: indent head/head.html

* style adjustment

* style: add missing -

* style: format demo/config/params.toml

* style: remove redundant comments from cookies.scss

* style: update box-shadow for cookie banner content

---------

Co-authored-by: delize <4028612+delize@users.noreply.github.com>
Co-authored-by: Jimmy Cai <jimmy@cai.im>
powerfullz pushed a commit to powerfullz/hugo-theme-stack-upstream that referenced this pull request Mar 10, 2026
* feat: add GDPR cookie consent banner

Add a GDPR-compliant cookie consent banner that gates analytics (Google
Analytics) and functional cookies (comments) until user consent is given.

Features:
- Theme-consistent styling using CSS variables (light/dark mode)
- Settings panel with category toggles (necessary, analytics, functional)
- Consent stored in cookie for 365 days
- Google Analytics only loads after analytics consent
- Comments only load after functional consent
- Translations for all 32 supported languages
- Accessible with proper ARIA attributes and focus management

Configuration in hugo.yaml:
  params:
    cookies:
      enabled: true
      categories:
        analytics: true
        functional: true

When cookies.enabled is false, scripts load normally without consent gating.

Closes CaiJimmy#412

* refactor: move consent-gated GA to cookies/analytics.html

Move Google Analytics consent logic to avoid shadowing Hugo's internal
`_internal/google_analytics.html` template.

Changes:
- Rename google_analytics.html → cookies/analytics.html
- Update head.html to conditionally load:
  - cookies.enabled=true: cookies/analytics.html (consent-gated)
  - cookies.enabled=false: Hugo's _internal/google_analytics.html
- Align cookies/analytics.html with Hugo's internal template:
  - Support Privacy.GoogleAnalytics.Disable setting
  - Support Privacy.GoogleAnalytics.RespectDoNotTrack setting
  - Add UA- prefix deprecation warning

Note: Custom JS is required for consent-gated GA because Hugo templates
render at build time, but consent happens at runtime. We cannot call
Hugo's internal template after the user grants consent - we must
dynamically inject the GA script via JavaScript.

* style: indent cookies/analytics.html

* refactor: don't use default, put default configurations in params.toml

* fix: don't use `description` as translation key because it's reserved and will throw error

* fix: remove footer/components/custom-font.html call

* fix: banner showSettings key

* style: indent comments/include

* Add missing article.alert translation back

* style: format i18n toml files

* style: indent head/head.html

* style adjustment

* style: add missing -

* style: format demo/config/params.toml

* style: remove redundant comments from cookies.scss

* style: update box-shadow for cookie banner content

---------

Co-authored-by: delize <4028612+delize@users.noreply.github.com>
Co-authored-by: Jimmy Cai <jimmy@cai.im>
@delize delize review requested due to automatic review settings March 23, 2026 20:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: GDPR prompt

3 participants