212 lines
6.5 KiB
JavaScript
212 lines
6.5 KiB
JavaScript
/**
|
|
* GDPR Cookie Consent Helper for PrestaShop
|
|
*
|
|
* @author Walzen665
|
|
* @copyright Copyright (c) 2025
|
|
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
|
*/
|
|
|
|
// This script runs early in the page load to tag inline scripts with appropriate consent categories
|
|
(function() {
|
|
// Known script patterns to identify analytics, marketing and functional scripts
|
|
const scriptPatterns = {
|
|
analytics: [
|
|
/google[\s\-_]?analytics/i,
|
|
/ga\s*\(\s*['"]create/i,
|
|
/googletagmanager/i,
|
|
/gtag/i,
|
|
/\_gaq/i,
|
|
/matomo/i,
|
|
/piwik/i,
|
|
/mixpanel/i,
|
|
/hotjar/i,
|
|
/clarity/i
|
|
],
|
|
marketing: [
|
|
/facebook[\s\-_]?pixel/i,
|
|
/fbq\s*\(\s*['"]init/i,
|
|
/doubleclick/i,
|
|
/adwords/i,
|
|
/google[\s\-_]?ad[\s\-_]?services/i,
|
|
/google[\s\-_]?tag[\s\-_]?manager/i,
|
|
/gtm/i,
|
|
/twitter[\s\-_]?pixel/i,
|
|
/pinterest[\s\-_]?tag/i
|
|
],
|
|
functional: [
|
|
/recaptcha/i,
|
|
/chat/i,
|
|
/livechat/i,
|
|
/support/i,
|
|
/feedback/i,
|
|
/preference/i,
|
|
/usercentrics/i
|
|
]
|
|
};
|
|
|
|
// Function to process and tag a script element
|
|
function processScript(script) {
|
|
// Skip if it already has a consent attribute
|
|
if (script.hasAttribute('data-cookieconsent')) {
|
|
return;
|
|
}
|
|
|
|
// Skip our own scripts
|
|
if (script.src && script.src.indexOf('gdpr_cookie') !== -1) {
|
|
script.setAttribute('data-cookieconsent', 'necessary');
|
|
return;
|
|
}
|
|
|
|
// Check content for patterns
|
|
const content = script.innerHTML || '';
|
|
const src = script.src || '';
|
|
|
|
// Determine script category
|
|
let category = 'necessary'; // Default category
|
|
|
|
for (const [cat, patterns] of Object.entries(scriptPatterns)) {
|
|
for (const pattern of patterns) {
|
|
if (pattern.test(content) || pattern.test(src)) {
|
|
category = cat;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (category !== 'necessary') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Tag the script
|
|
script.setAttribute('data-cookieconsent', category);
|
|
|
|
// For non-necessary scripts, we'll create a duplicate with the correct attribute
|
|
// but disabled until consent is given
|
|
if (category !== 'necessary') {
|
|
const originalScript = script;
|
|
const newScript = document.createElement('script');
|
|
|
|
// Copy attributes
|
|
Array.from(originalScript.attributes).forEach(attr => {
|
|
if (attr.name !== 'data-cookieconsent') {
|
|
newScript.setAttribute(attr.name, attr.value);
|
|
}
|
|
});
|
|
|
|
// Set consent attribute
|
|
newScript.setAttribute('data-cookieconsent', category);
|
|
|
|
// Copy content if it's an inline script
|
|
if (!originalScript.src && originalScript.innerHTML) {
|
|
newScript.innerHTML = originalScript.innerHTML;
|
|
}
|
|
|
|
// Replace the original script
|
|
originalScript.parentNode.replaceChild(newScript, originalScript);
|
|
|
|
// Prevent execution by removing src and content
|
|
newScript.removeAttribute('src');
|
|
newScript.innerHTML = '';
|
|
}
|
|
}
|
|
|
|
// Process existing scripts
|
|
document.querySelectorAll('script').forEach(processScript);
|
|
|
|
// Use a MutationObserver to catch dynamically added scripts
|
|
const observer = new MutationObserver(mutations => {
|
|
mutations.forEach(mutation => {
|
|
mutation.addedNodes.forEach(node => {
|
|
if (node.tagName === 'SCRIPT') {
|
|
processScript(node);
|
|
} else if (node.querySelectorAll) {
|
|
node.querySelectorAll('script').forEach(processScript);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// Start observing the document
|
|
observer.observe(document.documentElement, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
|
|
// Also process iframes
|
|
function processIframe(iframe) {
|
|
// Skip if it already has a consent attribute
|
|
if (iframe.hasAttribute('data-cookieconsent')) {
|
|
return;
|
|
}
|
|
|
|
const src = iframe.src || '';
|
|
|
|
// Common third-party iframe sources
|
|
const iframePatterns = {
|
|
marketing: [
|
|
/youtube/i,
|
|
/vimeo/i,
|
|
/facebook\.com\/plugins/i,
|
|
/twitter\.com\/widgets/i,
|
|
/instagram\.com/i,
|
|
/pinterest\.com/i,
|
|
/doubleclick/i,
|
|
/ads/i
|
|
],
|
|
analytics: [
|
|
/googletagmanager/i,
|
|
/analytics/i
|
|
],
|
|
functional: [
|
|
/recaptcha/i,
|
|
/maps\.google/i,
|
|
/google\.com\/maps/i,
|
|
/disqus/i,
|
|
/livechat/i,
|
|
/chat/i
|
|
]
|
|
};
|
|
|
|
// Determine iframe category
|
|
let category = 'necessary'; // Default category
|
|
|
|
for (const [cat, patterns] of Object.entries(iframePatterns)) {
|
|
for (const pattern of patterns) {
|
|
if (pattern.test(src)) {
|
|
category = cat;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (category !== 'necessary') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Tag the iframe
|
|
iframe.setAttribute('data-cookieconsent', category);
|
|
}
|
|
|
|
// Process existing iframes
|
|
document.querySelectorAll('iframe').forEach(processIframe);
|
|
|
|
// Use the observer to catch dynamically added iframes
|
|
const iframeObserver = new MutationObserver(mutations => {
|
|
mutations.forEach(mutation => {
|
|
mutation.addedNodes.forEach(node => {
|
|
if (node.tagName === 'IFRAME') {
|
|
processIframe(node);
|
|
} else if (node.querySelectorAll) {
|
|
node.querySelectorAll('iframe').forEach(processIframe);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// Start observing for iframes
|
|
iframeObserver.observe(document.documentElement, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
})();
|