false, 'language' => 'auto', 'consent_mode_v2_enabled' => false, 'gtm_enabled' => false, 'gtm_id' => '', 'video_blocking_enabled' => false, ]; } function samtyk_cmp_normalize_language($language): string { if (!is_string($language) || $language === '' || strtolower($language) === 'auto') { return 'auto'; } $language = strtolower(str_replace('_', '-', trim($language))); return preg_match('/^[a-z]{2,3}(?:-[a-z0-9]{2,8})?$/', $language) ? $language : 'auto'; } function samtyk_cmp_is_valid_gtm_id($gtm_id): bool { return is_string($gtm_id) && preg_match('/^GTM-[A-Z0-9]+$/i', trim($gtm_id)) === 1; } function samtyk_cmp_get_settings(): array { $defaults = samtyk_cmp_get_default_settings(); $saved = get_option('samtyk_cmp_settings', []); if (!is_array($saved)) { return $defaults; } $settings = $defaults; $settings['enabled'] = !empty($saved['enabled']); $settings['language'] = samtyk_cmp_normalize_language($saved['language'] ?? 'auto'); $settings['consent_mode_v2_enabled'] = !empty($saved['consent_mode_v2_enabled']); $settings['gtm_id'] = isset($saved['gtm_id']) && is_string($saved['gtm_id']) ? trim($saved['gtm_id']) : ''; $settings['gtm_enabled'] = !empty($saved['gtm_enabled']) && samtyk_cmp_is_valid_gtm_id($settings['gtm_id']); $settings['video_blocking_enabled'] = !empty($saved['video_blocking_enabled']); return $settings; } function samtyk_cmp_get_stored_consent(): ?array { $encoded_consent = isset($_COOKIE['CookiePopupConsent']) && is_string($_COOKIE['CookiePopupConsent']) ? sanitize_text_field(wp_unslash($_COOKIE['CookiePopupConsent'])) : ''; if (!is_string($encoded_consent) || $encoded_consent === '') { return null; } $normalized_consent = strtr($encoded_consent, '-_', '+/'); $padding_length = (4 - (strlen($normalized_consent) % 4)) % 4; $decoded_consent = base64_decode($normalized_consent . str_repeat('=', $padding_length), true); if (!is_string($decoded_consent)) { return null; } $consent = json_decode($decoded_consent, true); if ( !is_array($consent) || ($consent['v'] ?? null) !== 1 || !isset($consent['categories']) || !is_array($consent['categories']) ) { return null; } return $consent; } function samtyk_cmp_has_consent(string $category): bool { $consent = samtyk_cmp_get_stored_consent(); return $consent !== null && ($consent['categories'][$category] ?? false) === true; } function samtyk_cmp_protect_mailchimp_campaign_tracking(): void { if (!class_exists('MailChimp_Service')) { return; } $service = MailChimp_Service::instance(); $settings = samtyk_cmp_get_settings(); if (!$settings['enabled'] || samtyk_cmp_has_consent('marketing')) { return; } remove_action('init', [$service, 'handleCampaignTracking']); } function samtyk_cmp_enqueue_frontend_assets(): void { $settings = samtyk_cmp_get_settings(); if (!$settings['enabled']) { return; } wp_enqueue_script( 'samtyk-cmp-runtime', 'https://consent.samtyk.com/cookiepopup.js', [], SAMTYK_CMP_VERSION, false ); if ($settings['consent_mode_v2_enabled']) { wp_add_inline_script( 'samtyk-cmp-runtime', "window.dataLayer = window.dataLayer || [];\nfunction gtag() { dataLayer.push(arguments); }\ngtag('consent', 'default', {\nad_storage: 'denied',\nanalytics_storage: 'denied',\nad_user_data: 'denied',\nad_personalization: 'denied',\nfunctionality_storage: 'denied',\npersonalization_storage: 'denied',\nsecurity_storage: 'granted',\nwait_for_update: 500\n});\ngtag('set', 'ads_data_redaction', true);", 'before' ); } if ($settings['gtm_enabled']) { wp_add_inline_script( 'samtyk-cmp-runtime', "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer'," . wp_json_encode($settings['gtm_id']) . ');', 'before' ); } if ($settings['video_blocking_enabled']) { samtyk_cmp_enqueue_placeholder_styles(); wp_enqueue_style( 'samtyk-cmp-video-embeds', SAMTYK_CMP_PLUGIN_URL . 'assets/frontend.css', [], SAMTYK_CMP_VERSION ); wp_enqueue_script( 'samtyk-cmp-video-embeds', SAMTYK_CMP_PLUGIN_URL . 'assets/frontend.js', [], SAMTYK_CMP_VERSION, true ); wp_add_inline_script( 'samtyk-cmp-video-embeds', 'window.SamtykCmpEmbedConfig = ' . wp_json_encode(samtyk_cmp_get_video_runtime_config($settings['language'])) . ';', 'before' ); } } function samtyk_cmp_add_runtime_script_attributes(string $tag, string $handle): string { if ($handle !== 'samtyk-cmp-runtime') { return $tag; } $language = samtyk_cmp_get_settings()['language']; return preg_replace( '~ 'youtube', 'category' => 'functional,statistics,marketing', 'src' => $src]; } if (preg_match('~^(?:https?:)?//(?:(?:www\.)?vimeo\.com/showcase/[0-9]+/embed2(?:[/?#]|$)|player\.vimeo\.com/video/)~i', $src)) { // Only exempt DNT explicitly enabled in the original embed URL. $query = []; parse_str((string) wp_parse_url($src, PHP_URL_QUERY), $query); if (isset($query['dnt']) && in_array($query['dnt'], ['1', 'true'], true)) { return false; } if (strpos($src, '//') === 0) { $src = 'https:' . $src; } return ['type' => 'vimeo', 'category' => 'statistics', 'src' => samtyk_cmp_add_query_parameter($src, 'dnt', '1')]; } if (preg_match('~^(?:https?:)?//open\.spotify\.com/embed/~i', $src)) { if (strpos($src, '//') === 0) { $src = 'https:' . $src; } return ['type' => 'spotify', 'category' => 'functional,statistics,marketing', 'src' => $src]; } if (preg_match('~^(?:https?:)?//e\.issuu\.com/embed\.html(?:[?#]|$)~i', $src)) { if (strpos($src, '//') === 0) { $src = 'https:' . $src; } return ['type' => 'issuu', 'category' => 'functional,statistics,marketing', 'src' => $src]; } return false; } function samtyk_cmp_enqueue_placeholder_styles(): void { wp_enqueue_style('samtyk-cmp-placeholders', SAMTYK_CMP_PLUGIN_URL . 'assets/script-embed-manager.css', [], SAMTYK_CMP_VERSION); } function samtyk_cmp_get_placeholder_default_text(array $categories): string { $key = implode(',', array_intersect(['functional', 'statistics', 'marketing'], $categories)); switch ($key) { case 'functional': return __('Displaying this content requires consent for functional cookies.', 'samtyk-cmp'); case 'statistics': return __('Displaying this content requires consent for statistics cookies.', 'samtyk-cmp'); case 'marketing': return __('Displaying this content requires consent for marketing cookies.', 'samtyk-cmp'); case 'functional,statistics': return __('Displaying this content requires consent for functional and statistics cookies.', 'samtyk-cmp'); case 'functional,marketing': return __('Displaying this content requires consent for functional and marketing cookies.', 'samtyk-cmp'); case 'statistics,marketing': return __('Displaying this content requires consent for statistics and marketing cookies.', 'samtyk-cmp'); case 'functional,statistics,marketing': return __('Displaying this content requires consent for all cookie categories.', 'samtyk-cmp'); default: return __('This content requires your consent.', 'samtyk-cmp'); } } function samtyk_cmp_is_default_placeholder_text(string $text): bool { // Earlier versions saved this generic default as text. Treat it as automatic too. return in_array(trim($text), ['', 'This content requires your consent.', 'Dette indhold kræver dit samtykke.'], true); } function samtyk_cmp_get_placeholder_default_texts(): array { $texts = []; foreach (['', 'functional', 'statistics', 'marketing', 'functional,statistics', 'functional,marketing', 'statistics,marketing', 'functional,statistics,marketing'] as $key) { $texts[$key] = samtyk_cmp_get_placeholder_default_text($key === '' ? [] : explode(',', $key)); } return $texts; } function samtyk_cmp_get_video_text(string $type, string $language): array { $normalized_language = samtyk_cmp_normalize_language($language); $locale = function_exists('get_locale') ? (string) get_locale() : 'en_US'; if ($normalized_language !== 'auto') { $language_code = strtolower(substr($normalized_language, 0, 2)); $available_locales = function_exists('get_available_languages') ? get_available_languages() : []; $available_locales[] = $locale; if ($language_code === 'en') { $locale = 'en_US'; } elseif ($language_code === 'da') { $locale = 'da_DK'; } else { $locale = str_replace('-', '_', $normalized_language); } foreach (array_unique($available_locales) as $available_locale) { if (strtolower(substr((string) $available_locale, 0, 2)) === $language_code) { $locale = (string) $available_locale; break; } } } $current_locale = function_exists('get_locale') ? (string) get_locale() : $locale; $switched = $locale !== $current_locale && function_exists('switch_to_locale') && switch_to_locale($locale); switch ($type) { case 'youtube': $message = __('Displaying YouTube requires consent for all cookie categories.', 'samtyk-cmp'); break; case 'vimeo': $message = __('Displaying Vimeo requires consent for statistics cookies.', 'samtyk-cmp'); break; case 'spotify': $message = __('Displaying Spotify requires consent for all cookie categories.', 'samtyk-cmp'); break; case 'issuu': $message = __('Displaying Issuu requires consent for all cookie categories.', 'samtyk-cmp'); break; case 'instagram': $message = __('Displaying Instagram requires consent for marketing cookies.', 'samtyk-cmp'); break; default: $message = ''; break; } $button = __('Manage consent', 'samtyk-cmp'); if ($switched && function_exists('restore_previous_locale')) { restore_previous_locale(); } return ['message' => $message, 'button' => $button]; } function samtyk_cmp_get_video_placeholder(string $type, string $language): string { $text = samtyk_cmp_get_video_text($type, $language); return '
' . '
' . esc_html($text['message']) . '
' . '' . '
'; } function samtyk_cmp_process_video_iframes(string $html, bool &$replaced = false, ?string $language = null): string { $language = $language ?? samtyk_cmp_get_settings()['language']; return preg_replace_callback('~]*>.*?~is', function (array $matches) use (&$replaced, $language): string { $iframe = $matches[0]; if (stripos($iframe, 'data-cookiepopup-category=') !== false || !preg_match('~\bsrc\s*=\s*(["\'])(.*?)\1~is', $iframe, $src_match)) { return $iframe; } $embed = samtyk_cmp_detect_video_embed(html_entity_decode($src_match[2], ENT_QUOTES | ENT_HTML5, 'UTF-8')); if ($embed === false || !preg_match('~^]*)>~is', $iframe, $opening_match)) { return $iframe; } $attributes = $opening_match[1]; $spotify_height = 352; if ($embed['type'] === 'spotify' && preg_match('~\bheight\s*=\s*(["\'])([0-9]+)\1~i', $attributes, $height_match)) { $spotify_height = max(1, min(2000, (int) $height_match[2])); } $attributes = preg_replace('~\s+(?:src|data-src|style|width|height)\s*=\s*(["\']).*?\1~is', '', $attributes); $attributes = preg_replace('~\s+hidden(?:\s*=\s*(["\']).*?\1)?~is', '', $attributes); if (!preg_match('~\bloading\s*=~i', $attributes)) { $attributes .= ' loading="lazy"'; } $attributes .= ' data-src="' . esc_attr($embed['src']) . '"'; $attributes .= ' data-cookiepopup-category="' . esc_attr($embed['category']) . '" hidden'; $attributes .= ' style="position:absolute!important;inset:0!important;z-index:1!important;width:100%!important;height:100%!important;border:0!important;"'; $replaced = true; $container_size = $embed['type'] === 'spotify' ? 'height:' . $spotify_height . 'px!important;' : 'aspect-ratio:16/9!important;'; return '
' . samtyk_cmp_get_video_placeholder($embed['type'], $language) . '
'; }, $html); } function samtyk_cmp_process_divi_multiview(string $html, bool &$replaced = false, ?string $language = null): string { return preg_replace_callback('~\bdata-et-multi-view\s*=\s*(["\'])(.*?)\1~is', function (array $matches) use (&$replaced, $language): string { $data = json_decode(html_entity_decode($matches[2], ENT_QUOTES | ENT_HTML5, 'UTF-8'), true); if (!is_array($data) || !isset($data['schema']['content']) || !is_array($data['schema']['content'])) { return $matches[0]; } $changed = false; foreach (['desktop', 'tablet', 'phone'] as $device) { $content = $data['schema']['content'][$device] ?? null; if (!is_string($content) || $content === '') { continue; } $content_replaced = false; $data['schema']['content'][$device] = samtyk_cmp_process_video_iframes($content, $content_replaced, $language); $changed = $changed || $content_replaced; } if (!$changed) { return $matches[0]; } $replaced = true; return 'data-et-multi-view=' . $matches[1] . esc_attr(wp_json_encode($data)) . $matches[1]; }, $html); } function samtyk_cmp_defer_instagram_media(string $html): string { return preg_replace_callback('~<(?:img|video|source)\b[^>]*>~is', function (array $matches): string { return preg_replace( '~\s+(src|srcset|poster)\s*=~i', ' data-cookiepopup-$1=', $matches[0] ) ?: $matches[0]; }, $html); } function samtyk_cmp_find_balanced_div_end(string $html, int $start): ?int { if (!preg_match_all('~]*>~is', $html, $matches, PREG_OFFSET_CAPTURE, $start)) { return null; } $depth = 0; foreach ($matches[0] as $match) { $tag = $match[0]; $depth += stripos($tag, ']*\bid\s*=\s*(["\'])sb_instagram\1)[^>]*>~is', $html, $opening_match, PREG_OFFSET_CAPTURE, $offset)) { $opening = $opening_match[0][0]; $start = $opening_match[0][1]; if (stripos($opening, 'data-cookiepopup-instagram-feed') !== false) { $offset = $start + strlen($opening); continue; } $end = samtyk_cmp_find_balanced_div_end($html, $start); if ($end === null) { break; } $feed = substr($html, $start, $end - $start); $feed = preg_replace( '~^]*)>~i', '