gdprcookieconsent/gdprcookieconsent.php

476 lines
23 KiB
PHP

<?php
/**
* GDPR Cookie Consent Module for PrestaShop
*
* @author Walzen665
* @copyright Copyright (c) 2025
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
*/
if (!defined('_PS_VERSION_')) {
exit;
}
class GdprCookieConsent extends Module
{
public function __construct()
{
$this->name = 'gdprcookieconsent';
$this->tab = 'front_office_features';
$this->version = '1.0.1';
$this->author = 'Walzen665';
$this->need_instance = 0;
$this->ps_versions_compliancy = [
'min' => '1.7.0.0',
'max' => _PS_VERSION_
];
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('GDPR Cookie Consent');
$this->description = $this->l('Adds a GDPR compliant cookie consent modal to your shop');
$this->confirmUninstall = $this->l('Are you sure you want to uninstall?');
}
/**
* Install the module
*/
public function install()
{
return parent::install() &&
$this->registerHook('displayHeader') &&
$this->registerHook('displayFooter') &&
Configuration::updateValue('GDPR_COOKIE_ENABLED', 1) &&
Configuration::updateValue('GDPR_COOKIE_MESSAGE', 'This website uses cookies to ensure you get the best experience. We collect and process your data for website functionality, analytics, and personalized advertising.') &&
Configuration::updateValue('GDPR_COOKIE_ACCEPT', 'Accept All Cookies') &&
Configuration::updateValue('GDPR_COOKIE_DECLINE', 'Decline Non-Essential') &&
Configuration::updateValue('GDPR_COOKIE_SETTINGS', 'Cookie Settings') &&
Configuration::updateValue('GDPR_COOKIE_MORE_INFO', 'More Information') &&
Configuration::updateValue('GDPR_COOKIE_MORE_INFO_URL', 'https://yourstore.net/content/privacy-policy') &&
Configuration::updateValue('GDPR_COOKIE_DATA_CONTROLLER', 'Your Company Name') &&
Configuration::updateValue('GDPR_COOKIE_RETENTION_PERIOD', '365 days') &&
Configuration::updateValue('GDPR_COOKIE_THIRD_PARTIES', 'Google Analytics, Facebook, etc.') &&
Configuration::updateValue('GDPR_COOKIE_MANAGE_TEXT', 'Manage Cookie Preferences') &&
Configuration::updateValue('GDPR_COOKIE_ONLY_REQUIRED', 1) &&
Configuration::updateValue('GDPR_COOKIE_NECESSARY_DESC', 'Necessary cookies help make a website usable by enabling basic functions like page navigation and access to secure areas. The website cannot function properly without these cookies.') &&
Configuration::updateValue('GDPR_COOKIE_FUNCTIONAL_DESC', 'Functional cookies enable a website to remember information that changes the way the website behaves or looks, like your preferred language or the region you are in.') &&
Configuration::updateValue('GDPR_COOKIE_ANALYTICS_DESC', 'Analytics cookies help website owners understand how visitors interact with websites by collecting and reporting information anonymously.') &&
Configuration::updateValue('GDPR_COOKIE_MARKETING_DESC', 'Marketing cookies are used to track visitors across websites. The intention is to display ads that are relevant and engaging for the individual user.');
}
/**
* Uninstall the module
*/
public function uninstall()
{
return parent::uninstall() &&
Configuration::deleteByName('GDPR_COOKIE_ENABLED') &&
Configuration::deleteByName('GDPR_COOKIE_MESSAGE') &&
Configuration::deleteByName('GDPR_COOKIE_ACCEPT') &&
Configuration::deleteByName('GDPR_COOKIE_DECLINE') &&
Configuration::deleteByName('GDPR_COOKIE_SETTINGS') &&
Configuration::deleteByName('GDPR_COOKIE_MORE_INFO') &&
Configuration::deleteByName('GDPR_COOKIE_MORE_INFO_URL') &&
Configuration::deleteByName('GDPR_COOKIE_DATA_CONTROLLER') &&
Configuration::deleteByName('GDPR_COOKIE_RETENTION_PERIOD') &&
Configuration::deleteByName('GDPR_COOKIE_THIRD_PARTIES') &&
Configuration::deleteByName('GDPR_COOKIE_MANAGE_TEXT') &&
Configuration::deleteByName('GDPR_COOKIE_ONLY_REQUIRED') &&
Configuration::deleteByName('GDPR_COOKIE_NECESSARY_DESC') &&
Configuration::deleteByName('GDPR_COOKIE_FUNCTIONAL_DESC') &&
Configuration::deleteByName('GDPR_COOKIE_ANALYTICS_DESC') &&
Configuration::deleteByName('GDPR_COOKIE_MARKETING_DESC');
}
/**
* Load the configuration form
*/
public function getContent()
{
$output = '';
// If form submitted
if (Tools::isSubmit('submitGdprCookieModule')) {
// Get configuration values from form
$enabled = (int)Tools::getValue('GDPR_COOKIE_ENABLED');
$message = Tools::getValue('GDPR_COOKIE_MESSAGE');
$accept = Tools::getValue('GDPR_COOKIE_ACCEPT');
$decline = Tools::getValue('GDPR_COOKIE_DECLINE');
$settings = Tools::getValue('GDPR_COOKIE_SETTINGS');
$moreInfo = Tools::getValue('GDPR_COOKIE_MORE_INFO');
$moreInfoUrl = Tools::getValue('GDPR_COOKIE_MORE_INFO_URL');
$dataController = Tools::getValue('GDPR_COOKIE_DATA_CONTROLLER');
$retentionPeriod = Tools::getValue('GDPR_COOKIE_RETENTION_PERIOD');
$thirdParties = Tools::getValue('GDPR_COOKIE_THIRD_PARTIES');
$manageText = Tools::getValue('GDPR_COOKIE_MANAGE_TEXT');
$onlyRequired = Tools::getValue('GDPR_COOKIE_ONLY_REQUIRED');
$necessaryDesc = Tools::getValue('GDPR_COOKIE_NECESSARY_DESC');
$functionalDesc = Tools::getValue('GDPR_COOKIE_FUNCTIONAL_DESC');
$analyticsDesc = Tools::getValue('GDPR_COOKIE_ANALYTICS_DESC');
$marketingDesc = Tools::getValue('GDPR_COOKIE_MARKETING_DESC');
// Update configuration values
Configuration::updateValue('GDPR_COOKIE_ENABLED', $enabled);
Configuration::updateValue('GDPR_COOKIE_MESSAGE', $message);
Configuration::updateValue('GDPR_COOKIE_ACCEPT', $accept);
Configuration::updateValue('GDPR_COOKIE_DECLINE', $decline);
Configuration::updateValue('GDPR_COOKIE_SETTINGS', $settings);
Configuration::updateValue('GDPR_COOKIE_MORE_INFO', $moreInfo);
Configuration::updateValue('GDPR_COOKIE_MORE_INFO_URL', $moreInfoUrl);
Configuration::updateValue('GDPR_COOKIE_DATA_CONTROLLER', $dataController);
Configuration::updateValue('GDPR_COOKIE_RETENTION_PERIOD', $retentionPeriod);
Configuration::updateValue('GDPR_COOKIE_THIRD_PARTIES', $thirdParties);
Configuration::updateValue('GDPR_COOKIE_MANAGE_TEXT', $manageText);
Configuration::updateValue('GDPR_COOKIE_ONLY_REQUIRED', $onlyRequired);
Configuration::updateValue('GDPR_COOKIE_NECESSARY_DESC', $necessaryDesc);
Configuration::updateValue('GDPR_COOKIE_FUNCTIONAL_DESC', $functionalDesc);
Configuration::updateValue('GDPR_COOKIE_ANALYTICS_DESC', $analyticsDesc);
Configuration::updateValue('GDPR_COOKIE_MARKETING_DESC', $marketingDesc);
// Display confirmation
$output .= $this->displayConfirmation($this->l('Settings updated'));
}
// Display the configuration form
return $output . $this->displayForm();
}
/**
* Create the configuration form
*/
protected function displayForm()
{
// Init Fields form array
$form = [
'form' => [
'legend' => [
'title' => $this->l('Settings'),
'icon' => 'icon-cogs',
],
'input' => [
[
'type' => 'switch',
'label' => $this->l('Enable Cookie Consent'),
'name' => 'GDPR_COOKIE_ENABLED',
'is_bool' => true,
'values' => [
[
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
],
[
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Disabled')
]
],
],
[
'type' => 'textarea',
'label' => $this->l('Cookie Consent Message'),
'name' => 'GDPR_COOKIE_MESSAGE',
'required' => true,
],
[
'type' => 'text',
'label' => $this->l('Data Controller'),
'name' => 'GDPR_COOKIE_DATA_CONTROLLER',
'desc' => $this->l('Your company/organization name'),
'required' => true,
],
[
'type' => 'text',
'label' => $this->l('Cookie Retention Period'),
'name' => 'GDPR_COOKIE_RETENTION_PERIOD',
'desc' => $this->l('How long cookies will be stored (e.g., 365 days)'),
'required' => true,
],
[
'type' => 'textarea',
'label' => $this->l('Third-Party Recipients'),
'name' => 'GDPR_COOKIE_THIRD_PARTIES',
'desc' => $this->l('List third parties that receive cookie data'),
'required' => true,
],
[
'type' => 'text',
'label' => $this->l('Accept Button Text'),
'name' => 'GDPR_COOKIE_ACCEPT',
'required' => true,
],
[
'type' => 'text',
'label' => $this->l('Decline Button Text'),
'name' => 'GDPR_COOKIE_DECLINE',
'required' => true,
],
[
'type' => 'text',
'label' => $this->l('Settings Button Text'),
'name' => 'GDPR_COOKIE_SETTINGS',
'required' => true,
],
[
'type' => 'text',
'label' => $this->l('Manage Preferences Text'),
'name' => 'GDPR_COOKIE_MANAGE_TEXT',
'desc' => $this->l('Text for the manage preferences button (displayed after consent is given)'),
'required' => true,
],
[
'type' => 'text',
'label' => $this->l('More Info Button Text'),
'name' => 'GDPR_COOKIE_MORE_INFO',
'required' => true,
],
[
'type' => 'text',
'label' => $this->l('More Info URL'),
'desc' => $this->l('URL to your Privacy Policy page'),
'name' => 'GDPR_COOKIE_MORE_INFO_URL',
'required' => true,
],
[
'type' => 'switch',
'label' => $this->l('This cookie types are used'),
'name' => 'GDPR_COOKIE_ONLY_REQUIRED',
'desc' => $this->l('If this option is enabled, no config modal will be rendered and there will only be a single button to hide the cookie notice. (Only enable this, if you don\'t track any user data)'),
'is_bool' => true,
'required' => true,
'values' => [
[
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Nessessary only')
],
[
'id' => 'active_off',
'value' => 0,
'label' => $this->l('All cookies')
]
],
],
[
'type' => 'textarea',
'label' => $this->l('Necessary Cookies Description'),
'name' => 'GDPR_COOKIE_NECESSARY_DESC',
'desc' => $this->l('Description for necessary cookies shown in the modal'),
'required' => true,
],
[
'type' => 'textarea',
'label' => $this->l('Functional Cookies Description'),
'name' => 'GDPR_COOKIE_FUNCTIONAL_DESC',
'desc' => $this->l('Description for functional cookies shown in the modal'),
'required' => true,
],
[
'type' => 'textarea',
'label' => $this->l('Analytics Cookies Description'),
'name' => 'GDPR_COOKIE_ANALYTICS_DESC',
'desc' => $this->l('Description for analytics cookies shown in the modal'),
'required' => true,
],
[
'type' => 'textarea',
'label' => $this->l('Marketing Cookies Description'),
'name' => 'GDPR_COOKIE_MARKETING_DESC',
'desc' => $this->l('Description for marketing cookies shown in the modal'),
'required' => true,
],
],
'submit' => [
'title' => $this->l('Save'),
'class' => 'btn btn-default pull-right',
],
],
];
$helper = new HelperForm();
// Module, token and currentIndex
$helper->module = $this;
$helper->name_controller = $this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
// Language
$helper->default_form_language = $this->context->language->id;
$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', 0);
// Title and toolbar
$helper->title = $this->displayName;
$helper->show_toolbar = true;
$helper->toolbar_scroll = true;
$helper->submit_action = 'submitGdprCookieModule';
// Load current values
$helper->fields_value['GDPR_COOKIE_ENABLED'] = Configuration::get('GDPR_COOKIE_ENABLED');
$helper->fields_value['GDPR_COOKIE_MESSAGE'] = Configuration::get('GDPR_COOKIE_MESSAGE');
$helper->fields_value['GDPR_COOKIE_ACCEPT'] = Configuration::get('GDPR_COOKIE_ACCEPT');
$helper->fields_value['GDPR_COOKIE_DECLINE'] = Configuration::get('GDPR_COOKIE_DECLINE');
$helper->fields_value['GDPR_COOKIE_SETTINGS'] = Configuration::get('GDPR_COOKIE_SETTINGS');
$helper->fields_value['GDPR_COOKIE_MORE_INFO'] = Configuration::get('GDPR_COOKIE_MORE_INFO');
$helper->fields_value['GDPR_COOKIE_MORE_INFO_URL'] = Configuration::get('GDPR_COOKIE_MORE_INFO_URL');
$helper->fields_value['GDPR_COOKIE_DATA_CONTROLLER'] = Configuration::get('GDPR_COOKIE_DATA_CONTROLLER');
$helper->fields_value['GDPR_COOKIE_RETENTION_PERIOD'] = Configuration::get('GDPR_COOKIE_RETENTION_PERIOD');
$helper->fields_value['GDPR_COOKIE_THIRD_PARTIES'] = Configuration::get('GDPR_COOKIE_THIRD_PARTIES');
$helper->fields_value['GDPR_COOKIE_MANAGE_TEXT'] = Configuration::get('GDPR_COOKIE_MANAGE_TEXT');
$helper->fields_value['GDPR_COOKIE_ONLY_REQUIRED'] = Configuration::get('GDPR_COOKIE_ONLY_REQUIRED');
$helper->fields_value['GDPR_COOKIE_NECESSARY_DESC'] = Configuration::get('GDPR_COOKIE_NECESSARY_DESC');
$helper->fields_value['GDPR_COOKIE_FUNCTIONAL_DESC'] = Configuration::get('GDPR_COOKIE_FUNCTIONAL_DESC');
$helper->fields_value['GDPR_COOKIE_ANALYTICS_DESC'] = Configuration::get('GDPR_COOKIE_ANALYTICS_DESC');
$helper->fields_value['GDPR_COOKIE_MARKETING_DESC'] = Configuration::get('GDPR_COOKIE_MARKETING_DESC');
return $helper->generateForm([$form]);
}
/**
* Add CSS and JS to the header
*/
public function hookDisplayHeader()
{
if (!Configuration::get('GDPR_COOKIE_ENABLED')) {
return;
}
// Add CSS
$this->context->controller->addCSS($this->_path . 'views/css/gdpr_cookie.css');
// Add JS
$this->context->controller->addJS($this->_path . 'views/js/gdpr_cookie.js');
// Add JS variables for modal
Media::addJsDef([
'gdprCookieMessage' => Configuration::get('GDPR_COOKIE_MESSAGE'),
'gdprCookieAccept' => Configuration::get('GDPR_COOKIE_ACCEPT'),
'gdprCookieDecline' => Configuration::get('GDPR_COOKIE_DECLINE'),
'gdprCookieSettings' => Configuration::get('GDPR_COOKIE_SETTINGS'),
'gdprCookieMoreInfo' => Configuration::get('GDPR_COOKIE_MORE_INFO'),
'gdprCookieMoreInfoUrl' => Configuration::get('GDPR_COOKIE_MORE_INFO_URL'),
'gdprCookieDataController' => Configuration::get('GDPR_COOKIE_DATA_CONTROLLER', ''),
'gdprCookieRetentionPeriod' => Configuration::get('GDPR_COOKIE_RETENTION_PERIOD', '365 days'),
'gdprCookieThirdParties' => Configuration::get('GDPR_COOKIE_THIRD_PARTIES', ''),
'gdprCookieManageText' => Configuration::get('GDPR_COOKIE_MANAGE_TEXT', 'Manage Cookies'),
'gdprCookieOnlyRequired' => Configuration::get('GDPR_COOKIE_ONLY_REQUIRED'),
]);
// Assign variables to Smarty for the manage button template
$this->context->smarty->assign([
'gdprCookieManageText' => Configuration::get('GDPR_COOKIE_MANAGE_TEXT', 'Manage Cookies'),
]);
// If not in required-only mode, add script for tagging known third-party scripts
if (!Configuration::get('GDPR_COOKIE_ONLY_REQUIRED')) {
$this->tagThirdPartyScripts();
}
// Return the template content - but don't throw an error if it doesn't exist yet
if (file_exists(_PS_MODULE_DIR_ . $this->name . '/views/templates/hook/manage_button.tpl')) {
return $this->display(__FILE__, 'views/templates/hook/manage_button.tpl');
}
}
/**
* Add the cookie modal to the footer
*/
public function hookDisplayFooter()
{
if (!Configuration::get('GDPR_COOKIE_ENABLED')) {
return;
}
$this->smarty->assign([
'gdprCookieMessage' => Configuration::get('GDPR_COOKIE_MESSAGE'),
'gdprCookieAccept' => Configuration::get('GDPR_COOKIE_ACCEPT'),
'gdprCookieDecline' => Configuration::get('GDPR_COOKIE_DECLINE'),
'gdprCookieSettings' => Configuration::get('GDPR_COOKIE_SETTINGS'),
'gdprCookieMoreInfo' => Configuration::get('GDPR_COOKIE_MORE_INFO'),
'gdprCookieMoreInfoUrl' => Configuration::get('GDPR_COOKIE_MORE_INFO_URL'),
'gdprCookieDataController' => Configuration::get('GDPR_COOKIE_DATA_CONTROLLER'),
'gdprCookieRetentionPeriod' => Configuration::get('GDPR_COOKIE_RETENTION_PERIOD'),
'gdprCookieThirdParties' => Configuration::get('GDPR_COOKIE_THIRD_PARTIES'),
'gdprCookieManageText' => Configuration::get('GDPR_COOKIE_MANAGE_TEXT'),
'gdprCookieOnlyRequired' => Configuration::get('GDPR_COOKIE_ONLY_REQUIRED'),
'gdprCookieNecessaryDesc' => Configuration::get('GDPR_COOKIE_NECESSARY_DESC'),
'gdprCookieFunctionalDesc' => Configuration::get('GDPR_COOKIE_FUNCTIONAL_DESC'),
'gdprCookieAnalyticsDesc' => Configuration::get('GDPR_COOKIE_ANALYTICS_DESC'),
'gdprCookieMarketingDesc' => Configuration::get('GDPR_COOKIE_MARKETING_DESC'),
]);
return $this->display(__FILE__, 'views/templates/hook/footer.tpl');
}
/**
* Helper function to tag third-party scripts with appropriate consent categories
*/
protected function tagThirdPartyScripts()
{
// Require the script detector class
require_once(dirname(__FILE__).'/classes/GdprScriptDetector.php');
// Get PrestaShop's currently registered JS files
$jsFiles = $this->context->controller->js_files;
// Loop through JS files and add consent attributes based on patterns
foreach ($jsFiles as $key => $jsFile) {
// Use the detector class
$category = GdprScriptDetector::detectCategory($jsFile);
// Add attribute to the script
$this->context->smarty->assign([
'js_' . md5($jsFile) . '_attributes' => 'data-cookieconsent="' . $category . '"'
]);
}
// Inject a helper script to tag inline scripts as well
$this->context->controller->registerJavascript(
'gdpr-cookie-helper',
$this->_path . 'views/js/gdpr_cookie_helper.js',
['position' => 'head', 'priority' => 1]
);
}
/**
* Modifies scripts in the HTML head
*/
public function hookActionHtmlHeadFooter($params)
{
if (!Configuration::get('GDPR_COOKIE_ENABLED') || Configuration::get('GDPR_COOKIE_ONLY_REQUIRED')) {
return;
}
// Get the current HTML content
$html = $params['html_content'];
// Modify script tags to add data-cookieconsent attribute
$patterns = [
// Google Analytics pattern
'/<script([^>]*)(gtag|googletagmanager|google-analytics)([^>]*)>/' => '<script$1$2$3 data-cookieconsent="analytics">',
// Facebook Pixel pattern
'/<script([^>]*)(connect\.facebook\.net|fbevents\.js)([^>]*)>/' => '<script$1$2$3 data-cookieconsent="marketing">',
// Generic analytics patterns
'/<script([^>]*)(analytics|piwik|matomo|stats)([^>]*)>/' => '<script$1$2$3 data-cookieconsent="analytics">',
// Marketing patterns
'/<script([^>]*)(ads|adsbygoogle|doubleclick|googlesyndication)([^>]*)>/' => '<script$1$2$3 data-cookieconsent="marketing">',
// Functional patterns (more conservative, as these might be necessary)
'/<script([^>]*)(recaptcha|chat)([^>]*)>/' => '<script$1$2$3 data-cookieconsent="functional">',
];
foreach ($patterns as $pattern => $replacement) {
$html = preg_replace($pattern, $replacement, $html);
}
// Update the HTML content
$params['html_content'] = $html;
}
}