vwo-8.x-1.1/vwo.module
vwo.module
<?php
/**
* @file
* VWO module main functionality.
*/
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Cache\Cache;
/**
* Implements hook_page_attachments().
*/
function vwo_page_attachments(array &$attachments) {
$state = &drupal_static('vwo_state', [
'add' => FALSE,
'added' => FALSE,
'custom_url' => FALSE,
'cache_contexts' => [],
]);
// Do not attempt to add more than once.
if ($state['added']) {
return;
}
$config = \Drupal::config('vwo.settings');
$id = $config->get('id');
// If not configured, no point to continue.
if ($id == NULL) {
return;
}
// Do not proceed if not flagged to add, and filtering not enabled.
$filter = ($config->get('filter.enabled') == 'on');
if (!$filter && !$state['add']) {
return;
}
// Check filter and add appropriate cache contexts.
if ($filter) {
// Assumption is that we add the code and negate with tests.
$state['add'] = TRUE;
// Need account for user and role checks.
$account = \Drupal::currentUser();
// Per user opt-out.
$usercontrol = $config->get('filter.userconfig');
if ($usercontrol != 'nocontrol' && $account->isAuthenticated()) {
// Start with default.
$add_js = ($usercontrol == 'optin') ? FALSE : TRUE;
// Get user data and set if needed.
$userconfig = \Drupal::service('user.data')
->get('vwo', $account->id(), 'userconfig');
if (isset($userconfig)) {
$add_js = $userconfig;
}
// Add the caching context and indicate choice.
$state['add'] = $add_js;
$state['cache_contexts'][] = 'user';
}
// Node type filtering.
if ($state['add'] && $include_node_types = $config->get('filter.nodetypes')) {
$node = \Drupal::routeMatch()->getParameter('node');
if ($node) {
$state['add'] = in_array($node->getType(), $include_node_types);
$state['cache_contexts'][] = 'url.path';
}
else {
// Condition requires that the page be a node based one.
$state['add'] = FALSE;
}
}
// Role filtering.
if ($state['add'] && $include_roles = $config->get('filter.roles')) {
$intersect = array_intersect($include_roles, $account->getRoles());
$state['add'] = ($intersect) ? TRUE : FALSE;
$state['cache_contexts'][] = 'user.roles';
}
// Path filtering.
if ($state['add'] && $pathlist = $config->get('filter.page.list')) {
$filter_type = $config->get('filter.page.type');
// Eval the PHP code.
if ($filter_type == 'usephp') {
// Only actually run if the php module is also here.
// See https://www.drupal.org/node/2088811
if (\Drupal::moduleHandler()->moduleExists('php')) {
// @phpstan-ignore function.notFound
if (php_eval($pathlist)) {
$state['add'] = TRUE;
}
else {
$state['add'] = FALSE;
}
}
}
// Check against the path and alias.
else {
$path_matcher = \Drupal::service('path.matcher');
$current_path = \Drupal::service('path.current')->getPath();
$matched = $path_matcher->matchPath($current_path, $pathlist);
// If we haven't matched, also check against the alias.
if (!$matched) {
// Get the alias.
$alias = \Drupal::service('path_alias.manager')->getAliasByPath($current_path);
// Only check again if there's a difference.
if ($current_path != $alias) {
$matched = $path_matcher->matchPath($alias, $pathlist);
}
}
if ($filter_type == 'listexclude' && $matched) {
$state['add'] = FALSE;
}
if ($filter_type == 'listinclude' && !$matched) {
$state['add'] = FALSE;
}
}
$state['cache_contexts'][] = 'url.path';
}
}
// Add JS if we are going to.
if ($state['add']) {
// Set cache tags.
$attachments['#cache']['tags'] = Cache::mergeTags($attachments['#cache']['tags'] ?? [], $config->getCacheTags());
$settings = [
'id' => $id,
];
if ($config->get('loading.type') == 'async') {
$settings['timeout_setting'] = $config->get('loading.timeout.settings');
$settings['testnull'] = NULL;
$script = "window._vwo_code ||
(function () {
var w=window,
d=document;
if (d.URL.indexOf('__vwo_disable__') > -1 || w._vwo_code) {
return;
}
var account_id={$settings['id']},
version=2.2,
settings_tolerance={$settings['timeout_setting']},
hide_element='body',
background_color='white',
hide_element_style = 'opacity:0 !important;filter:alpha(opacity=0) !important;background:' + background_color + ' !important;transition:none !important;',
/* DO NOT EDIT BELOW THIS LINE */
f=!1,v=d.querySelector('#vwoCode'),cc={};try{var e=JSON.parse(localStorage.getItem('_vwo_'+account_id+'_config'));cc=e&&'object'==typeof e?e:{}}catch(e){}function r(t){try{return decodeURIComponent(t)}catch(e){return t}}var s=function(){var e={combination:[],combinationChoose:[],split:[],exclude:[],uuid:null,consent:null,optOut:null},t=d.cookie||'';if(!t)return e;for(var n,i,o=/(?:^|;s*)(?:(_vis_opt_exp_(d+)_combi=([^;]*))|(_vis_opt_exp_(d+)_combi_choose=([^;]*))|(_vis_opt_exp_(d+)_split=([^:;]*))|(_vis_opt_exp_(d+)_exclude=[^;]*)|(_vis_opt_out=([^;]*))|(_vwo_global_opt_out=[^;]*)|(_vwo_uuid=([^;]*))|(_vwo_consent=([^;]*)))/g;null!==(n=o.exec(t));)try{n[1]?e.combination.push({id:n[2],value:r(n[3])}):n[4]?e.combinationChoose.push({id:n[5],value:r(n[6])}):n[7]?e.split.push({id:n[8],value:r(n[9])}):n[10]?e.exclude.push({id:n[11]}):n[12]?e.optOut=r(n[13]):n[14]?e.optOut=!0:n[15]?e.uuid=r(n[16]):n[17]&&(i=r(n[18]),e.consent=i&&3<=i.length?i.substring(0,3):null)}catch(e){}return e}();function i(){var e=function(){if(w.VWO&&Array.isArray(w.VWO))for(var e=0;e<w.VWO.length;e++){var t=w.VWO[e];if(Array.isArray(t)&&('setVisitorId'===t[0]||'setSessionId'===t[0]))return!0}return!1}(),t='a='+account_id+'&u='+encodeURIComponent(w._vis_opt_url||d.URL)+'&vn='+version+('undefined'!=typeof platform?'&p='+platform:'')+'&st='+w.performance.now();e||((n=function(){var e,t=[],n={},i=w.VWO&&w.VWO.appliedCampaigns||{};for(e in i){var o=i[e]&&i[e].v;o&&(t.push(e+'-'+o+'-1'),n[e]=!0)}if(s&&s.combination)for(var r=0;r<s.combination.length;r++){var a=s.combination[r];n[a.id]||t.push(a.id+'-'+a.value)}return t.join('|')}())&&(t+='&c='+n),(n=function(){var e=[],t={};if(s&&s.combinationChoose)for(var n=0;n<s.combinationChoose.length;n++){var i=s.combinationChoose[n];e.push(i.id+'-'+i.value),t[i.id]=!0}if(s&&s.split)for(var o=0;o<s.split.length;o++)t[(i=s.split[o]).id]||e.push(i.id+'-'+i.value);return e.join('|')}())&&(t+='&cc='+n),(n=function(){var e={},t=[];if(w.VWO&&Array.isArray(w.VWO))for(var n=0;n<w.VWO.length;n++){var i=w.VWO[n];if(Array.isArray(i)&&'setVariation'===i[0]&&i[1]&&Array.isArray(i[1]))for(var o=0;o<i[1].length;o++){var r,a=i[1][o];a&&'object'==typeof a&&(r=a.e,a=a.v,r&&a&&(e[r]=a))}}for(r in e)t.push(r+'-'+e[r]);return t.join('|')}())&&(t+='&sv='+n)),s&&s.optOut&&(t+='&o='+s.optOut);var n=function(){var e=[],t={};if(s&&s.exclude)for(var n=0;n<s.exclude.length;n++){var i=s.exclude[n];t[i.id]||(e.push(i.id),t[i.id]=!0)}return e.join('|')}();return n&&(t+='&e='+n),s&&s.uuid&&(t+='&id='+s.uuid),s&&s.consent&&(t+='&consent='+s.consent),w.name&&-1<w.name.indexOf('_vis_preview')&&(t+='&pM=true'),w.VWO&&w.VWO.ed&&(t+='&ed='+w.VWO.ed),t}code={nonce:v&&v.nonce,library_tolerance:function(){return'undefined'!=typeof library_tolerance?library_tolerance:void 0},settings_tolerance:function(){return cc.sT||settings_tolerance},hide_element_style:function(){return'{'+(cc.hES||hide_element_style)+'}'},hide_element:function(){return performance.getEntriesByName('first-contentful-paint')[0]?'':'string'==typeof cc.hE?cc.hE:hide_element},getVersion:function(){return version},finish:function(e){var t;f||(f=!0,(t=d.getElementById('_vis_opt_path_hides'))&&t.parentNode.removeChild(t),e&&((new Image).src='https://dev.visualwebsiteoptimizer.com/ee.gif?a='+account_id+e))},finished:function(){return f},addScript:function(e){var t=d.createElement('script');t.type='text/javascript',e.src?t.src=e.src:t.text=e.text,v&&t.setAttribute('nonce',v.nonce),d.getElementsByTagName('head')[0].appendChild(t)},load:function(e,t){t=t||{};var n=new XMLHttpRequest;n.open('GET',e,!0),n.withCredentials=!t.dSC,n.responseType=t.responseType||'text',n.onload=function(){if(t.onloadCb)return t.onloadCb(n,e);200===n.status?_vwo_code.addScript({text:n.responseText}):_vwo_code.finish('&e=loading_failure:'+e)},n.onerror=function(){if(t.onerrorCb)return t.onerrorCb(e);_vwo_code.finish('&e=loading_failure:'+e)},n.send()},init:function(){var e,t=this.settings_tolerance();w._vwo_settings_timer=setTimeout(function(){_vwo_code.finish()},t),'body'!==this.hide_element()?(n=d.createElement('style'),e=(t=this.hide_element())?t+this.hide_element_style():'',t=d.getElementsByTagName('head')[0],n.setAttribute('id','_vis_opt_path_hides'),v&&n.setAttribute('nonce',v.nonce),n.setAttribute('type','text/css'),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(d.createTextNode(e)),t.appendChild(n)):(n=d.getElementsByTagName('head')[0],(e=d.createElement('div')).style.cssText='z-index: 2147483647 !important;position: fixed !important;left: 0 !important;top: 0 !important;width: 100% !important;height: 100% !important;background:'+background_color+' !important;',e.setAttribute('id','_vis_opt_path_hides'),e.classList.add('_vis_hide_layer'),n.parentNode.insertBefore(e,n.nextSibling));var n='https://dev.visualwebsiteoptimizer.com/j.php?'+i();-1!==w.location.search.indexOf('_vwo_xhr')?this.addScript({src:n}):this.load(n+'&x=true',{l:1})}};w._vwo_code=code;code.init();})();";
$attachments['#attached']['drupalSettings']['vwo'] = $settings;
$attachments['#attached']['html_head'][] = [
[
'#tag' => 'script',
'#attributes' => [
"data-cfasync" => "false",
"type" => "text/javascript",
"id" => "vwoCode",
],
'#value' => Markup::create($script),
], 'vwo',
];
}
else {
// Synchronous adding of code is not implemented. Do not alter cache
// contexts.
$src = "https://dev.visualwebsiteoptimizer.com/lib/{$settings['id']}.js";
$attachments['#attached']['drupalSettings']['vwo'] = $settings;
$attachments['#attached']['html_head'][] = [
[
'#tag' => 'script',
'#attributes' => [
"data-cfasync" => "false",
"type" => "text/javascript",
"id" => "vwoCode",
"src" => $src,
],
'#value' => '',
], 'vwo',
];
return;
}
}
// Add the cache contexts if set.
if ($state['cache_contexts']) {
if (isset($attachments['#cache']['contexts'])) {
$attachments['#cache']['contexts'] = array_merge(
$attachments['#cache']['contexts'],
$state['cache_contexts']
);
}
else {
$attachments['#cache']['contexts'] = $state['cache_contexts'];
}
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function vwo_form_user_form_alter(&$form, FormStateInterface $form_state, $form_id) {
// This hook is called for more than just the user editing.
if ($form_id == 'user_form') {
$config = \Drupal::config('vwo.settings');
$userfilter = $config->get('filter.userconfig');
// If there is no user control, or the module is not working/enabled
// then do not show the options.
if ($userfilter == 'nocontrol'
|| $config->get('id') == NULL) {
return;
}
// Default setting based on visibility setting.
$vwo_checkbox = ($userfilter == 'optin') ? 0 : 1;
// User settings stored in user.data.
$account = $form_state->getFormObject()->getEntity();
$userconfig = \Drupal::service('user.data')
->get('vwo', $account->id(), 'userconfig');
if (isset($userconfig)) {
$vwo_checkbox = $userconfig;
}
$form['vwo_user'] = [
'#type' => 'details',
'#open' => TRUE,
'#title' => t('VWO'),
];
$form['vwo_user']['vwo_userfilter'] = [
'#type' => 'checkbox',
'#title' => t('Include VWO A/B testing'),
'#description' => t('This website may run A/B testing at times. If this box is checked, the javascript required for it to work will be included.'),
'#default_value' => $vwo_checkbox,
];
$form['actions']['submit']['#submit'][] = '_vwo_form_user_form_alter_submit';
}
}
/**
* Submit handler to save user choice on VWO code optin/out.
*/
function _vwo_form_user_form_alter_submit($form, FormStateInterface $form_state) {
// Save data in the user data store.
$account = $form_state->getFormObject()->getEntity();
\Drupal::service('user.data')->set(
'vwo',
$account->id(),
'userconfig',
$form_state->getValue('vwo_userfilter')
);
}
/**
* Implements hook_help().
*/
function vwo_help($route_name, RouteMatchInterface $route_match) {
if ($route_name == 'vwo.settings'|| $route_name == 'help.page.vwo') {
\Drupal::moduleHandler()->loadInclude('vwo', 'inc', 'vwo.help');
return _vwo_help_settings();
}
elseif ($route_name == 'vwo.settings.visibility') {
\Drupal::moduleHandler()->loadInclude('vwo', 'inc', 'vwo.help');
return _vwo_help_visibility();
}
elseif ($route_name == 'vwo.settings.vwoid') {
\Drupal::moduleHandler()->loadInclude('vwo', 'inc', 'vwo.help');
return _vwo_help_vwoid();
}
}
