diff --git a/.env.dist b/.env.dist index cd08d3e..5843837 100644 --- a/.env.dist +++ b/.env.dist @@ -1,4 +1,32 @@ -WORDPRESS_DB_HOST=mariadb -WORDPRESS_DB_USER=root +WORDPRESS_VERSION=latest +# To test on specific PHP version: +# WORDPRESS_VERSION=6.0.0-php8.0-apache + +WORDPRESS_LOCALE=en_US + +MYSQL_DATABASE=database +MYSQL_USER=user +MYSQL_PASSWORD=password +MYSQL_ROOT_PASSWORD=test + +DB_HOST=mysql +DB_CHARSET= +DB_COLLATE= +TABLE_PREFIX=wp_ + +WP_DEBUG=true +WP_DEBUG_LOG= +WP_CACHE= +WPCACHEHOME= +UPLOADS= + +FS_METHOD= +DISABLE_WP_CRON= +DISALLOW_FILE_EDIT= +TAR_OPTIONS=--no-same-owner +TAG_CONCIERGE_API_URL=https://beta-api.tagconcierge.com + +WORDPRESS_DB_NAME=database +WORDPRESS_DB_USER=user WORDPRESS_DB_PASSWORD=password -WORDPRESS_DB_NAME=wordpress +WORDPRESS_DB_HOST=mysql diff --git a/.gitignore b/.gitignore index a30310f..5bf975c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /.env /dist /vendor/ +.wordpress_data diff --git a/assets/icon-256x256.png b/assets/icon-256x256.png new file mode 100644 index 0000000..21b04d5 Binary files /dev/null and b/assets/icon-256x256.png differ diff --git a/assets/screenshot-1.gif b/assets/screenshot-1.gif new file mode 100644 index 0000000..a1701f3 Binary files /dev/null and b/assets/screenshot-1.gif differ diff --git a/assets/screenshot-2.png b/assets/screenshot-2.png new file mode 100644 index 0000000..b17b0eb Binary files /dev/null and b/assets/screenshot-2.png differ diff --git a/assets/screenshot-3.png b/assets/screenshot-3.png new file mode 100644 index 0000000..285868d Binary files /dev/null and b/assets/screenshot-3.png differ diff --git a/assets/screenshot-4.png b/assets/screenshot-4.png new file mode 100644 index 0000000..9b24ace Binary files /dev/null and b/assets/screenshot-4.png differ diff --git a/assets/screenshot-5.png b/assets/screenshot-5.png new file mode 100644 index 0000000..80c28f3 Binary files /dev/null and b/assets/screenshot-5.png differ diff --git a/assets/screenshot-6.png b/assets/screenshot-6.png new file mode 100644 index 0000000..b0556ac Binary files /dev/null and b/assets/screenshot-6.png differ diff --git a/assets/screenshot-7.png b/assets/screenshot-7.png new file mode 100644 index 0000000..9403599 Binary files /dev/null and b/assets/screenshot-7.png differ diff --git a/assets/screenshot-8.png b/assets/screenshot-8.png new file mode 100644 index 0000000..e4aa4da Binary files /dev/null and b/assets/screenshot-8.png differ diff --git a/composer.json b/composer.json index c6eeba6..5efd9de 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,10 @@ { - "name": "tagconcierge/gc-wordpress-plugin-free", + "name": "tagconcierge/gtm-consent-mode-banner-wordpress", "type": "wordpress-plugin", "minimum-stability": "stable", "autoload": { "psr-4": { - "TagConcierge\\GtmCookiesFree\\": "src" + "TagConcierge\\GtmConsentModeBanner\\": "src" } }, "require-dev": { diff --git a/composer.lock b/composer.lock index 428c58c..340e77a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,29 +4,29 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0187c73b831200f75d218652d3188242", + "content-hash": "873c235ee966c8857ee2227949735c26", "packages": [], "packages-dev": [ { "name": "johnpbloch/wordpress-core", - "version": "6.2.0", + "version": "6.4.2", "source": { "type": "git", "url": "https://github.com/johnpbloch/wordpress-core.git", - "reference": "cec139b6b71913343b68fbf043c468407a921225" + "reference": "00ea636cf89fd17daacbc3862f368a2782267825" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/johnpbloch/wordpress-core/zipball/cec139b6b71913343b68fbf043c468407a921225", - "reference": "cec139b6b71913343b68fbf043c468407a921225", + "url": "https://api.github.com/repos/johnpbloch/wordpress-core/zipball/00ea636cf89fd17daacbc3862f368a2782267825", + "reference": "00ea636cf89fd17daacbc3862f368a2782267825", "shasum": "" }, "require": { "ext-json": "*", - "php": ">=5.6.20" + "php": ">=7.0.0" }, "provide": { - "wordpress/core-implementation": "6.2.0" + "wordpress/core-implementation": "6.4.2" }, "type": "wordpress-core", "notification-url": "https://packagist.org/downloads/", @@ -46,7 +46,14 @@ "cms", "wordpress" ], - "time": "2023-03-30T04:14:50+00:00" + "support": { + "forum": "https://wordpress.org/support/", + "irc": "irc://irc.freenode.net/wordpress", + "issues": "https://core.trac.wordpress.org/", + "source": "https://core.trac.wordpress.org/browser", + "wiki": "https://codex.wordpress.org/" + }, + "time": "2023-12-06T16:30:44+00:00" } ], "aliases": [], @@ -55,5 +62,6 @@ "prefer-stable": false, "prefer-lowest": false, "platform": [], - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "2.6.0" } diff --git a/dev/scripts/build.sh b/dev/scripts/build.sh index d3bf554..0b59daf 100755 --- a/dev/scripts/build.sh +++ b/dev/scripts/build.sh @@ -4,13 +4,14 @@ docker-compose run --rm -T php-cli <initialize(); diff --git a/gtm-cookies-free.php b/gtm-cookies-free.php deleted file mode 100644 index 9f60a8c..0000000 --- a/gtm-cookies-free.php +++ /dev/null @@ -1,20 +0,0 @@ -initialize(); diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..c1fcc31 --- /dev/null +++ b/readme.txt @@ -0,0 +1,62 @@ +=== GTM Consent Mode Banner === +Contributors: Tag Concierge +Tags: google tag manager, consent mode, cookies banner, privacy +Requires at least: 5.1.0 +Tested up to: 6.2.2 +Requires PHP: 7.0 +Stable tag: 1.0.0 +License: GPLv2 or later +License URI: http://www.gnu.org/licenses/gpl-2.0.html + +Lightweight (1.9 kB) Consent/Cookies Banner compatible with GTM Consent Mode. + +== Description == + +GTM Consent Mode Banner is a lightweight (1.9 kB), user-friendly WordPress plugin designed to integrate Google Tag Manager Consent Mode seamlessly into your website. It offers a simple and efficient way for website owners to comply with cookie and privacy regulations like GDPR and CCPA, by enabling visitors to select their cookie preferences easily. + +## Features + +- **Simple Setup**: Integrate with Google Tag Manager with minimal configuration. +- **Customizable Consent Banner**: Tailor the appearance and message of your consent banner. +- **User Preference Control**: Allows users to specify their consent for different types of cookies (e.g., necessary, analytics, marketing). +- **Compliance with Privacy** Laws: Helps in making your website compliant with GDPR, CCPA, and other privacy regulations. +- **Lightweight and Fast**: Designed to be non-intrusive and does not affect your website's load time. + + +== Installation == + +1. Upload or install `GTM Consent Mode Banner` plugin from WordPress plugins directory. +2. Activate the plugin through the `Plugins` menu in WordPress. +3. That's it! Consent State will be pushed to DataLayer adhering to Consent Mode API +4. Use plugin settings to customise the content and consent settings. +5. Optionally use plugin settings to install GTM snippets + +== Frequently Asked Questions == + += How to inject GTM tracking snippet? = + +By default this plugin push consent information to the GTM DataLayer object that can be installed by other plugins or directly in the theme code. +It can also embed GTM snippets, go to settings to configure it. + += Do I need to configure anything in GTM to enable consent mode = + +Once your Consent Banner is deployed you need to review all your GTM tags to ensure they have correct consent checks settings. +You can use Consent Overview screen to quickly review and update tags. [Read more here](https://docs.tagconcierge.com/article/59-how-to-configure-gtm-consent-mode) + +== Screenshots == + +1. Consent Banner in action +2. Consent Banner displayed as modal +3. Consent Banner displayed as bar without "wall" +4. Consent Banner settings screen with all consent types listed +5. Consent Banner WP Admin basic settings +6. Consent Banner WP Admin banner content settings +7. Consent Banner WP Admin GTM snippets settings +8. Consent Banner WP Admin consent types settings + + +== Changelog == + += 1.0.0 = + +* Initial version diff --git a/src/DependencyInjection/Container.php b/src/DependencyInjection/Container.php index d3259ff..f2f8362 100644 --- a/src/DependencyInjection/Container.php +++ b/src/DependencyInjection/Container.php @@ -1,11 +1,11 @@ outputUtil = new OutputUtil(); $this->settingsUtil = new SettingsUtil(); - $this->gtmSnippetService = new GtmSnippetService($this->settingsUtil, $this->outputUtil); + $this->gtmSnippetService = new GtmConsentModeService($this->settingsUtil, $this->outputUtil); $this->settingsService = new SettingsService($this->settingsUtil); } diff --git a/src/GtmConsentModeBanner.php b/src/GtmConsentModeBanner.php new file mode 100644 index 0000000..c8e8f9b --- /dev/null +++ b/src/GtmConsentModeBanner.php @@ -0,0 +1,19 @@ +container = new Container(); + } +} diff --git a/src/GtmCookiesFree.php b/src/GtmCookiesFree.php deleted file mode 100644 index 8d793a1..0000000 --- a/src/GtmCookiesFree.php +++ /dev/null @@ -1,19 +0,0 @@ -container = new Container(); - } -} diff --git a/src/Service/GtmConsentModeService.php b/src/Service/GtmConsentModeService.php new file mode 100644 index 0000000..a9c483c --- /dev/null +++ b/src/Service/GtmConsentModeService.php @@ -0,0 +1,192 @@ +settingsUtil = $settingsUtil; + $this->outputUtil = $outputUtil; + $this->dataLayerVariableName = true === $this->eventDeferring || true === $this->requireConsentBeforeGtmLoad ? 'gtmCookieDataLayer' : 'dataLayer'; + + $this->initialScripts(); + $this->bannerScripts(); + } + private function initialScripts(): void + { + if ('1' === $this->settingsUtil->getOption('disabled')) { + return; + } + + $consentTypes = json_encode(array_reduce($this->settingsUtil->getOption('consent_types'), function($agg, $type) { + if ('' === $type['name']) { + return $agg; + } + $agg[$type['name']] = $type['default']; + return $agg; + }, [])); + + $script = <<outputUtil->addInlineScript($script, false); + } + + private function bannerScripts(): void + { + if ('1' === $this->settingsUtil->getOption('disabled')) { + return; + } + + $settings = array_reduce([ + 'banner_display_mode', + 'banner_display_wall', + 'banner_title', + 'banner_description', + 'banner_buttons_accept', + 'banner_buttons_settings', + 'banner_settings_title', + 'banner_settings_description', + 'banner_settings_buttons_save', + 'banner_settings_buttons_close', + ], function($agg, $setName) { + $agg[$setName] = $this->settingsUtil->getOption($setName); + return $agg; + }, []); + + $consentTypes = array_filter($this->settingsUtil->getOption('consent_types'), function ($type) { + return $type['name']; + }); + $config = json_encode([ + 'display' => [ + 'mode' => $settings['banner_display_mode'], + 'wall' => $settings['banner_display_wall'] == 1 + ], + 'consent_types' => $consentTypes, + 'modal' => [ + 'title' => $settings['banner_title'], + 'description' => $settings['banner_description'], + 'buttons' => [ + 'accept' => $settings['banner_buttons_accept'], + 'settings' => $settings['banner_buttons_settings'], + ] + ], + 'settings' => [ + 'title' => $settings['banner_settings_title'], + 'description' => $settings['banner_settings_description'], + 'buttons' => [ + 'save' => $settings['banner_settings_buttons_save'], + 'close' => $settings['banner_settings_buttons_close'], + ] + ], + ]); + $script = <<outputUtil->loadExternalScript('https://public-assets.tagconcierge.com/consent-banner.min.js'); + $this->outputUtil->addInlineScript($script); + } +} diff --git a/src/Service/GtmSnippetService.php b/src/Service/GtmSnippetService.php deleted file mode 100644 index ffc6450..0000000 --- a/src/Service/GtmSnippetService.php +++ /dev/null @@ -1,218 +0,0 @@ -settingsUtil = $settingsUtil; - $this->outputUtil = $outputUtil; - - $this->eventDeferring = '1' === $this->settingsUtil->getOption('defer_events'); - $this->requireConsentBeforeGtmLoad = '1' === $this->settingsUtil->getOption('gtm_snippet_consent_required'); - $this->dataLayerVariableName = true === $this->eventDeferring || true === $this->requireConsentBeforeGtmLoad ? 'gtmCookieDataLayer' : 'dataLayer'; - $this->consentEventName = $this->settingsUtil->getOption('consent_event_name'); - - $this->initialize(); - } - - private function initialize(): void - { - if ('1' === $this->settingsUtil->getOption('disabled')) { - return; - } - - $requireConsentBeforeGtmLoad = $this->requireConsentBeforeGtmLoad ? 'true' : 'false'; - $eventDeferring = $this->eventDeferring ? 'true' : 'false'; - - $script = <<consentEventName}', - requireConsentBeforeGtmLoad: {$requireConsentBeforeGtmLoad} - }, - deferredEvents: [], - isConsentGranted: function () { return '1' === localStorage.getItem('GTM_COOKIES_CONSENT');}, - setConsent: function (isGranted) { return localStorage.setItem('GTM_COOKIES_CONSENT', true === isGranted ? '1' : '0'); }, - callbacks: {}, - on: function(event, callback) { - if (false === gtmCookies.callbacks.hasOwnProperty(event)) { - gtmCookies.callbacks[event] = []; - } - - gtmCookies.callbacks[event].push(callback); - }, - emit: function(event, data) { - if (false === gtmCookies.callbacks.hasOwnProperty(event)) { - return; - } - gtmCookies.callbacks[event].forEach(function(callback) { callback(data); }); - }, - grantConsent: function() { - dataLayer.push({'event': gtmCookies.config.consentEventName}); - gtmCookies.setConsent(true); - gtmCookies.emit('consentGranted'); - }, - repushEvents: function() { - let events = []; - while (0 < gtmCookies.deferredEvents.length) { - events.push(gtmCookies.deferredEvents.pop()); - } - - while (0 < events.length) { - {$this->dataLayerVariableName}.push(events.pop()); - } - } -}; - -gtmCookies.on('gtmLoaded', function() { - gtmCookies.config.gtmLoaded = true; -}); - -const checkGtm = function() { - if ('undefined' === typeof window['google_tag_manager']) { - setTimeout(checkGtm, 500); - return; - } - - gtmCookies.emit('gtmLoaded'); -}; - -checkGtm(); - -EOD; - $this->outputUtil->addInlineScript($script, false); - - - if (true === $this->eventDeferring || true === $this->requireConsentBeforeGtmLoad) { - $script = <<outputUtil->addInlineScript($script, false); - } - - - if (false === empty($headSnippet = $this->settingsUtil->getOption('gtm_snippet_head'))) { - if (true === $this->requireConsentBeforeGtmLoad) { - $gtmId = $this->extractGtmId($headSnippet); - - $script = <<dataLayerVariableName}','{$gtmId}'); -}; - -gtmCookiesLoadHeadSnippet(); -EOD; - $this->outputUtil->addInlineScript($script); - } else { - add_action( 'wp_head', [$this, 'headSnippet'], 0 ); - } - } - - if (false === empty($bodySnippet = $this->settingsUtil->getOption('gtm_snippet_body'))) { - if (true === $this->requireConsentBeforeGtmLoad) { - $gtmId = $this->extractGtmId($bodySnippet); - $script = <<outputUtil->addInlineScript($script); - } else { - add_action( 'wp_body_open', [$this, 'bodySnippet'], 0 ); - } - } - } - - public function headSnippet(): void - { - $snippet = $this->settingsUtil->getOption('gtm_snippet_head'); - - if (true === $this->eventDeferring) { - $snippet = str_replace('\'dataLayer\',', '\''.$this->dataLayerVariableName.'\',', $snippet); - } - - echo filter_var($snippet, FILTER_FLAG_STRIP_BACKTICK) . "\n"; - } - - public function bodySnippet(): void - { - echo filter_var($this->settingsUtil->getOption('gtm_snippet_body'), FILTER_FLAG_STRIP_BACKTICK) . "\n"; - } - - private function extractGtmId(string $string): string - { - preg_match('/GTM-[a-zA-Z0-9]+/', $string, $matches); - - return false === empty($matches) ? $matches[0] : ''; - } -} diff --git a/src/Service/SettingsService.php b/src/Service/SettingsService.php index af060d7..e38f1d1 100644 --- a/src/Service/SettingsService.php +++ b/src/Service/SettingsService.php @@ -1,9 +1,9 @@ settingsUtil->addTab( 'event_settings', - 'Cookies Categories' + 'Consent Types' ); add_action( 'admin_init', [$this, 'settingsInit'] ); @@ -38,28 +38,35 @@ public function settingsInit(): void $this->settingsUtil->addSettingsSection( 'basic', 'Basic Settings', - 'GTM Cookies allows to quickly deploy robust, privacy-oriented setup using Google Tag Manager and dataLayer. [LINK TO DOCS]', + 'This plugin allows to quickly deploy robust, privacy-oriented setup using Google Tag Manager Consent Mode. Under the hood it uses a lightweight (1.9kB) Cookie Banner.', 'settings' ); $this->settingsUtil->addSettingsSection( - 'gtm_snippet', - 'Google Tag Manager snippet', - 'Paste two snippets provided by GTM. To find those snippets navigate to `Admin` tab in GTM console and click `Install Google Tag Manager`. If you already implemented GTM snippets in your page, paste them below, but select appropriate `Prevent loading GTM Snippet` option.', + 'banner', + 'Banner Main Modal', + 'Customise content of the main banner modal that is shown when user has not provided their consent. It allows user to grant all consent types or open settings.', + 'settings' + ); + + $this->settingsUtil->addSettingsSection( + 'banner_settings_modal', + 'Banner Settings Modal', + 'Customise content of the settings modal that allows user to grant only selected consent types.', 'settings' ); $this->settingsUtil->addSettingsSection( - 'consent_event', - 'Consent event', - 'Consent event is pushed to DataLayer when user decides on their cookies preference. This event will contain detailed consent information for each cookie category. [LINK TO DOCS]', + 'gtm_snippet', + 'Google Tag Manager snippet', + 'You can use the settings below to optionally load GTM instance. If you are already loading GTM snippets somewhere else e.g. other plugins or directly in the theme code leave those fields empty. Paste two snippets provided by GTM. To find those snippets navigate to `Admin` tab in GTM console and click `Install Google Tag Manager`. If you already implemented GTM snippets in your page, paste them below, but select appropriate `Prevent loading GTM Snippet` option.', 'settings' ); $this->settingsUtil->addSettingsSection( - 'consent_event_parameters', - 'Cookies Categories', - 'Use the table below to specify all categories of cookies and tools that your website use. Each entry consist of title, detailed description, option to make it required and name of the parameter being pushed to GTM DataLayer.', + 'consent_settings', + 'Consent Types', + 'Consent type is a category of ', 'event_settings' ); @@ -72,11 +79,29 @@ public function settingsInit(): void ); $this->settingsUtil->addSettingsField( - 'gtm_snippet_consent_required', - 'Prevent loading GTM container before consent?', + 'banner_display_mode', + 'Display Mode', + [$this, 'selectField'], + 'basic', + 'Form of the banner, small bar at the bottom of the page or center modal covering content.', + ['options' => ['bar' => 'Bar', 'modal' => 'Modal']] + ); + + $this->settingsUtil->addSettingsField( + 'banner_display_wall', + 'Wall', [$this, 'checkboxField'], - 'gtm_snippet', - 'When checked the GTM container won\'t load before user provides information about their consent. Only after any settings on the cookies banner are saved the GTM will be initated. It ensures no 3rd party tools and cookies are loaded before user consents. [LINK TO DOCS]' + 'basic', + 'Whether to display a "wall" which will cover (with some default opacity) the content of the page when banner is shown.', + ); + + $this->settingsUtil->addSettingsField( + 'banner_theme', + 'Theme', + [$this, 'selectField'], + 'basic', + 'Select theme of the banner that will apply default styling.', + ['options' => ['light' => 'Light', 'dark' => 'Dark']] ); $this->settingsUtil->addSettingsField( @@ -98,31 +123,120 @@ public function settingsInit(): void ); $this->settingsUtil->addSettingsField( - 'consent_event_name', - 'Consent event name', + 'banner_title', + 'Title', [$this, 'inputField'], - 'consent_event', - 'Name of the consent event emitted to GTM container.', - ['type' => 'text', 'placeholder' => 'user_consent'] + 'banner', + 'Title of the main banner modal. Not shown when Display Mode is set to "bar".' ); $this->settingsUtil->addSettingsField( - 'defer_events', - 'Defer events?', - [$this, 'checkboxField'], - 'consent_event', - 'Select to use with eCommerce events or any tags that rely on both consent event and GTM Variable Version 1 [LINK TO DOCS].' + 'banner_description', + 'Content', + [$this, 'inputField'], + 'banner', + 'Content of the banner. Supports simple markdown like [links](https://url.com) or **bold**. Buttons will be shown on the right side of this content.' + ); + + $this->settingsUtil->addSettingsField( + 'banner_buttons_accept', + 'Accept Button', + [$this, 'inputField'], + 'banner', + 'Text of accept button on the main banner.' + ); + + $this->settingsUtil->addSettingsField( + 'banner_buttons_settings', + 'Open Settings Button', + [$this, 'inputField'], + 'banner', + 'Text of settings button on the main banner.' + ); + + $this->settingsUtil->addSettingsField( + 'banner_settings_title', + 'Title', + [$this, 'inputField'], + 'banner_settings_modal', + 'Title of the main banner modal. Not shown when Display Mode is set to "bar".' ); - // Tags that rely on both consent event and variables may not receive correct values when events are not pushed $this->settingsUtil->addSettingsField( - 'consent_event_parameters', - 'Consent event parameters', + 'banner_settings_description', + 'Content', + [$this, 'inputField'], + 'banner_settings_modal', + 'Content of the banner. Supports simple markdown like [links](https://url.com) or **bold**. ' + ); + + $this->settingsUtil->addSettingsField( + 'banner_settings_buttons_save', + 'Save Button', + [$this, 'inputField'], + 'banner_settings_modal', + 'Text of save button on the main banner.' + ); + + $this->settingsUtil->addSettingsField( + 'banner_settings_buttons_close', + 'Close Button', + [$this, 'inputField'], + 'banner_settings_modal', + 'Text of settings button on the main banner.' + ); + + $this->settingsUtil->addSettingsField( + 'consent_types', + 'Consent Types', [$this, 'consentEventParametersFields'], - 'consent_event_parameters', + 'consent_settings', 'Name of consent event emitted to GTM container.', ['type' => 'array'] ); + + $defaults = [ + 'banner_display_mode' => 'bar', + 'banner_display_wall' => 0, + 'banner_title' => 'Cookies Policy', + 'banner_description' => 'We are using various cookies files. Learn more in our [privacy policy](#) and make your choice.', + 'banner_buttons_accept' => 'Accept', + 'banner_buttons_settings' => 'Settings', + 'banner_settings_title' => 'Cookies Settings', + 'banner_settings_description' => 'In order to provide you with best experience we use various...', + 'banner_settings_buttons_save' => 'Save preferences', + 'banner_settings_buttons_close' => 'Close', + 'consent_types' => [ + [ + 'name' => 'analytics_storage', + 'title' => "Analytics storage", + 'description' => 'Enables storage, such as cookies, related to analytics (for example, visit duration)', + 'default' => 'denied' + ], [ + 'name' => "ad_storage", + 'title' => "Ads storage", + 'description' => "Enables storage, such as cookies, related to advertising [link](https =>//www.google.com)", + 'default' => 'denied' + ], [ + 'name' => 'ad_user_data', + 'title' => "User Data", + 'description' => 'Sets consent for sending user data to Google for online advertising purposes.', + 'default' => 'denied' + ], [ + 'name' => 'ad_personalization', + 'title' => "Personalization", + 'description' => 'Sets consent for personalized advertising.', + 'default' => 'denied' + ] + ] + ]; + + foreach ($defaults as $defOpt => $defVal) { + // $this->settingsUtil->deleteOption($defOpt); + if ( false === $this->settingsUtil->getOption($defOpt) ) { + $this->settingsUtil->updateOption($defOpt, $defVal); + } + } } public function consentEventParametersFields($args): void @@ -130,42 +244,27 @@ public function consentEventParametersFields($args): void $fieldsConfiguration = [ 'name' => [ 'renderMethodName' => 'inputField', - 'description' => 'Cookies category title', + 'placeholder' => 'Internal Consent Type Name', + 'type' => 'text', + ], + 'title' => [ + 'renderMethodName' => 'inputField', + 'placeholder' => 'User facing title', 'type' => 'text', - 'placeholder' => 'Marketing', ], 'description' => [ 'renderMethodName' => 'textareaField', - 'description' => 'Detailed description of what those cookies are used for.', + 'placeholder' => 'Detailed description of what those cookies are used for.', 'rows' => 6, ], - 'is_required' => [ + 'default' => [ 'renderMethodName' => 'selectField', - 'description' => 'Is this consent mandatory?', - 'options' => [ - '0' => 'optional', - '1' => 'required', - ] - ], - 'data_layer_name' => [ - 'renderMethodName' => 'inputField', - 'description' => 'Parameter passed to dataLayer.', - 'type' => 'text', - 'placeholder' => 'marketing_consent', + 'placeholder' => 'Default state', + 'options' => ['denied' => 'denied', 'granted' => 'granted'], ], ]; - $consentEventParameters = $this->settingsUtil->getOption('consent_event_parameters'); - - if (false === $consentEventParameters) { - $consentEventParameters = [ - [ - 'name' => 'Marketing consent', - 'description' => 'Consent to marketing purposes.', - 'is_required' => '0', - 'data_layer_name' => 'marketing_consent', - ] - ]; - } + // $this->settingsUtil->deleteOption('consent_types'); + $consentEventParameters = $this->settingsUtil->getOption('consent_types'); if (false === is_array($consentEventParameters)) { $consentEventParameters = []; @@ -174,7 +273,7 @@ public function consentEventParametersFields($args): void $hasEmptyRow = false; foreach ($consentEventParameters as $consentEventParameter) { - if (false === isset($consentEventParameter['data_layer_name']) || true === empty($consentEventParameter['data_layer_name'])) { + if (false === isset($consentEventParameter['name']) || true === empty($consentEventParameter['name'])) { $hasEmptyRow = true; break; } @@ -183,13 +282,18 @@ public function consentEventParametersFields($args): void if (false === $hasEmptyRow) { $consentEventParameters[] = [ 'name' => '', + 'title' => '', 'description' => '', - 'is_required' => '0', - 'data_layer_name' => '', + 'default' => '', ]; } echo ''; + echo ''; + echo ''; + echo ''; + echo ''; foreach ($consentEventParameters as $index => $parameterConfig) { echo ''; foreach ($parameterConfig as $name => $value) { @@ -199,7 +303,7 @@ public function consentEventParametersFields($args): void if (null === $fieldConfiguration) { continue; } - echo '
'; + echo '
Consent TypeTitleDescriptionDefault
'; + echo ''; $this->{$fieldConfiguration['renderMethodName']}(array_merge($fieldConfiguration, [ 'label_for' => $fieldName, 'value' => $value, @@ -229,9 +333,11 @@ public function checkboxField( $args ): void value="1" /> +

