Problème RGPD avec le plugin GA4

  • Posts: 628
  • Thank you received: 28
  • Hikashop Business
2 days 6 hours ago #369337

-- HikaShop version -- : 6.1.0
-- Joomla version -- : 5.4.0
-- PHP version -- : 8.3.25

Bonjour,

Je viens de m'apercevoir que mon site n'est pas conforme au RGPD. J'utilise une plateforme externe (LegalBlink) pour la gestion du consentement.

L'intégration de Google Analytics 4 (GA4) via votre plugin pose problème: le script GA4 est chargé et des données de tracking sont envoyées immédiatement (sans consentement) lors du chargement de la page.
Je rencontre le même type de difficulté avec le plugin du Meta Pixel de Joomlamax, ce qui m'indique que la solution passe par une modification du code.

La procédure de Blocage Préalable (Prior Blocking) requise par LegalBlink exige que les balises <script> de GA4 et des événements E-commerce reçoivent les attributs suivants: type="text/plain" class="lb-third-party-stats-cookies".

Pour mettre en place cette modification de manière propre et sans altérer les futures mises à jour du plugin, j'aimerais savoir :

- S'il est possible de faire un override (une surcharge) pour votre plugin Google Analytics et, si oui, quel est le nom du fichier PHP à modifier et dans quel dossier de mon template Joomla créer l'override?
- Serait-il envisageable d'intégrer une fonctionnalité de "Prior Blocking" native dans une prochaine mise à jour de votre plugin, permettant d'ajouter facilement la classe de blocage nécessaire pour assurer la conformité RGPD?

Merci,
Lorenzo

Please Log in or Create an account to join the conversation.

  • Posts: 84660
  • Thank you received: 13772
  • MODERATOR
2 days 3 hours ago #369339

Bonjour,

Normalement, avec Joomla, toutes les extensions rajoutent leur javascript via le code PHP:

$doc = JFactory::getDocument();
$doc->addScript($url); // for a JS file
$doc->addScriptDeclaration($jsCode); // for JS code directly added to the head of the HTML

Vous pouvez retrouver ce code dans le fichier plugins/system/hikashop_ga4/hikashop_ga4.php :
$doc = JFactory::getDocument();
$doc->addScript('https://www.googletagmanager.com/gtag/js?id='.$this->site_id, array(), array('async'=>'async'));
$doc->addScriptDeclaration($js);

Ensuite, c'est Joomla qui se charge de faire l'affichage des tag scripts lors du processus de rendu de la page.
Donc, idéalement, une intégration RGPD avec acceptation de cookies devrait se faire via un plugin du groupe "system" implémentant soit l'évènement onBeforeCompileHead ( docs.joomla.org/Plugin/Events/System#onBeforeCompileHead juste avant que le head de la page ne soit généré ) ou onAfterRender ( docs.joomla.org/Plugin/Events/System#onAfterRender une fois que l'HTML complet soit généré ). Le deuxième évènement permet de pouvoir gérer plus d'extension car certaines pourraient rajouter leur JS après onBeforeCompileHead.
Le code pour faire cela est assez simple. Par exemple:
	function onAfterRender() {
		if(!class_exists('JFactory'))
			class_alias('Joomla\CMS\Factory', 'JFactory');
		$app = JFactory::getApplication();
		$body = $app->getBody();
                   // replace stuff in the HTML if necessary. For example:
                   // if($this->cookies_not_accepted) $body = str_replace(array('type="text/javascript"', '<script'), array('', '<script type="text/plain"class="lb-third-party-stats-cookies"'), $body);
		$app->setBody($body);
	}
Donc, normalement, pas besoin de modifier les plugins ou de faire d'override. Il suffit que le plugin RGPD pour Joomla fasse quelque chose du genre et il devrait pouvoir gérer toutes les extensions, y compris notre plugin pour GA et le plugin de joomlaMAX pour Meta.

Please Log in or Create an account to join the conversation.

  • Posts: 628
  • Thank you received: 28
  • Hikashop Business
2 days 2 hours ago #369342

Bonjour Nicolas,

Je dois clarifier un point crucial: LegalBlink n'est pas un plugin Joomla, mais une plateforme externe. Son système ne fonctionne pas avec l'événement onAfterRender et exige que les balises script non consenties soient modifiées.

Je suis en train de résoudre un problème similaire avec le développeur du plugin Meta Pixel for Hikashop de Joomlamax qui dans la nouvelle version du plugin a eu la bonne idée d'ajouter un onglet dans la partie "Privacy & GDPR Compliance" qui permet d'insérer du code dans un champ de condition JavaScript intégré.
J'ai expliqué mon cas au développeur et je dois dire qu'il a été très réactif en sortant une mise à jour du plugin et m'a fourni le code à insérer.
Le code fourni permet d'intégrer le Blocage Préalable (Prior Blocking) basé sur un cookie:

