PluginProbe
CookieAdmin – Cookie Consent Banner / 1.2.3
CookieAdmin – Cookie Consent Banner v1.2.3
1.2.3 1.2.2 1.2.1 1.2.0 1.1.9 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8
← All changes | includes/enduser.php +334 -50 1.1.01.2.3 View file →
@@ -12,20 +12,30 @@
12 12 static $categorized_cookies = array();
13 13
14 14 static function enqueue_scripts(){
15 15 global $wpdb;
16 -
17 - $view = get_option('cookieadmin_law', 'cookieadmin_gdpr');
16 +
17 + $view = get_option('cookieadmin_law', 'cookieadmin_gdpr');
18 18 $policy = cookieadmin_load_policy();
19 19 $table_name = esc_sql($wpdb->prefix . 'cookieadmin_cookies');
20 20 //cookieadmin_r_print($view);
21 21 //cookieadmin_r_print($policy);
22 22
23 - if(!empty($policy) && !empty($view)){
23 + if(!empty($policy) && !empty($view) && !cookieadmin_is_editor_mode()){
24 +
25 + add_filter('mepr_design_style_handle_prefixes', '\CookieAdmin\Enduser::memberpress_allow_style_prefix');
24 26
25 27 wp_enqueue_style('cookieadmin-style', COOKIEADMIN_PLUGIN_URL . 'assets/css/consent.css', [], COOKIEADMIN_VERSION);
26 28
27 - wp_enqueue_script('cookieadmin_js', COOKIEADMIN_PLUGIN_URL . 'assets/js/consent.js', [], COOKIEADMIN_VERSION, 'async');
29 + $js_deps = [];
30 + // Free consent.js is the base script from where the functionality gets triggered
31 + // So we need to make sure the dependencies of free script gets loaded first
32 + // Like the pro/consent.js is a dependency of the free one.
33 + if(defined('COOKIEADMIN_PREMIUM')){
34 + $js_deps[] = 'cookieadmin_pro_js';
35 + }
36 +
37 + wp_enqueue_script('cookieadmin_js', COOKIEADMIN_PLUGIN_URL . 'assets/js/consent.js', $js_deps, COOKIEADMIN_VERSION);
28 38
29 39 $policy[$view]['ajax_url'] = admin_url('admin-ajax.php');
30 40 $policy[$view]['nonce'] = wp_create_nonce('cookieadmin_js_nonce');
31 41 $policy[$view]['http_cookies'] = self::$http_cookies;
@@ -39,12 +49,13 @@
39 49
40 50 // Used for setting cookie
41 51 $policy[$view]['base_path'] = $base_path;
42 52
43 - $policy[$view]['lang']['show_more'] = __('show more', 'cookieadmin');
44 - $policy[$view]['lang']['show_less'] = __('show less', 'cookieadmin');
53 + // NOTE: Check the polylang string registration if changing these
54 + $policy[$view]['lang']['show_less'] = __('Show less', 'cookieadmin');
45 55 $policy[$view]['lang']['duration'] = __('Duration', 'cookieadmin');
46 56 $policy[$view]['lang']['session'] = __('Session', 'cookieadmin');
57 + $policy[$view]['lang']['days'] = __('Days', 'cookieadmin');
47 58
48 59 // cookieadmin_r_print($policy);die();
49 60
50 61 $rows = $wpdb->get_results("SELECT cookie_name, category, expires, description, patterns FROM {$table_name}");
@@ -55,90 +66,359 @@
55 66 }
56 67
57 68 $policy[$view]['categorized_cookies'] = self::$categorized_cookies = $cookie_data;
58 69
70 + $policy[$view] = apply_filters('cookieadmin_before_localize', $policy[$view]);
71 +
59 72 wp_localize_script('cookieadmin_js', 'cookieadmin_policy', $policy[$view]);
60 73
61 74 }
62 75 }
63 76
64 - /* static function cookieadmin_block_cookie_init_php(){
77 + static function cookieadmin_block_cookie_init_php(){
65 78
66 - //New - To catch, remove and send cookies in WP enqueue
79 + if(headers_sent() || (is_admin() && !wp_doing_ajax()) || defined('COOKIEADMIN_SCANNER') || cookieadmin_is_editor_mode()){
80 + return;
81 + }
82 +
83 + $view = get_option('cookieadmin_law', 'cookieadmin_gdpr');
84 +
85 + if(empty($view)){
86 + return;
87 + }
88 +
67 89 $http_cookies = array();
68 - $headers = headers_list();
90 + $set_cookie_headers = array();
69 91
70 - foreach($headers as $header) {
71 -
72 - if (stripos(trim($header), 'Set-Cookie:') === 0) {
92 + foreach(headers_list() as $header) {
93 + if(stripos(trim($header), 'Set-Cookie:') === 0){
73 94 $header = trim(substr($header, strlen('Set-Cookie:')));
74 - $name = trim(explode('=', $header)[0]);
75 - $http_cookies[$name]['string'] = trim($header);
76 - setcookie($name, '', time() - 999999, '/');
95 + $set_cookie_headers[] = $header;
77 96 }
78 97 }
79 98
99 + if(empty($set_cookie_headers)){
100 + return;
101 + }
102 +
103 + $policy = cookieadmin_load_policy();
104 +
105 + if(empty($policy) || empty($policy[$view])){
106 + return;
107 + }
108 +
109 + $categories = self::get_cookie_categories();
110 + $consent = self::get_consent();
111 + $preload = self::get_preload_categories($policy, $view);
112 + $allowed_headers = array();
113 +
114 + foreach($set_cookie_headers as $set_cookie){
115 + $name = self::get_cookie_name_from_header($set_cookie);
116 +
117 + if(empty($name)){
118 + continue;
119 + }
120 +
121 + if(self::is_response_cookie_allowed($set_cookie, $categories, $consent, $preload)){
122 + $allowed_headers[] = $set_cookie;
123 + continue;
124 + }
125 +
126 + $http_cookies[$name]['string'] = trim($set_cookie);
127 + }
128 +
129 + header_remove('Set-Cookie');
130 +
131 + foreach($allowed_headers as $set_cookie){
132 + header('Set-Cookie: ' . $set_cookie, false);
133 + }
134 +
80 135 $http_cookies['cookieadmin_consent'] = ["string" => "cookieadmin_consent=CookieAdmin Cookie Initialization"];
81 136
82 137 self::$http_cookies = $http_cookies;
83 - } */
138 + }
139 +
140 + static function get_cookie_categories(){
141 + global $wpdb;
142 +
143 + $table_name = $wpdb->prefix . 'cookieadmin_cookies';
144 + if(!self::cookieadmin_table_exists($table_name)){
145 + return array();
146 + }
147 +
148 + $categories = array(
149 + 'exact' => array(),
150 + 'prefix' => array(),
151 + );
152 + $rows = $wpdb->get_results("SELECT cookie_name, raw_name, category FROM {$table_name}");
153 +
154 + foreach($rows as $row){
155 + if(!empty($row->cookie_name) && !empty($row->category)){
156 + $category = strtolower($row->category);
157 + $categories['exact'][$row->cookie_name] = $category;
158 +
159 + if(!empty($row->raw_name)){
160 + $categories['exact'][$row->raw_name] = $category;
161 +
162 + if($row->raw_name !== $row->cookie_name && strpos($row->raw_name, $row->cookie_name) === 0){
163 + $categories['prefix'][$row->cookie_name] = $category;
164 + }
165 + }
166 + }
167 + }
168 +
169 + uksort($categories['prefix'], function($a, $b){
170 + return strlen($b) - strlen($a);
171 + });
172 +
173 + return $categories;
174 + }
175 +
176 + static function get_consent(){
177 + if(empty($_COOKIE['cookieadmin_consent'])){
178 + return array();
179 + }
180 +
181 + $consent = json_decode(wp_unslash($_COOKIE['cookieadmin_consent']), true);
182 + if(!is_array($consent)){
183 + return array();
184 + }
185 +
186 + $sanitized = array();
187 + foreach($consent as $key => $value){
188 + $sanitized[sanitize_key($key)] = sanitize_text_field($value);
189 + }
190 +
191 + return $sanitized;
192 + }
193 +
194 + static function get_preload_categories($policy, $view){
195 + if(empty($policy) || empty($policy[$view]['preload']) || !is_array($policy[$view]['preload'])){
196 + return array();
197 + }
198 +
199 + $preload = array();
200 + foreach($policy[$view]['preload'] as $category){
201 + $preload[] = strtolower(sanitize_key($category));
202 + }
203 +
204 + return $preload;
205 + }
206 +
207 + static function get_cookie_name_from_header($set_cookie){
208 + $parts = explode('=', $set_cookie, 2);
209 + $name = trim($parts[0]);
210 +
211 + if(empty($name)){
212 + return '';
213 + }
214 +
215 + return $name;
216 + }
217 +
218 + static function is_response_cookie_allowed($set_cookie, $categories, $consent, $preload = array()){
219 + $name = self::get_cookie_name_from_header($set_cookie);
220 +
221 + if(empty($name)){
222 + return false;
223 + }
224 +
225 + // A deletion never adds a cookie and must not be prevented.
226 + if(preg_match('/(?:^|;)\s*max-age\s*=\s*(-?\d+)/i', $set_cookie, $age) && (int) $age[1] <= 0){
227 + return true;
228 + }
229 +
230 + if(preg_match('/(?:^|;)\s*expires\s*=\s*([^;]+)/i', $set_cookie, $expires)){
231 + $expires_at = strtotime($expires[1]);
232 + if($expires_at !== false && $expires_at < time()){
233 + return true;
234 + }
235 + }
236 +
237 + if($name === 'cookieadmin_consent'){
238 + return true;
239 + }
240 +
241 + $category = self::get_cookie_category($name, $categories);
242 +
243 + if(empty($category)){
244 + return !empty($consent['accept']) && $consent['accept'] === 'true';
245 + }
246 +
247 + if($category === 'necessary' || in_array($category, $preload, true)){
248 + return true;
249 + }
250 +
251 + if(!empty($consent['reject']) && $consent['reject'] === 'true'){
252 + return false;
253 + }
254 +
255 + if(!empty($consent['accept']) && $consent['accept'] === 'true'){
256 + return true;
257 + }
258 +
259 + return !empty($consent[$category]) && $consent[$category] === 'true';
260 + }
261 +
262 + static function get_cookie_category($name, $categories){
263 + if(!empty($categories['exact'][$name])){
264 + return $categories['exact'][$name];
265 + }
266 +
267 + if(empty($categories['prefix'])){
268 + return '';
269 + }
270 +
271 + foreach($categories['prefix'] as $prefix => $category){
272 + if(strpos($name, $prefix) === 0){
273 + return $category;
274 + }
275 + }
276 +
277 + return '';
278 + }
84 279
85 - static function check_if_cookies_allowed($tag, $handle, $src){
280 + static function block_scripts(){
86 281
282 + if(wp_doing_ajax() || is_admin() || defined('REST_REQUEST') || defined('COOKIEADMIN_SCANNER') || cookieadmin_is_editor_mode()){
283 + return;
284 + }
285 +
286 + $settings = get_option('cookieadmin_settings');
287 +
288 + if(empty($settings) || empty($settings['block_scripts'])){
289 + return;
290 + }
291 +
292 + $view = get_option('cookieadmin_law', 'cookieadmin_gdpr');
293 + $policy = cookieadmin_load_policy();
294 + if(empty($policy) || empty($view)){
295 + return;
296 + }
297 +
298 + ob_start([__CLASS__, 'update_tracking_scripts']);
299 + }
300 +
301 + static function update_tracking_scripts($html){
302 + global $cookieadmin_settings;
303 +
304 + if(stripos($html, '<script') === false){
305 + return $html;
306 + }
307 +
308 + if(empty(self::$categorized_cookies)){
309 + return $html;
310 + }
311 +
87 312 $cookieadmin_consent = isset($_COOKIE['cookieadmin_consent'])
88 313 ? json_decode(wp_unslash($_COOKIE['cookieadmin_consent']), true)
89 314 : [];
90 315
316 + // Sanitizing cookies
91 317 array_walk( $cookieadmin_consent, function( $value, $key ) use ( &$cookieadmin_consent ) {
92 318 $sanitized_key = sanitize_key( $key );
93 319 $cookieadmin_consent[ $sanitized_key ] = sanitize_text_field($value);
94 320 } );
95 -
96 - foreach (self::$categorized_cookies as $item) {
97 - $category = strtolower($item->category);
98 - $patterns = json_decode($item->patterns, true);
99 -
100 - if (!empty($patterns) && !empty($category)) {
101 - foreach ($patterns as $pattern) {
102 - if (strpos($src, $pattern) !== false) {
103 -
104 - if ( $category !== 'necessary' &&
105 - (empty($cookieadmin_consent) ||
106 - (!empty($cookieadmin_consent[$category]) && $cookieadmin_consent[$category] == 'false') ||
107 - $cookieadmin_consent['reject'] == 'true')
108 - ) {
109 -
110 - // User has NOT consented -> block the script
111 321
112 - // Option 1 - completely remove script:
113 - // return '';
322 + $html = preg_replace_callback(
323 + '/<script\b([^>]*)>([\s\S]*?)<\/script>/i',
324 + function($match) use ($cookieadmin_consent, $cookieadmin_settings){
325 + $attrs = $match[1];
326 + $content = $match[2];
327 + $full_tag = $match[0];
114 328
115 - // Option 2 - transform to type="text/plain"
116 - $tag = str_replace(
117 - '<script ',
118 - '<script type="text/plain" data-cookieadmin-category="' . esc_attr($category) . '" ',
119 - $tag
120 - );
121 -
122 - return $tag;
329 + if(preg_match('/\btype\s*=\s*["\']text\/plain["\']/i', $attrs)){
330 + return $full_tag;
331 + }
332 +
333 + if(preg_match('/\b(id|src)\s*=\s*["\'][^"\']*cookieadmin[^"\']*["\']/i', $attrs)){
334 + return $full_tag;
335 + }
336 +
337 + if(preg_match('/\btype\s*=\s*["\']([^"\']+)["\']/i', $attrs, $type_match)){
338 + $type = strtolower(trim($type_match[1]));
339 + if($type !== 'text/javascript' && $type !== 'module'){
340 + return $full_tag;
341 + }
342 + }
343 +
344 + $src = '';
345 + if(preg_match('/\bsrc\s*=\s*["\']([^"\']*)["\']/i', $attrs, $src_match)){
346 + $src = $src_match[1];
347 + }
348 +
349 + $match_against = !empty($src) ? $src : trim($attrs . ' ' . $content);
350 +
351 + if(empty($match_against)){
352 + return $full_tag;
353 + }
354 +
355 + if(!empty($cookieadmin_settings['cookieadmin_google_advance_consent_mode'])){
356 + // External Google tag loader
357 + if(!empty($src) && stripos($src, 'googletagmanager.com/gtag/js') !== false){
358 + return $full_tag;
359 + }
360 + // Inline gtag() snippet
361 + if(empty($src) && stripos($content, 'gtag(') !== false){
362 + return $full_tag;
363 + }
364 + }
365 +
366 + foreach (self::$categorized_cookies as $item) {
367 + $category = !empty($item->category) ? strtolower($item->category) : '';
368 + $patterns = !empty($item->patterns) ? json_decode($item->patterns, true) : '';
369 +
370 + if(empty($patterns) || empty($category)){
371 + continue;
372 + }
373 +
374 + foreach ($patterns as $pattern) {
375 + if(strpos($match_against, $pattern) !== false){
376 + if($category !== 'necessary' &&
377 + (empty($cookieadmin_consent) ||
378 + (!empty($cookieadmin_consent[$category]) && $cookieadmin_consent[$category] == 'false') ||
379 + (!empty($cookieadmin_consent['reject']) && $cookieadmin_consent['reject'] == 'true')
380 + )
381 + ){
382 + if($attrs === ''){
383 + return '<script type="text/plain" data-cookieadmin-category="' . esc_attr($category) . '">' . $content . '</script>';
384 + }
385 + return '<script type="text/plain" data-cookieadmin-category="' . esc_attr($category) . '"' . $attrs . '>' . $content . '</script>';
386 + }
123 387 }
124 388 }
125 389 }
126 - }
127 - }
128 390
129 - return $tag;
391 + return $full_tag;
392 + },
393 + $html
394 + );
395 +
396 + return $html;
130 397 }
131 398
132 399 static function cookieadmin_show_banner(){
400 +
401 + $view = get_option('cookieadmin_law', 'cookieadmin_gdpr');
402 + $policy = cookieadmin_load_policy();
403 +
404 + // Do not show banner if banner is off via Geo rule
405 + if(empty($view)){
406 + return;
407 + }
133 408
134 - $view = get_option('cookieadmin_law', 'cookieadmin_gdpr');
135 - $policy = cookieadmin_load_policy();
409 + $raw_template = cookieadmin_load_consent_template($policy[$view], $view);
410 +
411 + if(!is_array($raw_template) || empty($raw_template)){
412 + return false;
413 + }
136 414
137 - $templates = implode("", cookieadmin_load_consent_template($policy[$view], $view));
415 + $templates = implode('', $raw_template);
138 416
139 417 $allowed_tags = cookieadmin_kses_allowed_html();
140 418
419 + $templates = apply_filters('cookieadmin_after_banner', $templates);
420 +
141 421 // var_dump($policy[$view]);
142 422 echo wp_kses($templates, $allowed_tags);
143 423 }
144 424
@@ -148,6 +428,10 @@
148 428 $query = $wpdb->prepare("SHOW TABLES LIKE %s", $table_name);
149 429
150 430 return $wpdb->get_var($query) === $table_name;
151 431 }
432 +
433 + static function memberpress_allow_style_prefix($prefix_arr){
434 + $prefix_arr[] = 'cookieadmin';
435 + return $prefix_arr;
436 + }
152 437 }
153 -