+ " class="large-text code" rows="" + placeholder="" name="">

@@ -303,8 +410,8 @@ public function optionsPage(): void { $this->settingsUtil->addSubmenuPage( 'options-general.php', - 'GTM Cookies', - 'GTM Cookies', + 'GTM Consent Mode Banner', + 'GTM Consent Mode', 'manage_options' ); } diff --git a/src/Util/OutputUtil.php b/src/Util/OutputUtil.php index c56acbb..2694b5d 100644 --- a/src/Util/OutputUtil.php +++ b/src/Util/OutputUtil.php @@ -1,15 +1,23 @@ [], 'footer' => []]; + private $externalScripts = ['header' => [], 'footer' => []]; public function __construct() { add_action( 'wp_head', [$this, 'wpHead'], 0 ); - add_action( 'wp_footer', [$this, 'wpFooter'], 0 ); + add_action( 'wp_footer', [$this, 'wpFooter'], 1 ); + } + + public function loadExternalScript($script, $footer = true): OutputUtil + { + $this->externalScripts[true === $footer ? 'footer' : 'header'][] = $script; + + return $this; } public function addInlineScript($script, $footer = true): OutputUtil @@ -34,6 +42,12 @@ public function wpHead(): void public function wpFooter(): void { + foreach ($this->externalScripts['footer'] as $script) { + echo '' . "\n"; + } + if (0 === count($this->inlineScripts['footer'])) { echo ''; return; diff --git a/src/Util/SanitizationUtil.php b/src/Util/SanitizationUtil.php index a09f4d2..efcfcdd 100644 --- a/src/Util/SanitizationUtil.php +++ b/src/Util/SanitizationUtil.php @@ -1,6 +1,6 @@ snakeCaseNamespace = GtmCookiesFree::SNAKE_CASE_NAMESPACE; - $this->spineCaseNamespace = GtmCookiesFree::SPINE_CASE_NAMESPACE; + $this->snakeCaseNamespace = GtmConsentModeBanner::SNAKE_CASE_NAMESPACE; + $this->spineCaseNamespace = GtmConsentModeBanner::SPINE_CASE_NAMESPACE; } public function getOption( $optionName) {