return (function() {
	try {
		var m = document.cookie.match(/(?:^|;\s*)lb_csc=([^;]+)/);
		if (!m) return false;
		var c = JSON.parse(decodeURIComponent(m[1]));
		return!!(c && (c.advertising === 1 || c.ads === 1));
	} catch (e) {
		return false;
	}
})();






J'attends actuellement la réponse de LegalBlink pour obtenir les clés exactes de consentement. Les chaînes c.advertising et c.ads ne sont pas valides dans ma configuration, ce qui empêche le déblocage du Pixel, sinon pour le reste c'est ok, cela signifie que le plugin de Joomlamax est fonctionnel, mais que je suis bloqué par cette information manquante.

Pour retourner à votre Plugin GA4, pourriez-vous m'indiquer la procédure d'override (surcharge) propre pour le plugin hikashop_ga4 afin que je puisse insérer moi-même les attributs LegalBlink (type="text/plain" class="lb-third-party-stats-cookies") dans le fichier PHP que vous avez indiqué?
J'aimerais aussi suggérer d'intégrer une fonctionnalité similaire (champ pour les conditions JS) dans une future version du plugin GA4, comme l'a fait Joomlamax afin d'aider tous les utilisateurs qui n'utilisent pas dans Joomla un plugin pour le RGPD.

Merci!

Attachments:
Last edit: 2 days 2 hours ago by kilou.

Please Log in or Create an account to join the conversation.

  • Posts: 84660
  • Thank you received: 13772
  • MODERATOR
1 day 18 hours ago #369349

Bonjour,

Merci pour les détails. Nous pourrions en effet rajouter un option pour cela. Il serait intéressant de connaître le code JS définitif.

Concernant la surcharge je vous ai déjà donner l'information dans mon précédent message. Sans option additionnelle, il faut développer un petit plugin system pour remplacer les scripts lors du rendu de la page. Les plugins ne sont pas overridables avec Joomla.

Please Log in or Create an account to join the conversation.

  • Posts: 628
  • Thank you received: 28
  • Hikashop Business
7 hours 1 minute ago #369370

Bonjour,

Merci pour les détails. Nous pourrions en effet rajouter un option pour cela. Il serait intéressant de connaître le code JS définitif.


Le code JS définitif pour le plugin Meta Pixel de Joomlamax est le suivant, en tout cas dans mon cas et avec LegalBlink cela fonctionne parfaitement:

return (function() {
    try {
        var m = document.cookie.match(/(?:^|;\s*)lb_csc=([^;]+)/);
        if (!m) return false;
        var c = JSON.parse(decodeURIComponent(m[1]));
        
        // Cette ligne vérifie si le tableau 'level' contient la catégorie 'third_party_adv_cookies'
        return !!(c && c.level && c.level.includes("third_party_adv_cookies")); 
        
    } catch (e) {
        return false;
    }
})();


