Further changes required for GDPR compliance
Hey, this is a great plugin! I would love to use it but I think some more changes are required to make it GDPR compliant.
It appears the plugin will:
- For youtube videos - use youtube-nocookie.com which still tracks users and is not compliant
- vimeo - use the dnt qs param, appears compliant
However, these changes do not consider cookies which may load from all over services which your plugin supports like an embedded tweet for example which will also load marketing cookies.
A GDPR setting implies being compliant when it might not be, especially where other services like twitter might be used which may load cookies via a different method.
Suggested solution
Having only really worked with CookieBot as a solution I feel their approach is good, but as it's not a standard approach though giving us access to do the following I think is cookie-blocking service ambiguous enough? Though I can't really comment on what the other services require.
Here is an example that is compliant with CookieBot
<iframe
data-cookieblock-src="https://www.youtube.com/embed/xxxxxxxxxxx"
data-cookieconsent="marketing"
frameborder="0"
allowfullscreen
></iframe>
Where if marketing cookies are accepted, the data-cookieblock-src updates to a src attribute.
So maybe it would be best to give devs the opportunity to disable the src attribute so they can do this.
RE how to handle other services
If a script element is responsible for create an iframe element like a tweet used to (not sure if that's what happens anymore), we can perform a similar change:
<script type="text/plain" data-cookieconsent="marketing"></script>
where the type attribute changes on accepting.
Though of course this requires extending the twig variables a bit more if that's something which could be considered?
I first raised a request concerning this, perhaps without giving full consideration to GDPR requirements: https://github.com/wrav/oembed/issues/23
What I think I'd like to see is:
- Interface / documentation language changed so that people don't think they're automatically compliant (I will try and find time for a pull request). I still see some value to this plugin setting as it is now.
- A solution like yours @joepagan - to enhance this and help people towards full GDPR compliance. I wonder what other approaches there are?
Hmm interesting, so @joepagan and @iparr we'd need something like:
$iframe = $dom->getElementsByTagName('iframe')->item(0);
$src = $iframe->getAttribute('src');
$src = $this->manageGDPR($src);
if (Oembed::getInstance()->getSettings()->enableGdpr) {
$iframe->setAttribute('data-cookieblock-src', $src);
$iframe->setAttribute('data-cookieconsent', 'marketing');
}
I do a ton of backend the past year or two, ML stuff, so don't follow GDPR much.
Updated v3.0.3 with new changes with a new setting to support.
It looks like this update will set 'data-cookieblock-src' in addition to the 'src' attribute, though the Cookiebot implementation removes the 'src' attribute.
It would be great if we could also display a placeholder before or after the iframe-tag
<div class="cookieconsent-optout-marketing">
Please
<a href="javascript:Cookiebot.renew()">accept marketing-cookies</a>
to watch this video.
</div>
This is the original Cookiebot page:
@paulwaddington is correct RE cookiebot, it would needed to remove the src attribute otherwise the iframe will load regardless of cookie consent. Once the user accepts the relevant cookies, Cookiebot updates the iframe's src to its data-cookieblock-src.
I wrote a solution which removes the src and also handles other embeds like TikTok, which provides a <script> rather than an <iframe>
public function addConsentChecksToEmbed(string $code): string
{
try {
$dom = new DOMDocument();
// Disable errors - TikTok puts a <section> in a <blockquote> for some reason which raises a PHP warning
libxml_use_internal_errors(true);
$dom->loadHTML($code);
libxml_use_internal_errors(false);
// Ensure there is a root level element
$body = $dom->getElementsByTagName('body')->item(0);
$childNodes = iterator_to_array($body->childNodes);
// Get the nodes under body which are elements
/** @var DOMElement[] $childElements */
$childElements = array_filter(
$childNodes,
fn (DomNode $node): bool => $node instanceof DOMElement,
);
if (count($childElements) === 1) {
$root = $childElements[0];
} else {
// Wrap the elements in a div
$root = $dom->createElement('div');
if (!$root) {
Craft::error('Could not create root element', __METHOD__);
return '';
}
foreach ($childNodes as $child) {
$root->appendChild($child);
}
$body->appendChild($root);
}
/** @var DOMElement $script */
foreach($dom->getElementsByTagName('script') as $script) {
$script->setAttribute('data-cookieconsent', 'marketing');
$script->setAttribute('type', 'text/plain');
}
/** @var DOMElement $iframe */
foreach($dom->getElementsByTagName('iframe') as $iframe) {
$iframe->setAttribute('data-cookieconsent', 'marketing');
$iframe->setAttribute('data-cookieblock-src', $iframe->getAttribute('src'));
$iframe->removeAttribute('src');
}
return $dom->saveHTML($root);
} catch (DOMException $e) {
Craft::error($e->getMessage(), __METHOD__);
return '';
}
}
I'm currently using that in a Craft module with
{{ craft.videoEmbed.addConsentChecksToEmbed(entry.myField.embed(oEmbedOptions).code)|raw }}
@MangoMarcus If you have a working local solution please send a PR I'd be happen to give it a look and test. If all good I'll merge it through 🍻
Hey @reganlawton
Just checking if any progress has been made here? We have several customers complaining about compliance issues
@D3VM4TT I throw together a quick branch of @MangoMarcus code you can try testing using dev-feature/consent-checks branch in composer.
Hey @reganlawton, I've tested out that branch with cookiebot and it does seem to be correctly blocking youtube/vimeo/tiktok cookies from loading completely until a user grants consent!
This has been updated in v3.1.5