From 19accfbca673074a51815ea959592b8f5806bdc5 Mon Sep 17 00:00:00 2001 From: Matt Friedman Date: Sun, 19 Apr 2026 07:02:24 -0700 Subject: [PATCH 1/2] Support for phpbb consent manager --- event/listener.php | 23 +++++ language/en/common.php | 27 ++++++ .../overall_header_stylesheets_after.html | 43 +++------- tests/event/listener_test.php | 50 +++++++++++ .../google_analytics_consentmanager_test.php | 85 +++++++++++++++++++ 5 files changed, 198 insertions(+), 30 deletions(-) create mode 100644 language/en/common.php create mode 100644 tests/functional/google_analytics_consentmanager_test.php diff --git a/event/listener.php b/event/listener.php index c47718e..b76ecb0 100644 --- a/event/listener.php +++ b/event/listener.php @@ -64,6 +64,7 @@ public static function getSubscribedEvents() 'core.acp_board_config_edit_add' => 'add_googleanalytics_configs', 'core.validate_config_variable' => 'validate_googleanalytics_id', 'core.page_footer_after' => 'append_agreement', + 'phpbb.consentmanager.collect_registrations' => 'register_analytics', ]; } @@ -193,4 +194,26 @@ public function append_agreement() $this->template->append_var('AGREEMENT_TEXT', $this->language->lang('PHPBB_ANALYTICS_PRIVACY_POLICY', $this->config['sitename'])); } + + /** + * Register Google Analytics with Consent Manager when available. + * + * @param \phpbb\event\data|array $event The event object or event data + * @return void + */ + public function register_analytics($event) + { + if (!$this->config['googleanalytics_id']) + { + return; + } + + $this->language->add_lang('common', 'phpbb/googleanalytics'); + + $event['consent_manager']->register('phpbb.googleanalytics', [ + 'label' => $this->language->lang('GOOGLEANALYTICS_LABEL'), + 'category' => 'analytics', + 'description' => $this->language->lang('GOOGLEANALYTICS_DESCRIPTION'), + ]); + } } diff --git a/language/en/common.php b/language/en/common.php new file mode 100644 index 0000000..4c8d8c9 --- /dev/null +++ b/language/en/common.php @@ -0,0 +1,27 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +*/ + +/** +* DO NOT CHANGE +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +if (empty($lang) || !is_array($lang)) +{ + $lang = array(); +} + +$lang = array_merge($lang, array( + 'GOOGLEANALYTICS_LABEL' => 'Google Analytics', + 'GOOGLEANALYTICS_DESCRIPTION' => 'Tracks the pages you visit, the time spent on each page, and general usage patterns.' +)); diff --git a/styles/all/template/event/overall_header_stylesheets_after.html b/styles/all/template/event/overall_header_stylesheets_after.html index 4ad533b..0991b00 100644 --- a/styles/all/template/event/overall_header_stylesheets_after.html +++ b/styles/all/template/event/overall_header_stylesheets_after.html @@ -1,33 +1,16 @@ {% if GOOGLEANALYTICS_ID %} - {# 0 = Legacy (analytics.js) - Google Analytics #} - {# 1 = Global site tag (gtag.js) - Google Analytics #} - {% if GOOGLEANALYTICS_TAG == 1 %} - - - + + window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); - gtag('config', '{{ GOOGLEANALYTICS_ID }}', { - {%- EVENT phpbb_googleanalytics_gtag_options -%} - {%- if S_REGISTERED_USER %}'user_id': '{{ GOOGLEANALYTICS_USER_ID }}',{% endif -%} - {%- if S_ANONYMIZE_IP %}'anonymize_ip': true,{% endif -%} - {%- if S_COOKIE_SECURE -%}'cookie_flags': 'samesite=none;secure',{%- endif -%} - }); - - {% else %} - - {% endif %} + gtag('config', '{{ GOOGLEANALYTICS_ID }}', { + {%- EVENT phpbb_googleanalytics_gtag_options -%} + {%- if S_REGISTERED_USER %}'user_id': '{{ GOOGLEANALYTICS_USER_ID }}',{% endif -%} + {%- if S_ANONYMIZE_IP %}'anonymize_ip': true,{% endif -%} + {%- if S_COOKIE_SECURE -%}'cookie_flags': 'samesite=none;secure',{%- endif -%} + }); + {% endif %} diff --git a/tests/event/listener_test.php b/tests/event/listener_test.php index ea42e30..ff7a289 100644 --- a/tests/event/listener_test.php +++ b/tests/event/listener_test.php @@ -93,6 +93,7 @@ public function test_getSubscribedEvents() 'core.acp_board_config_edit_add', 'core.validate_config_variable', 'core.page_footer_after', + 'phpbb.consentmanager.collect_registrations', ], array_keys(\phpbb\googleanalytics\event\listener::getSubscribedEvents())); } @@ -306,4 +307,53 @@ public function test_append_agreement($s_agreement, $agreement_title, $expected_ $this->set_listener(); $this->listener->append_agreement(); } + + public function register_analytics_data() + { + return [ + 'configured analytics' => ['G-A1B2C3D4E5', 1], + 'missing analytics id' => ['', 0], + ]; + } + + /** + * @dataProvider register_analytics_data + */ + public function test_register_analytics($googleanalytics_id, $expected_calls) + { + $this->config['googleanalytics_id'] = $googleanalytics_id; + $this->set_listener(); + + $consent_manager = new consent_manager_double(); + + $this->listener->register_analytics([ + 'consent_manager' => $consent_manager, + ]); + + self::assertCount($expected_calls, $consent_manager->registrations); + + if ($expected_calls) + { + self::assertSame('phpbb.googleanalytics', $consent_manager->registrations[0]['id']); + self::assertSame([ + 'label' => $this->language->lang('GOOGLEANALYTICS_LABEL'), + 'category' => 'analytics', + 'description' => $this->language->lang('GOOGLEANALYTICS_DESCRIPTION'), + ], $consent_manager->registrations[0]['definition']); + } + } +} + +class consent_manager_double +{ + /** @var array */ + public $registrations = []; + + public function register($id, array $definition) + { + $this->registrations[] = [ + 'id' => $id, + 'definition' => $definition, + ]; + } } diff --git a/tests/functional/google_analytics_consentmanager_test.php b/tests/functional/google_analytics_consentmanager_test.php new file mode 100644 index 0000000..50f9166 --- /dev/null +++ b/tests/functional/google_analytics_consentmanager_test.php @@ -0,0 +1,85 @@ +login(); + $this->admin_login(); + $this->add_lang('acp/board'); + $this->add_lang_ext('phpbb/googleanalytics', 'googleanalytics_acp'); + + $crawler = self::request('GET', 'adm/index.php?i=acp_board&mode=settings&sid=' . $this->sid); + $form = $crawler->selectButton($this->lang('SUBMIT'))->form(); + $values = $form->getValues(); + $values['config[googleanalytics_id]'] = $this->sample_ga_code; + $form->setValues($values); + self::submit($form); + + $crawler = self::request('GET', 'index.php'); + + self::assertSame( + 'https://www.googletagmanager.com/gtag/js?id=' . $this->sample_ga_code, + $crawler->filter('head > script[type="text/plain"][data-consent-category="analytics"][src*="googletagmanager.com/gtag/js"]')->attr('src') + ); + self::assertGreaterThan( + 0, + $crawler->filter('head > script[type="text/plain"][data-consent-category="analytics"]')->count() + ); + } + + public function test_google_analytics_runs_normally_when_analytics_category_is_disabled() + { + $this->login(); + $this->admin_login(); + $this->add_lang('acp/board'); + $this->add_lang_ext('phpbb/googleanalytics', 'googleanalytics_acp'); + $this->add_lang_ext('phpbb/consentmanager', 'acp_consentmanager'); + + $crawler = self::request('GET', 'adm/index.php?i=acp_board&mode=settings&sid=' . $this->sid); + $form = $crawler->selectButton($this->lang('SUBMIT'))->form(); + $values = $form->getValues(); + $values['config[googleanalytics_id]'] = $this->sample_ga_code; + $form->setValues($values); + self::submit($form); + + $crawler = self::request('GET', 'adm/index.php?i=-phpbb-consentmanager-acp-consentmanager_module&mode=settings&sid=' . $this->sid); + $form = $crawler->selectButton($this->lang('SUBMIT'))->form(); + $values = $form->getValues(); + $values['consentmanager_analytics_enabled'] = '0'; + $form->setValues($values); + self::submit($form); + + $crawler = self::request('GET', 'index.php'); + + self::assertSame( + 'https://www.googletagmanager.com/gtag/js?id=' . $this->sample_ga_code, + $crawler->filter('head > script[src*="googletagmanager.com/gtag/js"]')->attr('src') + ); + self::assertSame( + 0, + $crawler->filter('head > script[type="text/plain"][data-consent-category="analytics"]')->count() + ); + } +} From 8c82a30cccdae92fd7e1383f7ecf110bac8385a3 Mon Sep 17 00:00:00 2001 From: Matt Friedman Date: Tue, 26 May 2026 11:42:49 -0700 Subject: [PATCH 2/2] Fix functional test relying on consent manager --- .../google_analytics_consentmanager_test.php | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/functional/google_analytics_consentmanager_test.php b/tests/functional/google_analytics_consentmanager_test.php index 50f9166..ad23cdc 100644 --- a/tests/functional/google_analytics_consentmanager_test.php +++ b/tests/functional/google_analytics_consentmanager_test.php @@ -20,11 +20,23 @@ class google_analytics_consentmanager_test extends \phpbb_functional_test_case protected static function setup_extensions() { - return ['phpbb/consentmanager', 'phpbb/googleanalytics']; + $extensions = ['phpbb/googleanalytics']; + + if (self::is_consentmanager_available()) + { + array_unshift($extensions, 'phpbb/consentmanager'); + } + + return $extensions; } public function test_consentmanager_defers_google_analytics_scripts() { + if (!self::is_consentmanager_available()) + { + self::markTestSkipped('Consent Manager extension is not available.'); + } + $this->login(); $this->admin_login(); $this->add_lang('acp/board'); @@ -51,6 +63,11 @@ public function test_consentmanager_defers_google_analytics_scripts() public function test_google_analytics_runs_normally_when_analytics_category_is_disabled() { + if (!self::is_consentmanager_available()) + { + self::markTestSkipped('Consent Manager extension is not available.'); + } + $this->login(); $this->admin_login(); $this->add_lang('acp/board'); @@ -82,4 +99,9 @@ public function test_google_analytics_runs_normally_when_analytics_category_is_d $crawler->filter('head > script[type="text/plain"][data-consent-category="analytics"]')->count() ); } + + protected static function is_consentmanager_available() + { + return is_file(__DIR__ . '/../../../../phpbb/consentmanager/ext.php'); + } }