Embed videos GDPR (DSGVO) compliant in Drupal 8



The following tutorial shows you how to prevent embedded youtube or vimeo videos from loading in Drupal 8. As long as the user has not accepted cookies, a banner with a preview of the video is shown instead of the video.

Why?

GDPR (DSGVO) requires you to introduce another click before the video loads. That is because youtube sets cookies even before the video is started. After the click, the video embedded code should load.

Components

For this sample the following components are used.

Drupal 8
Video Embed Field Module  (optional, could be any moduleto embedded videos)
EU Cookie Compliance Module (could be any module for cookies)

Step 1: Prevent Youtube from loading.

To prevent YoutTube from loading we have to replace the src attribute of the IFrame with a data-src attribute. If you have embedded the video manual, you can edit it.

If you use the Video Embed Field Module you can override the template by creating the following twig file in your theme folder.

video-embed-iframe.html.twig
<iframe{{ attributes }}{% if url is not empty %} data-src="{{ url }}{% if query is not empty %}?{{ query | url_encode }}{% endif %}"{% endif %}></iframe>
{% if description is not empty %}
    {{ description }}
{% endif %}


Step 2: Prepare a function to check if cookies are allowed 

Create a file named headerScripts.js in your theme folder with the following code. Adjust code if you use another module for cookie consent.

headerScripts.js
window.hasCookieAgreed = function () {
  var value = document.cookie.replace(/(?:(?:^|.*;\s*)cookie-agreed\s*\=\s*([^;]*).*$)|^.*$/, "$1");
  value = parseInt(value);
  if (isNaN(value)) {
    value = null;
  }
  var agreed = (value === 1 || value === 2);
  return agreed;
}


Add  the following code to your theme library file so that the functions are called before the drupal behaviours.

THEME_FOLDER/THEME_NAME.library.yml 
header-scripts:
  header: true
  weight: -1000
  js:
    headerScripts.js: {}


Add the following entry to the libraries section of your theme info file.

THEME_FOLDER/THEME_NAME.info.yml
libraries: 
  - 'THEME_NAME/header-scripts'

Step 3: Create JS Code to either show a Blocking Window or load the video

Use a drupal behaviour to accomplish this. If cookies are allowed we just create a src attribute with the value from the data-src attribute. If not we show the banner with a preview of the video an explanation and the buttons to enable cookies.

  Drupal.behaviors.disableYoutTubeOrVimeoIfNoCookieAgreed = {
    attach(context, settings) {

      if (!$("iframe", context).length) {
        return;
      }

      if (window.hasCookieAgreed()) {
        // If Cookie is agreed just correct src Attributes
        $("iframe", context).each(function () {
          const videoFrame = $(this);
          const video_src = videoFrame.data("src");

          if (!video_src) {
            return;
          }

          if (video_src.match(/youtube|vimeo/) != null) {
            videoFrame.attr('src', video_src);
          }
        })
      } else {

        const getWallText = function getWallText(isYouTube){

          const title = isYouTube ? Drupal.t("YouTubeBlockTitle") : Drupal.t("VimeoBlockTitle");
          const text = isYouTube ? Drupal.t("YouTubeBlockText") : Drupal.t("VimeoBlockText");
          const btncAcceptText = Drupal.t("YouTubeBlock Accept");
          const btnMoreInfoText = Drupal.t("YouTubeBlock More Info");

          const wall_text = `<div class="description">
          <div class="title">${title}</div>
          <div class="text">${text}</div>
          <div class="button-bar">
          <button class="btn-accept btn-yellow"> ${btncAcceptText} </button>
          <button class="btn-more-info btn-gray"> ${btnMoreInfoText} </button>
          </div></div>`;

          return wall_text;
        };

        $("iframe", context).each(function () {
          const videoFrame = $(this);
          const videoSrc = videoFrame.data("src");
          if (!videoSrc) {
            return;
          }

          const isYouTube = videoSrc.match(/youtube/) != null;
          const isVimeo = videoSrc.match(/vimeo/) != null;
          if (!isYouTube && !isVimeo) {
            return;
          }

          // If preview is provides as data-preview we use it
          // let videoPreview = video_frame.dataset.preview;
          let videoPreview = videoFrame.data("preview");

          if (!videoPreview) {
            if (isYouTube) {
              // Try to get video from YouTube. Not so easy for vimeo though
              const videoId = videoSrc.match(/(embed|video)\/([^?\s]*)/)[2];
              videoPreview = `https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`;
            }
            else {
              // eslint-disable-next-line no-console
              console.log("Error. No data-preview attribute set. This is required for Vimeo Videos")
            }
          }

          const jqWall = $('<article class="video-wall"></article>');
          jqWall.html(getWallText(isYouTube));
          jqWall.find(".btn-accept").click(Drupal.eu_cookie_compliance.acceptAction);
          jqWall.find(".btn-more-info").click(Drupal.eu_cookie_compliance.moreInfoAction);
          jqWall.css("background-image", `url("${videoPreview}")`);

          videoFrame.parent().addClass("video-embed-blocked");
          videoFrame.replaceWith(jqWall);

        });
      }
    }
  }

Step 4: Styling

Style the banner as you like. Here is an example of our styling:

Video-Wall.scss 
.youttube-embed-blocked{ 
  &:after{ 
    padding-bottom: 0px; 
  }
}
.video-wall {
  position: relative;
  font: 400 22px Roboto, Arial, sans-serif;
  color: white;
  display: inline-block;
  margin: 0;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  top: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  .title {
    display: block;
    text-align: center;
    font-size: 1.5em;
    margin: 0;
    font-weight: 700;
  }
  .wall-background {
    height: 100%;
    width: 100%;
    opacity: .6;
    background-color: black;
  }
  .description {
    padding: 4em 2em 1em 2em;
    background: rgba(0,0,0,0.7);
  }
  .text {
    font-size: 1em;
    margin: 30px 0 1em;
    text-align: center;
    color: white;
    line-height: 1.2;
  }
  .button-bar {
    text-align: center;
    button {
      margin: 5px;
    }
  }
  .show-cookie-window {
    position: absolute;
    left: 50%;
    bottom: 1em;
    transform: translateX(-50%);
    width: auto;
    height: auto;
    &:focus {
      outline: none;
    }
  }
  @media(max-width: $screen-xs-max) {
    font-size: 14px;
    .description {
      padding: 7.5px;
    }
    .text {
      margin-top: 5px;
      margin-bottom: 5px;
    }
    .title {
      font-size: 1.2em;
    }
    button {
      padding: 1px 8px !important;
      border-width: 1px !important;
      font-size: 14px !important;
      bottom: 5px;
    }
  }
}

 

Kommentare

Beliebte Posts aus diesem Blog

Use different image content for mobile and desktop in Drupal 8 (Art direction)