Dans l'attente d'une solution intégrée à votre plugin (à l'image du plugin Meta Pixel de Joomlamax) j'ai essayé de l'adapter pour le faire fonctionner avec le consentement de LegalBlink, ...cela n'a pas été chose simple, n'étant pas développeur je me suis fait aider par l'IA :whistle: :dry:

Petite explication préalable.
Le système de LegalBlink exige que tous les scripts de suivi soient bloqués avant le consentement de l'utilisateur.

Voici comment j'ai abordé le problème du blocage du suivi de LegalBlink pour l'appliquer à votre plugin:
Blocage (Côté Serveur / PHP): Le code PHP d'HikaShop (dans hikashop_ga4.php) a été modifié pour insérer l'attribut type="text/plain" sur toutes les balises <script> de GA4.
Ce changement neutralise le script, l'empêchant d'être exécuté par le navigateur.
Exemple:

// Remplace addScript par addCustomTag pour ajouter les attributs de blocage pour le fichier gtag.js externe.
$doc->addCustomTag('<script type="text/plain" class="lb-third-party-stats-cookies" async src="https://www.googletagmanager.com/gtag/js?id='.$this->site_id.'"></script>');
Déblocage (Côté Client / JavaScript): Lorsque l'utilisateur clique sur "Accepter", le script JavaScript qui a été intégré s'active. Ce script recherche tous les éléments avec type="text/plain" et les remplace dynamiquement par de nouvelles balises <script type="text/javascript">, forçant ainsi leur exécution.

Pour avoir une vision complète du code reporté plus bas: le bloc de code PHP n'est pas un simple exemple, mais un correctif spécifique qui a été intégré: il gère l'injection conditionnelle de l'événement begin_checkout (mais dans un état bloqué), car cet événement n'était pas tracé de manière fiable sur les pages du panier et du checkout.
Le JavaScript s'occupe ensuite de la réactivation effective du script correctement injecté.
Ce bloc de code a été injecté sur toutes les pages avant la fermeture de la balise </body> via ReReplacer.

<?php
// PHP : Correction pour l'événement manquant 'begin_checkout'
defined('_JEXEC') or die('Restricted access');
$ctrl = JFactory::getApplication()->input->getCmd('ctrl');
$view = JFactory::getApplication()->input->getCmd('view');

if ($ctrl == 'checkout' || $view == 'user' || $view == 'cart') {
    // Injection de l'événement en état BLOQUÉ (type="text/plain")
    echo '<script type="text/plain" class="lb-third-party-stats-cookies">gtag(\'event\', \'begin_checkout\', {});</script>';
}
?>

<script>
// JavaScript : Mécanisme de Déblocage et de Buffer des Événements

// File d'attente (buffer) pour les événements gtag() reçus AVANT le consentement
var LB_TEMP_DATALAYER_QUEUE = [];
var LB_STATS_CONSENTED = false;
var LB_STATS_CLASS = ".lb-third-party-stats-cookies"; // Classe des scripts à débloquer

function executeLegalBlinkHardFix() {
    // Empêche l'exécution multiple
    if (LB_STATS_CONSENTED) return;
    
    LB_STATS_CONSENTED = true;
    
    // 1. Déblocage : Recherche tous les scripts bloqués et les remplace par des scripts actifs
    document.querySelectorAll(LB_STATS_CLASS).forEach(function(script) {
        if (script.getAttribute('type') === 'text/plain') { 
            var newScript = document.createElement('script');
            newScript.type = 'text/javascript'; // Rend le script actif
            if (script.innerHTML) newScript.innerHTML = script.innerHTML;
            if (script.hasAttribute('async')) newScript.setAttribute('async', 'async');
            if (script.hasAttribute('src')) newScript.setAttribute('src', script.getAttribute('src'));
            script.parentNode.replaceChild(newScript, script);
        }
    });

    // 2. Exécution du Buffer : Déclenche tous les événements mis en attente
    if (LB_TEMP_DATALAYER_QUEUE.length > 0) {
        for (var i = 0; i < LB_TEMP_DATALAYER_QUEUE.length; i++) {
            // Utilise la fonction gtag originale (gtag_temp)
            window.gtag_temp.apply(null, LB_TEMP_DATALAYER_QUEUE[i]);
        }
        LB_TEMP_DATALAYER_QUEUE = [];
    }
    
    // 3. Restauration : Restaure la fonction gtag() d'origine
    window.gtag = window.gtag_temp;
    delete window.gtag_temp;
}

// Interception des événements : Enregistre la fonction gtag() originale et la remplace
window.gtag_temp = window.gtag;
window.gtag = function() {
    if (LB_STATS_CONSENTED) {
        // Si le consentement est donné, exécute la fonction originale immédiatement
        window.gtag_temp.apply(null, arguments);
    } else {
        // Si pas de consentement (attente), met en mémoire tampon uniquement les événements ('event')
        if (arguments[0] === 'event') {
            LB_TEMP_DATALAYER_QUEUE.push(arguments);
        }
        // Laisse passer les commandes 'config' et 'js' car elles sont essentielles au chargement initial
        if (arguments[0] === 'config' || arguments[0] === 'js') {
            window.gtag_temp.apply(null, arguments);
        }
    }
};

// Déclenchement : Écoute l'événement de consentement de LegalBlink
document.addEventListener("legalblink_stats_consentgiven", function() {
    if (typeof LegalBlink !== 'undefined' && LegalBlink.lbConsent && LegalBlink.lbConsent.level.includes("third_party_stats_cookies")) {
        // Délai de 500ms pour garantir le chargement complet des autres scripts
        setTimeout(executeLegalBlinkHardFix, 500);
    }
});
</script>

Après tout cela, le système est validé et le suivi est opérationnel, sauf pour les événements add_shipping_info et add_payment_info qui semblent être visibles uniquement lorsqu'on change leur statut manuellement.
Si mes souvenirs sont bons, c'est le comportement d'origine de ces deux événements de votre plugin même sans cette implémentation...?

En comparant les deux approches, celle du plugin de Joomlamax et l'intégration pour votre plugin, même si cette dernière semble bien fonctionner (je note juste un petit doute sur la "Debug View" dans GA, mais les événements s'affichent bien dans la "Vue d'ensemble en temps réel", donc cela reste fiable), elle a nécessité la modification directe du fichier principal de votre plugin, hikashop_ga4.php, ce qui posera problème pour les futures mises à jour.

J'ai essayé de comprendre comment le plugin de Joomlamax a géré ce problème.
Il me semble de comprendre qu'il utilise une méthode plus propre et plus simple: au lieu de bloquer un script déjà injecté, leur plugin vérifie d'abord le consentement de l'utilisateur avant même d'injecter le code dans la page.
Ceci serait l'idéal pour votre plugin, car cela éviterait d'intégrer cette solution "maison".

Désolé pour ce long post mais je pense que c'était necessaire... merci.

Last edit: 4 hours 43 minutes ago by kilou.

Please Log in or Create an account to join the conversation.

Time to create page: 0.085 seconds
Powered by Kunena Forum