iubenda Cookie Solution for GDPR - Version 2.3.4

Version Description

  • Security Fix: limit url sanitize to http protocols
Download this release

Release Info

Developer iubenda
Plugin Icon 128x128 iubenda Cookie Solution for GDPR
Version 2.3.4
Comparing to
See all releases

Code changes from version 2.3.3 to 2.3.4

iubenda-cookie-class/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # Read Me
2
 
3
  ***PHP class for the iubenda cookie law solution***
4
-
5
- If you have European users you need to obtain and manage consent for the use of most cookies.
6
  The iubenda Cookie Solution is an all-in-one approach developed by iubenda, that helps to make your website GDPR and Cookie Law compliant by integrating with your cookie policy, providing a compliant cookie banner and the blocking management of cookie scripts. The Cookie Solution also allows users to set advertising preferences on-site and within the solution, facilitated the recent-but-widely adopted IAB Europe Transparency & Consent [framework](https://www.iubenda.com/en/help/7440#aboutIAB).
7
 
8
  [Read more about the Cookie Solution here](https://www.iubenda.com/en/features#cookie-solution).
@@ -16,7 +16,7 @@ The iubenda Cookie Solution is an all-in-one approach developed by iubenda, that
16
 
17
  ## Functionality
18
 
19
- This class works with the iubenda Cookie Law Solution and allows you to block the most common widgets and third-party cookies to comply with Cookie Law.
20
 
21
  The class is currently able to detect and automatically block the following scripts:
22
 
@@ -88,16 +88,19 @@ Simply copy your method into the PHP document and then call it with the followin
88
  * Automatic parsing/replacing of iframe that contain defined src
89
  * Automatic parsing/replacing of scripts that contain defined src
90
 
91
- These operations take place in accordance with the rules explained in [this guide](https://www.iubenda.com/en/help/posts/1229). We suggest that you consult the posts relating to the alteration of script, img and iframe tags.
92
 
93
  ## Additional Help and docs
94
 
95
  * [Full Cookie Solution Documentation](https://www.iubenda.com/en/help/1205-technical-documentation-for-the-cookie-law-solution-banner-cookie-policy-and-consent-management)
96
- * [Prior Blocking Guide](https://www.iubenda.com/en/help/1229-cookie-law-solution-preventing-code-execution-that-could-install-cookies)
97
  * [Cookie Solution Feature Overview](https://www.iubenda.com/en/features#cookie-solution)
98
 
99
  ## Changelog
100
 
 
 
 
101
  ##### 4.1.0
102
  * New: Google AMP support
103
 
@@ -132,4 +135,4 @@ These operations take place in accordance with the rules explained in [this guid
132
 
133
  ### License
134
 
135
- This project is licensed under the GPl 3 license.
1
+ # Read Me
2
 
3
  ***PHP class for the iubenda cookie law solution***
4
+
5
+ If you have European users you need to obtain and manage consent for the use of most cookies.
6
  The iubenda Cookie Solution is an all-in-one approach developed by iubenda, that helps to make your website GDPR and Cookie Law compliant by integrating with your cookie policy, providing a compliant cookie banner and the blocking management of cookie scripts. The Cookie Solution also allows users to set advertising preferences on-site and within the solution, facilitated the recent-but-widely adopted IAB Europe Transparency & Consent [framework](https://www.iubenda.com/en/help/7440#aboutIAB).
7
 
8
  [Read more about the Cookie Solution here](https://www.iubenda.com/en/features#cookie-solution).
16
 
17
  ## Functionality
18
 
19
+ This class works with the iubenda Cookie Law Solution and allows you to block the most common widgets and third-party cookies to comply with Cookie Law.
20
 
21
  The class is currently able to detect and automatically block the following scripts:
22
 
88
  * Automatic parsing/replacing of iframe that contain defined src
89
  * Automatic parsing/replacing of scripts that contain defined src
90
 
91
+ These operations take place in accordance with the rules explained in [this guide](https://www.iubenda.com/en/help/posts/1229). We suggest that you consult the posts relating to the alteration of script, img and iframe tags.
92
 
93
  ## Additional Help and docs
94
 
95
  * [Full Cookie Solution Documentation](https://www.iubenda.com/en/help/1205-technical-documentation-for-the-cookie-law-solution-banner-cookie-policy-and-consent-management)
96
+ * [Prior Blocking Guide](https://www.iubenda.com/en/help/1229-cookie-law-solution-preventing-code-execution-that-could-install-cookies)
97
  * [Cookie Solution Feature Overview](https://www.iubenda.com/en/features#cookie-solution)
98
 
99
  ## Changelog
100
 
101
+ ##### 4.1.1
102
+ * Fix: AddThis per-purpose category
103
+
104
  ##### 4.1.0
105
  * New: Google AMP support
106
 
135
 
136
  ### License
137
 
138
+ This project is licensed under the GPl 3 license.
iubenda-cookie-class/iubenda.class.faster.php CHANGED
@@ -1,13 +1,13 @@
1
  <?php
2
  /**
3
  * iubenda.class.faster.php
4
- *
5
  * @author iubenda s.r.l
6
- * @copyright 2018-2019, iubenda s.r.l
7
  * @license GNU/GPL
8
  * @version 2.0.3
9
  * @deprecated
10
- *
11
  * This program is free software: you can redistribute it and/or modify
12
  * it under the terms of the GNU General Public License as published by
13
  * the Free Software Foundation, either version 3 of the License, or
@@ -23,7 +23,7 @@
23
  */
24
 
25
  class iubendaFaster {
26
-
27
  // variables
28
  const IUB_REGEX_PATTERN = '/<!--\s*IUB_COOKIE_POLICY_START\s*-->(.*?)<!--\s*IUB_COOKIE_POLICY_END\s*-->/s';
29
  const IUB_REGEX_PATTERN_2 = '/<!--\s*IUB-COOKIE-BLOCK-START\s*-->(.*?)<!--\s*IUB-COOKIE-BLOCK-END\s*-->/s';
@@ -63,7 +63,7 @@ class iubendaFaster {
63
 
64
  /**
65
  * Methods
66
- *
67
  * @param type $offender
68
  * @param type $blacklist
69
  * @return boolean
@@ -86,9 +86,9 @@ class iubendaFaster {
86
  }
87
 
88
  /**
89
- * Parse automatically all the scripts in the page and converts it in text/plain
90
  * if src or the whole output has inside one of the elements in $auto_script_tags array
91
- *
92
  * @param mixed $content
93
  * @return mixed
94
  */
@@ -149,7 +149,7 @@ class iubendaFaster {
149
 
150
  /**
151
  * Parse all IUBENDAs comment and convert the code inside with create_tags method
152
- *
153
  * @param mixed $content
154
  * @return mixed
155
  */
@@ -183,7 +183,7 @@ class iubendaFaster {
183
 
184
  /**
185
  * Convert scripts, iframe and other code inside IUBENDAs comment in text/plain to not generate cookies
186
- *
187
  * @param mixed $content
188
  * @return mixed
189
  */
@@ -224,4 +224,4 @@ class iubendaFaster {
224
  return $js;
225
  }
226
 
227
- }
1
  <?php
2
  /**
3
  * iubenda.class.faster.php
4
+ *
5
  * @author iubenda s.r.l
6
+ * @copyright 2018-2020, iubenda s.r.l
7
  * @license GNU/GPL
8
  * @version 2.0.3
9
  * @deprecated
10
+ *
11
  * This program is free software: you can redistribute it and/or modify
12
  * it under the terms of the GNU General Public License as published by
13
  * the Free Software Foundation, either version 3 of the License, or
23
  */
24
 
25
  class iubendaFaster {
26
+
27
  // variables
28
  const IUB_REGEX_PATTERN = '/<!--\s*IUB_COOKIE_POLICY_START\s*-->(.*?)<!--\s*IUB_COOKIE_POLICY_END\s*-->/s';
29
  const IUB_REGEX_PATTERN_2 = '/<!--\s*IUB-COOKIE-BLOCK-START\s*-->(.*?)<!--\s*IUB-COOKIE-BLOCK-END\s*-->/s';
63
 
64
  /**
65
  * Methods
66
+ *
67
  * @param type $offender
68
  * @param type $blacklist
69
  * @return boolean
86
  }
87
 
88
  /**
89
+ * Parse automatically all the scripts in the page and converts it in text/plain
90
  * if src or the whole output has inside one of the elements in $auto_script_tags array
91
+ *
92
  * @param mixed $content
93
  * @return mixed
94
  */
149
 
150
  /**
151
  * Parse all IUBENDAs comment and convert the code inside with create_tags method
152
+ *
153
  * @param mixed $content
154
  * @return mixed
155
  */
183
 
184
  /**
185
  * Convert scripts, iframe and other code inside IUBENDAs comment in text/plain to not generate cookies
186
+ *
187
  * @param mixed $content
188
  * @return mixed
189
  */
224
  return $js;
225
  }
226
 
227
+ }
iubenda-cookie-class/iubenda.class.page.php CHANGED
@@ -1,13 +1,13 @@
1
  <?php
2
  /**
3
  * iubenda.class.page.php
4
- *
5
  * @author iubenda s.r.l
6
- * @copyright 2018-2019, iubenda s.r.l
7
  * @license GNU/GPL
8
  * @version 1.0.3
9
  * @deprecated
10
- *
11
  * This program is free software: you can redistribute it and/or modify
12
  * it under the terms of the GNU General Public License as published by
13
  * the Free Software Foundation, either version 3 of the License, or
@@ -61,7 +61,7 @@ class iubendaPage {
61
 
62
  /**
63
  * Construct: the whole HTML output of the page
64
- *
65
  * @param mixed $content_page
66
  */
67
  public function __construct( $content_page ) {
@@ -71,7 +71,7 @@ class iubendaPage {
71
 
72
  /**
73
  * Print iubenda banner, parameter: the script code of iubenda to print the banner
74
- *
75
  * @param string $banner
76
  * @return string
77
  */
@@ -99,7 +99,7 @@ if('callback' in _iub.csConfiguration) {
99
 
100
  /**
101
  * Static, detect bot & crawler
102
- *
103
  * @return bool
104
  */
105
  static function bot_detected() {
@@ -108,7 +108,7 @@ if('callback' in _iub.csConfiguration) {
108
 
109
  /**
110
  * Static, utility function: Return true if the user has already given consent on the page
111
- *
112
  * @return boolean
113
  */
114
  static function consent_given() {
@@ -122,7 +122,7 @@ if('callback' in _iub.csConfiguration) {
122
 
123
  /**
124
  * Static, utility function: strpos for array
125
- *
126
  * @param type $haystack
127
  * @param type $needle
128
  * @return boolean
@@ -144,7 +144,7 @@ if('callback' in _iub.csConfiguration) {
144
 
145
  /**
146
  * Convert scripts, iframe and other code inside IUBENDAs comment in text/plain to not generate cookies
147
- *
148
  * @param mixed $html
149
  * @return mixed
150
  */
@@ -209,12 +209,12 @@ if('callback' in _iub.csConfiguration) {
209
  }
210
 
211
  /**
212
- * Parse automatically all the scripts in the page and converts it in text/plain
213
  * if src or the whole output has inside one of the elements in $auto_script_tags array
214
  */
215
  public function parse_scripts() {
216
  $html = str_get_html( $this->content_page, $lowercase = true, $forceTagsClosed = true, $stripRN = false );
217
-
218
  if ( is_object( $html ) ) {
219
  $scripts = $html->find( "script" );
220
  if ( is_array( $scripts ) ) {
@@ -340,7 +340,7 @@ if('callback' in _iub.csConfiguration) {
340
  */
341
  public function parse_iframe() {
342
  $html = str_get_html( $this->content_page, $lowercase = true, $forceTagsClosed = true, $stripRN = false );
343
-
344
  if ( is_object( $html ) ) {
345
  $iframes = $html->find( "iframe" );
346
  if ( is_array( $iframes ) ) {
@@ -374,11 +374,11 @@ if('callback' in _iub.csConfiguration) {
374
 
375
  /**
376
  * Return the final page to output
377
- *
378
  * @return mixed
379
  */
380
  public function get_converted_page() {
381
  return $this->content_page;
382
  }
383
 
384
- }
1
  <?php
2
  /**
3
  * iubenda.class.page.php
4
+ *
5
  * @author iubenda s.r.l
6
+ * @copyright 2018-2020, iubenda s.r.l
7
  * @license GNU/GPL
8
  * @version 1.0.3
9
  * @deprecated
10
+ *
11
  * This program is free software: you can redistribute it and/or modify
12
  * it under the terms of the GNU General Public License as published by
13
  * the Free Software Foundation, either version 3 of the License, or
61
 
62
  /**
63
  * Construct: the whole HTML output of the page
64
+ *
65
  * @param mixed $content_page
66
  */
67
  public function __construct( $content_page ) {
71
 
72
  /**
73
  * Print iubenda banner, parameter: the script code of iubenda to print the banner
74
+ *
75
  * @param string $banner
76
  * @return string
77
  */
99
 
100
  /**
101
  * Static, detect bot & crawler
102
+ *
103
  * @return bool
104
  */
105
  static function bot_detected() {
108
 
109
  /**
110
  * Static, utility function: Return true if the user has already given consent on the page
111
+ *
112
  * @return boolean
113
  */
114
  static function consent_given() {
122
 
123
  /**
124
  * Static, utility function: strpos for array
125
+ *
126
  * @param type $haystack
127
  * @param type $needle
128
  * @return boolean
144
 
145
  /**
146
  * Convert scripts, iframe and other code inside IUBENDAs comment in text/plain to not generate cookies
147
+ *
148
  * @param mixed $html
149
  * @return mixed
150
  */
209
  }
210
 
211
  /**
212
+ * Parse automatically all the scripts in the page and converts it in text/plain
213
  * if src or the whole output has inside one of the elements in $auto_script_tags array
214
  */
215
  public function parse_scripts() {
216
  $html = str_get_html( $this->content_page, $lowercase = true, $forceTagsClosed = true, $stripRN = false );
217
+
218
  if ( is_object( $html ) ) {
219
  $scripts = $html->find( "script" );
220
  if ( is_array( $scripts ) ) {
340
  */
341
  public function parse_iframe() {
342
  $html = str_get_html( $this->content_page, $lowercase = true, $forceTagsClosed = true, $stripRN = false );
343
+
344
  if ( is_object( $html ) ) {
345
  $iframes = $html->find( "iframe" );
346
  if ( is_array( $iframes ) ) {
374
 
375
  /**
376
  * Return the final page to output
377
+ *
378
  * @return mixed
379
  */
380
  public function get_converted_page() {
381
  return $this->content_page;
382
  }
383
 
384
+ }
iubenda-cookie-class/iubenda.class.php CHANGED
@@ -5,7 +5,7 @@
5
  * @author iubenda s.r.l
6
  * @copyright 2018-2020, iubenda s.r.l
7
  * @license GNU/GPL
8
- * @version 4.1.0
9
  * @deprecated
10
  *
11
  * This program is free software: you can redistribute it and/or modify
5
  * @author iubenda s.r.l
6
  * @copyright 2018-2020, iubenda s.r.l
7
  * @license GNU/GPL
8
+ * @version 4.1.1
9
  * @deprecated
10
  *
11
  * This program is free software: you can redistribute it and/or modify
iubenda-cookie-class/test.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
2
  /**
3
  * test.php
4
- *
5
  * @author iubenda s.r.l
6
- * @copyright 2018-2019, iubenda s.r.l
7
  * @license GNU/GPL
8
- *
9
  * This program is free software: you can redistribute it and/or modify
10
  * it under the terms of the GNU General Public License as published by
11
  * the Free Software Foundation, either version 3 of the License, or
@@ -49,7 +49,9 @@ ini_set( 'max_execution_time', 300 );
49
 
50
  <?php
51
  if ( ! empty( $_POST['url'] ) )
52
- $url = filter_var( $_POST['url'], FILTER_SANITIZE_URL );
 
 
53
  else
54
  $url = '';
55
 
@@ -111,4 +113,4 @@ ini_set( 'max_execution_time', 300 );
111
  </div>
112
 
113
  </body>
114
- </html>
1
  <?php
2
  /**
3
  * test.php
4
+ *
5
  * @author iubenda s.r.l
6
+ * @copyright 2018-2020, iubenda s.r.l
7
  * @license GNU/GPL
8
+ *
9
  * This program is free software: you can redistribute it and/or modify
10
  * it under the terms of the GNU General Public License as published by
11
  * the Free Software Foundation, either version 3 of the License, or
49
 
50
  <?php
51
  if ( ! empty( $_POST['url'] ) )
52
+ if (substr($_POST['url'], 0, 4) == "http") {
53
+ $url = filter_var( $_POST['url'], FILTER_SANITIZE_URL );
54
+ }
55
  else
56
  $url = '';
57
 
113
  </div>
114
 
115
  </body>
116
+ </html>
iubenda-cookie-class/usage.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
2
  /**
3
  * usage.php
4
- *
5
  * @author iubenda s.r.l
6
- * @copyright 2018-2019, iubenda s.r.l
7
  * @license GNU/GPL
8
- *
9
  * This program is free software: you can redistribute it and/or modify
10
  * it under the terms of the GNU General Public License as published by
11
  * the Free Software Foundation, either version 3 of the License, or
@@ -43,4 +43,4 @@ function iubenda_system( $html, $type = 'page' ) {
43
  *
44
  * echo iubenda_system( "<html> ...content... </html>", 'faster' );
45
  *
46
- */
1
  <?php
2
  /**
3
  * usage.php
4
+ *
5
  * @author iubenda s.r.l
6
+ * @copyright 2018-2020, iubenda s.r.l
7
  * @license GNU/GPL
8
+ *
9
  * This program is free software: you can redistribute it and/or modify
10
  * it under the terms of the GNU General Public License as published by
11
  * the Free Software Foundation, either version 3 of the License, or
43
  *
44
  * echo iubenda_system( "<html> ...content... </html>", 'faster' );
45
  *
46
+ */
readme.txt CHANGED
@@ -150,6 +150,9 @@ We will be very happy to receive feedback here: [Uservoice forum](https://suppor
150
 
151
  == Changelog ==
152
 
 
 
 
153
  = 2.3.3 =
154
  * Fix: AddThis purpose category
155
 
150
 
151
  == Changelog ==
152
 
153
+ = 2.3.4 =
154
+ * Security Fix: limit url sanitize to http protocols
155
+
156
  = 2.3.3 =
157
  * Fix: AddThis purpose category
158
 
trunk/css/admin.css ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #iubenda-header {
2
+ margin-bottom: 30px;
3
+ }
4
+ .iubenda-title {
5
+ margin-top: 10px;
6
+ font-weight: bold;
7
+ }
8
+ .iubenda-link {
9
+ display: table;
10
+ margin: 0 auto 10px;
11
+ }
12
+ .iubenda-text {
13
+ margin: 10px auto;
14
+ color: #434149
15
+ }
16
+ .button.button-primary.iub-autodetect-forms {
17
+ background: #1CC691;
18
+ border-color: #169970;
19
+ box-shadow: 0 1px 0 #138461;
20
+ text-shadow: 0 -1px 1px #138461,1px 0 1px #138461,0 1px 1px #138461,-1px 0 1px #138461;
21
+ display: inline-block;
22
+ margin-bottom: 30px;
23
+ }
24
+ .button.button-primary.iub-autodetect-forms:hover {
25
+ background: #1ACC94;
26
+ }
27
+ .button.button-primary.iub-autodetect-forms:focus {
28
+ box-shadow: 0 1px 0 #138461,0 0 2px 1px #1CC691;
29
+ }
30
+ #iubenda-consent-forms .tablenav.bottom {
31
+ display: none;
32
+ }
33
+ #iubenda-tabs .submit.submit-cons {
34
+ padding-top: 0;
35
+ }
36
+ #iubenda-tabs {
37
+ margin: 30px auto 20px;
38
+ }
39
+ #iub_parser_engine_container {
40
+ margin-top: 10px;
41
+ }
42
+ #iub_parser_engine_container > div:not(:last-child) {
43
+ margin-bottom: 10px;
44
+ }
45
+ #iub_amp_options_container {
46
+ margin-top: 10px;
47
+ }
48
+ #iub_amp_options_container > div:not(:last-child) {
49
+ margin-bottom: 10px;
50
+ }
51
+ #iubenda-tabs .contextual-help-wrap {
52
+ overflow: auto;
53
+ margin: 0;
54
+ position: relative;
55
+ }
56
+ #iubenda-tabs .contextual-help-back {
57
+ position: absolute;
58
+ top: 0;
59
+ bottom: 0;
60
+ left: 150px;
61
+ right: 0;
62
+ border: 1px solid #e1e1e1;
63
+ background: #f6fbfd;
64
+ }
65
+ #iubenda-tabs .contextual-help-columns {
66
+ position: relative;
67
+ }
68
+ #iubenda-tabs .help-tab-content {
69
+ margin-right: 0;
70
+ }
71
+ #iubenda-tabs .help-tab-content .description {
72
+ margin-bottom: 10px;
73
+ }
74
+ #iubenda-tabs .help-tab-content .custom-script-field, #iubenda-tabs .help-tab-content .custom-iframe-field {
75
+ padding-bottom: 10px;
76
+ }
77
+ #iubenda-tabs .help-tab-content .custom-script-field input, #iubenda-tabs .help-tab-content .custom-iframe-field input {
78
+ vertical-align: middle;
79
+ }
80
+ #tab-panel-scripts, #tab-panel-iframes {
81
+ margin-top: 16px;
82
+ margin-bottom: 18px;
83
+ }
84
+ #iubenda-tabs .postbox-container .widefat {
85
+ border: none;
86
+ box-shadow: none;
87
+ }
88
+ #iubenda-tabs .postbox-container .widefat h4 {
89
+ margin: 8px 0;
90
+ }
91
+ #iubenda-tabs .postbox-container .widefat select {
92
+ min-width: 50%;
93
+ }
94
+ #iubenda-tabs .postbox-container .widefat thead .label {
95
+ font-weight: bold;
96
+ }
97
+ #iubenda-tabs .postbox-container .widefat .table-label {
98
+ width: 25%;
99
+ }
100
+ #iubenda-tabs .postbox-container .widefat thead td {
101
+ border: none;
102
+ width: 50%;
103
+ }
104
+ #iubenda-tabs .postbox-container .widefat .widefat tbody td {
105
+ padding-top: 5px;
106
+ padding-bottom: 5px;
107
+ }
108
+ .iubenda-notice {
109
+ border-left-color: #1CC691;
110
+ padding-left: 0;
111
+ display: flex;
112
+ justify-content: flex-start;
113
+ align-items: center;
114
+ }
115
+ .iubenda-notice::before {
116
+ display: inline-block;
117
+ content: '';
118
+ height: 49px;
119
+ width: 22px;
120
+ margin: 1em 2em;
121
+ background-size: contain;
122
+ background-position: center center;
123
+ background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIyMjFweCIgaGVpZ2h0PSI0OTBweCIgdmlld0JveD0iMCAwIDIyMSA0OTAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+ICAgICAgICA8dGl0bGU+aXViZW5kYSB2ZWN0b3IgbG9nb192M19vbmx5X2lfZ3JlZW48L3RpdGxlPiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4gICAgPGRlZnM+PC9kZWZzPiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4gICAgICAgIDxnIGlkPSJpdWJlbmRhLXZlY3Rvci1sb2dvX3YzX29ubHlfaV9ncmVlbiIgZmlsbD0iIzFDQzY5MSIgZmlsbC1ydWxlPSJub256ZXJvIj4gICAgICAgICAgICA8cGF0aCBkPSJNMjIwLjYsMTA4LjQgQzIyMC42LDEzNSAyMTAuOCwxNTkuMyAxOTQuNSwxNzguMSBMMjE3LjksNDg5LjQgTDguNSw0ODkuNCBMMzEuMiwxODMuNSBDMTEuOSwxNjQuMiAwLDEzNy43IDAsMTA4LjQgQzAsNDguNyA0OS40LDAuNCAxMTAuMywwLjQgQzE3MS4yLDAuNCAyMjAuNiw0OC43IDIyMC42LDEwOC40IFogTTExMC4zLDEzMyBDMTI1LDEzMyAxMzYuOCwxMjEuMiAxMzYuOCwxMDYuNyBDMTM2LjgsOTIuMiAxMjQuOSw4MC41IDExMC4zLDgwLjUgQzk1LjYsODAuNSA4My44LDkyLjMgODMuOCwxMDYuNyBDODMuOCwxMjEuMyA5NS42LDEzMyAxMTAuMywxMzMgWiBNMTMxLjIsMjI3IEw5NC45LDI2My4zIEw5NC45LDQwMy44IEwxMzEuMiw0MDMuOCBMMTMxLjIsMjI3IFoiIGlkPSJTaGFwZSI+PC9wYXRoPiAgICAgICAgPC9nPiAgICA8L2c+PC9zdmc+);
124
+ }
125
+ .iubenda-notice .notice-question {
126
+ margin-bottom: 5px;
127
+ display: block;
128
+ }
129
+ .iubenda-notice .notice-reply {
130
+ margin-top: 0;
131
+ }
132
+ .iubenda-notice .step-2 {
133
+ display: none;
134
+ }
135
+ .iubenda-notice .reply-yes {
136
+ margin-right: 10px;
137
+ }
138
+ .iubenda-notice .reply-yes:before,
139
+ .iubenda-notice .reply-no:before {
140
+ font-family: dashicons;
141
+ display: inline-block;
142
+ line-height: 1;
143
+ font-weight: 400;
144
+ font-style: normal;
145
+ speak: none;
146
+ text-decoration: inherit;
147
+ text-transform: none;
148
+ text-rendering: auto;
149
+ -webkit-font-smoothing: antialiased;
150
+ -moz-osx-font-smoothing: grayscale;
151
+ width: 20px;
152
+ height: 20px;
153
+ font-size: 20px;
154
+ vertical-align: top;
155
+ text-align: center;
156
+ transition: color .1s ease-in;
157
+ text-decoration: none;
158
+ }
159
+ .iubenda-notice .reply-yes:before {
160
+ content: "\f147";
161
+ }
162
+ .iubenda-notice .reply-no:before {
163
+ content: "\f335";
164
+ }
trunk/includes/amp.php ADDED
@@ -0,0 +1,399 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * iubenda_AMP class.
8
+ *
9
+ * @class iubenda_AMP
10
+ */
11
+ class iubenda_AMP {
12
+
13
+ /**
14
+ * Class constructor.
15
+ */
16
+ public function __construct() {
17
+ // actions
18
+ add_action( 'wp_head', array( $this, 'wp_head_amp' ), 100 );
19
+ add_action( 'wp_footer', array( $this, 'wp_footer_amp' ), 100 );
20
+ add_action( 'amp_post_template_css', array( $this, 'amp_post_template_css' ), 100 );
21
+ add_action( 'amp_post_template_footer', array( $this, 'wp_footer_amp' ), 100 );
22
+ add_action( 'amp_post_template_footer', array( $this, 'fix_analytics_amp_for_wp' ), 1 );
23
+
24
+ // filters
25
+ add_filter( 'amp_post_template_data', array( $this, 'amp_post_template_data' ), 100 );
26
+ add_filter( 'amp_analytics_entries', array( $this, 'fix_analytics_wp_amp' ), 10 );
27
+ }
28
+
29
+ /**
30
+ * Add scripts and CSS to WP AMP plugin in Transitional mode.
31
+ *
32
+ * @return mixed
33
+ */
34
+ public function wp_head_amp() {
35
+ if ( iubenda()->options['cs']['amp_support'] === false )
36
+ return;
37
+
38
+ if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() && ! function_exists( 'ampforwp_is_amp_endpoint' ) ) {
39
+ echo '
40
+ <script async custom-element="amp-consent" src="https://cdn.ampproject.org/v0/amp-consent-latest.js"></script>
41
+ <script async custom-element="amp-iframe" src="https://cdn.ampproject.org/v0/amp-iframe-latest.js"></script>';
42
+
43
+ // optional geo support
44
+ if ( iubenda()->multilang && ! empty( iubenda()->lang_current ) ) {
45
+ $code = iubenda()->options['cs']['code_' . iubenda()->lang_current];
46
+ } else {
47
+ $code = iubenda()->options['cs']['code_default'];
48
+ }
49
+
50
+ $configuration_raw = iubenda()->parse_configuration( $code );
51
+
52
+ if ( isset( $configuration_raw['gdprAppliesGlobally'] ) && ! $configuration_raw['gdprAppliesGlobally'] ) {
53
+ echo '
54
+ <script async custom-element="amp-geo" src="https://cdn.ampproject.org/v0/amp-geo-0.1.js"></script>';
55
+ }
56
+
57
+ // CSS style
58
+ echo '
59
+ <style amp-custom>
60
+ .popupOverlay {
61
+ position:fixed;
62
+ top: 0;
63
+ bottom: 0;
64
+ left: 0;
65
+ right: 0;
66
+ }
67
+ amp-iframe {
68
+ margin: 0;
69
+ }
70
+ amp-consent.amp-active {
71
+ position:fixed;
72
+ top: 0;
73
+ bottom: 0;
74
+ left: 0;
75
+ right: 0;
76
+ }
77
+ </style>';
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Add AMP consent HTML to WP AMP plugin in Transitional mode.
83
+ *
84
+ * @return mixed
85
+ */
86
+ public function wp_footer_amp() {
87
+ if ( iubenda()->options['cs']['amp_support'] === false )
88
+ return;
89
+
90
+ if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() || ( function_exists( 'ampforwp_is_amp_endpoint' ) && ampforwp_is_amp_endpoint() ) ) {
91
+
92
+ // get code
93
+ if ( iubenda()->multilang && ! empty( iubenda()->lang_current ) ) {
94
+ $code = iubenda()->options['cs']['code_' . iubenda()->lang_current];
95
+ } else {
96
+ $code = iubenda()->options['cs']['code_default'];
97
+ }
98
+
99
+ $configuration = iubenda()->parse_configuration( $code );
100
+
101
+ if ( empty( $configuration ) )
102
+ return;
103
+
104
+ // local file
105
+ if ( iubenda()->options['cs']['amp_source'] === 'local' ) {
106
+ // multilang support
107
+ if ( iubenda()->multilang && ! empty( iubenda()->lang_current ) )
108
+ $template_url = $this->get_amp_template_url( iubenda()->lang_current );
109
+ else
110
+ $template_url = $this->get_amp_template_url();
111
+ // remote file
112
+ } else {
113
+ // multilang support
114
+ if ( iubenda()->multilang && ! empty( iubenda()->lang_current ) )
115
+ $template_url = esc_url( isset( iubenda()->options['cs']['amp_template'][iubenda()->lang_current] ) ? iubenda()->options['cs']['amp_template'][iubenda()->lang_current] : '' );
116
+ else
117
+ $template_url = esc_url( iubenda()->options['cs']['amp_template'] );
118
+ }
119
+
120
+ if ( empty( $template_url ) )
121
+ return;
122
+
123
+ echo '
124
+ <amp-consent id="myUserConsent" layout="nodisplay">
125
+ <script type="application/json">
126
+ {
127
+ "consentInstanceId": "consent' . $configuration['siteId'] . '",
128
+ "consentRequired": true,
129
+ "promptUI": "myConsentFlow"
130
+ }
131
+ </script>
132
+ <div id="myConsentFlow" class="popupOverlay">
133
+ <amp-iframe
134
+ layout="fill"
135
+ sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
136
+ src="' . esc_url( $template_url ) . '">
137
+ <div placeholder>' . __( 'Loading', 'iubenda' ) . '</div>
138
+ </amp-iframe>
139
+ </div>
140
+ </amp-consent>';
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Add scripts to AMP for WP plugin and WP AMP plugin in Standard mode.
146
+ *
147
+ * @return mixed
148
+ */
149
+ public function amp_post_template_data( $data ) {
150
+ if ( iubenda()->options['cs']['amp_support'] === false )
151
+ return $data;
152
+
153
+ if ( function_exists( 'ampforwp_is_amp_endpoint' ) && ampforwp_is_amp_endpoint() ) {
154
+ $data['amp_component_scripts'] = array_merge( $data['amp_component_scripts'],
155
+ array( 'amp-consent' => 'https://cdn.ampproject.org/v0/amp-consent-latest.js' )
156
+ );
157
+ $data['amp_component_scripts'] = array_merge( $data['amp_component_scripts'],
158
+ array( 'amp-iframe' => 'https://cdn.ampproject.org/v0/amp-iframe-latest.js' )
159
+ );
160
+ }
161
+
162
+ return $data;
163
+ }
164
+
165
+ /**
166
+ * Add CSS to AMP for WP plugin and WP AMP plugin in Standard mode.
167
+ *
168
+ * @return mixed
169
+ */
170
+ public function amp_post_template_css( $data ) {
171
+ if ( iubenda()->options['cs']['amp_support'] === false )
172
+ return;
173
+
174
+ echo '
175
+ .popupOverlay {
176
+ position:fixed;
177
+ top: 0;
178
+ bottom: 0;
179
+ left: 0;
180
+ right: 0;
181
+ }
182
+ amp-iframe {
183
+ margin: 0;
184
+ }
185
+ amp-consent.amp-active {
186
+ position:fixed;
187
+ top: 0;
188
+ bottom: 0;
189
+ left: 0;
190
+ right: 0;
191
+ }';
192
+ }
193
+
194
+ /**
195
+ * Block analytics in AMP for WP plugin.
196
+ *
197
+ * @return mixed
198
+ */
199
+ public function fix_analytics_amp_for_wp( $data ) {
200
+ if ( iubenda()->options['cs']['amp_support'] === false )
201
+ return $data;
202
+
203
+ global $redux_builder_amp;
204
+
205
+ if ( $redux_builder_amp == null ) {
206
+ $redux_builder_amp = get_option( 'redux_builder_amp', true );
207
+ }
208
+
209
+ // trick to block the analytics using global $redux_builder_amp variable
210
+ if ( ! iubendaParser::consent_given() )
211
+ $redux_builder_amp = true;
212
+
213
+ return $data;
214
+ }
215
+
216
+ /**
217
+ * Block analytics in WP AMP plugin.
218
+ *
219
+ * @return mixed
220
+ */
221
+ public function fix_analytics_wp_amp( $analytics_entries ) {
222
+ if ( iubenda()->options['cs']['amp_support'] === false )
223
+ return $analytics_entries;
224
+
225
+ // block the analytics using the entries filter hook
226
+ if ( ! iubendaParser::consent_given() && ! empty( $analytics_entries ) && is_array( $analytics_entries ) ) {
227
+ foreach ( $analytics_entries as $id => $entry ) {
228
+ $entry['attributes'] = ! empty( $entry['attributes'] ) ? $entry['attributes'] : array();
229
+
230
+ $analytics_entries[$id]['attributes'] = array_merge( array( 'data-block-on-consent' => '_till_accepted' ), $entry['attributes'] );
231
+ }
232
+ }
233
+
234
+ return $analytics_entries;
235
+ }
236
+
237
+ /**
238
+ * Prepare HTML iframe template for the AMP.
239
+ *
240
+ * @return mixed
241
+ */
242
+ public function prepare_amp_template( $code ) {
243
+ $html = '';
244
+
245
+ $configuration_raw = iubenda()->parse_configuration( $code );
246
+
247
+ if ( ! empty( $configuration_raw ) ) {
248
+ // get script
249
+ $script_src = ! empty( $configuration_raw['script'] ) ? $configuration_raw['script'] : '//cdn.iubenda.com/cs/iubenda_cs.js';
250
+
251
+ // remove from configuration
252
+ if ( isset( $configuration_raw['script'] ) )
253
+ unset( $configuration_raw['script'] );
254
+
255
+ // encode array
256
+ $configuration = json_encode( $configuration_raw );
257
+
258
+ // remove quotes
259
+ $configuration = preg_replace( '/"([a-zA-Z]+[a-zA-Z0-9]*)":/', '$1:', $configuration );
260
+ // replace brackets
261
+ $configuration = str_replace( array( '{', '}' ), '', $configuration );
262
+
263
+ $html .= '<!DOCTYPE html>
264
+ <html lang="' . $configuration_raw['lang'] . '">
265
+ <head>
266
+ <meta charset="UTF-8">
267
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
268
+ <meta name="robots" content="noindex">
269
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
270
+ <title>' . __( 'AMP Cookie Consent', 'iubenda' ) . '</title>
271
+ <script type="text/javascript">
272
+ var _iub = _iub || [];
273
+ _iub.csConfiguration = {
274
+ ';
275
+ // print configuration
276
+ $html .= $configuration . ',';
277
+ $html .= '
278
+ banner: {
279
+ position: \'float-bottom-center\',
280
+ acceptButtonDisplay: true,
281
+ customizeButtonDisplay: true,
282
+ rejectButtonDisplay: true,
283
+ backgroundOverlay: true
284
+ },
285
+ callback: { // Mandatory
286
+ onPreferenceExpressed: function(preference) {
287
+ var consentAction = \'reject\';
288
+ var consentObject = {
289
+ type: \'consent-response\'
290
+ };
291
+
292
+ if (preference && preference.consent) {
293
+ consentAction = \'accept\';
294
+ }
295
+
296
+ consentObject.action = consentAction;
297
+
298
+ if (_iub.cs.options.enableCMP) {
299
+ __cmp(\'getConsentData\', null, function(res) {
300
+ var consentString = res.consentData;
301
+
302
+ if (consentString.length <= 200) {
303
+ consentObject.info = consentString;
304
+ }
305
+
306
+ console.log(\'send consent-response\', consentAction, \'with CMP consent string\', consentString);
307
+
308
+ window.parent.postMessage(consentObject, \'*\');
309
+ });
310
+ }
311
+ else {
312
+ console.log(\'send consent-response\', consentAction);
313
+
314
+ window.parent.postMessage(consentObject, \'*\');
315
+ }
316
+ }
317
+ }
318
+ };
319
+ </script>
320
+ <script async src="' . $script_src . '"></script>
321
+ </head>
322
+ <body></body>
323
+ </html>';
324
+ }
325
+
326
+ return $html;
327
+ }
328
+
329
+ /**
330
+ * Get local file template url;
331
+ *
332
+ * @return string
333
+ */
334
+ public function get_amp_template_url( $template_lang = '' ) {
335
+ $template_url = '';
336
+ $template_lang = ! empty( $template_lang ) && is_string( $template_lang ) ? $template_lang : '';
337
+
338
+ // get basic site host and template file data
339
+ $file_url = ! empty( $template_lang ) ? IUBENDA_PLUGIN_URL . '/templates/amp' . '-' . $template_lang . '.html' : IUBENDA_PLUGIN_URL . '/templates/amp.html';
340
+ // $file_url = 'https://cdn.iubenda.com/cs/test/cs-for-amp.html'; // debug only
341
+ $parsed_site = parse_url( home_url() );
342
+ $parsed_file = parse_url( $file_url );
343
+ $site_host = $parsed_site['host'] !== 'localhost' ? iubenda()->domain( $parsed_site['host'] ) : 'localhost';
344
+ $file_host = $parsed_file['host'] !== 'localhost' ? iubenda()->domain( $parsed_file['host'] ) : 'localhost';
345
+ $is_localhost = (bool) ( $site_host == 'localhost' );
346
+ $is_subdomain = ! $is_localhost ? (bool) ( $parsed_file['host'] !== $file_host ) : false;
347
+
348
+ // check if file host and server host match
349
+ // if not, we're good to go
350
+ if ( $site_host !== $file_host ) {
351
+ $template_url = $file_url;
352
+ // if are located on same host do additional tweaks
353
+ } else {
354
+ // all ok if we're on different subdomains
355
+ if ( $parsed_site['host'] !== $parsed_file['host'] )
356
+ $template_url = $file_url;
357
+ // same hosts, let's tweak the http/https
358
+ else {
359
+ $has_www = strpos( $parsed_file['host'], 'www.' ) === 0;
360
+
361
+ // add or remove www from url string to make iframe url pass AMP validation
362
+ $tweaked_host = ! $is_localhost && ( ! $is_subdomain || $has_www ) ? ( ! $has_www ? 'www.' . $parsed_file['host'] : preg_replace( '/^www\./i', '', $parsed_file['host'] ) ) : $parsed_file['host'];
363
+
364
+ // generate new url
365
+ $tweaked_url = $parsed_file['scheme'] . '://' . $tweaked_host . ( isset( $parsed_file['port'] ) ? ':' . $parsed_file['port'] : '' ) . $parsed_file['path'] . ( ! empty( $parsed_file['query'] ) ? '?' . $parsed_file['query'] : '' );
366
+
367
+ // check if file url is valid
368
+ if ( $tweaked_url ) {
369
+ $template_url = $tweaked_url;
370
+ }
371
+ }
372
+ }
373
+
374
+ return $template_url;
375
+ }
376
+
377
+ /**
378
+ * Generate HTML iframe template for the AMP.
379
+ *
380
+ * @return mixed
381
+ */
382
+ public function generate_amp_template( $code = '', $lang = '' ) {
383
+ if ( empty( $code ) )
384
+ return false;
385
+
386
+ $template_dir = IUBENDA_PLUGIN_PATH . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR;
387
+ $template_file = $template_dir . ( ! empty( $lang ) && in_array( $lang, array_keys( iubenda()->languages ) ) ? 'amp' . '-' . $lang . '.html' : 'amp.html' );
388
+ $html = $this->prepare_amp_template( $code );
389
+
390
+ // bail if the template was not created properly
391
+ if ( empty( $html ) )
392
+ return false;
393
+
394
+ $result = file_put_contents( $template_file, $html );
395
+
396
+ return (bool) $result;
397
+ }
398
+
399
+ }
trunk/includes/forms-list-table.php ADDED
@@ -0,0 +1,367 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * iubenda_List_Table_Forms class.
8
+ *
9
+ * @class iubenda_List_Table_Forms
10
+ */
11
+ class iubenda_List_Table_Forms extends WP_List_Table {
12
+
13
+ public $items;
14
+ public $extra_items;
15
+ public $base_url;
16
+
17
+ /**
18
+ * Class constructor.
19
+ */
20
+ public function __construct() {
21
+ global $status, $page;
22
+
23
+ // set parent defaults
24
+ parent::__construct( array(
25
+ 'ajax' => false
26
+ ) );
27
+
28
+ $this->base_url = esc_url_raw( add_query_arg( array( 'tab' => 'cons' ), iubenda()->base_url ) );
29
+ }
30
+
31
+
32
+
33
+ /**
34
+ * Prepare the items for the table to process.
35
+ */
36
+ public function prepare_items() {
37
+ if ( ! empty( $_GET['status'] ) && array_key_exists( $_GET['status'], iubenda()->forms->statuses ) )
38
+ $status = $_GET['status'];
39
+ else
40
+ $status = '';
41
+
42
+ $orderby = ( isset( $_GET['orderby'] ) ) ? esc_attr( $_GET['orderby'] ) : 'date';
43
+ $order = ( isset( $_GET['order'] ) ) && in_array( $_GET['order'], array( 'asc', 'desc' ) ) ? esc_attr( $_GET['order'] ) : 'desc';
44
+
45
+ $per_page = 20;
46
+
47
+ if ( isset( $_GET['number'] ) ) {
48
+ $number = (int) $_GET['number'];
49
+ } else {
50
+ $number = $per_page + min( 8, $per_page ); // grab a few extra
51
+ }
52
+ $page = $this->get_pagenum();
53
+
54
+ $args = array(
55
+ 'orderby' => $orderby,
56
+ 'order' => $order,
57
+ 'offset' => 0,
58
+ 'number' => 0,
59
+ 'post_status' => $status
60
+ );
61
+
62
+ $items = iubenda()->forms->get_forms( $args );
63
+
64
+ // echo '<pre>'; print_r( $items ); echo '</pre>';
65
+
66
+ if ( is_array( $items ) ) {
67
+ $this->items = array_slice( $items, 0, $per_page );
68
+ $this->extra_items = array_slice( $items, $per_page );
69
+ }
70
+
71
+ // echo '<pre>'; print_r( $this->extra_items ); echo '</pre>';
72
+
73
+ $this->set_pagination_args( array(
74
+ 'total_items' => count( $items ),
75
+ 'per_page' => $per_page,
76
+ ) );
77
+
78
+ $columns = $this->get_columns();
79
+ $hidden = array();
80
+ $sortable = $this->get_sortable_columns();
81
+ $this->_column_headers = array( $columns, $hidden, $sortable );
82
+ }
83
+
84
+ /**
85
+ * Override the parent columns method. Defines the columns to use in your listing table.
86
+ *
87
+ * @return array
88
+ */
89
+ public function get_columns() {
90
+ $columns = array(
91
+ 'cb' => '<input type="checkbox"/>',
92
+ 'title' => __( 'Form Title', 'iubenda' ),
93
+ 'ID' => __( 'Form ID', 'iubenda' ),
94
+ 'source' => __( 'Form Source', 'iubenda' ),
95
+ 'fields' => __( 'Fields', 'iubenda' ),
96
+ 'date' => __( 'Date', 'iubenda' ),
97
+ );
98
+
99
+ return $columns;
100
+ }
101
+
102
+ /**
103
+ * Define the sortable columns.
104
+ *
105
+ * @return array
106
+ */
107
+ public function get_sortable_columns() {
108
+ $columns = array(
109
+ 'title' => array( 'name', true )
110
+ );
111
+ return $columns;
112
+ }
113
+
114
+ /**
115
+ * Handle single row content.
116
+ *
117
+ * @param array $item
118
+ * @return mixed
119
+ */
120
+ public function single_row( $item ) {
121
+ $classes = array();
122
+ $classes[] = 'item-' . $item->ID;
123
+ ?>
124
+ <tr id="item-<?php echo $item->ID; ?>" class="<?php echo implode( ' ', $classes ); ?>">
125
+ <?php $this->single_row_columns( $item ); ?>
126
+ </tr>
127
+ <?php
128
+ }
129
+
130
+ /**
131
+ * Get the name of the default primary column.
132
+ *
133
+ * @return string Name of the default primary column, in this case, 'title'.
134
+ */
135
+ public function get_default_primary_column_name() {
136
+ return 'title';
137
+ }
138
+
139
+ /**
140
+ * Generate and display row actions links.
141
+ *
142
+ * @param object $item
143
+ * @param string $column_name
144
+ * @param string $primary
145
+ * @return string|void
146
+ */
147
+ public function handle_row_actions( $item, $column_name, $primary ) {
148
+ if ( $column_name !== 'title' ) {
149
+ return '';
150
+ }
151
+
152
+ $output = '';
153
+
154
+ $del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "delete-form_{$item->ID}" ) );
155
+ $url = add_query_arg( array( 'form_id' => $item->ID ), $this->base_url );
156
+ $edit_url = add_query_arg( array( 'action' => 'edit' ), $url );
157
+ $delete_url = add_query_arg( array( 'action' => 'delete' ), $url ) . "&$del_nonce";
158
+
159
+ // preorder it: View | Approve | Unapprove | Delete
160
+ $actions = array(
161
+ 'view' => '',
162
+ 'delete' => ''
163
+ );
164
+
165
+ $actions['view'] = "<a href='$edit_url' aria-label='" . esc_attr__( 'Edit this form', 'iubenda' ) . "'>" . __( 'Edit' ) . '</a>';
166
+ $actions['delete'] = "<a href='$delete_url' aria-label='" . esc_attr__( 'Delete this form', 'iubenda' ) . "'>" . __( 'Delete', 'iubenda' ) . '</a>';
167
+
168
+ $i = 0;
169
+ $output .= '<div class="row-actions">';
170
+ foreach ( $actions as $action => $link ) {
171
+ ++ $i;
172
+ $sep = ( 1 === $i ) ? $sep = '' : $sep = ' | ';
173
+ $output .= '<span class="' . ( $action === 'delete' ? 'delete delete-form' : $action ) . '">' . $sep . $link . '</span>';
174
+ }
175
+ $output .= '</div>';
176
+
177
+ return $output;
178
+ }
179
+
180
+ /**
181
+ * Define what data to show on each column of the table.
182
+ *
183
+ * @param array $item
184
+ * @param string $column_name
185
+ * @return mixed
186
+ */
187
+ public function column_default( $item, $column_name ) {
188
+ $output = '';
189
+
190
+ if ( ! empty( $_GET['status'] ) && array_key_exists( $_GET['status'], iubenda()->forms->statuses ) )
191
+ $status = $_GET['status'];
192
+ else
193
+ $status = '';
194
+
195
+ // print_r( $item );
196
+
197
+ // get columns content
198
+ switch ( $column_name ) {
199
+ case 'ID':
200
+ $output = $item->ID;
201
+ break;
202
+ case 'title':
203
+ $output = '<strong>' . ( current_user_can( 'edit_post', $item->ID ) ? '<a href="' . esc_url_raw( add_query_arg( array( 'form_id' => $item->ID, 'action' => 'edit' ), $this->base_url ) ) . '">' . $item->post_title . '</a>' : $item->post_title );
204
+
205
+ if ( ! $status ) {
206
+ if ( in_array( $item->post_status, array( 'publish', 'needs_update' ) ) ) {
207
+ $output .= ' &mdash; ';
208
+ $output .= '<span class="post-state to-map-state">' . iubenda()->forms->statuses[$item->post_status] . '</span>';
209
+ }
210
+ }
211
+
212
+ $output .= '</strong>';
213
+
214
+ break;
215
+ case 'source':
216
+ $output = array_key_exists( $item->form_source, iubenda()->forms->sources ) ? iubenda()->forms->sources[$item->form_source] : '&#8212;';
217
+ break;
218
+ case 'fields':
219
+ $output = count( $item->form_fields );
220
+ break;
221
+ case 'date':
222
+ $output = date_i18n( $item->post_date );
223
+ break;
224
+ default:
225
+ break;
226
+ }
227
+
228
+ return $output;
229
+ }
230
+
231
+ /**
232
+ * Display checkboxex callback.
233
+ *
234
+ * @return string
235
+ */
236
+ public function column_cb( $item ) {
237
+ return sprintf(
238
+ '<input type="checkbox" name="%1$s[]" value="%2$s" />', 'form', $item->ID
239
+ );
240
+ }
241
+
242
+ /**
243
+ * Generate the table navigation above or below the table
244
+ *
245
+ * @since 3.1.0
246
+ * @param string $which
247
+ */
248
+ protected function display_tablenav( $which ) {
249
+ ?>
250
+ <div class="tablenav <?php echo esc_attr( $which ); ?>">
251
+ <?php
252
+ // $this->extra_tablenav( $which );
253
+ $this->pagination( $which );
254
+ ?>
255
+
256
+ <br class="clear" />
257
+ </div>
258
+ <?php
259
+ }
260
+
261
+ /**
262
+ * @param string $which
263
+ */
264
+ protected function extra_tablenav( $which ) {
265
+ ?>
266
+ <div class="alignleft actions">
267
+ <?php
268
+ if ( 'top' === $which ) {
269
+ ob_start();
270
+
271
+ $this->sources_dropdown();
272
+
273
+ $output = ob_get_clean();
274
+
275
+ if ( ! empty( $output ) ) {
276
+ echo $output;
277
+ submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
278
+ }
279
+ }
280
+ ?>
281
+ </div>
282
+ <?php
283
+ }
284
+
285
+ /**
286
+ * Displays a sources drop-down for filtering on the list table.
287
+ *
288
+ * @return mixed
289
+ */
290
+ protected function sources_dropdown() {
291
+ if ( ! empty( iubenda()->forms->sources ) ) {
292
+ $current = ! empty( $_GET['source'] ) && in_array( $_GET['source'], iubenda()->forms->sources ) ? esc_attr( $_GET['source'] ) : '';
293
+ echo '
294
+ <label class="screen-reader-text" for="cat">' . __( 'Filter by source', 'iubenda' ) . '</label>
295
+ <select name="source" id="filter-by-source">
296
+ <option ' . selected( '', $current, false ) . 'value="">' . __( 'All form sources', 'iubenda' ) . '</option>';
297
+ foreach ( iubenda()->forms->sources as $key => $label ) {
298
+ echo '
299
+ <option ' . selected( $key, $current, false ) . 'value="' . $key . '">' . $label . '</option>';
300
+ }
301
+
302
+ echo '</select>';
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Display views.
308
+ *
309
+ * @return array
310
+ */
311
+ public function get_views() {
312
+ if ( ! empty( $_GET['status'] ) && array_key_exists( $_GET['status'], iubenda()->forms->statuses ) )
313
+ $status = $_GET['status'];
314
+ else
315
+ $status = '';
316
+
317
+ $orderby = ( isset( $_GET['orderby'] ) ) ? esc_attr( $_GET['orderby'] ) : '';
318
+ $order = ( isset( $_GET['order'] ) ) ? esc_attr( $_GET['order'] ) : '';
319
+
320
+ $per_page = 20;
321
+
322
+ if ( isset( $_GET['number'] ) ) {
323
+ $number = (int) $_GET['number'];
324
+ } else {
325
+ $number = $per_page + min( 8, $per_page ); // grab a few extra
326
+ }
327
+ $page = $this->get_pagenum();
328
+ $items_total = 0;
329
+
330
+ $args = array(
331
+ 'orderby' => $orderby,
332
+ 'order' => $order,
333
+ 'offset' => 0,
334
+ 'number' => 0
335
+ );
336
+
337
+ foreach ( iubenda()->forms->statuses as $key => $view ) {
338
+ $args['post_status'] = $key;
339
+
340
+ $items = iubenda()->forms->get_forms( $args );
341
+
342
+ $items_count[$key] = count( $items );
343
+ $items_total = $items_total + $items_count[$key];
344
+ }
345
+
346
+ $views = $items_total > 0 ? array(
347
+ 'all' => '<a href="' . $this->base_url . '"' . ($status === '' ? ' class="current"' : '') . '>' . esc_html__( 'All' ) . ' <span class="count">(' . $items_total . ')</span></a>'
348
+ ) : '';
349
+
350
+ foreach ( iubenda()->forms->statuses as $key => $view ) {
351
+ if ( (int) $items_count[$key] > 0 )
352
+ $views[$key] = '<a href="' . esc_url_raw( add_query_arg( array( 'status' => $key ), $this->base_url ) ) . '" ' . ($status === $key ? ' class="current"' : '') . '>' . sprintf( _n( '%1$s <span class="count">(%2$s)</span>', '%1$s <span class="count">(%2$s)</span>', $items_count[$key], 'iubenda' ), $view, $items_count[$key] ) . '</a>';
353
+ }
354
+
355
+ return $views;
356
+ }
357
+
358
+ /**
359
+ * Display empty result.
360
+ *
361
+ * @return string
362
+ */
363
+ public function no_items() {
364
+ echo __( 'No forms found.', 'iubenda' );
365
+ }
366
+
367
+ }
trunk/includes/forms.php ADDED
@@ -0,0 +1,969 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * iubenda_Forms class.
8
+ *
9
+ * @class iubenda_Forms
10
+ */
11
+ class iubenda_Forms {
12
+
13
+ public $sources = array();
14
+ public $statuses = array();
15
+
16
+ /**
17
+ * Class constructor.
18
+ */
19
+ public function __construct() {
20
+ // actions
21
+ add_action( 'plugins_loaded', array( $this, 'init' ) );
22
+ add_action( 'init', array( $this, 'register_post_type' ) );
23
+ add_action( 'init', array( $this, 'register_post_status' ) );
24
+ add_action( 'wp_enqueue_scripts', array( $this, 'wp_enqueue_scripts' ) );
25
+ }
26
+
27
+ /**
28
+ * Initialize forms data.
29
+ *
30
+ * @return void
31
+ */
32
+ public function init() {
33
+ // WOrdPress commenting form
34
+ $this->sources['wp_comment_form'] = 'WordPress Comment';
35
+
36
+ // check if Contact Form 7 is active
37
+ if ( class_exists( 'WPCF7' ) ) {
38
+ $this->sources['wpcf7'] = 'Contact Form 7';
39
+ }
40
+
41
+ // check if WP Forms is active
42
+ if ( function_exists( 'wpforms' ) ) {
43
+ $this->sources['wpforms'] = 'WP Forms';
44
+ }
45
+
46
+ // check if EooCommerce is active
47
+ if ( function_exists( 'WC' ) ) {
48
+ $this->sources['woocommerce'] = 'WooCommerce Checkout';
49
+ }
50
+
51
+ $this->sources = apply_filters( 'iub_supported_form_sources', $this->sources );
52
+
53
+ $this->statuses = array(
54
+ 'publish' => _x( 'To Map', 'post status', 'iubenda' ),
55
+ 'mapped' => _x( 'Mapped', 'post status', 'iubenda' ),
56
+ 'needs_update' => _x( 'Needs Update', 'post status', 'iubenda' ),
57
+ // 'trash' => _x( 'Ignored', 'post status', 'iubenda' )
58
+ );
59
+ }
60
+
61
+ /**
62
+ * Enqueue frontend script.
63
+ */
64
+ public function wp_enqueue_scripts() {
65
+ if ( ! empty( iubenda()->options['cons']['public_api_key'] ) ) {
66
+ wp_register_script( 'iubenda-forms', IUBENDA_PLUGIN_URL . '/js/frontend.js', array( 'jquery' ), iubenda()->version, true );
67
+
68
+ $args = array();
69
+
70
+ $form_args = array(
71
+ 'post_status' => array( 'mapped', 'needs_update' )
72
+ );
73
+
74
+ $forms = $this->get_forms( $form_args );
75
+
76
+ // echo '<pre>'; print_r( $forms ); echo '</pre>';
77
+
78
+ if ( ! empty( $forms ) ) {
79
+ // required form parameters
80
+ $form_parameters = array(
81
+ 'subject',
82
+ 'preferences',
83
+ 'exclude',
84
+ 'legal_notices'
85
+ );
86
+ // loop through forms
87
+ foreach ( $forms as $form ) {
88
+ // bail if user is logged in and source is WP comment form
89
+ if ( $form->form_source == 'wp_comment_form' && is_user_logged_in() )
90
+ continue;
91
+
92
+ // we need unique identifier for the html form
93
+ // by default it's object id, used in form html id
94
+ $args[$form->form_source][$form->object_id] = array();
95
+
96
+ foreach ( $form_parameters as $parameter ) {
97
+ $parameter_name = 'form_' . $parameter;
98
+ $parameter_value = ! empty( $form->$parameter_name ) ? $form->$parameter_name : '';
99
+
100
+ // echo '<pre>'; print_r( $parameter_value ); echo '</pre>';
101
+
102
+ switch ( $parameter ) {
103
+ case 'legal_notices' :
104
+ if ( $parameter_value && is_array( $parameter_value ) ) {
105
+ foreach( $parameter_value as $value ) {
106
+ $args[$form->form_source][$form->object_id]['consent']['legal_notices'][] = array( 'identifier' => $value );
107
+ }
108
+ }
109
+ break;
110
+ default :
111
+ if ( $parameter_value ) {
112
+ switch ( $form->form_source ) {
113
+ case 'wpforms' :
114
+ // replace integers with field names
115
+ foreach ( $parameter_value as $index => $parameter_item ) {
116
+ $parameter_value[$index] = $form->form_fields[$parameter_item]['name'];
117
+ }
118
+ $args[$form->form_source][$form->object_id]['form']['map'][$parameter] = $parameter_value;
119
+ break;
120
+ default :
121
+ $args[$form->form_source][$form->object_id]['form']['map'][$parameter] = $parameter_value;
122
+ break;
123
+ }
124
+ }
125
+ break;
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ // echo '<pre>'; print_r( $args ); echo '</pre>'; exit;
132
+
133
+ wp_localize_script(
134
+ 'iubenda-forms',
135
+ 'iubForms',
136
+ json_encode( $args )
137
+ );
138
+
139
+ wp_enqueue_script( 'iubenda-forms' );
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Register iubenda form post type.
145
+ */
146
+ public function register_post_type() {
147
+ register_post_type( 'iubenda_form', array(
148
+ 'labels' => array(
149
+ 'name' => __( 'Forms', 'iubenda' ),
150
+ 'singular_name' => __( 'Form', 'iubenda' ),
151
+ ),
152
+ 'rewrite' => false,
153
+ 'query_var' => false,
154
+ 'public' => false,
155
+ 'capability_type' => 'page'
156
+ ) );
157
+ }
158
+
159
+ /**
160
+ * Register iubenda form post status.
161
+ */
162
+ public function register_post_status() {
163
+ foreach ( $this->statuses as $name => $label ) {
164
+ if ( $name === 'publish' )
165
+ continue;
166
+
167
+ register_post_status( $name, array(
168
+ 'label' => $label,
169
+ 'public' => true,
170
+ 'exclude_from_search' => false,
171
+ 'show_in_admin_all_list' => true,
172
+ 'show_in_admin_status_list' => true,
173
+ 'post_type' => array( 'iubenda_form' ),
174
+ // 'label_count' => _n_noop( 'Mapped <span class="count">(%s)</span>', 'Mapped <span class="count">(%s)</span>', 'iubenda' ),
175
+ ) );
176
+ }
177
+
178
+ }
179
+
180
+ /**
181
+ * Get iubenda forms function.
182
+ *
183
+ * @param type $args
184
+ * @return array
185
+ */
186
+ public function get_forms( $args = array() ) {
187
+ $defaults = array(
188
+ 'post_status' => 'any',
189
+ 'posts_per_page' => -1,
190
+ 'offset' => 0,
191
+ 'orderby' => 'ID',
192
+ 'order' => 'ASC',
193
+ 'form_source' => 'any'
194
+ );
195
+
196
+ $args = wp_parse_args( $args, $defaults );
197
+
198
+ $args['post_type'] = 'iubenda_form';
199
+
200
+ // specific sources only
201
+ if ( $args['form_source'] != 'any' && ( is_string( $args['form_source'] ) || is_array( $args['form_source'] ) ) ) {
202
+ $args['meta_query'] = array(
203
+ array(
204
+ 'key' => '_iub_form_source',
205
+ 'value' => $args['form_source'],
206
+ 'compare' => 'IN',
207
+ ),
208
+ );
209
+ }
210
+
211
+ $q = new WP_Query();
212
+
213
+ $posts = $q->query( $args );
214
+
215
+ $metakeys = array(
216
+ 'form_source',
217
+ 'object_type',
218
+ 'object_id',
219
+ 'form_fields',
220
+ 'form_subject',
221
+ 'form_preferences',
222
+ 'form_exclude',
223
+ 'form_legal_notices'
224
+ );
225
+
226
+ if ( ! empty( $posts ) ) {
227
+ foreach ( $posts as $index => $post ) {
228
+ // get form data
229
+ $metadata_raw = get_metadata( 'post', $post->ID );
230
+
231
+ foreach ( $metakeys as $metakey ) {
232
+ $metadata = ! empty( $metadata_raw['_iub_' . $metakey][0] ) ? maybe_unserialize( $metadata_raw['_iub_' . $metakey][0] ) : '';
233
+
234
+ if ( ! empty( $metadata ) ) {
235
+ // unset empty values
236
+ if ( is_array( $metadata ) ) {
237
+ foreach ( $metadata as $metadata_key => $metadata_value ) {
238
+ if ( $metadata_value == '' && ! in_array( $metakey, array( 'form_legal_notices' ) ) )
239
+ unset( $metadata[$metadata_key] );
240
+ }
241
+ }
242
+
243
+ $posts[$index]->{$metakey} = $metadata;
244
+ }
245
+ /* object id needs to ba an integer
246
+ } elseif ( in_array( $metakey, array( 'object_id' ) ) ) {
247
+ $posts[$index]->{$metakey} = ! empty( $metadata ) ? absint( $metadata ) : 0;
248
+ }
249
+ */
250
+ }
251
+ }
252
+ }
253
+
254
+ return $posts;
255
+ }
256
+
257
+ /**
258
+ * Get form function.
259
+ *
260
+ * @param int
261
+ * @return object
262
+ */
263
+ public function get_form( $id ) {
264
+ $form_id = ! empty( $id ) ? absint( $id ) : 0;
265
+
266
+ if ( ! $form_id )
267
+ return false;
268
+
269
+ $form = get_post( $form_id );
270
+
271
+ if ( ! $form )
272
+ return false;
273
+
274
+ $metakeys = array(
275
+ 'form_source',
276
+ 'object_type',
277
+ 'object_id',
278
+ 'form_fields',
279
+ 'form_subject',
280
+ 'form_preferences',
281
+ 'form_exclude',
282
+ 'form_legal_notices'
283
+ );
284
+
285
+ // get form data
286
+ $metadata = get_metadata( 'post', $form->ID );
287
+
288
+ foreach ( $metakeys as $metakey ) {
289
+ $form->{$metakey} = ! empty( $metadata['_iub_' . $metakey][0] ) ? maybe_unserialize( $metadata['_iub_' . $metakey][0] ) : '';
290
+ }
291
+
292
+ return $form;
293
+ }
294
+
295
+ /**
296
+ * Delete form function.
297
+ *
298
+ * @param int
299
+ * @return int
300
+ */
301
+ public function delete_form( $id ) {
302
+ $form_id = ! empty( $id ) ? absint( $id ) : 0;
303
+
304
+ if ( ! $form_id )
305
+ return false;
306
+
307
+ $form = get_post( $form_id );
308
+
309
+ if ( ! $form )
310
+ return false;
311
+
312
+ $result = wp_delete_post( $id, true );
313
+
314
+ return $result;
315
+ }
316
+
317
+ /**
318
+ * Insert form function.
319
+ *
320
+ * @param array $args
321
+ * @return int
322
+ */
323
+ public function save_form( $args = array() ) {
324
+ $defaults = array(
325
+ 'ID' => 0,
326
+ 'status' => 'publish',
327
+ 'object_type' => 'post', // object type where the form data is stored
328
+ 'object_id' => 0, // unique object id
329
+ 'form_source' => '', // source slug
330
+ 'form_title' => '', // form title
331
+ 'form_date' => current_time( 'mysql' ), // form last modified date
332
+ 'form_fields' => array(), // form field names array
333
+ 'form_subject' => array(), // mapped form with iubenda consent subject param
334
+ 'form_preferences' => array(), // mapped form with iubenda consent preferences param
335
+ 'form_exclude' => array(), // mapped form with iubenda consent exclude param
336
+ 'form_legal_notices' => array() // form legal notices
337
+ );
338
+
339
+ $args = wp_parse_args( $args, $defaults );
340
+
341
+ // sanitize args
342
+ $args['ID'] = ! empty( $args['ID'] ) ? absint( $args['ID'] ) : 0;
343
+ $args['status'] = ! empty( $args['status'] ) && in_array( $args['status'], array_keys( $this->statuses ) ) ? $args['status'] : 'publish';
344
+ $args['object_type'] = 'post';
345
+ $args['object_id'] = ! empty( $args['object_id'] ) ? (int) $args['object_id'] : 0;
346
+ $args['form_source'] = ! empty( $args['form_source'] ) && in_array( $args['form_source'], array_keys( $this->sources ) ) ? $args['form_source'] : '';
347
+ $args['form_title'] = ! empty( $args['form_title'] ) ? esc_html( $args['form_title'] ) : '';
348
+ $args['form_date'] = date( 'Y-m-d H:i:s', ( ! empty( $args['form_date'] ) ? strtotime( $args['form_date'] ) : current_time( 'mysql' ) ) );
349
+ $args['form_fields'] = ! empty( $args['form_fields'] ) && is_array( $args['form_fields'] ) ? $args['form_fields'] : array();
350
+ $args['form_subject'] = ! empty( $args['form_subject'] ) && is_array( $args['form_subject'] ) ? array_map( 'esc_attr', $args['form_subject'] ) : array();
351
+ $args['form_preferences'] = ! empty( $args['form_preferences'] ) && is_array( $args['form_preferences'] ) ? array_map( 'esc_attr', $args['form_preferences'] ) : array();
352
+ $args['form_exclude'] = ! empty( $args['form_exclude'] ) && is_array( $args['form_exclude'] ) ? array_map( 'esc_attr', $args['form_exclude'] ) : array();
353
+ $args['form_legal_notices'] = ! empty( $args['form_legal_notices'] ) && is_array( $args['form_legal_notices'] ) ? array_map( 'esc_attr', $args['form_legal_notices'] ) : array();
354
+
355
+ $form_fields = array();
356
+
357
+ // sanitize form fields
358
+ if ( ! empty( $args['form_fields'] ) && is_array( $args['form_fields'] ) ) {
359
+ foreach ( $args['form_fields'] as $form_field ) {
360
+ if ( ! empty( $form_field ) && is_array( $form_field ) ) {
361
+ $form_fields[] = array_map( 'esc_attr', $form_field );
362
+ } else {
363
+ $form_fields[] = esc_attr( $form_field );
364
+ }
365
+ }
366
+ }
367
+
368
+ // echo '<pre>'; print_r( $args ); echo '</pre>'; exit;
369
+
370
+ // bail if any issues
371
+ if ( ! $args['form_source'] || ! $args['form_fields'] )
372
+ return false;
373
+
374
+ $post = $args['ID'] !== 0 ? get_post( $args['ID'] ) : false;
375
+ $update = empty( $post ) ? false : true;
376
+
377
+ // insert new form
378
+ if ( ! $update ) {
379
+ $post_id = wp_insert_post( array(
380
+ 'post_type' => 'iubenda_form',
381
+ 'post_status' => $args['status'],
382
+ 'post_title' => $args['form_title'],
383
+ 'post_content' => '',
384
+ 'post_date' => $args['form_date'],
385
+ 'post_modified' => $args['form_date']
386
+ ) );
387
+ // update form
388
+ } else {
389
+ $post_id = wp_update_post( array(
390
+ 'ID' => $args['ID'],
391
+ 'post_status' => $args['status'],
392
+ 'post_modified' => $args['form_date']
393
+ ) );
394
+ }
395
+
396
+ // save form source
397
+ if ( isset( $args['form_source'] ) )
398
+ update_post_meta( $post_id, '_iub_form_source', $args['form_source'] );
399
+
400
+ // save object type
401
+ if ( isset( $args['object_type'] ) )
402
+ update_post_meta( $post_id, '_iub_object_type', $args['object_type'] );
403
+
404
+ // save object id
405
+ if ( isset( $args['object_id'] ) )
406
+ update_post_meta( $post_id, '_iub_object_id', absint( $args['object_id'] ) );
407
+
408
+ // save form fields
409
+ if ( isset( $args['form_fields'] ) )
410
+ update_post_meta( $post_id, '_iub_form_fields', $form_fields );
411
+
412
+ // save form subject
413
+ if ( isset( $args['form_subject'] ) )
414
+ update_post_meta( $post_id, '_iub_form_subject', $args['form_subject'] );
415
+
416
+ // save form preferences
417
+ if ( isset( $args['form_preferences'] ) )
418
+ update_post_meta( $post_id, '_iub_form_preferences', $args['form_preferences'] );
419
+
420
+ // save form exclude
421
+ if ( isset( $args['form_exclude'] ) )
422
+ update_post_meta( $post_id, '_iub_form_exclude', $args['form_exclude'] );
423
+
424
+ // save legal notices
425
+ if ( isset( $args['form_legal_notices'] ) )
426
+ update_post_meta( $post_id, '_iub_form_legal_notices', $args['form_legal_notices'] );
427
+
428
+ return $post_id;
429
+ }
430
+
431
+ /**
432
+ * Autodetect forms action.
433
+ *
434
+ * @return bool
435
+ */
436
+ public function autodetect_forms() {
437
+ $found_forms = $new_forms = array();
438
+
439
+ // get forms from active sources
440
+ if ( ! empty( $this->sources ) ) {
441
+ foreach ( $this->sources as $source => $source_name ) {
442
+ $found_forms[$source] = call_user_func( array( $this, 'get_source_forms' ), $source );
443
+ }
444
+ }
445
+
446
+ // insert forms
447
+ if ( ! empty( $found_forms ) ) {
448
+ foreach ( $found_forms as $source => $source_forms ) {
449
+ if ( ! empty( $source_forms ) ) {
450
+
451
+ foreach ( $source_forms as $formdata ) {
452
+
453
+ $exists = $this->get_form_by_object_id( array(
454
+ 'id' => $formdata['object_id'],
455
+ 'source' => $formdata['form_source']
456
+ ) );
457
+
458
+ // form does not exist
459
+ if ( ! $exists ) {
460
+ $result = $this->save_form( $formdata );
461
+
462
+ if ( $result )
463
+ $new_forms['new'] = $result;
464
+ } else {
465
+ // check for fields changes
466
+ $new_fields = array_merge( array_diff( $formdata['form_fields'], $exists->form_fields ), array_diff( $exists->form_fields, $formdata['form_fields'] ) );
467
+
468
+ if ( $new_fields ) {
469
+ $new_forms['updated'] = $exists->ID;
470
+
471
+ // update form
472
+ $formdata['ID'] = $exists->ID;
473
+
474
+ // update to need status if form is already mapped
475
+ if ( $exists->post_status == 'mapped' )
476
+ $formdata['status'] = 'needs_update';
477
+
478
+ // echo '<pre>'; print_r( $formdata ); echo '</pre>'; exit;
479
+
480
+ $result = $this->save_form( $formdata );
481
+ }
482
+ }
483
+ }
484
+ }
485
+ }
486
+ }
487
+
488
+ // echo '<pre>'; print_r( $found_forms ); echo '</pre>'; exit;
489
+
490
+ return ! empty( $new_forms ) ? $new_forms : array();
491
+ }
492
+
493
+ /**
494
+ * Get source forms.
495
+ *
496
+ * @param string
497
+ * @return array
498
+ */
499
+ public function get_source_forms( $source = '' ) {
500
+ $source = ! empty( $source ) && in_array( $source, array_keys( $this->sources ) ) ? $source : '';
501
+ $forms = array();
502
+
503
+ $restricted_fields = apply_filters( "iub_{$source}_restricted_fields", array(
504
+ 'submit',
505
+ 'file',
506
+ 'quiz'
507
+ ) );
508
+
509
+ switch ( $source ) {
510
+ case 'wpforms' :
511
+ $args = array(
512
+ 'post_type' => 'wpforms',
513
+ 'no_found_rows' => true,
514
+ 'nopaging' => true,
515
+ );
516
+ $posts = get_posts( $args );
517
+
518
+ // echo '<pre>'; print_r( $posts ); echo '</pre>'; exit;
519
+
520
+ if ( ! empty( $posts ) ) {
521
+ foreach ( $posts as $post ) {
522
+ // get form data
523
+ $formdata = array(
524
+ 'object_type' => 'post', // object type where the form data is stored
525
+ 'object_id' => $post->ID, // unique object id
526
+ 'form_source' => $source, // source slug
527
+ 'form_title' => $post->post_title, // form title
528
+ 'form_date' => $post->post_modified, // form last modified date
529
+ 'form_fields' => array() // form field names array
530
+ );
531
+
532
+ $input_fields = array(
533
+ 'text',
534
+ 'textarea',
535
+ 'select',
536
+ 'radio',
537
+ 'checkbox',
538
+ 'gdpr-checkbox',
539
+ 'email',
540
+ 'address',
541
+ 'url',
542
+ 'name',
543
+ 'hidden',
544
+ 'date-time',
545
+ 'phone',
546
+ 'number',
547
+ );
548
+
549
+ $fields_raw = function_exists( 'wpforms_get_form_fields' ) ? wpforms_get_form_fields( $post->ID ) : false;
550
+
551
+ // echo '<pre>'; print_r( $fields_raw ); echo '</pre>'; exit;
552
+
553
+ if ( ! empty( $fields_raw ) ) {
554
+ foreach ( $fields_raw as $index => $field ) {
555
+ // specific field types only
556
+ if ( ! empty( $field['type'] ) && in_array( $field['type'], $input_fields ) ) {
557
+ switch ( $field['type'] ) {
558
+ case 'name' :
559
+ if ( ! empty( $field['format'] ) ) {
560
+ switch ( $field['format'] ) {
561
+ case 'first-last' :
562
+ $formdata['form_fields'][] = array(
563
+ 'id' => $field['id'],
564
+ 'name' => 'wpforms[fields][' . $index . '][first]',
565
+ 'type' => $field['type'],
566
+ 'label' => __( 'First name', 'iubenda' )
567
+ );
568
+ $formdata['form_fields'][] = array(
569
+ 'id' => $field['id'],
570
+ 'name' => 'wpforms[fields][' . $index . '][last]',
571
+ 'type' => $field['type'],
572
+ 'label' => __( 'Last name', 'iubenda' )
573
+ );
574
+ break;
575
+ case 'first-middle-last' :
576
+ $formdata['form_fields'][] = array(
577
+ 'id' => $field['id'],
578
+ 'name' => 'wpforms[fields][' . $index . '][first]',
579
+ 'type' => $field['type'],
580
+ 'label' => __( 'First name', 'iubenda' )
581
+ );
582
+ $formdata['form_fields'][] = array(
583
+ 'id' => $field['id'],
584
+ 'name' => 'wpforms[fields][' . $index . '][middle]',
585
+ 'type' => $field['type'],
586
+ 'label' => __( 'Middle name', 'iubenda' )
587
+ );
588
+ $formdata['form_fields'][] = array(
589
+ 'id' => $field['id'],
590
+ 'name' => 'wpforms[fields][' . $index . '][last]',
591
+ 'type' => $field['type'],
592
+ 'label' => __( 'Last name', 'iubenda' )
593
+ );
594
+ break;
595
+ default :
596
+ $formdata['form_fields'][] = array(
597
+ 'id' => $field['id'],
598
+ 'name' => 'wpforms[fields][' . $index . ']',
599
+ 'type' => $field['type'],
600
+ 'label' => $field['label']
601
+ );
602
+ break;
603
+ }
604
+ } else {
605
+ $formdata['form_fields'][] = array(
606
+ 'id' => $field['id'],
607
+ 'name' => 'wpforms[fields][' . $index . ']',
608
+ 'type' => $field['type'],
609
+ 'label' => $field['label']
610
+ );
611
+ }
612
+ break;
613
+ // fix multiple choice checkbox
614
+ case 'checkbox' :
615
+ $formdata['form_fields'][] = array(
616
+ 'id' => $field['id'],
617
+ 'name' => 'wpforms[fields][' . $index . '][]',
618
+ 'type' => $field['type'],
619
+ 'label' => $field['label']
620
+ );
621
+ break;
622
+ default :
623
+ $formdata['form_fields'][] = array(
624
+ 'id' => $field['id'],
625
+ 'name' => 'wpforms[fields][' . $index . ']',
626
+ 'type' => $field['type'],
627
+ 'label' => $field['label']
628
+ );
629
+ }
630
+
631
+ }
632
+ }
633
+ }
634
+
635
+ $forms[] = $formdata;
636
+ }
637
+
638
+ // echo '<pre>'; print_r( $forms ); echo '</pre>'; exit;
639
+ }
640
+
641
+ break;
642
+
643
+ case 'wpcf7' :
644
+ $args = array(
645
+ 'post_type' => 'wpcf7_contact_form',
646
+ 'posts_per_page' => -1
647
+ );
648
+ $posts = get_posts( $args );
649
+
650
+ if ( ! empty( $posts ) ) {
651
+ foreach ( $posts as $post ) {
652
+ // get form data
653
+ $contact_form = class_exists( 'WPCF7_ContactForm' ) ? WPCF7_ContactForm::get_instance( $post->ID ) : false;
654
+
655
+ if ( ! empty( $contact_form ) ) {
656
+ $formdata = array(
657
+ 'object_type' => 'post', // object type where the form data is stored
658
+ 'object_id' => $post->ID, // unique object id
659
+ 'form_source' => $source, // source slug
660
+ 'form_title' => $post->post_title, // form title
661
+ 'form_date' => $post->post_modified, // form last modified date
662
+ 'form_fields' => array() // form field names array
663
+ );
664
+
665
+ $fields_raw = $contact_form->scan_form_tags();
666
+
667
+ // echo '<pre>'; print_r( $fields_raw ); echo '</pre>'; exit;
668
+
669
+ if ( ! empty( $fields_raw ) ) {
670
+ foreach ( $fields_raw as $field ) {
671
+ // specific field types only
672
+ if ( ! empty( $field['basetype'] ) && ! in_array( $field['basetype'], $restricted_fields ) ) {
673
+ $formdata['form_fields'][] = $field['name'];
674
+ }
675
+ }
676
+ }
677
+
678
+ $forms[] = $formdata;
679
+ }
680
+
681
+ // echo '<pre>'; print_r( $contact_form ); echo '</pre>'; exit;
682
+ }
683
+ }
684
+
685
+ break;
686
+
687
+ case 'woocommerce' :
688
+ $checkout_form = '';
689
+
690
+ ob_start();
691
+
692
+ // Ensure gateways and shipping methods are loaded early.
693
+ WC()->payment_gateways();
694
+ WC()->shipping();
695
+
696
+ /*
697
+ * First lets start the session. You cant use here WC_Session directly
698
+ * because it's an abstract class. But you can use WC_Session_Handler which
699
+ * extends WC_Session
700
+ */
701
+ WC()->session = new WC_Session_Handler;
702
+
703
+ /*
704
+ * Next lets create a customer so we can access checkout fields
705
+ * If you will check a constructor for WC_Customer class you will see
706
+ * that if you will not provide user to create customer it will use some
707
+ * default one. Magic.
708
+ */
709
+ WC()->customer = new WC_Customer;
710
+
711
+ // Create a cart contents
712
+ WC()->cart = new WC_Cart;
713
+
714
+ // Create an abstract order
715
+ WC()->order = new WC_Order;
716
+
717
+ wc_get_template(
718
+ 'checkout/form-checkout.php', array(
719
+ 'checkout' => WC()->checkout()
720
+ )
721
+ );
722
+
723
+ wc_get_template(
724
+ 'checkout/form-pay.php', array(
725
+ 'order' => WC()->order
726
+ )
727
+ );
728
+
729
+ $checkout_form = ob_get_contents();
730
+ ob_end_clean();
731
+
732
+ if ( ! empty( $checkout_form ) ) {
733
+ $formdata = array(
734
+ 'object_type' => 'custom', // object type where the form data is stored
735
+ 'object_id' => 0, // unique object id
736
+ 'form_source' => $source, // source slug
737
+ 'form_title' => $this->sources[$source], // form title
738
+ 'form_date' => current_time( 'mysql' ), // form last modified date
739
+ 'form_fields' => array() // form field names array
740
+ );
741
+
742
+ $input_fields = array(
743
+ 'input',
744
+ 'textarea',
745
+ 'select'
746
+ );
747
+
748
+ // DOMDoc parser
749
+ if ( iubenda()->options['cs']['parser_engine'] == 'new' ) {
750
+ libxml_use_internal_errors( true );
751
+
752
+ $document = new DOMDocument();
753
+
754
+ // set document arguments
755
+ $document->formatOutput = true;
756
+ $document->preserveWhiteSpace = false;
757
+
758
+ // load HTML
759
+ $document->loadHTML( $checkout_form );
760
+
761
+ // search for nodes
762
+ foreach ( $input_fields as $input_field ) {
763
+ $fields_raw = $document->getElementsByTagName( $input_field );
764
+
765
+ if ( ! empty( $fields_raw ) && is_object( $fields_raw ) ) {
766
+ foreach ( $fields_raw as $field ) {
767
+ $field_name = $field->getAttribute( 'name' );
768
+ $field_type = $field->getAttribute( 'type' );
769
+
770
+ // exclude submit
771
+ if ( ! empty( $field_type ) && ! in_array( $field_type, array( 'submit', 'hidden' ) ) )
772
+ $formdata['form_fields'][] = $field->getAttribute( 'name' );
773
+ }
774
+ }
775
+ }
776
+
777
+ $forms[] = $formdata;
778
+
779
+ libxml_use_internal_errors( false );
780
+
781
+ // Simple HTML Dom parser
782
+ } else {
783
+ $html = str_get_html( $checkout_form, $lowercase = true, $force_tags_closed = true, $strip = false );
784
+
785
+ if ( is_object( $html ) ) {
786
+ // search for nodes
787
+ foreach ( $input_fields as $input_field ) {
788
+ $fields_raw = $html->find( $input_field );
789
+
790
+ if ( is_array( $fields_raw ) ) {
791
+ foreach ( $fields_raw as $field ) {
792
+ $field_name = $field->name;
793
+ $field_type = $field->type;
794
+
795
+ // exclude submit
796
+ if ( ! empty( $field_type ) && ! in_array( $field_type, array( 'submit', 'hidden' ) ) )
797
+ $formdata['form_fields'][] = $field->getAttribute( 'name' );
798
+ }
799
+ }
800
+ }
801
+
802
+ $forms[] = $formdata;
803
+
804
+ }
805
+ }
806
+
807
+ }
808
+
809
+ /*
810
+ echo '<pre>';
811
+ print_r( $checkout_form );
812
+ echo '</pre>';
813
+ exit;
814
+ */
815
+ break;
816
+
817
+ case 'wp_comment_form' :
818
+ $comment_form = '';
819
+
820
+ // get comment form for logged out user
821
+ $current_user_id = get_current_user_id();
822
+
823
+ // get first post
824
+ $post_args = array(
825
+ 'numberposts' => 1,
826
+ 'orderby' => 'ID',
827
+ 'order' => 'ASC',
828
+ 'fields' => 'ids'
829
+ );
830
+
831
+ $posts = get_posts( $post_args );
832
+
833
+ // get comment form
834
+ if ( ! empty( $posts ) ) {
835
+ wp_set_current_user( 0 );
836
+
837
+ ob_start();
838
+
839
+ comment_form( array(), $posts[0] );
840
+
841
+ $comment_form = ob_get_contents();
842
+ ob_end_clean();
843
+
844
+ wp_set_current_user( $current_user_id );
845
+ }
846
+
847
+ if ( ! empty( $comment_form ) ) {
848
+ $formdata = array(
849
+ 'object_type' => 'custom', // object type where the form data is stored
850
+ 'object_id' => 0, // unique object id
851
+ 'form_source' => $source, // source slug
852
+ 'form_title' => $this->sources[$source], // form title
853
+ 'form_date' => current_time( 'mysql' ), // form last modified date
854
+ 'form_fields' => array() // form field names array
855
+ );
856
+
857
+ $input_fields = array(
858
+ 'input',
859
+ 'textarea',
860
+ 'select'
861
+ );
862
+
863
+ // DOMDoc parser
864
+ if ( iubenda()->options['cs']['parser_engine'] == 'new' ) {
865
+ libxml_use_internal_errors( true );
866
+
867
+ $document = new DOMDocument();
868
+
869
+ // set document arguments
870
+ $document->formatOutput = true;
871
+ $document->preserveWhiteSpace = false;
872
+
873
+ // load HTML
874
+ $document->loadHTML( $comment_form );
875
+
876
+ // search for nodes
877
+ foreach ( $input_fields as $input_field ) {
878
+ $fields_raw = $document->getElementsByTagName( $input_field );
879
+
880
+ if ( ! empty( $fields_raw ) && is_object( $fields_raw ) ) {
881
+ foreach ( $fields_raw as $field ) {
882
+ $field_name = $field->getAttribute( 'name' );
883
+ $field_type = $field->getAttribute( 'type' );
884
+
885
+ // exclude submit
886
+ if ( ! empty( $field_type ) && ! in_array( $field_type, array( 'submit' ) ) )
887
+ $formdata['form_fields'][] = $field->getAttribute( 'name' );
888
+ }
889
+ }
890
+ }
891
+
892
+ $forms[] = $formdata;
893
+
894
+ libxml_use_internal_errors( false );
895
+
896
+ // Simple HTML Dom parser
897
+ } else {
898
+ $html = str_get_html( $comment_form, $lowercase = true, $force_tags_closed = true, $strip = false );
899
+
900
+ if ( is_object( $html ) ) {
901
+ // search for nodes
902
+ foreach ( $input_fields as $input_field ) {
903
+ $fields_raw = $html->find( $input_field );
904
+
905
+ if ( is_array( $fields_raw ) ) {
906
+ foreach ( $fields_raw as $field ) {
907
+ $field_name = $field->name;
908
+ $field_type = $field->type;
909
+
910
+ // exclude submit
911
+ if ( ! empty( $field_type ) && ! in_array( $field_type, array( 'submit' ) ) )
912
+ $formdata['form_fields'][] = $field->getAttribute( 'name' );
913
+ }
914
+ }
915
+ }
916
+
917
+ $forms[] = $formdata;
918
+
919
+ }
920
+ }
921
+ }
922
+
923
+ break;
924
+ }
925
+
926
+ return $forms;
927
+ }
928
+
929
+ /**
930
+ * Get Post object by post_meta query
931
+ *
932
+ * @return array
933
+ */
934
+ public function get_form_by_object_id( $args = array() ) {
935
+ // parse incoming $args into an array and merge it with $defaults
936
+ $args = wp_parse_args( $args );
937
+
938
+ // grab page
939
+ $args = array(
940
+ 'meta_query' => array(
941
+ array(
942
+ 'key' => '_iub_object_id',
943
+ 'value' => $args['id'],
944
+ ),
945
+ array(
946
+ 'key' => '_iub_form_source',
947
+ 'value' => $args['source'],
948
+ )
949
+ ),
950
+ 'post_type' => 'iubenda_form',
951
+ 'post_status' => 'any',
952
+ 'posts_per_page' => '1',
953
+ 'fields' => 'ids'
954
+ );
955
+
956
+ // run query
957
+ $posts = get_posts( $args );
958
+
959
+ // check result
960
+ if ( ! $posts || is_wp_error( $posts ) )
961
+ return false;
962
+
963
+ $form = $this->get_form( $posts[0] );
964
+
965
+ // kick back results
966
+ return $form;
967
+ }
968
+
969
+ }
trunk/includes/settings.php ADDED
@@ -0,0 +1,1811 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * iubenda_Settings class.
8
+ *
9
+ * @class Post_Views_Counter_Settings
10
+ */
11
+ class iubenda_Settings {
12
+
13
+ public $tabs = array();
14
+ public $action = '';
15
+ public $links = array();
16
+ public $notice_types = array( 'error', 'success', 'notice' );
17
+ public $subject_fields = array();
18
+
19
+ public function __construct() {
20
+ // actions
21
+ add_action( 'after_setup_theme', array( $this, 'load_defaults' ) );
22
+ add_action( 'admin_init', array( $this, 'register_options' ) );
23
+ add_action( 'admin_init', array( $this, 'update_plugin' ), 9 );
24
+ add_action( 'admin_init', array( $this, 'admin_page_redirect' ), 20 );
25
+ add_action( 'admin_init', array( $this, 'process_actions' ), 20 );
26
+ add_action( 'admin_init', array( $this, 'maybe_show_notice' ) );
27
+ add_action( 'admin_menu', array( $this, 'admin_menu_options' ) );
28
+ add_action( 'admin_notices', array( $this, 'settings_errors' ) );
29
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
30
+ add_action( 'admin_print_styles', array( $this, 'admin_print_styles' ) );
31
+ // add_action( 'admin_footer-options-discussion.php', array( $this, 'admin_footer' ) );
32
+ add_action( 'wp_ajax_iubenda_dismiss_notice', array( $this, 'dismiss_notice' ) );
33
+
34
+ // filters
35
+ add_filter( 'submenu_file', array( $this, 'submenu_file' ), 10, 2 );
36
+ }
37
+
38
+ /**
39
+ * Load default settings.
40
+ */
41
+ public function load_defaults() {
42
+ $this->subject_fields = array(
43
+ 'id' => __( 'string', 'iubenda' ),
44
+ 'email' => __( 'string', 'iubenda' ),
45
+ 'first_name' => __( 'string', 'iubenda' ),
46
+ 'last_name' => __( 'string', 'iubenda' ),
47
+ 'full_name' => __( 'string', 'iubenda' ),
48
+ // 'verified' => __( 'boolean', 'iubenda' ),
49
+ );
50
+
51
+ $this->legal_notices = array(
52
+ 'privacy_policy',
53
+ 'cookie_policy',
54
+ 'terms'
55
+ );
56
+
57
+ $this->tabs = array(
58
+ 'cs' => array(
59
+ 'name' => __( 'Cookie Solution', 'iubenda' ),
60
+ 'key' => 'iubenda_cookie_law_solution',
61
+ 'submit' => 'save_iubenda_options',
62
+ 'reset' => 'reset_iubenda_options'
63
+ ),
64
+ 'cons' => array(
65
+ 'name' => __( 'Consent Solution', 'iubenda' ),
66
+ 'key' => 'iubenda_consent_solution',
67
+ 'submit' => 'save_consent_options',
68
+ 'reset' => 'reset_consent_options'
69
+ )
70
+ );
71
+
72
+ $this->tag_types = array(
73
+ 0 => __( 'Not set', 'iubenda' ),
74
+ 1 => __( 'Strictly necessary', 'iubenda' ),
75
+ 2 => __( 'Basic interactions & functionalities', 'iubenda' ),
76
+ 3 => __( 'Experience enhancement', 'iubenda' ),
77
+ 4 => __( 'Analytics', 'iubenda' ),
78
+ 5 => __( 'Targeting & Advertising', 'iubenda' )
79
+ );
80
+
81
+ $links = array(
82
+ 'en' => array(
83
+ 'iab' => 'https://www.iubenda.com/en/help/7440-enable-preference-management-iab-framework',
84
+ 'guide' => 'https://www.iubenda.com/en/cookie-solution',
85
+ 'plugin_page' => 'https://www.iubenda.com/en/help/posts/1215',
86
+ 'generating_code' => 'https://www.iubenda.com/en/help/1177-cookie-solution-getting-started',
87
+ 'support_forum' => 'https://support.iubenda.com/support/home',
88
+ 'documentation' => 'https://www.iubenda.com/en/help/posts/1215'
89
+ ),
90
+ 'it' => array(
91
+ 'iab' => 'https://www.iubenda.com/en/help/7440-enable-preference-management-iab-framework',
92
+ 'guide' => 'https://www.iubenda.com/it/cookie-solution',
93
+ 'plugin_page' => 'https://www.iubenda.com/it/help/posts/810',
94
+ 'generating_code' => 'https://www.iubenda.com/it/help/680-introduzione-cookie-solution',
95
+ 'support_forum' => 'https://support.iubenda.com/support/home',
96
+ 'documentation' => 'https://www.iubenda.com/it/help/posts/810',
97
+ )
98
+ );
99
+
100
+ $locale = explode( '_', get_locale() );
101
+ $locale_code = $locale[0];
102
+
103
+ // assign links
104
+ $this->links = in_array( $locale_code, array_keys( $links ) ) ? $links[$locale_code] : $links['en'];
105
+
106
+ // handle actions
107
+ if ( ! empty( $_POST['save'] ) ) {
108
+ // update item action
109
+ $this->action = 'save';
110
+ } else {
111
+ $this->action = isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] ? esc_attr( $_REQUEST['action'] ) : '';
112
+ $this->action = isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] ? esc_attr( $_REQUEST['action2'] ) : $this->action;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Register plugin options.
118
+ *
119
+ * @return void
120
+ */
121
+ public function register_options() {
122
+ register_setting( 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution', array( $this, 'save_cookie_law_options' ) );
123
+
124
+ add_settings_section( 'iubenda_cookie_law_solution', '', '', 'iubenda_cookie_law_solution' );
125
+ add_settings_field( 'iub_code', __( 'Code', 'iubenda' ), array( $this, 'iub_code' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
126
+ add_settings_field( 'iub_amp_support', __( 'Google AMP', 'iubenda' ), array( $this, 'iub_amp_support' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
127
+ add_settings_field( 'iub_parse', __( 'Script blocking', 'iubenda' ), array( $this, 'iub_parse' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
128
+ add_settings_field( 'iub_custom_scripts', __( 'Custom scripts', 'iubenda' ), array( $this, 'iub_custom_scripts' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
129
+ add_settings_field( 'iub_ctype', __( 'Content type', 'iubenda' ), array( $this, 'iub_ctype' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
130
+ add_settings_field( 'iub_output_feed', __( 'RSS feed', 'iubenda' ), array( $this, 'iub_output_feed' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
131
+ add_settings_field( 'iub_output_post', __( 'POST requests', 'iubenda' ), array( $this, 'iub_output_post' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
132
+ add_settings_field( 'iub_menu_position', __( 'Menu position', 'iubenda' ), array( $this, 'iub_menu_position' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
133
+ add_settings_field( 'iub_deactivation', __( 'Deactivation', 'iubenda' ), array( $this, 'iub_deactivation' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
134
+
135
+ // forms list
136
+ if ( ! in_array( $this->action, array( 'save', 'edit' ) ) ) {
137
+ register_setting( 'iubenda_consent_solution', 'iubenda_consent_solution', array( $this, 'save_consent_options' ) );
138
+ add_settings_section( 'iubenda_consent_solution', __( 'Forms', 'iubenda' ), '', 'iubenda_consent_solution' );
139
+ add_settings_field( 'iub_public_api_key', __( 'Public Api Key', 'iubenda' ), array( $this, 'iub_public_api_key' ), 'iubenda_consent_solution', 'iubenda_consent_solution' );
140
+ // only if api key is given
141
+ if ( ! empty( iubenda()->options['cons']['public_api_key'] ) )
142
+ add_settings_section( 'iubenda_consent_forms', __( 'Field Mapping', 'iubenda' ), array( $this, 'iubenda_consent_forms' ), 'iubenda_consent_solution' );
143
+ // single form
144
+ } else {
145
+ register_setting( 'iubenda_consent_solution', 'iubenda_consent_forms' );
146
+ add_settings_section( 'iubenda_consent_form', __( 'Field Mapping', 'iubenda' ), array( $this, 'iubenda_consent_form' ), 'iubenda_consent_solution' );
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Display errors and notices.
152
+ *
153
+ * @global string $pagenow
154
+ */
155
+ public function settings_errors() {
156
+ global $pagenow;
157
+
158
+ // force display notices in top menu settings page
159
+ if ( $pagenow == 'options-general.php' )
160
+ return;
161
+
162
+ $tab_key = ! empty( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'cs';
163
+
164
+ settings_errors( "{$tab_key}_settings_errors" );
165
+ }
166
+
167
+ /**
168
+ * Add submenu.
169
+ *
170
+ * @return void
171
+ */
172
+ public function admin_menu_options() {
173
+ if ( iubenda()->options['cs']['menu_position'] === 'submenu' ) {
174
+ // sub menu
175
+ add_submenu_page(
176
+ 'options-general.php', 'iubenda', 'iubenda', apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ), 'iubenda', array( $this, 'options_page' )
177
+ );
178
+ } else {
179
+ // top menu
180
+ add_menu_page(
181
+ 'iubenda', 'iubenda', apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ), 'iubenda', array( $this, 'options_page' ), 'none'
182
+ );
183
+ add_submenu_page( 'iubenda', __( 'Cookie Solution', 'iubenda' ), __( 'Cookie Solution', 'iubenda' ), apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ), 'iubenda', array( $this, 'options_page' ) );
184
+ add_submenu_page( 'iubenda', __( 'Consent Solution', 'iubenda' ), __( 'Consent Solution', 'iubenda' ), apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ), 'iubenda&tab=cons', array( $this, 'options_page' ) );
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Load admin scripts and styles.
190
+ *
191
+ * @param string $page
192
+ * @return void
193
+ */
194
+ public function admin_enqueue_scripts( $page ) {
195
+ wp_enqueue_style( 'iubenda-admin', IUBENDA_PLUGIN_URL . '/css/admin.css' );
196
+
197
+ if ( ! in_array( $page, array( 'toplevel_page_iubenda', 'settings_page_iubenda' ) ) )
198
+ return;
199
+
200
+ wp_enqueue_script(
201
+ 'iubenda-admin', IUBENDA_PLUGIN_URL . '/js/admin.js', array( 'jquery' )
202
+ );
203
+
204
+ $args = array(
205
+ 'formId' => 0,
206
+ 'deleteForm' => __( 'Are you sure you want to delete this form?', 'iubenda' )
207
+ );
208
+
209
+ // get form data on edit screen
210
+ if ( in_array( $this->action, array( 'edit' ) ) ) {
211
+ $form_id = ! empty( $_GET['form_id'] ) ? absint( $_GET['form_id'] ) : 0;
212
+ $form = ! empty( $form_id ) ? iubenda()->forms->get_form( $form_id ) : array();
213
+
214
+ $args['formId'] = $form_id;
215
+ }
216
+
217
+ wp_localize_script(
218
+ 'iubenda-admin',
219
+ 'iubAdminArgs',
220
+ json_encode( $args )
221
+ );
222
+ }
223
+
224
+ /**
225
+ * Load admin style inline, for menu icon only.
226
+ *
227
+ * @return mixed
228
+ */
229
+ public function admin_print_styles() {
230
+ echo '
231
+ <style>
232
+ a.toplevel_page_iubenda .wp-menu-image {
233
+ background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj48c3ZnIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAyMzIgNTAzIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zOnNlcmlmPSJodHRwOi8vd3d3LnNlcmlmLmNvbS8iIHN0eWxlPSJmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6MS40MTQyMTsiPiAgICA8ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDEzNi4yNDcsMjY4LjgzMSkiPiAgICAgICAgPHBhdGggZD0iTTAsLTM1LjgxTC0zNi4zLDAuNDg5TC0zNi4zLDE0MC45NzhMMCwxNDAuOTc4TDAsLTM1LjgxWk0tMjAuOTM4LC0xMjkuODAyQy02LjI4NywtMTI5LjgwMiA1LjU4NywtMTQxLjU2NSA1LjU4NywtMTU2LjA2QzUuNTg3LC0xNzAuNTU2IC02LjI4NywtMTgyLjMwOCAtMjAuOTM4LC0xODIuMzA4Qy0zNS42LC0xODIuMzA4IC00Ny40NzQsLTE3MC41NTYgLTQ3LjQ3NCwtMTU2LjA2Qy00Ny40NzQsLTE0MS41NjUgLTM1LjYsLTEyOS44MDIgLTIwLjkzOCwtMTI5LjgwMk04OS4zNiwtMTU0LjQxNkM4OS4zNiwtMTI3LjgyNSA3OS41NzUsLTEwMy40OTkgNjMuMjY5LC04NC42NzJMODYuNjk0LDIyNi42MjhMLTEyMi43MjgsMjI2LjYyOEwtMTAwLjAyNCwtNzkuMjI5Qy0xMTkuMzUxLC05OC42NjggLTEzMS4yNDcsLTEyNS4xNTkgLTEzMS4yNDcsLTE1NC40MTZDLTEzMS4yNDcsLTIxNC4wODYgLTgxLjg3NCwtMjYyLjQzOCAtMjAuOTM4LC0yNjIuNDM4QzM5Ljk5OSwtMjYyLjQzOCA4OS4zNiwtMjE0LjA4NiA4OS4zNiwtMTU0LjQxNiIgc3R5bGU9ImZpbGw6d2hpdGU7ZmlsbC1ydWxlOm5vbnplcm87Ii8+ICAgIDwvZz48L3N2Zz4=);
234
+ background-position: center center;
235
+ background-repeat: no-repeat;
236
+ background-size: 7px auto;
237
+ }
238
+ </style>
239
+ ';
240
+ }
241
+
242
+ /**
243
+ * Highlight comments cookies opt-in checkbox option.
244
+ *
245
+ * @return mixed
246
+ */
247
+ public function admin_footer() {
248
+ if ( ! empty( $_GET['iub-highlight'] ) ) {
249
+ echo '
250
+ <style>
251
+ label[for=show_comments_cookies_opt_in] {
252
+ border: 1px dashed red;
253
+ }
254
+ </style>
255
+ ';
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Redirect to the correct urle after switching menu position.
261
+ *
262
+ * @global string $pagenow
263
+ * @return void
264
+ */
265
+ public function admin_page_redirect() {
266
+ if ( ! empty( $_GET['settings-updated'] ) && ! empty( $_GET['page'] ) && in_array( $_GET['page'], array( 'iubenda' ) ) ) {
267
+ global $pagenow;
268
+
269
+ // no redirect by default
270
+ $redirect_to = false;
271
+
272
+ if ( iubenda()->options['cs']['menu_position'] === 'submenu' && $pagenow === 'admin.php' ) {
273
+ // sub menu
274
+ $redirect_to = admin_url( 'options-general.php?page=iubenda' );
275
+ } elseif ( iubenda()->options['cs']['menu_position'] === 'topmenu' && $pagenow === 'options-general.php' ) {
276
+ // top menu
277
+ $redirect_to = admin_url( 'admin.php?page=iubenda' );
278
+ }
279
+
280
+ if ( $redirect_to ) {
281
+ // make sure it's current host location
282
+ wp_safe_redirect( add_query_arg( 'settings-updated', true, $redirect_to ) );
283
+ exit;
284
+ }
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Perform show notice on plugin installation/upgrade.
290
+ *
291
+ * @return void
292
+ */
293
+ public function maybe_show_notice() {
294
+ if ( ! current_user_can( 'install_plugins' ) )
295
+ return;
296
+
297
+ $current_update = 1;
298
+ $activation = (array) get_option( 'iubenda_activation_data', iubenda()->activation );
299
+
300
+ // delete_option( 'iubenda_activation_data' );
301
+ // echo '<pre>'; print_r( $activation ); echo '</pre>'; exit;
302
+
303
+ // get current time
304
+ $current_time = time();
305
+
306
+ if ( $activation['update_version'] < $current_update ) {
307
+ // check version, if update ver is lower than plugin ver, set update notice to true
308
+ $activation = array_merge( $activation, array( 'update_version' => $current_update, 'update_notice' => true ) );
309
+
310
+ // set activation date if not set
311
+ if ( $activation['update_date'] == false )
312
+ $activation = array_merge( $activation, array( 'update_date' => $current_time ) );
313
+
314
+ update_option( 'iubenda_activation_data', $activation );
315
+ }
316
+
317
+ // display current version notice
318
+ if ( $activation['update_notice'] === true ) {
319
+ // include notice js, only if needed
320
+ add_action( 'admin_print_scripts', array( $this, 'admin_inline_js' ), 999 );
321
+
322
+ // get activation date
323
+ $activation_date = $activation['update_date'];
324
+
325
+ // set delay in seconds
326
+ $delay = WEEK_IN_SECONDS * 2;
327
+
328
+ if ( (int) $activation['update_delay_date'] === 0 ) {
329
+ if ( $activation_date + $delay > $current_time )
330
+ $activation['update_delay_date'] = $activation_date + $delay;
331
+ else
332
+ $activation['update_delay_date'] = $current_time;
333
+
334
+ update_option( 'iubenda_activation_data', $activation );
335
+ }
336
+
337
+ if ( ( ! empty( $activation['update_delay_date'] ) ? (int) $activation['update_delay_date'] : $current_time ) <= $current_time ) {
338
+ // add notice
339
+ add_action( 'admin_notices', array( $this, 'show_notice' ) );
340
+ }
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Display admin notices at iubenda settings.
346
+ */
347
+ public function show_notice() {
348
+ global $pagenow;
349
+
350
+ $display = true;
351
+ /*
352
+ $page = isset( $_GET['page'] ) ? esc_attr( $_GET['page'] ) : '';
353
+
354
+ if ( iubenda()->options['cs']['menu_position'] === 'submenu' && $page === 'iubenda' ) {
355
+ $display = true;
356
+ } elseif ( iubenda()->options['cs']['menu_position'] === 'topmenu' && $page === 'iubenda' ) {
357
+ $display = true;
358
+ }
359
+ */
360
+ ?>
361
+ <?php if ( $display ) { ?>
362
+ <div class="iubenda-notice notice is-dismissible">
363
+ <div>
364
+ <p class="step-1">
365
+ <span class="notice-question"><?php _e( 'Enjoying the iubenda Cookie & Consent Solution Plugin?', 'iubenda' ); ?></span>
366
+ <span class="notice-reply">
367
+ <a href="#" class="reply-yes"><?php _e( 'Yes', 'iubenda' ); ?></a>
368
+ <a href="#" class="reply-no"><?php _e( 'No', 'iubenda' ); ?></a>
369
+ </span>
370
+ </p>
371
+ <p class="step-2 step-yes">
372
+ <span class="notice-question"><?php _e( "Whew, what a relief!? We've worked countless hours to make this plugin as useful as possible - so we're pretty happy that you're enjoying it. While you here, would you mind leaving us a 5 star rating? It would really help us out.", 'iubenda' ); ?></span>
373
+ <span class="notice-reply">
374
+ <a href="https://wordpress.org/support/plugin/iubenda-cookie-law-solution/reviews/?filter=5" target="_blank" class="reply-yes"><?php _e( 'Sure!', 'iubenda' ); ?></a>
375
+ <a href="javascript:void(0)" class="reply-no"><?php _e( 'No thanks', 'iubenda' ); ?></a>
376
+ </span>
377
+ </p>
378
+ <p class="step-2 step-no">
379
+ <span class="notice-question"><?php _e( "We're sorry to hear that. Would you mind giving us some feedback?", 'iubenda' ); ?></span>
380
+ <span class="notice-reply">
381
+ <a href="https://iubenda.typeform.com/to/BXuSMZ" target="_blank" class="reply-yes"><?php _e( 'Ok sure!', 'iubenda' ); ?></a>
382
+ <a href="javascript:void(0)" class="reply-no"><?php _e( 'No thanks', 'iubenda' ); ?></a>
383
+ </span>
384
+ </p>
385
+ </div>
386
+ </div>
387
+ <?php } ?>
388
+ <?php
389
+ }
390
+
391
+ /**
392
+ * Print admin scripts.
393
+ *
394
+ * @return void
395
+ */
396
+ public function admin_inline_js() {
397
+ if ( ! current_user_can( 'install_plugins' ) )
398
+ return;
399
+
400
+ $delay = MONTH_IN_SECONDS * 6;
401
+ ?>
402
+ <script type="text/javascript">
403
+ ( function ( $ ) {
404
+ $( document ).ready( function () {
405
+ // step 1
406
+ $( '.iubenda-notice .step-1 a' ).on( 'click', function ( e ) {
407
+ e.preventDefault();
408
+
409
+ $( '.iubenda-notice .step-1' ).slideUp( 'fast' );
410
+
411
+ if ( $( e.target ).hasClass( 'reply-yes' ) ) {
412
+ $( '.iubenda-notice .step-2.step-yes' ).slideDown( 'fast' );
413
+ } else {
414
+ $( '.iubenda-notice .step-2.step-no' ).slideDown( 'fast' );
415
+ };
416
+ } );
417
+ // step 2
418
+ $( '.iubenda-notice.is-dismissible' ).on( 'click', '.notice-dismiss, .step-2 a', function ( e ) {
419
+ // console.log( $( e ) );
420
+
421
+ var delay = <?php echo $delay; ?>;
422
+
423
+ if ( $( e.target ).hasClass( 'reply-yes' ) ) {
424
+ delay = 0;
425
+ }
426
+
427
+ $.post( ajaxurl, {
428
+ action: 'iubenda_dismiss_notice',
429
+ delay: delay,
430
+ url: '<?php echo admin_url( 'admin-ajax.php' ); ?>',
431
+ iubenda_nonce: '<?php echo wp_create_nonce( 'iubenda_dismiss_notice' ); ?>'
432
+ } );
433
+
434
+ $( e.delegateTarget ).slideUp( 'fast' );
435
+ } );
436
+ } );
437
+ } )( jQuery );
438
+ </script>
439
+ <?php
440
+ }
441
+
442
+ /**
443
+ * Dismiss notice.
444
+ *
445
+ * @return void
446
+ */
447
+ public function dismiss_notice() {
448
+ $result = false;
449
+
450
+ if ( ! current_user_can( 'install_plugins' ) )
451
+ return $result;
452
+
453
+ $nonce = wp_verify_nonce( $_REQUEST['iubenda_nonce'], 'iubenda_dismiss_notice' );
454
+
455
+ if ( $nonce ) {
456
+ $delay = ! empty( $_REQUEST['delay'] ) ? absint( $_REQUEST['delay'] ) : 0;
457
+ $activation = (array) get_option( 'iubenda_activation_data', iubenda()->activation );
458
+
459
+ // delay notice
460
+ if ( $delay > 0 ) {
461
+ $activation = array_merge( $activation, array( 'update_delay_date' => time() + $delay ) );
462
+ // hide notice permanently
463
+ } else {
464
+ $activation = array_merge( $activation, array( 'update_delay_date' => 0, 'update_notice' => false ) );
465
+ }
466
+
467
+ // update activation options
468
+ $result = update_option( 'iubenda_activation_data', $activation );
469
+ }
470
+
471
+ echo json_encode( $result );
472
+ exit;
473
+ }
474
+
475
+ /**
476
+ * Plugin options migration for versions < 1.14.0
477
+ *
478
+ * @return void
479
+ */
480
+ public function update_plugin() {
481
+ if ( ! current_user_can( 'install_plugins' ) )
482
+ return;
483
+
484
+ $db_version = get_option( 'iubenda_cookie_law_version' );
485
+ $db_version = ! $db_version ? '1.13.0' : $db_version;
486
+
487
+ if ( $db_version != false ) {
488
+ if ( version_compare( $db_version, '1.14.0', '<' ) ) {
489
+ $options = array();
490
+
491
+ $old_new = array(
492
+ 'iubenda_parse' => 'parse',
493
+ 'skip_parsing' => 'skip_parsing',
494
+ 'iubenda_ctype' => 'ctype',
495
+ 'iubenda_parse' => 'parse',
496
+ 'parser_engine' => 'parser_engine',
497
+ 'iubenda_output_feed' => 'output_feed',
498
+ 'iubenda-code-default' => 'code_default',
499
+ 'default_skip_parsing' => '',
500
+ 'default_iubendactype' => '',
501
+ 'default_iubendaparse' => '',
502
+ 'default_parser_engine' => '',
503
+ 'iub_code' => '',
504
+ );
505
+
506
+ foreach ( $old_new as $old => $new ) {
507
+ if ( $new ) {
508
+ $options[$new] = get_option( $old );
509
+ }
510
+ delete_option( $old );
511
+ }
512
+
513
+ // multilang support
514
+ if ( ! empty( iubenda()->languages ) ) {
515
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
516
+ $code = get_option( 'iubenda-code-' . $lang_id );
517
+
518
+ if ( ! empty( $code ) ) {
519
+ $options['code_' . $lang_id] = $code;
520
+
521
+ delete_option( 'iubenda-code-' . $lang_id );
522
+ }
523
+ }
524
+ }
525
+
526
+ add_option( 'iubenda_cookie_law_solution', $options, '', 'no' );
527
+ add_option( 'iubenda_cookie_law_version', iubenda()->version, '', 'no' );
528
+ }
529
+ }
530
+ }
531
+
532
+ /**
533
+ * Load admin options page.
534
+ *
535
+ * @return void
536
+ */
537
+ public function options_page() {
538
+ global $pagenow;
539
+
540
+ if ( ! current_user_can( apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ) ) ) {
541
+ wp_die( __( "You don't have permission to access this page.", 'iubenda' ) );
542
+ }
543
+
544
+ $tab_key = ! empty( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'cs';
545
+
546
+ // get redirect url
547
+ if ( iubenda()->options['cs']['menu_position'] === 'submenu' && $pagenow === 'admin.php' ) {
548
+ // sub menu
549
+ $redirect_to = admin_url( 'options-general.php?page=iubenda&tab=' . $tab_key );
550
+ } else {
551
+ // top menu
552
+ $redirect_to = admin_url( 'admin.php?page=iubenda&tab=' . $tab_key );
553
+ }
554
+ ?>
555
+ <div class="wrap">
556
+
557
+ <div id="iubenda-header">
558
+ <?php
559
+ echo '
560
+ <a class="iubenda-link" href="http://iubenda.com" title="iubenda" title="_blank">
561
+ <img id="iubenda-logo" alt="iubenda logo" width="300" height="90" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNjM3LjggMjgzLjUiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDYzNy44IDI4My41OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHN0eWxlIHR5cGU9InRleHQvY3NzIj4uc3Qwe2ZpbGw6IzFDQzY5MTt9LnN0MXtmaWxsOiM1MTUyNTQ7fTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MCIgZD0iTTE3OC45LDk5LjljMCw4LjItMywxNS42LTgsMjEuNGw3LjIsOTUuNGgtNjQuMmw3LTkzLjhjLTUuOS02LTkuNi0xNC4xLTkuNi0yMy4xYzAtMTguMywxNS4xLTMzLjEsMzMuOC0zMy4xUzE3OC45LDgxLjYsMTc4LjksOTkuOSBNMTQ1LjEsMTA3LjRjNC41LDAsOC4xLTMuNiw4LjEtOC4xcy0zLjYtOC04LjEtOGMtNC41LDAtOC4xLDMuNi04LjEsOFMxNDAuNiwxMDcuNCwxNDUuMSwxMDcuNCBNMTUxLjUsMTM2LjJsLTExLjEsMTEuMXY0My4xaDExLjFWMTM2LjJ6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTI2NS40LDE3OC42Yy0yLjMsMS4yLTQuNywxLjgtNy4yLDEuOGMtMi44LDAtNS4zLTAuOC03LjQtMi40Yy0yLjEtMS42LTMuNS0zLjctNC4zLTYuMmMtMC44LTIuNS0xLjItNi4xLTEuMi0xMC44di0xOC4yYzAsMCwwLTAuOSwwLTIuOGMwLTAuNSwwLTIuOC0xLjUtMy41Yy0wLjItMC4xLTAuNi0wLjItMS4yLTAuM2MtMC40LDAtMC44LTAuNC0wLjgtMC44bDAtMi40YzAtMC41LDAuNC0wLjksMC44LTAuOWg5LjNjMS4zLDAsMi40LDEuMSwyLjQsMi40VjE0N2wwLDE1LjVjMCw0LjYsMC44LDcuNywyLjUsOS4xYzEuNiwxLjUsMy42LDIuMiw1LjksMi4yYzEuNiwwLDMuNC0wLjUsNS40LTEuNWMyLTEsNS4zLTIuOCw4LjEtNS42bDAtMi40bDAtMjIuMlYxNDBjMC0wLjUsMC0yLjgtMS40LTMuNWMtMC4yLTAuMS0wLjYtMC4yLTEuMS0wLjNjLTAuNC0wLjEtMC44LTAuNC0wLjgtMC44bDAtMi40YzAtMC41LDAuNC0wLjksMC45LTAuOWg5LjJjMS4zLDAsMi40LDEuMSwyLjQsMi40djhjMCwwLjEsMCwwLjEsMCwwLjJ2MTYuNmMwLDMuOCwwLDcuNCwwLDEwLjZjMCwwLjcsMCwxLjIsMCwxLjJjMCwwLjUtMC4xLDMuMSwxLjQsMy44YzAuMiwwLjEsMC42LDAuMiwxLjIsMC4zYzAuNCwwLDAuOCwwLjQsMC44LDAuOGwwLDIuNGMwLDAuNS0wLjQsMC44LTAuOSwwLjloLTkuMmMtMS4zLDAtMi40LTEuMS0yLjQtMi40bDAtNC41bDAtMi41QzI3MS45LDE3NC41LDI2Ny43LDE3Ny40LDI2NS40LDE3OC42Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTMwOS4yLDE3NmMxLjksMC45LDMuOSwxLjMsNiwxLjNjMy4yLDAsNi4zLTEuNyw5LTUuMmMyLjgtMy41LDQuMi04LjUsNC4yLTE1LjJjMC02LjEtMS40LTEwLjgtNC4yLTE0LjFjLTIuOC0zLjMtNi00LjktOS41LTQuOWMtMS45LDAtMy44LDAuNS01LjcsMS40Yy0xLjIsMC42LTIuOCwxLjgtNC43LDMuNGMtMC41LDAuNS0wLjgsMS4xLTAuOCwxLjhWMTcxYzAsMC43LDAuMywxLjQsMC44LDEuOEMzMDYsMTc0LjIsMzA3LjYsMTc1LjMsMzA5LjIsMTc2IE0yOTQuOCwxMThjMC0wLjUsMC0yLjctMS40LTMuNGMtMC4yLTAuMS0wLjMtMC4xLTAuNi0wLjJjLTAuNC0wLjEtMC42LTAuNC0wLjYtMC44bDAtMi4zYzAtMC41LDAuNC0wLjgsMC45LTAuOWgxLjhoNi41YzEuMywwLDIuMywxLDIuMywyLjNsMCwxMnYxNS40YzQuNy02LjQsOS44LTkuNiwxNS4zLTkuNmM1LDAsOS40LDIuMSwxMy4xLDYuM2MzLjcsNC4yLDUuNiw5LjksNS42LDE3LjJjMCw4LjUtMi45LDE1LjMtOC42LDIwLjVjLTQuOSw0LjQtMTAuNSw2LjctMTYuNSw2LjdjLTIuOCwwLTUuNy0wLjUtOC43LTEuNWMtMi41LTAuOS01LjEtMi4xLTcuNy0zLjdjLTAuOC0wLjUtMS4zLTEuNC0xLjMtMi40di00NmMwLTAuOSwwLTIsMC0zLjNMMjk0LjgsMTE4eiIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0zODkuMywxNzkuMWMtMC41LDAtMC45LTAuNC0wLjktMC45bDAtMi4zYzAtMC40LDAuMy0wLjgsMC43LTAuOGMwLjUtMC4xLDAuOC0wLjEsMS0wLjJjMS40LTAuNywxLjQtMi45LDEuNC0zLjR2LTIuN2MwLDAsMC01LjgsMC0xNy41YzAtMS45LDAtMy44LDAuMS01LjVsMC00LjZjMC0wLjUsMC0xLDAtMS41YzAtMC42LDAtMi44LTEuNC0zLjVjLTAuMS0wLjEtMC4zLTAuMS0wLjUtMC4yYy0wLjQtMC4xLTAuNi0wLjQtMC42LTAuOGwwLTIuM2MwLTAuNSwwLjQtMC44LDAuOS0wLjloOC4xYzEuMywwLDIuMywxLDIuMywyLjN2My40YzAsMCwwLDAuNiwwLDEuOGMwLDAuMywwLjIsMC42LDAuNiwwLjZjMC4yLDAsMC4zLTAuMSwwLjQtMC4yYzUuNC01LjksMTIuMy04LjgsMTcuMi04LjhjMi43LDAsNSwwLjYsNi45LDEuOWMxLjksMS4zLDMuNCwzLjQsNC42LDYuM2MwLjgsMi4xLDEuMiw1LjIsMS4yLDkuNHYxNi41bDAsNi4zYzAsMC41LDAsMi43LDEuNCwzLjRjMC4yLDAuMSwwLjQsMC4yLDAuOCwwLjJjMC40LDAuMSwwLjcsMC40LDAuNywwLjhsMCwyLjNjMCwwLjUtMC40LDAuOC0wLjgsMC45Yy0wLjgsMC0xLjUsMC0yLDBoLTYuNWMtMC4xLDAtMC4zLDAtMC40LDBoLTMuMWMtMS4xLDAtMi0wLjktMi0yYzAtMSwwLjctMS45LDEuNi0yLjJjMC4xLDAsMC4xLDAsMC4yLTAuMWMxLTAuNSwxLjMtMS44LDEuNC0yLjd2LTcuNGwwLTE1LjJjMC00LjMtMC42LTcuNC0xLjctOS4zYy0xLjItMS45LTMuMS0yLjktNS44LTIuOWMtNC4yLDAtMTAuMywyLjItMTQuNCw2Ljd2MjAuOHYwLjNsMCw2LjRjMCwwLjUsMCwyLjgsMS40LDMuNWMwLjEsMCwwLjEsMCwwLjIsMC4xYzEsMC4zLDEuNiwxLjIsMS42LDIuMmMwLDEuMS0wLjksMi0yLDJIMzk0QzM5NCwxNzkuMSwzOTIuNCwxNzkuMSwzODkuMywxNzkuMSIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik01MTUsMTUzLjRjLTYuNiwxLjMtMTAuNCwyLjItMTEuNCwyLjVjLTMuNywxLjItNi42LDIuNi02LjgsOC43Yy0wLjEsMi41LDAuOCw0LjcsMi4zLDYuM2MxLjUsMS43LDMuMywyLjUsNS4zLDIuNWMyLjUsMCw1LjctMS44LDkuNi00LjhjMC43LTAuNSwxLjEtMS4zLDEuMS0yLjJWMTUzLjR6IE01MjMuOCwxNzAuOGMwLDAuMSwwLDAuMiwwLDAuMmMwLDAuMiwwLDAuMywwLDAuNGMwLjEsMS40LDAuNiwyLjQsMS40LDIuOGMwLjIsMC4xLDAuNCwwLjIsMC42LDAuMmMwLjQsMC4xLDAuNywwLjQsMC43LDAuOGwwLDIuNGMwLDAuNS0wLjQsMC44LTAuOSwwLjloLTguM2MtMS4zLDAtMi4zLTEtMi4zLTIuM3YtNC41Yy01LDMuOS04LjIsNi4xLTkuNSw2LjdjLTEuOSwwLjktNCwxLjMtNi4xLDEuM2MtMy40LDAtNi4yLTEuMi04LjQtMy40Yy0yLjItMi4zLTMuMy01LjMtMy4zLTkuMWMwLTIuNCwwLjUtNC40LDEuNi02LjJjMS41LTIuNCwzLjctNS4yLDcuNi02LjhjNC0xLjYsNy4zLTIsMTgtNC40YzAtMC4zLDAtNCwwLTQuM2MwLTQuNS0wLjgtOS4yLTguNC04LjdjLTUuMywwLjMtMTAuMiwyLTE0LjcsNWMtMC40LDAuMy0wLjksMC4yLTEuMi0wLjJjLTAuMS0wLjEtMC4xLTAuMy0wLjEtMC41di0yLjhjMC0xLjUsMC4zLTIuNCwwLjktMi45YzMuMS0yLjUsMTAuOS01LjUsMTguNS01YzguNCwwLjYsMTEuNCw0LDEyLjksOS4zYzAuNSwxLjYsMSwyLjgsMSw3LjV2MTQuNWMwLDIsMCw0LDAsNS44VjE3MC44eiIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik00NjUuNCwxMzcuOGMtMS43LTEtMy40LTEuNS01LTEuNWMtMywwLTUuOCwxLjMtOC4zLDMuOGMtMi43LDIuOC00LjYsNi41LTQuNiwxMy41YzAsNywxLjUsMTIuNCw0LjYsMTYuMmMzLDMuNyw2LjQsNS42LDEwLjIsNS42YzIuNywwLDUuMy0xLjEsNy44LTMuNGMwLjktMC44LDEuNC0xLjksMS40LTN2LTIwLjhDNDcxLjQsMTQzLjksNDY5LjEsMTQwLDQ2NS40LDEzNy44IE00ODEuMywxNzQuNmMwLjEsMC4xLDAuMywwLjEsMC41LDAuMmMwLjQsMC4xLDAuNiwwLjQsMC42LDAuOGwwLDIuM2MwLDAuNS0wLjQsMC44LTAuOSwwLjloLThjLTEuMiwwLTIuMy0xLTIuMy0yLjJ2LTIuMmMtMi4zLDIuNC00LjYsNC4yLTYuOCw1LjNjLTIuMiwxLjEtNC42LDEuNi03LjEsMS42Yy01LjIsMC05LjctMi4yLTEzLjYtNi42Yy0zLjktNC40LTUuOC0xMC01LjgtMTYuOXMyLjEtMTMuMSw2LjQtMTguOGM0LjMtNS43LDkuOC04LjUsMTYuNS04LjVjNC4yLDAsNy42LDEuMywxMC40LDR2LTE2LjdjMC0wLjUsMC0yLjctMS40LTMuNGMtMC4xLTAuMS0wLjMtMC4xLTAuNS0wLjJjLTAuNC0wLjEtMC42LTAuNC0wLjYtMC44bDAtMi40YzAtMC41LDAuNC0wLjksMC45LTAuOWg3LjljMS4yLDAsMi4zLDEsMi4zLDIuMnY1OC45QzQ3OS45LDE3MS44LDQ3OS45LDE3My45LDQ4MS4zLDE3NC42Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTM1MCwxNTAuMmMwLDAuMSwwLDAuMywwLjEsMC4zYzAuMSwwLjEsMC4yLDAuMSwwLjQsMC4xaDIzLjljMC4zLDAsMC41LTAuMiwwLjUtMC40YzAuMy0yLjUsMC40LTctMy4zLTEwLjhjLTEuOC0xLjktNC4xLTIuOC04LjMtMi44QzM1NS43LDEzNi42LDM1MC44LDE0My45LDM1MCwxNTAuMiBNMzQ3LjUsMTc0LjljLTMuOS00LjMtNS45LTExLjMtNS45LTE4LjJjMC03LjMsMi4zLTEzLjksNi40LTE4LjdjNC4zLTUsMTAuMi03LjcsMTcuMS03LjdjNS44LDAsMTAuMiwyLDEzLjIsNS44YzIuNywzLjYsNC4xLDguOCw0LjEsMTUuNGMwLDAuOCwwLDEuOS0wLjEsMy4zYy0wLjEsMC45LTAuOCwxLjYtMS43LDEuNmgtMjkuOGMtMC4xLDAtMC4zLDAuMS0wLjQsMC4xYy0wLjEsMC4xLTAuMSwwLjItMC4xLDAuNGMwLjEsNS40LDEuOCwxMCw1LDEzLjJjMy4xLDMuMiw3LjQsNC45LDEyLjQsNC45YzMuNywwLDguNi0xLDEyLjQtMi4xYzAuNS0wLjIsMS4xLDAuMSwxLjMsMC43YzAuMSwwLjIsMC4xLDAuNCwwLDAuNWwtMC41LDEuOWMtMC4yLDAuNy0wLjcsMS4zLTEuMywxLjZjLTMuNywxLjgtOS4zLDMuNS0xNSwzLjVDMzU3LjYsMTgxLjIsMzUxLjYsMTc5LjUsMzQ3LjUsMTc0LjkiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNMjMxLjEsMTM1Ljl2MzYuOWMwLDEsMC42LDEuOSwxLjQsMi4zYzAuOSwwLjQsMS40LDEuMywxLjQsMi4zdjAuN2MwLDAuOC0wLjYsMS40LTEuNCwxLjRIMjIwYy0wLjgsMC0xLjQtMC42LTEuNC0xLjR2LTAuN2MwLTEsMC42LTEuOSwxLjQtMi4zYzAuOS0wLjQsMS40LTEuMywxLjQtMi4zdi0zNS43YzAtMC41LTAuNC0wLjktMC45LTAuOXMtMC45LTAuNC0wLjktMC45di0xLjJjMC0xLjIsMC45LTIuMSwyLjEtMi4xaDUuNkMyMjkuNCwxMzIsMjMxLjEsMTMzLjcsMjMxLjEsMTM1LjkiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNMjI2LjMsMTEwLjhjMy4zLDAsNiwyLjcsNiw1LjljMCwzLjMtMi43LDUuOS02LDUuOXMtNi0yLjctNi01LjlDMjIwLjMsMTEzLjUsMjIzLDExMC44LDIyNi4zLDExMC44Ii8+PC9zdmc+"/>
562
+ </a>';
563
+
564
+ if ( $tab_key === 'cs' ) {
565
+ echo '
566
+ <p class="iubenda-text">
567
+ ' . __( "This plugin is the easiest and most comprehensive way to adapt your WordPress site to the ePrivacy (EU Cookie Law). Upon your users' first visit, the plugin will take care of collecting their consent, blocking the most popular cookie-scripts and subsequently reactivating these scripts as soon as consent is provided. The basic settings include obtaining consent by a simple scroll action (the most effective method) and script reactivation without refreshing the page (asynchronous script reactivation).", 'iubenda' ) . '
568
+ </p>
569
+ <p class="iubenda-text">
570
+ <span class="iubenda-title">' . __( "Does the Cookie Solution support IAB's Transparency and Consent Framework?", 'iubenda' ) . '</span><br />
571
+ ' . sprintf( __( "Yes it does. You can read more about it <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">here.</a>", 'iubenda' ), $this->links['iab'] ) . '
572
+ </p>
573
+ <p class="iubenda-text">
574
+ <span class="iubenda-title">' . __( "Would you like to know more about the cookie law?", 'iubenda' ) . '</span><br />
575
+ ' . sprintf( __( "Read our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">complete guide to the cookie law.</a>", 'iubenda' ), $this->links['guide'] ) . '
576
+ </p>
577
+ <p class="iubenda-text">
578
+ <span class="iubenda-title">' . __( "What is the full functionality of the plugin?", 'iubenda' ) . '</span><br />
579
+ ' . sprintf( __( "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">plugin page.</a>", 'iubenda' ), $this->links['plugin_page'] ) . '
580
+ </p>
581
+ <p class="iubenda-text">
582
+ <span class="iubenda-title">' . __( "Enter the iubenda code for the Cookie Solution below.", 'iubenda' ) . '</span><br />
583
+ ' . sprintf( __( "In order to run the plugin, you need to enter the iubenda code that activates the cookie law banner and the cookie policy in the form below. This code can be generated on www.iubenda.com, following <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">this guide.</a>", 'iubenda' ), $this->links['generating_code'] ) . '
584
+ </p>';
585
+ } else {
586
+ echo '
587
+ <p class="iubenda-text">
588
+ ' . __( 'Maintaining comprehensive records of consent is a vital part of privacy compliance in general but is specifically required under the GDPR. These records should include a way of identifying the user, store proof of consent, record of the consenting action, and the legal documents available to the user at the time of consent, among other things. You can read about the <a href="https://www.iubenda.com/en/help/5428-gdpr-guide#records-of-consent" target="_blank">full requirements here</a>.', 'iubenda' ) . '
589
+ </p>';
590
+ }
591
+ ?>
592
+ </div>
593
+
594
+ <?php
595
+ if ( $tab_key === 'cs' ) {
596
+ // add per-purpose notice
597
+ if ( iubenda()->options['cs']['skip_parsing'] ) {
598
+ $iubenda_code = '';
599
+
600
+ if ( iubenda()->multilang === true && defined( 'ICL_LANGUAGE_CODE' ) && isset( iubenda()->options['cs']['code_' . ICL_LANGUAGE_CODE] ) ) {
601
+ $iubenda_code = iubenda()->options['cs']['code_' . ICL_LANGUAGE_CODE];
602
+
603
+ // no code for current language, use default
604
+ if ( ! $iubenda_code )
605
+ $iubenda_code = iubenda()->options['cs']['code_default'];
606
+ } else
607
+ $iubenda_code = iubenda()->options['cs']['code_default'];
608
+
609
+ $per_purpose_enabled = preg_match( '/(?:"|\')perPurposeConsent(?:"|\')\: *(?:"|\'*)true(?:"|\'*)/', $iubenda_code );
610
+ $reject_enabled = preg_match( '/(?:"|\')rejectButtonDisplay(?:"|\')\: *(?:"|\'*)true(?:"|\'*)/', $iubenda_code );
611
+
612
+ if ( $per_purpose_enabled || $reject_enabled )
613
+ $this->add_notice( 'iub_per_purpose_enabled', sprintf( __( 'If you are using per-purpose script blocking or Reject option please disable the "Leave scripts untouched on the page if the user has already given consent" option. <a href="%s" target="_self">Disable now</a>', 'iubenda' ), esc_url( add_query_arg( 'action', 'disable_skip_parsing', $redirect_to ) ) ), 'notice' );
614
+ }
615
+
616
+ // add AMP notice
617
+ if ( iubenda()->options['cs']['amp_support'] && iubenda()->options['cs']['amp_template_done'] ) {
618
+ $ssl_support = true;
619
+
620
+ // multilang support
621
+ if ( iubenda()->multilang && ! empty( iubenda()->languages ) ) {
622
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
623
+ $url = iubenda()->options['cs']['amp_source'] === 'remote' ? iubenda()->options['cs']['amp_template'][$lang_id] : iubenda()->AMP->get_amp_template_url( $lang_id );
624
+ $bits = explode( '/', $url );
625
+
626
+ if ( $bits[0] === 'http:' )
627
+ $ssl_support = false;
628
+ }
629
+ } else {
630
+ $url = iubenda()->options['cs']['amp_source'] === 'remote' ? iubenda()->options['cs']['amp_template'] : iubenda()->AMP->get_amp_template_url();
631
+ $bits = explode( '/', $url );
632
+
633
+ if ( $bits[0] === 'http:' )
634
+ $ssl_support = false;
635
+ }
636
+
637
+ if ( ! $ssl_support )
638
+ $this->add_notice( 'iub_amp_ssl_required', __( 'AMP configuration file requires HTTPS. Make sure your SSL Certificate is configured correctly.', 'iubenda' ), 'error' );
639
+ }
640
+
641
+ }
642
+
643
+ // render custom notices
644
+ $this->print_notices();
645
+ ?>
646
+
647
+ <h2 style="display: none;"></h2>
648
+ <h2 class="nav-tab-wrapper iubenda-tab-wrapper">
649
+ <a class="nav-tab<?php echo $tab_key == 'cs' ? ' nav-tab-active' : ''; ?>" href="<?php echo esc_url( iubenda()->base_url ); ?>"><?php _e( 'Cookie Solution', 'iubenda' ); ?></a>
650
+ <a class="nav-tab<?php echo $tab_key == 'cons' ? ' nav-tab-active' : ''; ?>" href="<?php echo esc_url( add_query_arg( array( 'tab' => 'cons' ), iubenda()->base_url ) ); ?>"><?php _e( 'Consent Solution', 'iubenda' ); ?></a>
651
+ </h2>
652
+
653
+ <div id="iubenda-settings">
654
+
655
+ <form id="iubenda-tabs" action="options.php" method="post">
656
+
657
+
658
+ <?php
659
+ if ( $tab_key === 'cs' ) {
660
+ echo '<p>' . sprintf( __( 'This plugin drastically reduces the need for direct interventions in the code of the site by integrating with iubenda\'s Cookie Solution. It provides a fully customizable cookie banner, dynamically generates a cookie policy <a href="%s" target="_blank">to match the services in use on your site</a>, and, fully manages cookie-related consent - including the blocking of the most common widgets and third-party cookies before consent is received - in order to comply with the GDPR and ePrivacy.', 'iubenda' ), 'https://www.iubenda.com/en/help/19004-how-to-use-the-site-scanner-from-within-the-generator' ) . '</p>';
661
+ } else {
662
+ echo '<p>' . __( 'Maintaining valid records of consent is a vital part of privacy compliance in general, and it is specifically required under the GDPR. These records should include a userid, timestamp, consent proof, record of the consenting action, and the legal documents available to the user at the time of consent, among other things. This plugin is THE most complete solution for recording, sorting and maintaining GDPR records of consent*. The plugin also boasts built-in compatibility with WordPress comment form, Contact Form 7 and WP Forms plugins for your convenience, but can be manually integrated with any type of web-form and can even store consent proofs for consents collected offline (e.g in-store sign-ups) via WP media upload.' ) . '</p>';
663
+ }
664
+ ?>
665
+
666
+ <?php
667
+ settings_fields( $this->tabs[$tab_key]['key'] );
668
+ do_settings_sections( $this->tabs[$tab_key]['key'] );
669
+
670
+ if ( ! in_array( $this->action, array( 'save', 'edit' ) ) ) {
671
+ echo ' <p class="submit submit-' . $tab_key . '">';
672
+
673
+ // consent solution tab only
674
+ if ( $tab_key != 'cs' && ! empty( iubenda()->options['cons']['public_api_key'] ) ) {
675
+ echo '<a href="' . esc_url( add_query_arg( array( 'tab' => 'cons', 'action' => 'autodetect' ), iubenda()->base_url ) ) . '" class="button button-primary button-large iub-autodetect-forms">' . esc_html__( 'Autodetect Forms', 'iubenda' ) . '</a>';
676
+ echo '<br />';
677
+ }
678
+ submit_button( '', 'primary', $this->tabs[$tab_key]['submit'], false );
679
+ echo ' ';
680
+ submit_button( __( 'Reset to defaults', 'iubenda' ), 'secondary', $this->tabs[$tab_key]['reset'], false );
681
+ echo ' </p>';
682
+ }
683
+ ?>
684
+
685
+ </form>
686
+
687
+ </div>
688
+
689
+ <div id="iubenda-footer">
690
+ <?php echo '
691
+ <p class="iubenda-text">
692
+ <span class="iubenda-title">' . __( 'Need support for this plugin?', 'iubenda' ) . '</span><br />
693
+ ' . sprintf( __( "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">support forum.</a>", 'iubenda' ), $this->links['support_forum'] ) . '
694
+ </p>';
695
+ ?>
696
+ </div>
697
+
698
+ <div class="clear"></div>
699
+ </div>
700
+ <?php
701
+ }
702
+
703
+ /**
704
+ * Code option.
705
+ *
706
+ * @return mixed
707
+ */
708
+ public function iub_code() {
709
+ // multilang support
710
+ if ( iubenda()->multilang && ! empty( iubenda()->languages ) ) {
711
+ echo '
712
+ <div id="contextual-help-wrap" class="contextual-help-wrap hidden" tabindex="-1" style="display: block;">
713
+ <div id="contextual-help-back" class="contextual-help-back"></div>
714
+ <div id="contextual-help-columns" class="contextual-help-columns">
715
+ <div class="contextual-help-tabs">
716
+ <ul>';
717
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
718
+ echo '
719
+ <li class="' . ( iubenda()->lang_default == $lang_id ? 'active' : '' ) . '">
720
+ <a href="#tab-panel-' . $lang_id . '" aria-controls="tab-panel-' . $lang_id . '">' . $lang_name . '</a>
721
+ </li>';
722
+ }
723
+ echo '
724
+ </ul>
725
+ </div>
726
+
727
+ <div id="contextual-help-tabs-wrap" class="contextual-help-tabs-wrap">';
728
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
729
+ // get code for the language
730
+ $code = ! empty( iubenda()->options['cs']['code_' . $lang_id] ) ? html_entity_decode( iubenda()->parse_code( iubenda()->options['cs']['code_' . $lang_id] ) ) : '';
731
+ // handle default, if empty
732
+ $code = empty( $code ) && $lang_id == iubenda()->lang_default ? html_entity_decode( iubenda()->parse_code( iubenda()->options['cs']['code_default'] ) ) : $code;
733
+
734
+ echo '
735
+ <div id="tab-panel-' . $lang_id . '" class="help-tab-content' . ( iubenda()->lang_default == $lang_id ? ' active' : '' ) . '">
736
+ <textarea name="iubenda_cookie_law_solution[code_' . $lang_id . ']" class="large-text" cols="50" rows="10">' . $code . '</textarea>
737
+ <p class="description">' . sprintf( __( 'Enter the iubenda code for %s.', 'iubenda' ), $lang_name ) . '</p>
738
+ </div>';
739
+ }
740
+ echo '
741
+ </div>
742
+ </div>
743
+ </div>';
744
+ } else {
745
+ echo '
746
+ <div id="iub_code_default">
747
+ <textarea name="iubenda_cookie_law_solution[code_default]" class="large-text" cols="50" rows="10">' . html_entity_decode( iubenda()->parse_code( iubenda()->options['cs']['code_default'] ) ) . '</textarea>
748
+ <p class="description">' . __( 'Enter the iubenda code.', 'iubenda' ) . '</p>
749
+ </div>';
750
+ }
751
+ }
752
+
753
+ /**
754
+ * Custom scripts option.
755
+ *
756
+ * @return void
757
+ */
758
+ public function iub_custom_scripts() {
759
+ echo '
760
+ <div id="contextual-help-wrap-2" class="contextual-help-wrap hidden" tabindex="-1" style="display: block;">
761
+ <div id="contextual-help-back-2" class="contextual-help-back"></div>
762
+ <div id="contextual-help-columns-2" class="contextual-help-columns">
763
+ <div class="contextual-help-tabs">
764
+ <ul>
765
+ <li class="active">
766
+ <a href="#tab-panel-scripts" aria-controls="tab-panel-scripts">' . esc_html__( 'Scripts', 'iubenda' ) . '</a>
767
+ </li>
768
+ <li>
769
+ <a href="#tab-panel-iframes" aria-controls="tab-panel-iframes">' . esc_html__( 'Iframes', 'iubenda' ) . '</a>
770
+ </li>
771
+ </ul>
772
+ </div>
773
+ <div id="contextual-help-tabs-wrap-2" class="contextual-help-tabs-wrap">
774
+ <div id="tab-panel-scripts" class="help-tab-content active">
775
+ <p class="description">' . __( 'Provide a list of custom scripts you\'d like to block and assign their purpose.', 'iubenda' ) . '</p>
776
+ <div id="custom-script-field-template" class="template-field" style="display: none;">
777
+ <input type="text" class="regular-text" value="" name="iubenda_cookie_law_solution[custom_scripts][script][]" placeholder="' . __( 'Enter custom script', 'iubenda' ) . '" /> ' . $this->render_tag_types( 'script', 0 ) . ' <a href="#" class="remove-custom-script-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
778
+ </div>';
779
+
780
+ if ( ! empty( iubenda()->options['cs']['custom_scripts'] ) ) {
781
+ foreach ( iubenda()->options['cs']['custom_scripts'] as $script => $type ) {
782
+ echo '
783
+ <div class="custom-script-field">
784
+ <input type="text" class="regular-text" value="' . esc_attr( $script ) . '" name="iubenda_cookie_law_solution[custom_scripts][script][]" placeholder="' . __( 'Enter custom script', 'iubenda' ) . '" /> ' . $this->render_tag_types( 'script', $type ) . ' <a href="#" class="remove-custom-script-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
785
+ </div>';
786
+ }
787
+ }
788
+
789
+ echo '
790
+ <a href="#" class="add-custom-script-field button-secondary">Add New Script</a>
791
+ </div>
792
+ <div id="tab-panel-iframes" class="help-tab-content">
793
+ <p class="description">' . __( 'Provide a list of custom iframes you\'d like to block and assign their purpose. ', 'iubenda' ) . '</p>
794
+ <div id="custom-iframe-field-template" class="template-field" style="display: none;">
795
+ <input type="text" class="regular-text" value="" name="iubenda_cookie_law_solution[custom_iframes][iframe][]" placeholder="' . __( 'Enter custom iframe', 'iubenda' ) . '" /> ' . $this->render_tag_types( 'iframe', 0 ) . ' <a href="#" class="remove-custom-iframe-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
796
+ </div>';
797
+
798
+ if ( ! empty( iubenda()->options['cs']['custom_iframes'] ) ) {
799
+ foreach ( iubenda()->options['cs']['custom_iframes'] as $iframe => $type ) {
800
+ echo '
801
+ <div class="custom-iframe-field">
802
+ <input type="text" class="regular-text" value="' . esc_attr( $iframe ) . '" name="iubenda_cookie_law_solution[custom_iframes][iframe][]" placeholder="' . __( 'Enter custom iframe', 'iubenda' ) . '" /> ' . $this->render_tag_types( 'iframe', $type ) . ' <a href="#" class="remove-custom-iframe-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
803
+ </div>';
804
+ }
805
+ }
806
+
807
+ echo '
808
+ <a href="#" class="add-custom-iframe-field button-secondary">Add New Iframe</a>
809
+ </div>
810
+ </div>
811
+ </div>
812
+ </div>';
813
+ }
814
+
815
+ /**
816
+ * Prepare tag types select.
817
+ *
818
+ * @param string $type
819
+ * @param int $selected
820
+ * @return string
821
+ */
822
+ function render_tag_types( $type, $selected ) {
823
+ $html = '<select name="iubenda_cookie_law_solution[custom_' . $type . 's][type][]">';
824
+
825
+ foreach ( $this->tag_types as $tag_id => $tag_name ) {
826
+ $html .= '<option value="' . esc_attr( $tag_id ) . '" ' . selected( $selected, $tag_id, false ) . '>' . esc_html( $tag_name ) . '</option>';
827
+ }
828
+
829
+ return $html . '</select>';
830
+ }
831
+
832
+ /**
833
+ * Parsing option.
834
+ *
835
+ * @return mixed
836
+ */
837
+ public function iub_parse() {
838
+ echo '
839
+ <div id="iub_parse_container">
840
+ <label><input id="iub_parse" type="checkbox" name="iubenda_cookie_law_solution[parse]" value="1" ' . checked( true, (bool) iubenda()->options['cs']['parse'], false ) . '/>' . __( 'Automatically block scripts detected by the plugin', 'iubenda' ) . '</label>
841
+ <p class="description">' . '(' . sprintf( __( "see <a href=\"%s\" target=\"_blank\">our documentation</a> for the list of detected scripts.", 'iubenda' ), $this->links['documentation'] ) . ')' . '</p>
842
+ <div id="iub_parser_engine_container"' . ( iubenda()->options['cs']['parse'] === false ? ' style="display: none;"' : '' ) . '>
843
+ <div>
844
+ <label><input id="iub_parser_engine-new" type="radio" name="iubenda_cookie_law_solution[parser_engine]" value="new" ' . checked( 'new', iubenda()->options['cs']['parser_engine'], false ) . ' />' . __( 'Primary', 'iubenda' ) . '</label>
845
+ <label><input id="iub_parser_engine-default" type="radio" name="iubenda_cookie_law_solution[parser_engine]" value="default" ' . checked( 'default', iubenda()->options['cs']['parser_engine'], false ) . ' />' . __( 'Secondary', 'iubenda' ) . '</label>
846
+ <p class="description">' . __( 'Select parsing engine.', 'iubenda' ) . '</p>
847
+ </div>
848
+ <div>
849
+ <label><input id="iub_skip_parsing" type="checkbox" name="iubenda_cookie_law_solution[skip_parsing]" value="1" ' . checked( true, (bool) iubenda()->options['cs']['skip_parsing'], false ) . '/>' . __( 'Leave scripts untouched on the page if the user has already given consent', 'iubenda' ) . '</label>
850
+ <p class="description">(' . __( "improves performance, highly recommended, to be deactivated only if your site uses a caching system or if you're collecting per-category consent.", 'iubenda' ) . ')</p>
851
+ </div>
852
+ </div>
853
+ </div>';
854
+ }
855
+
856
+ /**
857
+ * Ctype option.
858
+ *
859
+ * @return mixed
860
+ */
861
+ public function iub_ctype() {
862
+ echo '
863
+ <div id="iub_ctype_container">
864
+ <label><input id="iub_ctype" type="checkbox" name="iubenda_cookie_law_solution[ctype]" value="1" ' . checked( true, (bool) iubenda()->options['cs']['ctype'], false ) . '/>' . __( 'Restrict the plugin to run only for requests that have "Content-type: text / html" (recommended)', 'iubenda' ) . '</label>
865
+ </div>';
866
+ }
867
+
868
+ /**
869
+ * RSS feed option.
870
+ *
871
+ * @return mixed
872
+ */
873
+ public function iub_output_feed() {
874
+ echo '
875
+ <div id="iub_output_feed_container">
876
+ <label><input id="iub_output_feed" type="checkbox" name="iubenda_cookie_law_solution[output_feed]" value="1" ' . checked( true, (bool) iubenda()->options['cs']['output_feed'], false ) . '/>' . __( 'Do not run the plugin inside the RSS feed (recommended)', 'iubenda' ) . '</label>
877
+ </div>';
878
+ }
879
+
880
+ /**
881
+ * POST request option.
882
+ *
883
+ * @return mixed
884
+ */
885
+ public function iub_output_post() {
886
+ echo '
887
+ <div id="iub_output_post_container">
888
+ <label><input id="iub_output_post" type="checkbox" name="iubenda_cookie_law_solution[output_post]" value="1" ' . checked( true, (bool) iubenda()->options['cs']['output_post'], false ) . '/>' . __( 'Do not run the plugin on POST requests (recommended)', 'iubenda' ) . '</label>
889
+ </div>';
890
+ }
891
+
892
+ /**
893
+ * Menu option.
894
+ *
895
+ * @return mixed
896
+ */
897
+ public function iub_menu_position() {
898
+ echo '
899
+ <div id="iub_menu_position_container">
900
+ <label><input id="iub_menu_position-topmenu" type="radio" name="iubenda_cookie_law_solution[menu_position]" value="topmenu" ' . checked( 'topmenu', iubenda()->options['cs']['menu_position'], false ) . ' />' . __( 'Top menu', 'iubenda' ) . '</label>
901
+ <label><input id="iub_menu_position-submenu" type="radio" name="iubenda_cookie_law_solution[menu_position]" value="submenu" ' . checked( 'submenu', iubenda()->options['cs']['menu_position'], false ) . ' />' . __( 'Submenu', 'iubenda' ) . '</label>
902
+ <p class="description">' . __( 'Select whether to display iubenda in a top admin menu or the Settings submenu.', 'iubenda' ) . '</p>
903
+ </div>';
904
+ }
905
+
906
+ /**
907
+ * Google AMP support option.
908
+ *
909
+ * @return mixed
910
+ */
911
+ public function iub_amp_support() {
912
+ echo '
913
+ <div id="iub_amp_support_container">
914
+ <label><input id="iub_amp_support" type="checkbox" name="iubenda_cookie_law_solution[amp_support]" value="1" ' . checked( true, (bool) iubenda()->options['cs']['amp_support'], false ) . '/>' . __( 'Enable Google AMP support.', 'iubenda' ) . '</label>
915
+ <p class="description">' . sprintf( __( 'This feature enables iubenda on AMP pages via the <a href="%s" target="_blank">AMP</a> and <a href="%s" target="_blank">AMP for WP</a> plugins. AMP requires specific configuration parameters and a page hosted on your domain where the configuration is loaded from. <a href="%s" target="_blank">Learn more on iubenda and AMP</a>.', 'iubenda' ), 'https://wordpress.org/plugins/amp/', 'https://wordpress.org/plugins/accelerated-mobile-pages/', 'https://www.iubenda.com/en/help/22135-cookie-solution-amp#wordpress' ) . '</p>
916
+ <div id="iub_amp_options_container"' . ( iubenda()->options['cs']['amp_support'] === false ? ' style="display: none;"' : '' ) . '>
917
+ <div>
918
+ <label><input id="iub_amp_source-local" class="iub_amp_source" type="radio" name="iubenda_cookie_law_solution[amp_source]" value="local" ' . checked( 'local', iubenda()->options['cs']['amp_source'], false ) . ' />' . __( 'Auto-generated configuration file', 'iubenda' ) . '</label>
919
+ <label><input id="iub_amp_source-remote" class="iub_amp_source" type="radio" name="iubenda_cookie_law_solution[amp_source]" value="remote" ' . checked( 'remote', iubenda()->options['cs']['amp_source'], false ) . ' />' . __( 'Custom configuration file', 'iubenda' ) . '</label>
920
+ <p class="description">' . __( 'Select the iubenda AMP configuration file location.', 'iubenda' ) . '</p>
921
+ </div>
922
+ <div id="iub_amp_template-local"' . ( iubenda()->options['cs']['amp_source'] === 'remote' ? ' style="display: none;"' : '' ) . '>';
923
+ if ( empty( iubenda()->options['cs']['amp_template_done'] ) ) {
924
+ echo '
925
+ <p class="description">' . __( 'No file available. Save changes to generate iubenda AMP configuration file.', 'iubenda' ) . '</p>';
926
+ } else {
927
+ // multilang support
928
+ if ( iubenda()->multilang && ! empty( iubenda()->languages ) ) {
929
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
930
+ echo $lang_name . ':
931
+ <a href="' . iubenda()->AMP->get_amp_template_url( $lang_id ) . '" target="_blank">' . iubenda()->AMP->get_amp_template_url( $lang_id ) . '</a><br />';
932
+ }
933
+ } else {
934
+ echo '
935
+ <a href="' . iubenda()->AMP->get_amp_template_url() . '" target="_blank">' . iubenda()->AMP->get_amp_template_url() . '</a>';
936
+ }
937
+ }
938
+ echo '
939
+ </div>
940
+ <div id="iub_amp_template-remote"' . ( iubenda()->options['cs']['amp_source'] === 'local' ? ' style="display: none;"' : '' ) . '>';
941
+
942
+ // multilang support
943
+ if ( iubenda()->multilang && ! empty( iubenda()->languages ) ) {
944
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
945
+ echo $lang_name . ':
946
+ <label><input id="iub_amp_template-' . $lang_id . '" type="text" class="regular-text" name="iubenda_cookie_law_solution[amp_template][' . $lang_id . ']" value="' . ( isset( iubenda()->options['cs']['amp_template'][$lang_id] ) ? esc_url( iubenda()->options['cs']['amp_template'][$lang_id] ) : '' ) . '" /></label><br />';
947
+ }
948
+ } else {
949
+ echo '
950
+ <label><input id="iub_amp_template" type="text" class="regular-text" name="iubenda_cookie_law_solution[amp_template]" value="' . ( isset( iubenda()->options['cs']['amp_template'] ) ? esc_url( iubenda()->options['cs']['amp_template'] ) : '' ) . '" /></label>';
951
+ }
952
+ echo '
953
+ <p class="description">' . __( 'If you\'re experiencing issues with AMP setup download the generated iubenda AMP configuration file, upload it to any SSL server and paste the file link to the field above.', 'iubenda' ) . '</p>
954
+ </div>
955
+ <p class="description">' . sprintf( __( 'Seeing the AMP cookie notice when testing from Google but not when visiting your AMP pages directly? <a href="%s" target="_blank">Learn how to fix it</a>.', 'iubenda' ), 'https://www.iubenda.com/en/help/3182-cookie-solution-amp#amp-domain' ) . '</p>
956
+ </div>
957
+ </div>';
958
+ }
959
+
960
+ /**
961
+ * Deactivation option.
962
+ *
963
+ * @return mixed
964
+ */
965
+ public function iub_deactivation() {
966
+ echo '
967
+ <div id="iub_deactivation_container">
968
+ <label><input id="iub_deactivation" type="checkbox" name="iubenda_cookie_law_solution[deactivation]" value="1" ' . checked( true, (bool) iubenda()->options['cs']['deactivation'], false ) . '/>' . __( 'Delete all plugin data upon deactivation', 'iubenda' ) . '</label>
969
+ </div>';
970
+ }
971
+
972
+ /**
973
+ * Public API Key option.
974
+ *
975
+ * @return mixed
976
+ */
977
+ public function iub_public_api_key() {
978
+ echo '
979
+ <div id="iub_public_api_key_container">
980
+ <label><input id="iub_public_api_key" type="text" class="regular-text" name="iubenda_consent_solution[public_api_key]" value="' . iubenda()->options['cons']['public_api_key'] . '" /></label>
981
+ <p class="description">' . __( 'Enter your iubenda Javascript library public API key.', 'iubenda' ) . '</p>
982
+ </div>';
983
+ }
984
+
985
+ /**
986
+ * Forms list.
987
+ *
988
+ * @return mixed
989
+ */
990
+ public function iubenda_consent_forms() {
991
+ $form_id = ! empty( $_GET['form_id'] ) ? absint( $_GET['form_id'] ) : 0;
992
+ $form = ! empty( $form_id ) ? iubenda()->forms->get_form( $form_id ) : false;
993
+
994
+ $supported_forms = iubenda()->forms->sources;
995
+
996
+ echo '
997
+ <p class="description">' . __( 'This section lists the forms available for field mapping. The plugin currently supports & detects: WordPress Comment, Contact Form 7, WooCommerce Checkout and WP Forms.', 'iubenda' ) . '</p>';
998
+
999
+ // list screen
1000
+ if ( ! class_exists( 'WP_List_Table' ) )
1001
+ include_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
1002
+
1003
+ include_once( IUBENDA_PLUGIN_PATH . '/includes/forms-list-table.php' );
1004
+
1005
+ $list_table = new iubenda_List_Table_Forms();
1006
+
1007
+ echo '
1008
+ <div id="iubenda-consent-forms">';
1009
+ $list_table->views();
1010
+ $list_table->prepare_items();
1011
+ $list_table->display();
1012
+
1013
+ echo '
1014
+ </div>';
1015
+ }
1016
+
1017
+ /**
1018
+ * Single form.
1019
+ *
1020
+ * @return mixed
1021
+ */
1022
+ public function iubenda_consent_form() {
1023
+ $form_id = ! empty( $_GET['form_id'] ) ? absint( $_GET['form_id'] ) : 0;
1024
+ $form = ! empty( $form_id ) ? iubenda()->forms->get_form( $form_id ) : false;
1025
+
1026
+ if ( ! $form )
1027
+ return;
1028
+
1029
+ $status = isset( $form->post_status ) && in_array( $form->post_status, array_keys( iubenda()->forms->statuses ) ) ? esc_attr( $form->post_status ) : 'publish';
1030
+ $subject = isset( $form->form_subject ) && is_array( $form->form_subject ) ? array_map( 'esc_attr', $form->form_subject ) : array();
1031
+ $preferences = isset( $form->form_preferences ) && is_array( $form->form_preferences ) ? array_map( 'esc_attr', $form->form_preferences ) : array();
1032
+ $exclude = isset( $form->form_exclude ) && is_array( $form->form_exclude ) ? array_map( 'esc_attr', $form->form_exclude ) : array();
1033
+ $legal_notices = isset( $form->form_legal_notices ) && is_array( $form->form_legal_notices ) ? array_map( 'esc_attr', $form->form_legal_notices ) : array();
1034
+
1035
+ $available_fields = array();
1036
+
1037
+ if ( ! empty( $form->form_fields ) && is_array( $form->form_fields ) ) {
1038
+ foreach ( $form->form_fields as $index => $form_field ) {
1039
+ if ( is_array( $form_field ) ) {
1040
+ // print_r( $form_field );
1041
+ $available_fields[] = $form_field['label'] . ' (' . $form_field['type'] . ')';
1042
+ } else {
1043
+ $available_fields[] = $form_field;
1044
+ }
1045
+ }
1046
+ }
1047
+
1048
+ // print_r( $form );
1049
+
1050
+ echo '
1051
+ <div id="poststuff">
1052
+ <div id="post-body" class="metabox-holder columns-2">
1053
+ <div id="post-body-content">
1054
+ <div id="titlediv">
1055
+ <div id="titlewrap">
1056
+ <h1>' . $form->post_title . '</h1>
1057
+ </div>
1058
+ <p class="description">' . sprintf( __( '%s form title.', 'iubenda' ), ( array_key_exists( $form->form_source, iubenda()->forms->sources ) ? iubenda()->forms->sources[$form->form_source] : __( 'Unknown', 'iubenda' ) ) ) . '</p>
1059
+
1060
+ <div style="margin-top: 18px"><strong>' . __( 'Available form fields:', 'iubenda' ) . '</strong><br /><p class="description">' . implode( ', ', $available_fields ) . '</p></div>
1061
+ </div>
1062
+ </div>
1063
+ <div id="postbox-container-1" class="postbox-container">
1064
+ <div id="side-sortables" class="">
1065
+ <div id="submitdiv" class="postbox ">
1066
+ <h3 class="hndle"><span>' . __( 'Publish' ) . '</span></h3>
1067
+ <div class="inside">
1068
+ <div id="submitpost" class="submitbox">
1069
+ <div id="minor-publishing">
1070
+ <div class="misc-pub-section misc-pub-post-status">
1071
+ <label for="status">' . __( 'Status' ) . ':</label>
1072
+ <div id="status-select" class="" style="margin: 3px 0 0;">
1073
+ <select id="status" name="status">';
1074
+ foreach ( iubenda()->forms->statuses as $name => $label ) {
1075
+ echo '
1076
+ <option value="' . $name . '"' . selected( $form->post_status, $name, true ) . '>' . $label . '</option>';
1077
+ }
1078
+ echo '
1079
+ </select>
1080
+ </div>
1081
+ </div>
1082
+ <div id="major-publishing-actions">
1083
+ <div id="delete-action">
1084
+ <a class="submitdelete deletion" href="' . esc_url( add_query_arg( array( 'tab' => 'cons' ), iubenda()->base_url ) ) . '">' . __( 'Cancel' ) . '</a>
1085
+ </div>
1086
+ <div id="publishing-action">
1087
+ <span class="spinner"></span>
1088
+ <input type="hidden" value="' . $form->ID . '" name="form_id">
1089
+ <input id="publish" class="button button-primary button-large" type="submit" value="' . __( 'Save' ) . '" name="save">
1090
+ </div>
1091
+ <div class="clear"></div>
1092
+ </div>
1093
+ </div>
1094
+ </div>
1095
+ </div>
1096
+ </div>
1097
+ </div>
1098
+ </div>
1099
+ <div id="postbox-container-2" class="postbox-container">
1100
+ <div id="normal-sortables" class="meta-box-sortables">
1101
+ <div id="map-fields" class="postbox">
1102
+ <h3 class="hndle ui-sortable-handle"><span>' . __( 'Map fields', 'iubenda' ) . '</span></h3>
1103
+ <div class="inside">
1104
+ <table class="widefat">
1105
+ <tbody>
1106
+ <tr>
1107
+ <td class="label table-label">
1108
+ <h4>' . __( 'Subject fields', 'iubenda' ) . ' <span class="required">(required)</span></h4>
1109
+ <p class="description">' . __( 'Subject fields allow you to store a series of identifying values about your individual subjects/users. Please map the subject field with the corresponding form fields where applicable.', 'iubenda' ) . '</p>
1110
+ </td>
1111
+ <td>
1112
+ <table class="widefat subject-table">
1113
+ <thead>
1114
+ <td class="label">' . __( 'Subject field', 'iubenda' ) . '</td>
1115
+ <td class="label">' . __( 'Form field', 'iubenda' ) . '</td>
1116
+ </thead>
1117
+ <tbody>';
1118
+
1119
+ foreach ( $this->subject_fields as $field_name => $field_label ) {
1120
+ $selected = isset( $subject[$field_name] ) ? $subject[$field_name] : '';
1121
+ $none = $field_name == 'id' ? __( 'Autogenerated', 'iubenda' ) : __( 'None', 'iubenda' );
1122
+
1123
+ echo '
1124
+ <tr class="subject-field options-field">
1125
+ <td>' . $field_name . ' (' . $field_label . ')' . '</td>
1126
+ <td>
1127
+ <select class="subject-fields-select select-' . $field_name . '" name="subject[' . $field_name . ']">
1128
+ <option value="" ' . selected( $selected, '', false ) . '>' . $none . '</option>';
1129
+ if ( ! empty( $form->form_fields ) ) {
1130
+ foreach ( $form->form_fields as $index => $form_field ) {
1131
+ // get field data
1132
+ $form_field_value = is_array( $form_field ) ? $index : $form_field;
1133
+ $form_field_label = is_array( $form_field ) ? $form_field['label'] . ' (' . $form_field['type'] . ')' : $form_field;
1134
+ $form_field_selected = is_array( $form_field ) ? $index : $form_field;
1135
+
1136
+ echo '<option value="' . $form_field_value . '" ' . selected( $selected, $form_field_selected, false ) . '>' . $form_field_label . '</option>';
1137
+ }
1138
+ }
1139
+ echo '
1140
+ </select>
1141
+ </td>
1142
+ </tr>
1143
+ ';
1144
+ }
1145
+ echo '
1146
+ </tbody>
1147
+ </table>
1148
+ </td>
1149
+ </tr>
1150
+ <tr>
1151
+ <td class="label table-label">
1152
+ <h4>' . __( 'Preferences fields', 'iubenda' ) . ' <span class="required">(required)</span></h4>
1153
+ <p class="description">' . __( 'Preferences fields allow you to store a record of the various opt-ins points at which the user has agreed or given consent, such as fields for agreeing to terms and conditions, newsletter, profiling, etc. *Please create at least one preference field.', 'iubenda' ) . '</p>
1154
+ </td>
1155
+ <td>
1156
+ <table class="widefat preferences-table">
1157
+ <thead>
1158
+ <td class="label">' . __( 'Preferences field', 'iubenda' ) . '</td>
1159
+ <td class="label">' . __( 'Form field', 'iubenda' ) . '</td>
1160
+ </thead>
1161
+ <tbody>';
1162
+ echo '
1163
+ <tr id="preferences-field-template" class="template-field" style="display: none;">
1164
+ <td><input type="text" class="regular-text" value="" name="preferences[__PREFERENCE_ID__][field]" placeholder="' . __( 'Enter field name', 'iubenda' ) . '" /></td>
1165
+ <td>
1166
+ <select class="preferences-fields-select select-' . $field_name . '" name="preferences[__PREFERENCE_ID__][value]">';
1167
+ if ( ! empty( $form->form_fields ) ) {
1168
+ foreach ( $form->form_fields as $index => $form_field ) {
1169
+ // get field data
1170
+ $form_field_value = is_array( $form_field ) ? $index : $form_field;
1171
+ $form_field_label = is_array( $form_field ) ? $form_field['label'] . ' (' . $form_field['type'] . ')' : $form_field;
1172
+
1173
+ echo '<option value="' . $form_field_value . '">' . $form_field_label . '</option>';
1174
+ }
1175
+ }
1176
+ echo '
1177
+ </select>
1178
+ <a href="javascript:void(0)" class="remove-preferences-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
1179
+ </td>
1180
+ </tr>';
1181
+
1182
+ if ( $preferences ) {
1183
+ $index = 0;
1184
+
1185
+ foreach ( $preferences as $field_name => $field_value ) {
1186
+ $selected = isset( $preferences[$field_name] ) ? $preferences[$field_name] : '';
1187
+
1188
+ echo '
1189
+ <tr class="preferences-field options-field">
1190
+ <td><input type="text" class="regular-text" value="' . $field_name . '" name="preferences[' . $index . '][field]" placeholder="' . __( 'Enter field name', 'iubenda' ) . '" /></td>
1191
+ <td>
1192
+ <select class="preferences-fields-select select-' . $field_name . '" name="preferences[' . $index . '][value]">';
1193
+ if ( ! empty( $form->form_fields ) ) {
1194
+ foreach ( $form->form_fields as $index => $form_field ) {
1195
+ // get field data
1196
+ $form_field_value = is_array( $form_field ) ? $index : $form_field;
1197
+ $form_field_label = is_array( $form_field ) ? $form_field['label'] . ' (' . $form_field['type'] . ')' : $form_field;
1198
+ $form_field_selected = is_array( $form_field ) ? $index : $form_field;
1199
+
1200
+ echo '<option value="' . $form_field_value . '" ' . selected( $selected, $form_field_selected, false ) . '>' . $form_field_label . '</option>';
1201
+ }
1202
+ }
1203
+ echo '
1204
+ </select>
1205
+ <a href="javascript:void(0)" class="remove-preferences-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
1206
+ </td>
1207
+ </tr>';
1208
+
1209
+ $index++;
1210
+ }
1211
+ }
1212
+
1213
+ echo '
1214
+ <tr class="submit-field"><td colspan="2"><a href="javascript:void(0)" class="add-preferences-field button-secondary">' . __( 'Add New Preference', 'iubenda' ) . '</a></td></tr>
1215
+ </tbody>
1216
+ </table>
1217
+ </td>
1218
+ </tr>
1219
+ <tr>
1220
+ <td class="label table-label">
1221
+ <h4>' . __( 'Exclude fields', 'iubenda' ) . '</h4>
1222
+ <p class="description">' . __( 'Exclude fields allow you to create a list of fields that you would like to exclude from your Consent Solution recorded proofs (for e.g. password or other fields not related to the consent).', 'iubenda' ) . '</p>
1223
+ </td>
1224
+ <td>
1225
+ <table class="widefat exclude-table">
1226
+ <thead>
1227
+ <td class="label">' . __( 'Exclude field', 'iubenda' ) . '</td>
1228
+ <td class="label"></td>
1229
+ </thead>
1230
+ <tbody>';
1231
+ echo '
1232
+ <tr id="exclude-field-template" class="template-field" style="display: none;">
1233
+ <td>
1234
+ <select class="exclude-fields-select select-' . $field_name . '" name="exclude[__EXCLUDE_ID__][field]">';
1235
+ if ( ! empty( $form->form_fields ) ) {
1236
+ foreach ( $form->form_fields as $index => $form_field ) {
1237
+ // get field data
1238
+ $form_field_value = is_array( $form_field ) ? $index : $form_field;
1239
+ $form_field_label = is_array( $form_field ) ? $form_field['label'] . ' (' . $form_field['type'] . ')' : $form_field;
1240
+
1241
+ echo '<option value="' . $form_field_value . '">' . $form_field_label . '</option>';
1242
+ }
1243
+ }
1244
+ echo '
1245
+ </select>
1246
+ <a href="javascript:void(0)" class="remove-exclude-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
1247
+ </td>
1248
+ <td></td>
1249
+
1250
+ </tr>';
1251
+
1252
+ if ( $exclude ) {
1253
+ $index = 0;
1254
+
1255
+ foreach ( $exclude as $index => $field_name ) {
1256
+ $selected = isset( $exclude[$index] ) ? $exclude[$index] : '';
1257
+
1258
+ echo '
1259
+ <tr class="exclude-field options-field">
1260
+ <td>
1261
+ <select class="exclude-fields-select select-' . $field_name . '" name="exclude[' . $index . '][field]">';
1262
+ if ( ! empty( $form->form_fields ) ) {
1263
+ foreach ( $form->form_fields as $index => $form_field ) {
1264
+ // get field data
1265
+ $form_field_value = is_array( $form_field ) ? $index : $form_field;
1266
+ $form_field_label = is_array( $form_field ) ? $form_field['label'] . ' (' . $form_field['type'] . ')' : $form_field;
1267
+ $form_field_selected = is_array( $form_field ) ? $index : $form_field;
1268
+
1269
+ echo '<option value="' . $form_field_value . '" ' . selected( $selected, $form_field_selected, false ) . '>' . $form_field_label . '</option>';
1270
+ }
1271
+ }
1272
+ echo '
1273
+ </select>
1274
+ <a href="javascript:void(0)" class="remove-exclude-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
1275
+ </td>
1276
+ <td></td>
1277
+ </tr>';
1278
+
1279
+ $index++;
1280
+ }
1281
+ }
1282
+
1283
+ echo '
1284
+ <tr class="submit-field"><td colspan="2"><a href="javascript:void(0)" class="add-exclude-field button-secondary">' . __( 'Add New Exclude', 'iubenda' ) . '</a></td></tr>
1285
+ </tbody>
1286
+ </table>
1287
+ </td>
1288
+ </tr>
1289
+ </tbody>
1290
+ </table>
1291
+ </div>
1292
+ </div>
1293
+ <div id="legal-notices" class="postbox">
1294
+ <h3 class="hndle ui-sortable-handle"><span>' . __( 'Legal Notices', 'iubenda' ) . '</span></h3>
1295
+ <div class="inside">
1296
+ <table class="widefat">
1297
+ <tbody>
1298
+ <tr>
1299
+ <td class="label table-label">
1300
+ <h4>' . __( 'Legal documents', 'iubenda' ) . '</h4>
1301
+ <p class="description">' . __( 'In general, it\'s important that you declare which legal documents are being agreed upon when each consent is collected. However, if you use iubenda for your legal documents, it is *required* that you identify the documents by selecting them here.', 'iubenda' ) . '</p>
1302
+ </td>
1303
+ <td>
1304
+ <table class="widefat legal_notices-table">
1305
+ <thead>
1306
+ <td class="label">' . __( 'Identifier', 'iubenda' ) . '</td>
1307
+ <td class="label"></td>
1308
+ </thead>
1309
+ <tbody>';
1310
+
1311
+ // default identifiers
1312
+ foreach ( $this->legal_notices as $index => $field_name ) {
1313
+ echo '
1314
+ <tr class="legal_notices-field default-field">
1315
+ <td>' . ( $index === 0 ? '<p class="description">' . __( 'Please select each legal document available on your site.', 'iubenda' ) . '</p>' : '' ) . '<label for="legal_notices-default-field=' . $index . '"><input id="legal_notices-default-field=' . $index . '" type="checkbox" value="' . $field_name . '" name="legal_notices[' . $index . '][field]"' . checked( in_array( $field_name, $legal_notices, true ), true, false ) . 'placeholder="' . __( 'Enter field name', 'iubenda' ) . '" />' . $field_name . '</label></td>
1316
+ <td></td>
1317
+ </tr>';
1318
+ }
1319
+
1320
+ $index++;
1321
+
1322
+ // custom identifiers
1323
+ echo '
1324
+ <tr id="legal_notices-field-template" class="template-field" style="display: none;">
1325
+ <td><input type="text" class="regular-text" value="" name="legal_notices[__LEGAL_NOTICE_ID__][field]" placeholder="' . __( 'Enter field name', 'iubenda' ) . '" /> <a href="javascript:void(0)" class="remove-legal_notices-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a></td>
1326
+ <td></td>
1327
+ </tr>';
1328
+
1329
+ echo '
1330
+ <tr>
1331
+ <td colspan="2"><p class="description" style="margin-bottom: 0;">' . __( 'Alternatively, you may add your own custom document identifiers.', 'iubenda' ) . '</p></td>
1332
+ </tr>';
1333
+
1334
+ if ( $legal_notices ) {
1335
+ foreach ( $legal_notices as $field_name ) {
1336
+ if ( in_array( $field_name, $this->legal_notices, true ) )
1337
+ continue;
1338
+
1339
+ echo '
1340
+ <tr class="legal_notices-field options-field">
1341
+ <td><input type="text" class="regular-text" value="' . $field_name . '" name="legal_notices[' . $index . '][field]" placeholder="' . __( 'Enter field name', 'iubenda' ) . '" /> <a href="javascript:void(0)" class="remove-legal_notices-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a></td>
1342
+ <td></td>
1343
+ </tr>';
1344
+
1345
+ $index++;
1346
+ }
1347
+ }
1348
+
1349
+ echo '
1350
+ <tr class="submit-field"><td colspan="2"><a href="javascript:void(0)" class="add-legal_notices-field button-secondary">' . __( 'Add New Document', 'iubenda' ) . '</a></td></tr>';
1351
+ echo '
1352
+ </tbody>
1353
+ </table>
1354
+ </td>
1355
+ </tr>
1356
+ </tbody>
1357
+ </table>
1358
+ </div>
1359
+ </div>
1360
+ </div>
1361
+ </div>
1362
+ </div>
1363
+ </div>
1364
+ <div class="clear"></div>';
1365
+
1366
+ // echo '<pre>'; print_r( $form ); echo '</pre>';
1367
+ }
1368
+
1369
+ /**
1370
+ * Save cookie solution options.
1371
+ *
1372
+ * @return void
1373
+ */
1374
+ public function save_cookie_law_options( $input ) {
1375
+ if ( ! current_user_can( apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ) ) )
1376
+ return $input;
1377
+
1378
+ // save options
1379
+ if ( isset( $_POST['save_iubenda_options'] ) ) {
1380
+ $input['parse'] = (bool) isset( $input['parse'] );
1381
+ $input['parser_engine'] = isset( $input['parser_engine'] ) && in_array( $input['parser_engine'], array( 'default', 'new' ) ) ? $input['parser_engine'] : iubenda()->defaults['cs']['parser_engine'];
1382
+ $input['skip_parsing'] = (bool) isset( $input['skip_parsing'] );
1383
+ $input['ctype'] = (bool) isset( $input['ctype'] );
1384
+ $input['output_feed'] = (bool) isset( $input['output_feed'] );
1385
+ $input['output_post'] = (bool) isset( $input['output_post'] );
1386
+ $input['menu_position'] = isset( $input['menu_position'] ) && in_array( $input['menu_position'], array( 'topmenu', 'submenu' ) ) ? $input['menu_position'] : iubenda()->defaults['cs']['menu_position'];
1387
+ $input['amp_support'] = (bool) isset( $input['amp_support'] );
1388
+ $input['deactivation'] = (bool) isset( $input['deactivation'] );
1389
+
1390
+ // multilang support
1391
+ if ( iubenda()->multilang && ! empty( iubenda()->languages ) ) {
1392
+ $iubenda_code = array();
1393
+
1394
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
1395
+ $input['code_' . $lang_id] = $iubenda_code[$lang_id] = ! empty( $input['code_' . $lang_id] ) ? iubenda()->parse_code( $input['code_' . $lang_id] ) : '';
1396
+
1397
+ // handle default lang too
1398
+ if ( $lang_id == iubenda()->lang_default ) {
1399
+ $input['code_default'] = ! empty( $input['code_' . $lang_id] ) ? iubenda()->parse_code( $input['code_' . $lang_id] ) : iubenda()->options['cs']['code_default'];
1400
+ }
1401
+ }
1402
+ } else {
1403
+ $iubenda_code = '';
1404
+
1405
+ $input['code_default'] = $iubenda_code = ! empty( $input['code_default'] ) ? iubenda()->parse_code( $input['code_default'] ) : '';
1406
+ }
1407
+
1408
+ // generate amp template file
1409
+ if ( isset( $input['amp_support'] ) ) {
1410
+ $template_done = false;
1411
+
1412
+ if ( ! empty( $iubenda_code ) ) {
1413
+ if ( is_array( $iubenda_code ) ) {
1414
+ $template_done = array();
1415
+
1416
+ foreach ( $iubenda_code as $lang => $code ) {
1417
+ $template_done[$lang] = (bool) iubenda()->AMP->generate_amp_template( $code, $lang );
1418
+ }
1419
+ } else {
1420
+ $template_done = (bool) iubenda()->AMP->generate_amp_template( $iubenda_code );
1421
+ }
1422
+ }
1423
+
1424
+ $input['amp_template_done'] = $template_done;
1425
+
1426
+ if ( is_array( $input['amp_template'] ) ) {
1427
+ foreach ( $input['amp_template'] as $lang => $template ) {
1428
+ $input['amp_template'][$lang] = esc_url( $template );
1429
+ }
1430
+ } else {
1431
+ $input['amp_template'] = esc_url( $input['amp_template'] );
1432
+ }
1433
+ }
1434
+
1435
+ // scripts
1436
+ if ( ! empty( $input['custom_scripts'] ) && ! empty( $input['custom_scripts']['script'] ) && ! empty( $input['custom_scripts']['type'] ) ) {
1437
+ $scripts = array();
1438
+
1439
+ // first field is template
1440
+ if ( count( $input['custom_scripts']['script'] ) > 1 ) {
1441
+ foreach ( $input['custom_scripts']['script'] as $number => $script ) {
1442
+ $trimmed = trim( $script );
1443
+
1444
+ if ( $trimmed !== '' )
1445
+ $scripts[$trimmed] = (int) $input['custom_scripts']['type'][$number];
1446
+ }
1447
+ }
1448
+
1449
+ $input['custom_scripts'] = $scripts;
1450
+ } else
1451
+ $input['custom_scripts'] = array();
1452
+
1453
+ // iframes
1454
+ if ( ! empty( $input['custom_iframes'] ) && ! empty( $input['custom_iframes']['iframe'] ) && ! empty( $input['custom_iframes']['type'] ) ) {
1455
+ $iframes = array();
1456
+
1457
+ // first field is template
1458
+ if ( count( $input['custom_iframes']['iframe'] ) > 1 ) {
1459
+ foreach ( $input['custom_iframes']['iframe'] as $number => $iframe ) {
1460
+ $trimmed = trim( $iframe );
1461
+
1462
+ if ( $trimmed !== '' )
1463
+ $iframes[$trimmed] = (int) $input['custom_iframes']['type'][$number];
1464
+ }
1465
+ }
1466
+
1467
+ $input['custom_iframes'] = $iframes;
1468
+ } else
1469
+ $input['custom_iframes'] = array();
1470
+
1471
+ add_settings_error( 'cs_settings_errors', 'iub_cs_settings_updated', __( 'Settings saved.', 'iubenda' ), 'updated' );
1472
+ // reset options
1473
+ } elseif ( isset( $_POST['reset_iubenda_options'] ) ) {
1474
+ $input = iubenda()->defaults['cs'];
1475
+
1476
+ // multilang support
1477
+ if ( iubenda()->multilang && ! empty( iubenda()->languages ) ) {
1478
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
1479
+ $input['code_' . $lang_id] = '';
1480
+ }
1481
+ }
1482
+
1483
+ add_settings_error( 'cs_settings_errors', 'iub_cs_settings_restored', __( 'Settings restored to defaults.', 'iubenda' ), 'updated' );
1484
+ }
1485
+
1486
+ return $input;
1487
+ }
1488
+
1489
+ /**
1490
+ * Save consent solution options.
1491
+ *
1492
+ * @return void
1493
+ */
1494
+ public function save_consent_options( $input ) {
1495
+
1496
+ if ( ! current_user_can( apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ) ) )
1497
+ return $input;
1498
+
1499
+ // save options
1500
+ if ( isset( $_POST['save_consent_options'] ) ) {
1501
+ $input['public_api_key'] = isset( $input['public_api_key'] ) ? esc_attr( $input['public_api_key'] ) : '';
1502
+
1503
+ add_settings_error( 'cons_settings_errors', 'iub_cons_settings_updated', __( 'Settings saved.', 'iubenda' ), 'updated' );
1504
+ // reset options
1505
+ } elseif ( isset( $_POST['reset_consent_options'] ) ) {
1506
+ $input = iubenda()->defaults['cons'];
1507
+
1508
+ add_settings_error( 'cons_settings_errors', 'iub_cons_settings_restored', __( 'Settings restored to defaults.', 'iubenda' ), 'updated' );
1509
+ }
1510
+
1511
+ return $input;
1512
+ }
1513
+
1514
+ /**
1515
+ * Process the bulk actions
1516
+ *
1517
+ * @return void
1518
+ */
1519
+ public function process_actions() {
1520
+ global $pagenow;
1521
+
1522
+ $page = ! empty( $_POST['option_page'] ) ? esc_attr( $_POST['option_page'] ) : ( ! empty( $_GET['page'] ) ? esc_attr( $_GET['page'] ) : '' );
1523
+ $id = isset( $_REQUEST['form_id'] ) ? ( is_array( $_REQUEST['form_id'] ) ? array_map( 'ansint', $_REQUEST['form_id'] ) : absint( $_REQUEST['form_id'] ) ) : false;
1524
+ $tab_key = ! empty( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'cs';
1525
+
1526
+ if ( ! $page )
1527
+ return;
1528
+
1529
+ // get redirect url
1530
+ if ( iubenda()->options['cs']['menu_position'] === 'submenu' && $pagenow === 'admin.php' ) {
1531
+ // sub menu
1532
+ $redirect_to = admin_url( 'options-general.php?page=iubenda&tab=' . $tab_key );
1533
+ } else {
1534
+ // top menu
1535
+ $redirect_to = admin_url( 'admin.php?page=iubenda&tab=' . $tab_key );
1536
+ }
1537
+
1538
+ // add comments cookie option notice
1539
+ if ( $tab_key != 'cs' && ! empty( iubenda()->options['cons']['public_api_key'] ) ) {
1540
+ $cookies_enabled = get_option( 'show_comments_cookies_opt_in' );
1541
+
1542
+ if ( ! $cookies_enabled ) {
1543
+ $this->add_notice( 'iub_comment_cookies_disabled', sprintf( __( 'Please enable comments cookies opt-in checkbox in the <a href="%s" target="_blank">Discussion settings</a>.', 'iubenda' ), esc_url( admin_url( 'options-discussion.php' ) ) ), 'notice' );
1544
+ }
1545
+ }
1546
+
1547
+ $result = null;
1548
+
1549
+ switch ( $this->action ) {
1550
+ case 'autodetect' :
1551
+ $result = iubenda()->forms->autodetect_forms();
1552
+
1553
+ // new forms notice
1554
+ if ( ! empty( $result['new'] ) )
1555
+ $this->add_notice( 'iub_autodetect_success', sprintf( _n( '%d form detected successfully.', '%d forms detected successfully.', count( $result['new'] ), 'iubenda' ), $result ), 'success' );
1556
+
1557
+ // forms changed notice
1558
+ if ( ! empty( $result['updated'] ) )
1559
+ $this->add_notice( 'iub_autodetect_success', sprintf( _n( '%d form change detected.', '%d form changes detected.', count( $result['updated'] ), 'iubenda' ), $result ), 'success' );
1560
+
1561
+ // no changes notice
1562
+ if ( empty( $result['new'] ) && empty( $result['updated'] ) )
1563
+ $this->add_notice( 'iub_autodetect_success', __( 'No forms or form changes detected.', 'iubenda' ), 'error' );
1564
+
1565
+ // make sure it's current host location
1566
+ wp_safe_redirect( $redirect_to );
1567
+ exit;
1568
+
1569
+ break;
1570
+
1571
+ case 'save' :
1572
+ if ( ! $id )
1573
+ return;
1574
+
1575
+ $form = iubenda()->forms->get_form( $id );
1576
+
1577
+ if ( $form->ID != $id )
1578
+ return;
1579
+
1580
+ $status = isset( $_POST['status'] ) && in_array( $_POST['status'], array_keys( iubenda()->forms->statuses ) ) ? esc_attr( $_POST['status'] ) : 'publish';
1581
+ $subject = isset( $_POST['subject'] ) && is_array( $_POST['subject'] ) ? array_map( 'esc_attr', $_POST['subject'] ) : array();
1582
+ $preferences = array();
1583
+ $exclude = array();
1584
+ $legal_notices = array();
1585
+
1586
+ $preferences_raw = isset( $_POST['preferences'] ) && is_array( $_POST['preferences'] ) ? array_map( array( $this, 'array_map_callback' ), $_POST['preferences'] ) : array();
1587
+ $exclude_raw = isset( $_POST['exclude'] ) && is_array( $_POST['exclude'] ) ? array_map( array( $this, 'array_map_callback' ), $_POST['exclude'] ) : array();
1588
+ $legal_notices_raw = isset( $_POST['legal_notices'] ) && is_array( $_POST['legal_notices'] ) ? array_map( array( $this, 'array_map_callback' ), $_POST['legal_notices'] ) : array();
1589
+
1590
+ // format preferences data
1591
+ if ( ! empty( $preferences_raw ) && is_array( $preferences_raw ) ) {
1592
+ foreach ( $preferences_raw as $index => $data ) {
1593
+ if ( ! empty( $data['field'] ) && ! empty( $data['value'] ) )
1594
+ $preferences[ sanitize_key( $data['field'] ) ] = $data['value'];
1595
+ }
1596
+ }
1597
+
1598
+ // format exclude data
1599
+ if ( ! empty( $exclude_raw ) && is_array( $exclude_raw ) ) {
1600
+ foreach ( $exclude_raw as $index => $data ) {
1601
+ if ( ! empty( $data['field'] ) )
1602
+ $exclude[] = $data['field'];
1603
+ }
1604
+ }
1605
+
1606
+ // format legal notices data
1607
+ if ( ! empty( $legal_notices_raw ) && is_array( $legal_notices_raw ) ) {
1608
+ foreach ( $legal_notices_raw as $index => $data ) {
1609
+ if ( ! empty( $data['field'] ) )
1610
+ $legal_notices[] = $data['field'];
1611
+ }
1612
+ }
1613
+
1614
+ // form first save, update status to mapped automatically
1615
+ if ( empty( $form->form_subject ) && empty( $form->form_preferences ) ) {
1616
+ $status = 'mapped';
1617
+ }
1618
+
1619
+ // echo '<pre>'; print_r( $_POST ); echo '</pre>'; exit;
1620
+
1621
+ // bail if empty fields
1622
+ if ( empty( $subject ) || empty( $preferences ) ) {
1623
+ $this->add_notice( 'iub_form_fields_missing', __( 'Form saving failed. Please fill the Subject and Preferences fields.', 'iubenda' ), 'error' );
1624
+ return;
1625
+ }
1626
+
1627
+ $args = array(
1628
+ 'ID' => $form->ID,
1629
+ 'status' => $status,
1630
+ 'object_type' => $form->object_type,
1631
+ 'object_id' => $form->object_id,
1632
+ 'form_source' => $form->form_source,
1633
+ 'form_title' => $form->post_title,
1634
+ 'form_date' => $form->post_modified,
1635
+ 'form_fields' => $form->form_fields,
1636
+ 'form_subject' => $subject,
1637
+ 'form_preferences' => $preferences,
1638
+ 'form_exclude' => $exclude,
1639
+ 'form_legal_notices' => $legal_notices
1640
+ );
1641
+
1642
+ $result = iubenda()->forms->save_form( $args );
1643
+
1644
+ if ( $result ) {
1645
+ // form save, inform about form status update
1646
+ if ( empty( $form->form_subject ) && empty( $form->form_preferences ) ) {
1647
+ $this->add_notice( 'iub_form_saved', __( 'Form saved successfully - form status changed to Mapped.', 'iubenda' ), 'success' );
1648
+ // form update
1649
+ } else {
1650
+ $this->add_notice( 'iub_form_updated', __( 'Form updated successfully.', 'iubenda' ), 'success' );
1651
+ }
1652
+ } else {
1653
+ $this->add_notice( 'iub_form_failed', __( 'Form saving failed.', 'iubenda' ), 'error' );
1654
+ }
1655
+
1656
+ break;
1657
+
1658
+ case 'delete' :
1659
+ if ( ! $id )
1660
+ return;
1661
+
1662
+ $form = iubenda()->forms->get_form( $id );
1663
+
1664
+ if ( empty( $form ) )
1665
+ return;
1666
+
1667
+ $result = iubenda()->forms->delete_form( $id );
1668
+
1669
+ if ( $result )
1670
+ $this->add_notice( 'iub_form_deleted', __( 'Form deleted successfully.', 'iubenda' ), 'success' );
1671
+ else
1672
+ $this->add_notice( 'iub_form_delete_failed', __( 'Form delete failed.', 'iubenda' ), 'error' );
1673
+
1674
+ // make sure it's current host location
1675
+ wp_safe_redirect( $redirect_to );
1676
+ exit;
1677
+
1678
+ break;
1679
+
1680
+ case 'disable_skip_parsing' :
1681
+
1682
+ // disable skip parsing option
1683
+ $options = iubenda()->options['cs'];
1684
+ $options['skip_parsing'] = false;
1685
+
1686
+ update_option( 'iubenda_cookie_law_solution', $options );
1687
+
1688
+ $this->add_notice( 'iub_settings_updated', __( 'Settings saved.', 'iubenda' ), 'success' );
1689
+
1690
+ // make sure it's current host location
1691
+ wp_safe_redirect( $redirect_to );
1692
+ exit;
1693
+
1694
+ break;
1695
+
1696
+ default :
1697
+ return;
1698
+ }
1699
+
1700
+ if ( ! empty ( $result ) ) {
1701
+ //
1702
+ } else {
1703
+ //
1704
+ }
1705
+ }
1706
+
1707
+ /**
1708
+ * Add admin notice.
1709
+ *
1710
+ * @param mixed $message
1711
+ * @param string $notice_type
1712
+ */
1713
+ public function add_notice( $key, $message, $notice_type = 'notice' ) {
1714
+ $key = ! empty( $key ) ? sanitize_key( $key ) : '';
1715
+ $message = ! empty( $message ) ? wp_kses_post( $message ) : '';
1716
+ $notice_type = ! empty( $notice_type ) && in_array( $notice_type, $this->notice_types ) ? $notice_type : 'notice';
1717
+
1718
+ if ( ! $key || ! $message )
1719
+ return;
1720
+
1721
+ $notices = get_transient( 'iubenda_dashboard_notices' );
1722
+ $delay = MINUTE_IN_SECONDS * 2;
1723
+
1724
+ if ( empty( $notices ) || ! array_key_exists( $key, $notices[$notice_type] ) ) {
1725
+ $notices[$notice_type][$key] = $message;
1726
+
1727
+ set_transient( 'iubenda_dashboard_notices', $notices, $delay );
1728
+ }
1729
+ }
1730
+
1731
+ /**
1732
+ * Display admin notices.
1733
+ *
1734
+ * @return mixed
1735
+ */
1736
+ public function print_notices() {
1737
+ $notices = get_transient( 'iubenda_dashboard_notices' );
1738
+ $notices_array = array();
1739
+
1740
+ foreach ( $this->notice_types as $notice_type ) {
1741
+ if ( $this->notice_count( $notices, $notice_type ) > 0 ) {
1742
+ echo '<div class="notice notice-' . ( $notice_type === 'notice' ? 'info' : $notice_type ) . ' below-h2 is-dismissible">';
1743
+
1744
+ foreach ( $notices[$notice_type] as $key => $notice ) {
1745
+ echo '<p><strong>' . wp_kses_post( $notice ) . '</strong></p>';
1746
+ }
1747
+
1748
+ echo '<button type="button" class="notice-dismiss"><span class="screen-reader-text">' . __( 'Dismiss this notice.' ) . '</span></button>';
1749
+
1750
+ echo '</div>';
1751
+ }
1752
+ }
1753
+
1754
+ delete_transient( 'iubenda_dashboard_notices' );
1755
+ }
1756
+
1757
+ /**
1758
+ * Count notices function.
1759
+ *
1760
+ * @param string $notice_type
1761
+ * @return int
1762
+ */
1763
+ public function notice_count( $all_notices = array(), $notice_type = '' ) {
1764
+ $notice_count = 0;
1765
+
1766
+ if ( isset( $all_notices[$notice_type] ) ) {
1767
+ $notice_count = absint( sizeof( $all_notices[$notice_type] ) );
1768
+ } elseif ( empty( $notice_type ) ) {
1769
+ foreach ( $all_notices as $notices ) {
1770
+ $notice_count += absint( sizeof( $all_notices ) );
1771
+ }
1772
+ }
1773
+
1774
+ return $notice_count;
1775
+ }
1776
+
1777
+ /**
1778
+ * Adjust highlighted menu.
1779
+ *
1780
+ * @param type $file
1781
+ * @return type
1782
+ */
1783
+ public function submenu_file( $submenu_file, $parent_file ) {
1784
+ global $menu, $submenu;
1785
+
1786
+ if ( $parent_file == 'iubenda' ) {
1787
+ $tab_key = ! empty( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'cs';
1788
+
1789
+ if ( $tab_key == 'cons' ) {
1790
+ $submenu_file = 'admin.php?page=iubenda&tab=cons';
1791
+ $submenu['iubenda'][1][2] = 'admin.php?page=iubenda&tab=cons';
1792
+ }
1793
+ }
1794
+
1795
+ return $submenu_file;
1796
+ }
1797
+
1798
+ /**
1799
+ * Sanitize array helper function.
1800
+ *
1801
+ * @param array $array
1802
+ * @return array
1803
+ */
1804
+ public function array_map_callback( $array ) {
1805
+ if ( ! is_array( $array ) )
1806
+ return array();
1807
+
1808
+ return array_map( 'esc_attr', $array );
1809
+ }
1810
+
1811
+ }
trunk/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
trunk/iubenda-cookie-class/README.md ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Read Me
2
+
3
+ ***PHP class for the iubenda cookie law solution***
4
+
5
+ If you have European users you need to obtain and manage consent for the use of most cookies.
6
+ The iubenda Cookie Solution is an all-in-one approach developed by iubenda, that helps to make your website GDPR and Cookie Law compliant by integrating with your cookie policy, providing a compliant cookie banner and the blocking management of cookie scripts. The Cookie Solution also allows users to set advertising preferences on-site and within the solution, facilitated the recent-but-widely adopted IAB Europe Transparency & Consent [framework](https://www.iubenda.com/en/help/7440#aboutIAB).
7
+
8
+ [Read more about the Cookie Solution here](https://www.iubenda.com/en/features#cookie-solution).
9
+
10
+ * * *
11
+ #### This class allows you to scan a page in PHP for scripts and run the automatic blocking of scripts
12
+
13
+ *This is the class on which our WordPress and Joomla! and Drupal plugins are based and you can use it to build your own plugin independently for a platform other than those for which we have already developed a dedicated solution.*
14
+
15
+ * * *
16
+
17
+ ## Functionality
18
+
19
+ This class works with the iubenda Cookie Law Solution and allows you to block the most common widgets and third-party cookies to comply with Cookie Law.
20
+
21
+ The class is currently able to detect and automatically block the following scripts:
22
+
23
+ * Google Analytics
24
+ * Google Maps
25
+ * Google AdSense
26
+ * Google ReCaptcha
27
+ * Google Site Search
28
+ * Google Tag Manager
29
+ * Google oAuth
30
+ * Google+ widgets
31
+ * Twitter widgets
32
+ * Facebook widgets
33
+ * Facebook Comments
34
+ * YouTube
35
+ * Vimeo
36
+ * Linkedin widgets
37
+ * ShareThis widgets
38
+ * Instagram widgets
39
+ * AddThis widgets
40
+ * Pinterest widgets
41
+ * PayPal widgets
42
+ * Disqus
43
+ * Optimizely
44
+ * Neodata
45
+ * Criteo
46
+ * Outbrain
47
+ * Headway
48
+ * Codepen
49
+ * Freshchat
50
+ * Uservoice
51
+ * AdRoll
52
+ * Olark
53
+ * Segment
54
+ * Kissmetrics
55
+ * Mixpanel
56
+ * Pingdom
57
+ * Bing
58
+ * Elevio
59
+
60
+
61
+ It also allows the manual blocking of all other resources without direct intervention on the actual scripts. Read more about the [prior blocking functionality here](https://www.iubenda.com/en/help/1229-cookie-law-solution-preventing-code-execution-that-could-install-cookies).
62
+
63
+ * * *
64
+
65
+ Here is an example of the PHP class integration:
66
+ ```php
67
+ function iubenda_system( $html, $type = 'page' ) {
68
+ if ( empty( $html ) )
69
+ return;
70
+
71
+ require_once( 'iubenda.class.php' );
72
+
73
+ // separator
74
+ if ( ! iubendaParser::consent_given() && ! iubendaParser::bot_detected() ) {
75
+ $iubenda = new iubendaParser( $html, array( 'type' => in_array( $type, array( 'page', 'faster' ), true ) ? $type : 'page' ) );
76
+ $html = $iubenda->parse();
77
+ }
78
+
79
+ // finished
80
+ return $html;
81
+ }
82
+ ```
83
+
84
+ The `iubenda_system` method verifies if the page visitor consents to the use of cookies. If they have consented, the script returns the HTML provided as a parameter without taking any action such as parsing/replacing.
85
+ Simply copy your method into the PHP document and then call it with the following syntax `iubenda_system("contenutohtml");` that will return the code.
86
+
87
+ * Parsing/replacing the portions of code contained within `<!--IUB-COOKIE-BLOCK-START-->` and `<!--IUB-COOKIE-BLOCK-END-->`
88
+ * Automatic parsing/replacing of iframe that contain defined src
89
+ * Automatic parsing/replacing of scripts that contain defined src
90
+
91
+ These operations take place in accordance with the rules explained in [this guide](https://www.iubenda.com/en/help/posts/1229). We suggest that you consult the posts relating to the alteration of script, img and iframe tags.
92
+
93
+ ## Additional Help and docs
94
+
95
+ * [Full Cookie Solution Documentation](https://www.iubenda.com/en/help/1205-technical-documentation-for-the-cookie-law-solution-banner-cookie-policy-and-consent-management)
96
+ * [Prior Blocking Guide](https://www.iubenda.com/en/help/1229-cookie-law-solution-preventing-code-execution-that-could-install-cookies)
97
+ * [Cookie Solution Feature Overview](https://www.iubenda.com/en/features#cookie-solution)
98
+
99
+ ## Changelog
100
+
101
+ ##### 4.1.1
102
+ * Fix: AddThis per-purpose category
103
+
104
+ ##### 4.1.0
105
+ * New: Google AMP support
106
+
107
+ ##### 4.0.0
108
+ * New: Per-purpose script blocking support
109
+ * New: Reject button support
110
+
111
+ ##### 3.4.0
112
+ * New: Introducing wildcard support for scripts and iframes
113
+
114
+ ##### 3.3.1
115
+ * Tweak: Improved Google Tag Manager script blocking
116
+
117
+ ##### 3.3.0
118
+ * Tweak: Simple HTML Dom PHP class update to 1.9
119
+
120
+ ##### 3.2.0
121
+ * New: Introducing a way to skip specific script parsing
122
+
123
+ ##### 3.1.2
124
+ * Tweak: Improved Youtube and Google Maps support
125
+
126
+ ##### 3.1.1
127
+ * Tweak: Update composer.json autoloader
128
+
129
+ ##### 3.1.0
130
+ * Tweak: Update and extend the list of blocked scripts including Google Site Search, Google oAuth, Linkedin widgets, PayPal widgets, Pinterest, AddThis, Disqus, Optimizely, Neodata, Criteo, Outbrain, Headway, Codepen, Freshchat, Uservoice
131
+ , AdRoll, Olark, Segment, Kissmetrics, Mixpanel, Pingdom, Bing and Elevio
132
+
133
+ ##### 3.0.0
134
+ * Tweak: Update and unify iubenda parsing engine
135
+
136
+ ### License
137
+
138
+ This project is licensed under the GPl 3 license.
trunk/iubenda-cookie-class/composer.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "iubenda/iubenda-cookie-class",
3
+ "type": "project",
4
+ "description": "PHP class for the cookie law solution",
5
+ "keywords": ["cookie","gdpr"],
6
+ "homepage": "https://github.com/iubenda/iubenda-cookie-class",
7
+ "license": "MIT",
8
+ "require": {
9
+ "php": ">=5.2.4"
10
+ },
11
+ "autoload": {
12
+ "files": [
13
+ "iubenda.class.php"
14
+ ]
15
+ }
16
+ }
trunk/iubenda-cookie-class/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
trunk/iubenda-cookie-class/iubenda.class.faster.php ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * iubenda.class.faster.php
4
+ *
5
+ * @author iubenda s.r.l
6
+ * @copyright 2018-2020, iubenda s.r.l
7
+ * @license GNU/GPL
8
+ * @version 2.0.3
9
+ * @deprecated
10
+ *
11
+ * This program is free software: you can redistribute it and/or modify
12
+ * it under the terms of the GNU General Public License as published by
13
+ * the Free Software Foundation, either version 3 of the License, or
14
+ * (at your option) any later version.
15
+ *
16
+ * This program is distributed in the hope that it will be useful,
17
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ * GNU General Public License for more details.
20
+ *
21
+ * You should have received a copy of the GNU General Public License
22
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
23
+ */
24
+
25
+ class iubendaFaster {
26
+
27
+ // variables
28
+ const IUB_REGEX_PATTERN = '/<!--\s*IUB_COOKIE_POLICY_START\s*-->(.*?)<!--\s*IUB_COOKIE_POLICY_END\s*-->/s';
29
+ const IUB_REGEX_PATTERN_2 = '/<!--\s*IUB-COOKIE-BLOCK-START\s*-->(.*?)<!--\s*IUB-COOKIE-BLOCK-END\s*-->/s';
30
+
31
+ public $iub_comments_detected = array();
32
+ private $getBlack = array(
33
+ array(
34
+ // domains
35
+ "platform.twitter.com/widgets.js",
36
+ "apis.google.com/js/plusone.js",
37
+ "apis.google.com/js/platform.js",
38
+ "connect.facebook.net",
39
+ "www.youtube.com/iframe_api",
40
+ "pagead2.googlesyndication.com/pagead/js/adsbygoogle.js",
41
+ "sharethis.com/button/buttons.js",
42
+ "addthis.com/js/",
43
+ // javascript
44
+ "window.adsbygoogle"
45
+ ),
46
+ array
47
+ (
48
+ "youtube.com",
49
+ "platform.twitter.com",
50
+ "www.facebook.com/plugins/like.php",
51
+ "www.facebook.com/plugins/likebox.php",
52
+ "apis.google.com",
53
+ "www.google.com/maps/embed/",
54
+ "player.vimeo.com/video",
55
+ "maps.google.it/maps",
56
+ "www.google.com/maps/embed"
57
+ )
58
+ );
59
+
60
+ /**/
61
+ private $getBlank = "//cdn.iubenda.com/cookie_solution/empty.html";
62
+ private $getClass = array( "_iub_cs_activate", "_iub_cs_activate-inline" );
63
+
64
+ /**
65
+ * Methods
66
+ *
67
+ * @param type $offender
68
+ * @param type $blacklist
69
+ * @return boolean
70
+ */
71
+ public function isBlack( $offender, $blacklist ) {
72
+ // check if a string is in the black list.
73
+ if ( empty( $offender ) || empty( $blacklist ) ) {
74
+
75
+ return false;
76
+ }
77
+
78
+ foreach ( $blacklist as $black ) {
79
+ if ( strpos( $offender, $black ) !== false ) {
80
+
81
+ return true;
82
+ }
83
+ }
84
+
85
+ return false;
86
+ }
87
+
88
+ /**
89
+ * Parse automatically all the scripts in the page and converts it in text/plain
90
+ * if src or the whole output has inside one of the elements in $auto_script_tags array
91
+ *
92
+ * @param mixed $content
93
+ * @return mixed
94
+ */
95
+ public function isParse( $content ) {
96
+ // parse the entrie document and search for black elements.
97
+ libxml_use_internal_errors( true );
98
+
99
+ // parse all IUBENDAs comment and convert the code inside
100
+ $content = $this->parse_iubenda_comments( $content );
101
+
102
+ $src = "";
103
+
104
+ $blank = $this->getBlank;
105
+ $class = $this->getClass;
106
+
107
+ $list_1 = $this->getBlack[0];
108
+ $list_2 = $this->getBlack[1];
109
+
110
+ $document = new DOMDocument();
111
+
112
+ $document->formatOutput = true;
113
+ $document->preserveWhiteSpace = false;
114
+
115
+ $document->loadHTML( $content );
116
+
117
+ $scripts = $document->getElementsByTagName( "script" );
118
+ $iframes = $document->getElementsByTagName( "iframe" );
119
+
120
+ // parse the founded elements and check who is in black.
121
+ foreach ( $scripts as $script ) {
122
+ $src = $script->getAttribute( "src" );
123
+
124
+ if ( $this->isBlack( $src, $list_1 ) ) {
125
+ $script->setAttribute( "type", "text/plain" );
126
+ $script->setAttribute( "class", $script->getAttribute( "class" ) . " " . $class[0] );
127
+ } elseif ( $this->isBlack( $script->nodeValue, $list_1 ) ) {
128
+ $script->setAttribute( "type", "text/plain" );
129
+ $script->setAttribute( "class", $script->getAttribute( "class" ) . " " . $class[1] );
130
+ }
131
+ }
132
+ foreach ( $iframes as $iframe ) {
133
+
134
+ $src = $iframe->getAttribute( "src" );
135
+
136
+ if ( $this->isBlack( $src, $list_2 ) ) {
137
+ $iframe->setAttribute( "src", $blank );
138
+ $iframe->setAttribute( "suppressedsrc", $src );
139
+ $iframe->setAttribute( "class", $iframe->getAttribute( "class" ) . " " . $class[0] );
140
+ }
141
+ }
142
+
143
+ $content = $document->saveHTML();
144
+
145
+ libxml_use_internal_errors( false );
146
+
147
+ return $content;
148
+ }
149
+
150
+ /**
151
+ * Parse all IUBENDAs comment and convert the code inside with create_tags method
152
+ *
153
+ * @param mixed $content
154
+ * @return mixed
155
+ */
156
+ public function parse_iubenda_comments( $content ) {
157
+ foreach ( array( 'IUB_REGEX_PATTERN', 'IUB_REGEX_PATTERN_2' ) as $pattern ) {
158
+ preg_match_all( constant( 'self::' . $pattern ), $content, $scripts );
159
+
160
+ // found any content?
161
+ if ( is_array( $scripts[1] ) ) {
162
+ $count = count( $scripts[1] );
163
+ $js_scripts = array();
164
+
165
+ for ( $j = 0; $j < $count; $j ++ ) {
166
+ // keep it for testing
167
+ $this->iub_comments_detected[] = $scripts[1][$j];
168
+
169
+ // get HTML dom from string
170
+ $html = str_get_html( $scripts[1][$j], true, true, false );
171
+
172
+ // convert scripts, iframes and other code inside IUBENDAs comment in text/plain to not generate cookies
173
+ $js_scripts[] = $this->create_tags( $html );
174
+ }
175
+
176
+ if ( is_array( $js_scripts ) && $count >= 1 && count( $js_scripts ) >= 1 )
177
+ $content = strtr( $content, array_combine( $scripts[1], $js_scripts ) );
178
+ }
179
+ }
180
+
181
+ return $content;
182
+ }
183
+
184
+ /**
185
+ * Convert scripts, iframe and other code inside IUBENDAs comment in text/plain to not generate cookies
186
+ *
187
+ * @param mixed $content
188
+ * @return mixed
189
+ */
190
+ public function create_tags( $content ) {
191
+ $elements = $content->find( "*" );
192
+ $js = '';
193
+
194
+ if ( is_array( $elements ) ) {
195
+ $count = count( $elements );
196
+
197
+ for ( $j = 0; $j < $count; $j ++ ) {
198
+ $e = $elements[$j];
199
+
200
+ switch ( $e->tag ) {
201
+ case 'script':
202
+ $class = $e->class;
203
+ $e->class = $class . ' _iub_cs_activate';
204
+ $e->type = 'text/plain';
205
+ $js .= $e->outertext;
206
+ break;
207
+
208
+ case 'iframe':
209
+ $new_src = "//cdn.iubenda.com/cookie_solution/empty.html";
210
+ $class = $e->class;
211
+ $e->suppressedsrc = $e->src;
212
+ $e->src = $new_src;
213
+ $e->class = $class . ' _iub_cs_activate';
214
+ $js .= $e->outertext;
215
+ break;
216
+
217
+ default:
218
+ $js = $content;
219
+ break;
220
+ }
221
+ }
222
+ }
223
+
224
+ return $js;
225
+ }
226
+
227
+ }
trunk/iubenda-cookie-class/iubenda.class.page.php ADDED
@@ -0,0 +1,384 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * iubenda.class.page.php
4
+ *
5
+ * @author iubenda s.r.l
6
+ * @copyright 2018-2020, iubenda s.r.l
7
+ * @license GNU/GPL
8
+ * @version 1.0.3
9
+ * @deprecated
10
+ *
11
+ * This program is free software: you can redistribute it and/or modify
12
+ * it under the terms of the GNU General Public License as published by
13
+ * the Free Software Foundation, either version 3 of the License, or
14
+ * (at your option) any later version.
15
+ *
16
+ * This program is distributed in the hope that it will be useful,
17
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ * GNU General Public License for more details.
20
+ *
21
+ * You should have received a copy of the GNU General Public License
22
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
23
+ */
24
+
25
+ class iubendaPage {
26
+
27
+ // variables
28
+ const IUB_REGEX_PATTERN = '/<!--\s*IUB_COOKIE_POLICY_START\s*-->(.*?)<!--\s*IUB_COOKIE_POLICY_END\s*-->/s';
29
+ const IUB_REGEX_PATTERN_2 = '/<!--\s*IUB-COOKIE-BLOCK-START\s*-->(.*?)<!--\s*IUB-COOKIE-BLOCK-END\s*-->/s';
30
+
31
+ public $auto_script_tags = array(
32
+ 'platform.twitter.com/widgets.js',
33
+ 'apis.google.com/js/plusone.js',
34
+ 'apis.google.com/js/platform.js',
35
+ 'connect.facebook.net',
36
+ 'www.youtube.com/iframe_api',
37
+ 'pagead2.googlesyndication.com/pagead/js/adsbygoogle.js',
38
+ 'sharethis.com/button/buttons.js',
39
+ 'addthis.com/js/',
40
+ 'window.adsbygoogle'
41
+ );
42
+ public $auto_iframe_tags = array(
43
+ 'youtube.com',
44
+ 'platform.twitter.com',
45
+ 'www.facebook.com/plugins/like.php',
46
+ 'www.facebook.com/plugins/likebox.php',
47
+ 'apis.google.com',
48
+ 'www.google.com/maps/embed/',
49
+ 'player.vimeo.com/video',
50
+ 'maps.google.it/maps',
51
+ 'www.google.com/maps/embed',
52
+ 'window.adsbygoogle'
53
+ );
54
+ public $iub_comments_detected = array();
55
+ public $iframe_detected = array();
56
+ public $iframe_converted = array();
57
+ public $scripts_detected = array();
58
+ public $scripts_inline_detected = array();
59
+ public $scripts_inline_converted = array();
60
+ public $scripts_converted = array();
61
+
62
+ /**
63
+ * Construct: the whole HTML output of the page
64
+ *
65
+ * @param mixed $content_page
66
+ */
67
+ public function __construct( $content_page ) {
68
+ $this->original_content_page = $content_page;
69
+ $this->content_page = $content_page;
70
+ }
71
+
72
+ /**
73
+ * Print iubenda banner, parameter: the script code of iubenda to print the banner
74
+ *
75
+ * @param string $banner
76
+ * @return string
77
+ */
78
+ public function print_banner( $banner ) {
79
+ return $banner .= "\n
80
+ <script>
81
+ var iCallback = function(){};
82
+
83
+ if('callback' in _iub.csConfiguration) {
84
+ if('onConsentGiven' in _iub.csConfiguration.callback) iCallback = _iub.csConfiguration.callback.onConsentGiven;
85
+
86
+ _iub.csConfiguration.callback.onConsentGiven = function()
87
+ {
88
+ iCallback();
89
+
90
+ /*
91
+ * Separator
92
+ */
93
+
94
+ jQuery('noscript._no_script_iub').each(function (a, b) { var el = jQuery(b); el.after(el.html()); });
95
+ };
96
+ };
97
+ </script>";
98
+ }
99
+
100
+ /**
101
+ * Static, detect bot & crawler
102
+ *
103
+ * @return bool
104
+ */
105
+ static function bot_detected() {
106
+ return ( isset( $_SERVER['HTTP_USER_AGENT'] ) && preg_match( '/bot|crawl|slurp|spider|google|yahoo/i', $_SERVER['HTTP_USER_AGENT'] ) );
107
+ }
108
+
109
+ /**
110
+ * Static, utility function: Return true if the user has already given consent on the page
111
+ *
112
+ * @return boolean
113
+ */
114
+ static function consent_given() {
115
+ foreach ( $_COOKIE as $key => $value ) {
116
+ if ( iubendaPage::strpos_array( $key, array( '_iub_cs-s', '_iub_cs' ) ) ) {
117
+ return true;
118
+ }
119
+ }
120
+ return false;
121
+ }
122
+
123
+ /**
124
+ * Static, utility function: strpos for array
125
+ *
126
+ * @param type $haystack
127
+ * @param type $needle
128
+ * @return boolean
129
+ */
130
+ static function strpos_array( $haystack, $needle ) {
131
+ if ( is_array( $needle ) ) {
132
+ foreach ( $needle as $need ) {
133
+ if ( strpos( $haystack, $need ) !== false ) {
134
+ return true;
135
+ }
136
+ }
137
+ } else {
138
+ if ( strpos( $haystack, $need ) !== false ) {
139
+ return true;
140
+ }
141
+ }
142
+ return false;
143
+ }
144
+
145
+ /**
146
+ * Convert scripts, iframe and other code inside IUBENDAs comment in text/plain to not generate cookies
147
+ *
148
+ * @param mixed $html
149
+ * @return mixed
150
+ */
151
+ public function create_tags( $html ) {
152
+
153
+ $elements = $html->find( "*" );
154
+ $js = '';
155
+
156
+ if ( is_array( $elements ) ) {
157
+ $count = count( $elements );
158
+ for ( $j = 0; $j < $count; $j ++ ) {
159
+ $e = $elements[$j];
160
+ switch ( $e->tag ) {
161
+ case 'script':
162
+ $class = $e->class;
163
+ $e->class = $class . ' _iub_cs_activate';
164
+ $e->type = 'text/plain';
165
+ $js .= $e->outertext;
166
+ break;
167
+
168
+ case 'iframe':
169
+ $new_src = "//cdn.iubenda.com/cookie_solution/empty.html";
170
+ $class = $e->class;
171
+ $e->suppressedsrc = $e->src;
172
+ $e->src = $new_src;
173
+ $e->class = $class . ' _iub_cs_activate';
174
+ $js .= $e->outertext;
175
+ break;
176
+
177
+ default:
178
+ $js = $html;
179
+ break;
180
+ }
181
+ }
182
+ }
183
+ return $js;
184
+ }
185
+
186
+ /**
187
+ * Parse all IUBENDAs comment and convert the code inside with create_tags method
188
+ */
189
+ public function parse_iubenda_comments() {
190
+ foreach ( array( 'IUB_REGEX_PATTERN', 'IUB_REGEX_PATTERN_2' ) as $pattern ) {
191
+ preg_match_all( constant( 'self::' . $pattern ), $this->content_page, $scripts );
192
+
193
+ if ( is_array( $scripts[1] ) ) {
194
+ $count = count( $scripts[1] );
195
+ $js_scripts = array();
196
+ for ( $j = 0; $j < $count; $j ++ ) {
197
+ $this->iub_comments_detected[] = $scripts[1][$j];
198
+ $html = str_get_html( $scripts[1][$j], $lowercase = true, $forceTagsClosed = true, $stripRN = false );
199
+ $js_scripts[] = $this->create_tags( $html );
200
+ }
201
+
202
+ if ( is_array( $scripts[1] ) && is_array( $js_scripts ) ) {
203
+ if ( count( $scripts[1] ) >= 1 && count( $js_scripts ) >= 1 ) {
204
+ $this->content_page = strtr( $this->content_page, array_combine( $scripts[1], $js_scripts ) );
205
+ }
206
+ }
207
+ }
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Parse automatically all the scripts in the page and converts it in text/plain
213
+ * if src or the whole output has inside one of the elements in $auto_script_tags array
214
+ */
215
+ public function parse_scripts() {
216
+ $html = str_get_html( $this->content_page, $lowercase = true, $forceTagsClosed = true, $stripRN = false );
217
+
218
+ if ( is_object( $html ) ) {
219
+ $scripts = $html->find( "script" );
220
+ if ( is_array( $scripts ) ) {
221
+ $count = count( $scripts );
222
+ for ( $j = 0; $j < $count; $j ++ ) {
223
+ $s = $scripts[$j];
224
+ if ( ! empty( $s->innertext ) ) {
225
+ $this->scripts_detected[] = $s->innertext;
226
+ if ( iubendaPage::strpos_array( $s->innertext, $this->auto_script_tags ) !== false ) {
227
+ $class = $s->class;
228
+ $s->class = $class . ' _iub_cs_activate-inline';
229
+ $s->type = 'text/plain';
230
+ $this->scripts_converted[] = $s->innertext;
231
+ }
232
+ } else {
233
+ $src = $s->src;
234
+ if ( $src ) {
235
+ $this->scripts_inline_detected[] = $src;
236
+ if ( iubendaPage::strpos_array( $src, $this->auto_script_tags ) !== false ) {
237
+ $class = $s->class;
238
+ $s->class = $class . ' _iub_cs_activate';
239
+ $s->type = 'text/plain';
240
+ $this->scripts_inline_converted[] = $src;
241
+ }
242
+ }
243
+ }
244
+ }
245
+ }
246
+
247
+ // AdSense check by Peste Vasile Alexandru, AdSense here
248
+ $ad_found = false;
249
+
250
+ while ( preg_match( "#google_ad_client =(.*?);#i", $html ) ) {
251
+ $ad_found = true;
252
+ $ad_client = null;
253
+ $ad_slot = null;
254
+ $ad_width = null;
255
+ $ad_height = null;
256
+ $ad_block = null;
257
+
258
+ preg_match( "#google_ad_client =(.*?);#i", $html, $ad_client );
259
+ preg_match( "#google_ad_slot =(.*?);#i", $html, $ad_slot );
260
+ preg_match( "#google_ad_width =(.*?);#i", $html, $ad_width );
261
+ preg_match( "#google_ad_height =(.*?);#i", $html, $ad_height );
262
+
263
+ $html = preg_replace( "#google_ad_client =(.*?);#i", "", $html, 1 );
264
+ $html = preg_replace( "#google_ad_slot =(.*?);#i", "", $html, 1 );
265
+ $html = preg_replace( "#google_ad_width =(.*?);#i", "", $html, 1 );
266
+ $html = preg_replace( "#google_ad_height =(.*?);#i", "", $html, 1 );
267
+
268
+ $ad_client = trim( $ad_client[1] );
269
+ $ad_slot = trim( $ad_slot[1] );
270
+ $ad_width = trim( $ad_width[1] );
271
+ $ad_height = trim( $ad_height[1] );
272
+
273
+ $ad_class = 'class="_iub_cs_activate_google_ads"';
274
+ $ad_style = 'style="width:' . $ad_width . 'px; height:' . $ad_height . 'px;"';
275
+
276
+ $ad_client = 'data-client=' . $ad_client;
277
+ $ad_slot = 'data-slot=' . $ad_slot;
278
+ $ad_width = 'data-width="' . $ad_width . '"';
279
+ $ad_height = 'data-height="' . $ad_height . '"';
280
+
281
+ $ad_block = "<div $ad_style $ad_class $ad_width $ad_height $ad_slot $ad_client></div>";
282
+
283
+ $html = preg_replace( '#(<[^>]+) src="//pagead2.googlesyndication.com/pagead/show_ads.js"(.*?)</script>#i', $ad_block, $html, 1 );
284
+ }
285
+
286
+ if ( $ad_found ) {
287
+ $adsense_callback = "
288
+ <script>
289
+ function iubenda_adsense_unblock(){
290
+ var t = 1;
291
+ jQuery('._iub_cs_activate_google_ads').each(function() {
292
+ var banner = jQuery(this);
293
+ setTimeout(function(){
294
+ var client = banner.data('client');
295
+ var slot = banner.data('slot');
296
+ var width = banner.data('width');
297
+ var height = banner.data('height');
298
+ var adsense_script = '<scr'+'ipt>'
299
+ + 'google_ad_client = " . chr( 34 ) . "'+client+'" . chr( 34 ) . ";'
300
+ + 'google_ad_slot = '+slot+';'
301
+ + 'google_ad_width = '+width+';'
302
+ + 'google_ad_height = '+height+';'
303
+ + '</scr'+'ipt>';
304
+ var script = document.createElement('script');
305
+ var ads = document.createElement('ads');
306
+ var w = document.write;
307
+ script.setAttribute('type', 'text/javascript');
308
+ script.setAttribute('src', 'http://pagead2.googlesyndication.com/pagead/show_ads.js');
309
+ document.write = (function(params) {
310
+ ads.innerHTML = params;
311
+ document.write = w;
312
+ });
313
+ banner.html(adsense_script).append(ads).append(script);
314
+ }, t);
315
+ t += 300;
316
+ });
317
+ }
318
+ if('callback' in _iub.csConfiguration) {
319
+ _iub.csConfiguration.callback.onConsentGiven = iubenda_adsense_unblock;
320
+ }
321
+ else
322
+ {
323
+ _iub.csConfiguration.callback = {};
324
+
325
+ _iub.csConfiguration.callback.onConsentGiven = iubenda_adsense_unblock;
326
+ }
327
+ </script>
328
+ ";
329
+
330
+ $html = str_replace( "</body>", $adsense_callback . "</body>", $html );
331
+ }
332
+
333
+ $this->content_page = $html;
334
+ }
335
+ }
336
+
337
+ /**
338
+ * Parse automatically all the iframe in the page and change the src to suppressedsrc
339
+ * if src has inside one of the elements in $auto_iframe_tags array
340
+ */
341
+ public function parse_iframe() {
342
+ $html = str_get_html( $this->content_page, $lowercase = true, $forceTagsClosed = true, $stripRN = false );
343
+
344
+ if ( is_object( $html ) ) {
345
+ $iframes = $html->find( "iframe" );
346
+ if ( is_array( $iframes ) ) {
347
+ $count = count( $iframes );
348
+ for ( $j = 0; $j < $count; $j ++ ) {
349
+ $i = $iframes[$j];
350
+ $src = $i->src;
351
+ $this->iframe_detected[] = $src;
352
+ if ( iubendaPage::strpos_array( $src, $this->auto_iframe_tags ) !== false ) {
353
+ $new_src = "//cdn.iubenda.com/cookie_solution/empty.html";
354
+ $class = $i->class;
355
+ $i->suppressedsrc = $src;
356
+ $i->src = $new_src;
357
+ $i->class = $class . ' _iub_cs_activate';
358
+ $this->iframe_converted[] = $src;
359
+ }
360
+ }
361
+ }
362
+ $this->content_page = $html;
363
+ }
364
+ }
365
+
366
+ /**
367
+ * Call three methods to parse the page, iubendas comment, scripts + iframe
368
+ */
369
+ public function parse() {
370
+ $this->parse_iubenda_comments();
371
+ $this->parse_scripts();
372
+ $this->parse_iframe();
373
+ }
374
+
375
+ /**
376
+ * Return the final page to output
377
+ *
378
+ * @return mixed
379
+ */
380
+ public function get_converted_page() {
381
+ return $this->content_page;
382
+ }
383
+
384
+ }
trunk/iubenda-cookie-class/iubenda.class.php ADDED
@@ -0,0 +1,1024 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * iubenda.class.php
4
+ *
5
+ * @author iubenda s.r.l
6
+ * @copyright 2018-2020, iubenda s.r.l
7
+ * @license GNU/GPL
8
+ * @version 4.1.1
9
+ * @deprecated
10
+ *
11
+ * This program is free software: you can redistribute it and/or modify
12
+ * it under the terms of the GNU General Public License as published by
13
+ * the Free Software Foundation, either version 3 of the License, or
14
+ * (at your option) any later version.
15
+ *
16
+ * This program is distributed in the hope that it will be useful,
17
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ * GNU General Public License for more details.
20
+ *
21
+ * You should have received a copy of the GNU General Public License
22
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
23
+ */
24
+
25
+ class iubendaParser {
26
+
27
+ // variables
28
+ const IUB_REGEX_PATTERN = '/<!--\s*IUB_COOKIE_POLICY_START\s*-->(.*?)<!--\s*IUB_COOKIE_POLICY_END\s*-->/s';
29
+ const IUB_REGEX_PATTERN_2 = '/<!--\s*IUB-COOKIE-BLOCK-START\s*-->(.*?)<!--\s*IUB-COOKIE-BLOCK-END\s*-->/s';
30
+ const IUB_REGEX_PURPOSE_PATTERN = '/<!--\s*IUB-COOKIE-BLOCK-START-PURPOSE-(\d+)\s*-->(.*?)<!--\s*IUB-COOKIE-BLOCK-END-PURPOSE-\d+\s*-->/s';
31
+ const IUB_REGEX_SKIP_PATTERN = '/<!--\s*IUB-COOKIE-BLOCK-SKIP-START\s*-->(.*?)<!--\s*IUB-COOKIE-BLOCK-SKIP-END\s*-->/s';
32
+
33
+ // scripts
34
+ public $auto_script_tags = array();
35
+
36
+ // iframes
37
+ public $auto_iframe_tags = array();
38
+
39
+ // purposes
40
+ public $purposes = array();
41
+
42
+ // per-purpose scripts
43
+ public $script_tags = array(
44
+ // Strictly necessary
45
+ 1 => array(),
46
+ // Basic interactions & functionalities
47
+ 2 => array(
48
+ 'apis.google.com/js/api.js',
49
+ 'cse.google.com/cse.js',
50
+ 'googletagmanager.com/gtm.js',
51
+ 'loader.engage.gsfn.us/loader.js',
52
+ 'headwayapp.co/widget.js',
53
+ 'wchat.freshchat.com',
54
+ 'widget.uservoice.com',
55
+ 'UserVoice.push',
56
+ 'static.olark.com/jsclient/loader0.js',
57
+ 'cdn.elev.io',
58
+ 'paypalobjects.com/js/external/api.js',
59
+ 'paypalobjects.com/api/checkout.js'
60
+ ),
61
+ // Experience enhancement
62
+ 3 => array(
63
+ 'apis.google.com/js/plusone.js',
64
+ 'apis.google.com/js/client/plusone.js',
65
+ 'apis.google.com/js/platform.js',
66
+ 'www.youtube.com/iframe_api',
67
+ 'youtu.be',
68
+ 'platform.twitter.com/widgets.js',
69
+ 'instawidget.net/js/instawidget.js',
70
+ 'disqus.com/embed.js',
71
+ 'platform.linkedin.com/in.js',
72
+ 'pinterest.com/js/pinit.js',
73
+ 'codepen.io',
74
+ 'addthis.com/js/',
75
+ 'bat.bing.com'
76
+ ),
77
+ // Analytics
78
+ 4 => array(
79
+ 'sharethis.com/button/buttons.js',
80
+ 'scorecardresearch.com/beacon.js',
81
+ 'neodatagroup.com',
82
+ 'lp4.io',
83
+ 'cdn.optimizely.com/js/',
84
+ 'cdn.segment.io/analytics.js',
85
+ 'cdn.segment.com/analytics.js',
86
+ 'i.kissmetrics.com/i.js',
87
+ 'cdn.mxpnl.com',
88
+ 'rum-static.pingdom.net/prum.min.js'
89
+ ),
90
+ // Targeting & Advertising
91
+ 5 => array(
92
+ 'googlesyndication.com/pagead/js/adsbygoogle.js',
93
+ 'googlesyndication.com/pagead/show_ads.js',
94
+ 'googleadservices.com/pagead/conversion.js',
95
+ 'www.googletagmanager.com/gtag/js',
96
+ 'window.adsbygoogle',
97
+ 'static.ads-twitter.com',
98
+ 'connect.facebook.net',
99
+ 'static.criteo.net/js/',
100
+ 'adagionet.com/uploads/js/sipra.js',
101
+ 'cdn-wx.rainbowtgx.com/rtgx.js',
102
+ 'outbrain.js',
103
+ 's.adroll.com',
104
+ 'scdn.cxense.com'
105
+ )
106
+ );
107
+
108
+ // per-purpose iframes
109
+ public $iframe_tags = array(
110
+ // Strictly necessary
111
+ 1 => array(),
112
+ // Basic interactions & functionalities
113
+ 2 => array(
114
+ 'googletagmanager.com/ns.html'
115
+ ),
116
+ // Experience enhancement
117
+ 3 => array(
118
+ 'apis.google.com',
119
+ 'maps.google.it/maps',
120
+ 'maps.google.com/maps',
121
+ 'www.google.com/maps/embed',
122
+ 'youtube.com',
123
+ 'platform.twitter.com',
124
+ 'player.vimeo.com',
125
+ 'www.facebook.com/plugins/like.php',
126
+ 'www.facebook.com/*/plugins/like.php',
127
+ 'www.facebook.com/plugins/likebox.php',
128
+ 'www.facebook.com/*/plugins/likebox.php'
129
+ ),
130
+ // Analytics
131
+ 4 => array(),
132
+ // Targeting & Advertising
133
+ 5 => array(
134
+ 'window.adsbygoogle',
135
+ '4wnet.com'
136
+ )
137
+ );
138
+
139
+ private $type = 'page';
140
+ private $amp = false;
141
+ public $iub_comments_detected = array();
142
+ public $skipped_comments_detected = array();
143
+ public $iframes_skipped = array();
144
+ public $iframes_detected = array();
145
+ public $iframes_converted = array();
146
+ public $scripts_skipped = array();
147
+ public $scripts_detected = array();
148
+ public $scripts_converted = array();
149
+ public $scripts_inline_skipped = array();
150
+ public $scripts_inline_detected = array();
151
+ public $scripts_inline_converted = array();
152
+ private $iub_empty = '//cdn.iubenda.com/cookie_solution/empty.html';
153
+ private $iub_class = '_iub_cs_activate';
154
+ private $iub_class_inline = '_iub_cs_activate-inline';
155
+ private $iub_class_skip = '_iub_cs_skip';
156
+
157
+ /**
158
+ * Construct: the whole HTML output of the page
159
+ *
160
+ * @param mixed $content_page
161
+ * @param array $args
162
+ */
163
+ public function __construct( $content_page = '', $args = array() ) {
164
+ // valid type?
165
+ $this->type = ! empty( $args['type'] ) && in_array( $args['type'], array( 'page', 'faster' ), true ) ? $args['type'] : 'page';
166
+
167
+ // amp support>
168
+ $this->amp = (bool) ( isset( $args['amp'] ) && $args['amp'] === true );
169
+
170
+ // load Simple HTML DOM if needed
171
+ if ( ! function_exists( 'file_get_html' ) || ! function_exists( 'str_get_html' ) )
172
+ require_once( dirname( __FILE__ ) . '/simple_html_dom.php' );
173
+
174
+ // set content
175
+ $this->original_content_page = $content_page;
176
+ $this->content_page = $content_page;
177
+
178
+ // get purposes
179
+ $this->purposes = self::get_purposes();
180
+
181
+ // check for additional scripts
182
+ if ( ! empty( $args['scripts'] ) && is_array( $args['scripts'] ) ) {
183
+ // array is not multidimensional, backward compatibility, so block it
184
+ if ( ! is_array( reset( $args['scripts'] ) ) ) {
185
+ $this->auto_script_tags = array_merge( $this->auto_script_tags, $args['scripts'] );
186
+ // array is multidimensional, assign per purpose
187
+ } else {
188
+ // block unassigned script
189
+ if ( array_key_exists( 0, $args['scripts'] ) ) {
190
+ $this->auto_script_tags = array_merge( $this->auto_script_tags, $args['scripts'][0] );
191
+ unset( $args['scripts'][0] );
192
+ }
193
+
194
+ $this->script_tags = $this->array_merge_custom( $this->script_tags, $args['scripts'] );
195
+ }
196
+ }
197
+
198
+ // check for additional iframes
199
+ if ( ! empty( $args['iframes'] ) && is_array( $args['iframes'] ) ) {
200
+ // array is not multidimensional, backward compatibility, so assign block it
201
+ if ( ! is_array( reset( $args['iframes'] ) ) ) {
202
+ $this->auto_iframe_tags = array_merge( $this->auto_iframe_tags, $args['iframes'] );
203
+ // array is multidimensional, assign per purpose
204
+ } else {
205
+ // block unassigned script
206
+ if ( array_key_exists( 0, $args['iframes'] ) ) {
207
+ $this->auto_iframe_tags = array_merge( $this->auto_iframe_tags, $args['iframes'][0] );
208
+ unset( $args['iframes'][0] );
209
+ }
210
+
211
+ $this->iframe_tags = $this->array_merge_custom( $this->iframe_tags, $args['iframes'] );
212
+ }
213
+ }
214
+
215
+ // get script tags to block
216
+ $this->auto_script_tags = array_unique( self::get_script_tags() );
217
+
218
+ // get iframes tags to block
219
+ $this->auto_iframe_tags = array_unique( self::get_iframe_tags() );
220
+ }
221
+
222
+ /**
223
+ * Static, detect bot & crawler
224
+ *
225
+ * @return bool
226
+ */
227
+ static function bot_detected() {
228
+ return ( isset( $_SERVER['HTTP_USER_AGENT'] ) && preg_match( '/bot|crawl|slurp|spider|google|yahoo/i', $_SERVER['HTTP_USER_AGENT'] ) );
229
+ }
230
+
231
+ /**
232
+ * Static, utility function: Return true if the user has already given consent on the page
233
+ *
234
+ * @return boolean
235
+ */
236
+ static function consent_given() {
237
+ $consent_given = false;
238
+
239
+ foreach ( $_COOKIE as $key => $value ) {
240
+ $found = self::strpos_array( $key, array( '_iub_cs-s', '_iub_cs' ) );
241
+
242
+ if ( $found !== false ) {
243
+ $consent_data = json_decode( stripslashes( $value ), true );
244
+
245
+ // read cookie value if given
246
+ if ( isset( $consent_data['consent'] ) && $consent_data['consent'] == true )
247
+ $consent_given = true;
248
+
249
+ // read purposes if given
250
+ if ( ! empty( $consent_data['purposes'] ) && is_array( $consent_data['purposes'] ) ) {
251
+ // all purposes accepted, consent given
252
+ if ( ! in_array( false, $consent_data['purposes'] ) )
253
+ $consent_given = true;
254
+ }
255
+ }
256
+ }
257
+
258
+ return $consent_given;
259
+ }
260
+
261
+ /**
262
+ * Get user accepted purposes.
263
+ *
264
+ * @return array
265
+ */
266
+ static function get_purposes() {
267
+ $purposes = array();
268
+
269
+ if ( ! empty( $_COOKIE ) ) {
270
+ foreach ( $_COOKIE as $key => $value ) {
271
+ $found = self::strpos_array( $key, array( '_iub_cs-s', '_iub_cs' ) );
272
+
273
+ if ( $found !== false ) {
274
+ $consent_data = json_decode( $value, true );
275
+
276
+ // read purposes if given
277
+ if ( ! empty( $consent_data['purposes'] ) && is_array( $consent_data['purposes'] ) )
278
+ $purposes = $consent_data['purposes'];
279
+ }
280
+ }
281
+ }
282
+
283
+ return $purposes;
284
+ }
285
+
286
+ /**
287
+ * Get script tags to be blocked.
288
+ *
289
+ * @return array
290
+ */
291
+ private function get_script_tags() {
292
+ $tags = $this->auto_script_tags;
293
+
294
+ foreach ( $this->script_tags as $purpose_id => $tags_list ) {
295
+ // empty tags list, go to another
296
+ if ( empty( $tags_list ) )
297
+ continue;
298
+
299
+ // purposes available, filter per purpose
300
+ if ( ! empty( $this->purposes ) ) {
301
+ // don't block scripts unavailable in the user purposes
302
+ // if ( array_key_exists( $purpose_id, $this->purposes ) && $this->purposes[$purpose_id] == false ) {
303
+
304
+ // block scripts unavailable in the user purposes
305
+ if ( ! isset( $this->purposes[$purpose_id] ) || $this->purposes[$purpose_id] == false ) {
306
+ foreach ( $tags_list as $tag ) {
307
+ $tags[] = $tag;
308
+ }
309
+ }
310
+ // no purposes yet, just add all scripts
311
+ } else {
312
+ foreach ( $tags_list as $tag ) {
313
+ $tags[] = $tag;
314
+ }
315
+ }
316
+ }
317
+
318
+ return $tags;
319
+ }
320
+
321
+ /**
322
+ * Get iframe tags to be blocked.
323
+ *
324
+ * @return array
325
+ */
326
+ private function get_iframe_tags() {
327
+ $tags = $this->auto_iframe_tags;
328
+
329
+ foreach ( $this->iframe_tags as $purpose_id => $tags_list ) {
330
+ // empty tags list, go to another
331
+ if ( empty( $tags_list ) )
332
+ continue;
333
+
334
+ // purposes available, filter per purpose
335
+ if ( ! empty( $this->purposes ) ) {
336
+ // don't block iframes unavailable in the user purposes
337
+ // if ( array_key_exists( $purpose_id, $this->purposes ) && $this->purposes[$purpose_id] == false ) {
338
+
339
+ // block iframes unavailable in the user purposes
340
+ if ( ! isset( $this->purposes[$purpose_id] ) && $this->purposes[$purpose_id] == false ) {
341
+ foreach ( $tags_list as $tag ) {
342
+ $tags[] = $tag;
343
+ }
344
+ }
345
+ // no purposes yet, just add all scripts
346
+ } else {
347
+ foreach ( $tags_list as $tag ) {
348
+ $tags[] = $tag;
349
+ }
350
+ }
351
+ }
352
+
353
+ return $tags;
354
+ }
355
+
356
+ /**
357
+ * Convert scripts, iframe and other code inside IUBENDAs comment in text/plain to not generate cookies
358
+ *
359
+ * @param mixed $content
360
+ * @return mixed
361
+ */
362
+ public function create_tags( $content, $args ) {
363
+ $elements = $content->find( "*" );
364
+ $js = '';
365
+
366
+ if ( is_array( $elements ) ) {
367
+ $count = count( $elements );
368
+
369
+ for ( $j = 0; $j < $count; $j++ ) {
370
+ $e = $elements[$j];
371
+
372
+ switch ( $e->tag ) {
373
+ case 'script':
374
+ if ( $args['pattern'] === 'IUB_REGEX_PURPOSE_PATTERN' )
375
+ $e->{'data-iub-purposes'} = $args['number'];
376
+
377
+ // AMP support
378
+ if ( $this->amp )
379
+ $e->{'data-block-on-consent'} = '_till_accepted';
380
+
381
+ $class = $e->class;
382
+ $e->class = $class . ' ' . $this->iub_class;
383
+ $e->type = 'text/plain';
384
+ $js .= $e->outertext;
385
+ break;
386
+
387
+ case 'iframe':
388
+ if ( $args['pattern'] === 'IUB_REGEX_PURPOSE_PATTERN' )
389
+ $e->{'data-iub-purposes'} = $args['number'];
390
+
391
+ // AMP support
392
+ if ( $this->amp )
393
+ $e->{'data-block-on-consent'} = '_till_accepted';
394
+
395
+ $new_src = $this->iub_empty;
396
+ $class = $e->class;
397
+ $e->suppressedsrc = $e->src;
398
+ $e->src = $new_src;
399
+ $e->class = $class . ' ' . $this->iub_class;
400
+ $js .= $e->outertext;
401
+ break;
402
+
403
+ default:
404
+ $js .= $e->outertext;
405
+ break;
406
+ }
407
+ }
408
+ }
409
+
410
+ return $js;
411
+ }
412
+
413
+ /**
414
+ * Skip scripts and iframes inside IUBENDAs comments.
415
+ *
416
+ * @param string $content
417
+ * @return string
418
+ */
419
+ public function skip_tags( $content ) {
420
+ $elements = $content->find( "*" );
421
+ $js = '';
422
+
423
+ if ( is_array( $elements ) ) {
424
+ $count = count( $elements );
425
+
426
+ for ( $j = 0; $j < $count; $j++ ) {
427
+ $element = $elements[$j];
428
+
429
+ switch ( $element->tag ) {
430
+ case 'script':
431
+ case 'iframe':
432
+ $class = trim( $element->class );
433
+ $element->class = ( $class !== '' ? $class . ' ' : '' ) . $this->iub_class_skip;
434
+ $js .= $element->outertext;
435
+ break;
436
+
437
+ default:
438
+ $js .= $element->outertext;
439
+ break;
440
+ }
441
+ }
442
+ }
443
+
444
+ return $js;
445
+ }
446
+
447
+ /**
448
+ * Parse automatically all the scripts in the page and converts it in text/plain
449
+ * if src or the whole output has inside one of the elements in $auto_script_tags array
450
+ *
451
+ * @return void
452
+ */
453
+ public function parse_scripts() {
454
+ switch ( $this->type ) {
455
+ case 'page':
456
+ // get page contents
457
+ $html = str_get_html( $this->content_page, true, true, false );
458
+
459
+ if ( is_object( $html ) ) {
460
+ // get scripts
461
+ $scripts = $html->find( 'script' );
462
+
463
+ if ( is_array( $scripts ) ) {
464
+ $count = count( $scripts );
465
+ $class_skip = $this->iub_class_skip;
466
+
467
+ // loop through scripts
468
+ for ( $j = 0; $j < $count; $j ++ ) {
469
+ $s = $scripts[$j];
470
+ $script_class = trim( $s->class );
471
+
472
+ if ( $script_class !== '' ) {
473
+ $classes = explode( ' ', $script_class );
474
+
475
+ if ( in_array( $class_skip, $classes, true ) ) {
476
+ // add script as skipped
477
+ if ( ! empty( $s->innertext ) )
478
+ $this->scripts_inline_skipped[] = $s->innertext;
479
+ else
480
+ $this->scripts_skipped[] = $s->src;
481
+
482
+ continue;
483
+ }
484
+ }
485
+
486
+ if ( ! empty( $s->innertext ) ) {
487
+ $this->scripts_inline_detected[] = $s->innertext;
488
+
489
+ $found = self::strpos_array( $s->innertext, $this->auto_script_tags );
490
+
491
+ if ( $found !== false ) {
492
+ $class = $s->class;
493
+ $s->class = $class . ' ' . $this->iub_class_inline;
494
+ $s->type = 'text/plain';
495
+ $this->scripts_inline_converted[] = $s->innertext;
496
+ }
497
+ } else {
498
+ $src = $s->src;
499
+
500
+ if ( $src ) {
501
+ $this->scripts_detected[] = $src;
502
+
503
+ $found = self::strpos_array( $src, $this->auto_script_tags );
504
+
505
+ if ( $found !== false ) {
506
+ $class = $s->class;
507
+ $s->class = $class . ' ' . $this->iub_class;
508
+ $s->type = 'text/plain';
509
+
510
+ // add data-iub-purposes attribute
511
+ $s->{'data-iub-purposes'} = $this->recursive_array_search( $found, $this->script_tags );
512
+
513
+ // AMP support
514
+ if ( $this->amp )
515
+ $s->{'data-block-on-consent'} = '_till_accepted';
516
+
517
+ $this->scripts_converted[] = $src;
518
+ }
519
+ }
520
+ }
521
+ }
522
+ }
523
+
524
+ // AdSense check by Peste Vasile Alexandru, AdSense here
525
+ $ad_found = false;
526
+
527
+ while ( preg_match( "#google_ad_client =(.*?);#i", $html ) ) {
528
+ $ad_found = true;
529
+ $ad_client = null;
530
+ $ad_slot = null;
531
+ $ad_width = null;
532
+ $ad_height = null;
533
+ $ad_block = null;
534
+
535
+ preg_match( "#google_ad_client =(.*?);#i", $html, $ad_client );
536
+ preg_match( "#google_ad_slot =(.*?);#i", $html, $ad_slot );
537
+ preg_match( "#google_ad_width =(.*?);#i", $html, $ad_width );
538
+ preg_match( "#google_ad_height =(.*?);#i", $html, $ad_height );
539
+
540
+ $html = preg_replace( "#google_ad_client =(.*?);#i", "", $html, 1 );
541
+ $html = preg_replace( "#google_ad_slot =(.*?);#i", "", $html, 1 );
542
+ $html = preg_replace( "#google_ad_width =(.*?);#i", "", $html, 1 );
543
+ $html = preg_replace( "#google_ad_height =(.*?);#i", "", $html, 1 );
544
+
545
+ $ad_client = trim( $ad_client[1] );
546
+ $ad_slot = trim( $ad_slot[1] );
547
+ $ad_width = trim( $ad_width[1] );
548
+ $ad_height = trim( $ad_height[1] );
549
+
550
+ $ad_class = 'class="' . $this->iub_class . '_google_ads"';
551
+ $ad_style = 'style="width:' . $ad_width . 'px; height:' . $ad_height . 'px;"';
552
+
553
+ $ad_client = 'data-client=' . $ad_client;
554
+ $ad_slot = 'data-slot=' . $ad_slot;
555
+ $ad_width = 'data-width="' . $ad_width . '"';
556
+ $ad_height = 'data-height="' . $ad_height . '"';
557
+
558
+ $ad_block = "<div $ad_style $ad_class $ad_width $ad_height $ad_slot $ad_client></div>";
559
+
560
+ $html = preg_replace( '#(<[^>]+) src="//pagead2.googlesyndication.com/pagead/show_ads.js"(.*?)</script>#i', $ad_block, $html, 1 );
561
+ }
562
+
563
+ if ( $ad_found ) {
564
+ $adsense_callback = "
565
+ <script>
566
+ function iubenda_adsense_unblock() {
567
+ var t = 1;
568
+ jQuery('." . $this->iub_class . "_google_ads').each(function() {
569
+ var banner = jQuery(this);
570
+ setTimeout(function(){
571
+ var client = banner.data('client');
572
+ var slot = banner.data('slot');
573
+ var width = banner.data('width');
574
+ var height = banner.data('height');
575
+ var adsense_script = '<scr'+'ipt>'
576
+ + 'google_ad_client = " . chr( 34 ) . "'+client+'" . chr( 34 ) . ";'
577
+ + 'google_ad_slot = '+slot+';'
578
+ + 'google_ad_width = '+width+';'
579
+ + 'google_ad_height = '+height+';'
580
+ + '</scr'+'ipt>';
581
+ var script = document.createElement('script');
582
+ var ads = document.createElement('ads');
583
+ var w = document.write;
584
+ script.setAttribute('type', 'text/javascript');
585
+ script.setAttribute('src', 'http://pagead2.googlesyndication.com/pagead/show_ads.js');
586
+ document.write = (function(params) {
587
+ ads.innerHTML = params;
588
+ document.write = w;
589
+ });
590
+ banner.html(adsense_script).append(ads).append(script);
591
+ }, t);
592
+ t += 300;
593
+ });
594
+ }
595
+
596
+ if ( 'callback' in _iub.csConfiguration ) {
597
+ _iub.csConfiguration.callback.onConsentGiven = iubenda_adsense_unblock;
598
+ } else {
599
+ _iub.csConfiguration.callback = {};
600
+
601
+ _iub.csConfiguration.callback.onConsentGiven = iubenda_adsense_unblock;
602
+ }
603
+ </script>";
604
+
605
+ $html = str_replace( '</body>', $adsense_callback . '</body>', $html );
606
+ }
607
+
608
+ $this->content_page = $html;
609
+ }
610
+ break;
611
+
612
+ case 'faster':
613
+ libxml_use_internal_errors( true );
614
+
615
+ // get class attributes for better performance
616
+ $script_tags = $this->auto_script_tags;
617
+ $class = $this->iub_class;
618
+ $class_inline = $this->iub_class_inline;
619
+ $class_skip = $this->iub_class_skip;
620
+
621
+ // create new DOM document
622
+ $document = new DOMDocument();
623
+
624
+ // set document arguments
625
+ $document->formatOutput = true;
626
+ $document->preserveWhiteSpace = false;
627
+
628
+ // load HTML
629
+ $document->loadHTML( $this->content_page );
630
+
631
+ // search for scripts
632
+ $scripts = $document->getElementsByTagName( 'script' );
633
+
634
+ // any scripts?
635
+ if ( ! empty( $scripts ) && is_object( $scripts ) ) {
636
+ foreach ( $scripts as $script ) {
637
+ $src = $script->getAttribute( 'src' );
638
+ $script_class = trim( $script->getAttribute( 'class' ) );
639
+
640
+ if ( $script_class !== '' ) {
641
+ $classes = explode( ' ', $script_class );
642
+
643
+ if ( in_array( $class_skip, $classes, true ) ) {
644
+ // add script as skipped
645
+ if ( ! empty( $src ) )
646
+ $this->scripts_skipped[] = $src;
647
+
648
+ // add inline script as skipped
649
+ if ( ! empty( $script->nodeValue ) )
650
+ $this->scripts_inline_skipped[] = $script->nodeValue;
651
+
652
+ continue;
653
+ }
654
+ }
655
+
656
+ // add script as detected
657
+ if ( ! empty( $src ) )
658
+ $this->scripts_detected[] = $src;
659
+
660
+ // add inline script as detected
661
+ if ( ! empty( $script->nodeValue ) )
662
+ $this->scripts_inline_detected[] = $script->nodeValue;
663
+
664
+ $found = self::strpos_array( $src, $script_tags );
665
+ $found_inline = self::strpos_array( $script->nodeValue, $script_tags );
666
+
667
+ if ( $found !== false ) {
668
+ $script->setAttribute( 'type', 'text/plain' );
669
+ $script->setAttribute( 'class', $script->getAttribute( 'class' ) . ' ' . $class );
670
+
671
+ // add data-iub-purposes attribute
672
+ $script->setAttribute( 'data-iub-purposes', $this->recursive_array_search( $found, $this->script_tags ) );
673
+
674
+ // AMP support
675
+ if ( $this->amp )
676
+ $script->setAttribute( 'data-block-on-consent', '_till_accepted' );
677
+
678
+ // add script as converted
679
+ $this->scripts_converted[] = $src;
680
+ } elseif ( $found_inline !== false ) {
681
+ $script->setAttribute( 'type', 'text/plain' );
682
+ $script->setAttribute( 'class', $script->getAttribute( 'class' ) . ' ' . $class_inline );
683
+
684
+ // AMP support
685
+ if ( $this->amp )
686
+ $script->setAttribute( 'data-block-on-consent', '_till_accepted' );
687
+
688
+ // add inline script as converted
689
+ $this->scripts_inline_converted[] = $script->nodeValue;
690
+ }
691
+ }
692
+ }
693
+
694
+ // save document content
695
+ $content = $document->saveHTML();
696
+
697
+ libxml_use_internal_errors( false );
698
+
699
+ // update content
700
+ $this->content_page = $content;
701
+ break;
702
+ }
703
+ }
704
+
705
+ /**
706
+ * Parse automatically all the iframe in the page and change the src to suppressedsrc
707
+ * if src has inside one of the elements in $auto_iframe_tags array
708
+ *
709
+ * @return void
710
+ */
711
+ public function parse_iframes() {
712
+ switch ( $this->type ) {
713
+ case 'page':
714
+ $html = str_get_html( $this->content_page, true, true, false );
715
+
716
+ if ( is_object( $html ) ) {
717
+ $iframes = $html->find( 'iframe' );
718
+
719
+ if ( is_array( $iframes ) ) {
720
+ $count = count( $iframes );
721
+ $class_skip = $this->iub_class_skip;
722
+
723
+ for ( $j = 0; $j < $count; $j ++ ) {
724
+ $i = $iframes[$j];
725
+ $iframe_class = trim( $i->class );
726
+
727
+ if ( $iframe_class !== '' ) {
728
+ $classes = explode( ' ', $iframe_class );
729
+
730
+ if ( in_array( $class_skip, $classes, true ) ) {
731
+ // add iframe as skipped
732
+ $this->iframes_skipped[] = $i->src;
733
+
734
+ continue;
735
+ }
736
+ }
737
+
738
+ $src = $i->src;
739
+ $this->iframes_detected[] = $src;
740
+
741
+ $found = self::strpos_array( $src, $this->auto_iframe_tags );
742
+
743
+ if ( $found !== false ) {
744
+ $class = $i->class;
745
+ $i->suppressedsrc = $src;
746
+ $i->src = $this->iub_empty;
747
+ $i->class = $class . ' ' . $this->iub_class;
748
+
749
+ // add data-iub-purposes attribute
750
+ $i->{'data-iub-purposes'} = $this->recursive_array_search( $found, $this->iframe_tags );
751
+
752
+ // AMP support
753
+ if ( $this->amp )
754
+ $i->{'data-block-on-consent'} = '_till_accepted';
755
+
756
+ $this->iframes_converted[] = $src;
757
+ }
758
+ }
759
+ }
760
+
761
+ $this->content_page = $html;
762
+ }
763
+ break;
764
+
765
+ case 'faster':
766
+ libxml_use_internal_errors( true );
767
+
768
+ // get class attributes for better performance
769
+ $iframe_tags = $this->auto_iframe_tags;
770
+ $empty = $this->iub_empty;
771
+ $class = $this->iub_class;
772
+ $class_skip = $this->iub_class_skip;
773
+
774
+ // create new DOM document
775
+ $document = new DOMDocument();
776
+
777
+ // set document arguments
778
+ $document->formatOutput = true;
779
+ $document->preserveWhiteSpace = false;
780
+
781
+ // load HTML
782
+ $document->loadHTML( $this->content_page );
783
+
784
+ // search for iframes
785
+ $iframes = $document->getElementsByTagName( 'iframe' );
786
+
787
+ // any iframes?
788
+ if ( ! empty( $iframes ) && is_object( $iframes ) ) {
789
+ foreach ( $iframes as $iframe ) {
790
+ $src = $iframe->getAttribute( 'src' );
791
+ $iframe_class = trim( $iframe->getAttribute( 'class' ) );
792
+
793
+ if ( $iframe_class !== '' ) {
794
+ $classes = explode( ' ', $iframe_class );
795
+
796
+ if ( in_array( $class_skip, $classes, true ) ) {
797
+ // add iframe as skipped
798
+ $this->iframes_skipped[] = $src;
799
+
800
+ continue;
801
+ }
802
+ }
803
+
804
+ // add iframe as detected
805
+ $this->iframes_detected[] = $src;
806
+
807
+ $found = self::strpos_array( $src, $iframe_tags );
808
+
809
+ if ( $found !== false ) {
810
+ $iframe->setAttribute( 'src', $empty );
811
+ $iframe->setAttribute( 'suppressedsrc', $src );
812
+ $iframe->setAttribute( 'class', $iframe_class . ' ' . $class );
813
+
814
+ // per purpose, add data-iub-purposes attribute
815
+ $iframe->setAttribute( 'data-iub-purposes', $this->recursive_array_search( $found, $this->iframe_tags ) );
816
+
817
+ // AMP support
818
+ if ( $this->amp )
819
+ $iframe->setAttribute( 'data-block-on-consent', '_till_accepted' );
820
+
821
+ // add iframe as converted
822
+ $this->iframes_converted[] = $src;
823
+ }
824
+ }
825
+ }
826
+
827
+ // save document content
828
+ $content = $document->saveHTML();
829
+
830
+ libxml_use_internal_errors( false );
831
+
832
+ // update content
833
+ $this->content_page = $content;
834
+ break;
835
+ }
836
+ }
837
+
838
+ /**
839
+ * Parse all IUBENDAs comments.
840
+ *
841
+ * @return void
842
+ */
843
+ public function parse_comments() {
844
+ // skip
845
+ preg_match_all( constant( 'self::IUB_REGEX_SKIP_PATTERN' ), $this->content_page, $scripts );
846
+
847
+ // found any content?
848
+ if ( is_array( $scripts[1] ) ) {
849
+ $count = count( $scripts[1] );
850
+ $js_scripts = array();
851
+
852
+ for ( $j = 0; $j < $count; $j++ ) {
853
+ $this->skipped_comments_detected[] = $scripts[1][$j];
854
+
855
+ // get HTML dom from string
856
+ $html = str_get_html( $scripts[1][$j], true, true, false );
857
+
858
+ // skip scripts and iframes inside iubenda's comments
859
+ $js_scripts[] = $this->skip_tags( $html );
860
+ }
861
+
862
+ if ( ( is_array( $scripts[1] ) && is_array( $js_scripts ) ) && ( $count >= 1 && count( $js_scripts ) >= 1 ) )
863
+ $this->content_page = strtr( $this->content_page, array_combine( $scripts[1], $js_scripts ) );
864
+ }
865
+
866
+ unset( $scripts );
867
+
868
+ // block
869
+ foreach ( array( 'IUB_REGEX_PATTERN', 'IUB_REGEX_PATTERN_2', 'IUB_REGEX_PURPOSE_PATTERN' ) as $pattern ) {
870
+ preg_match_all( constant( 'self::' . $pattern ), $this->content_page, $scripts );
871
+
872
+ $chunks = array();
873
+ $args = array(
874
+ 'pattern' => $pattern
875
+ );
876
+
877
+ if ( $pattern === 'IUB_REGEX_PURPOSE_PATTERN' ) {
878
+ $numbers = $scripts[1];
879
+ $chunks = $scripts[2];
880
+ } else
881
+ $chunks = $scripts[1];
882
+
883
+ // found any content?
884
+ if ( is_array( $chunks ) ) {
885
+ $count = count( $chunks );
886
+ $js_scripts = array();
887
+
888
+ for ( $j = 0; $j < $count; $j++ ) {
889
+ $this->iub_comments_detected[] = $chunks[$j];
890
+
891
+ // get HTML dom from string
892
+ $html = str_get_html( $chunks[$j], true, true, false );
893
+
894
+ if ( $pattern === 'IUB_REGEX_PURPOSE_PATTERN' )
895
+ $args['number'] = $numbers[$j];
896
+
897
+ // convert scripts, iframes and other code inside IUBENDAs comment in text/plain to not generate cookies
898
+ $js_scripts[] = $this->create_tags( $html, $args );
899
+ }
900
+
901
+ if ( ( is_array( $chunks ) && is_array( $js_scripts ) ) && ( $count >= 1 && count( $js_scripts ) >= 1 ) )
902
+ $this->content_page = strtr( $this->content_page, array_combine( $chunks, $js_scripts ) );
903
+ }
904
+ }
905
+ }
906
+
907
+ /**
908
+ * Call three methods to parse the page, iubendas comment, scripts and iframes
909
+ *
910
+ * @return string Content
911
+ */
912
+ public function parse() {
913
+ $this->parse_comments();
914
+ $this->parse_scripts();
915
+ $this->parse_iframes();
916
+
917
+ return $this->content_page;
918
+ }
919
+
920
+ /**
921
+ * Return the final page to output
922
+ *
923
+ * @return mixed
924
+ */
925
+ public function get_converted_page() {
926
+ return $this->content_page;
927
+ }
928
+
929
+ /**
930
+ * Print iubenda banner, parameter: the script code of iubenda to print the banner
931
+ *
932
+ * @param string $banner
933
+ * @return string
934
+ */
935
+ public function print_banner( $banner ) {
936
+ return $banner .= "\n
937
+ <script>
938
+ var iCallback = function(){};
939
+
940
+ if ( 'callback' in _iub.csConfiguration ) {
941
+ if ( 'onConsentGiven' in _iub.csConfiguration.callback )
942
+ iCallback = _iub.csConfiguration.callback.onConsentGiven;
943
+
944
+ _iub.csConfiguration.callback.onConsentGiven = function() {
945
+ iCallback();
946
+
947
+ jQuery( 'noscript._no_script_iub' ).each( function (a, b) { var el = jQuery(b); el.after( el.html() ); } );
948
+ };
949
+ };
950
+ </script>";
951
+ }
952
+
953
+ /**
954
+ * Static, utility function: strpos for array wilth wildcard support
955
+ *
956
+ * @param type $haystack
957
+ * @param type $needle
958
+ * @return boolean
959
+ */
960
+ static function strpos_array( $haystack, $needle ) {
961
+ if ( empty( $haystack ) || empty( $needle ) )
962
+ return false;
963
+
964
+ $needle = ! is_array( $needle ) ? array( $needle ) : $needle;
965
+
966
+ foreach ( $needle as $need ) {
967
+ // wildcard?
968
+ if ( strpos( $need, '/*/' ) !== false ) {
969
+ // strtok - removes query string
970
+ // str_replace - removes double slashes // from url
971
+ // preg_replace - removes http or https from url
972
+ $haystack = strtok( str_replace( '//', '', preg_replace( "(^https?://)", "", $haystack ) ), '?' );
973
+
974
+ if ( fnmatch( $need, $haystack ) !== false )
975
+ return $need;
976
+ // regular
977
+ } else {
978
+ if ( strpos( $haystack, $need ) !== false )
979
+ return $need;
980
+ }
981
+ }
982
+
983
+ return false;
984
+ }
985
+
986
+ /**
987
+ * Custom array merge helper function.
988
+ *
989
+ * @return array
990
+ */
991
+ public function array_merge_custom( $builtin, $data ) {
992
+ foreach ( $data as $type => $array ) {
993
+ // if ( $type === 0 )
994
+ // continue;
995
+
996
+ foreach ( $array as $block ) {
997
+ $builtin[$type][] = $block;
998
+ }
999
+
1000
+ $builtin[$type] = array_unique( $builtin[$type] );
1001
+ }
1002
+
1003
+ return $builtin;
1004
+ }
1005
+
1006
+ /**
1007
+ * Array search helper function.
1008
+ *
1009
+ * @param type $needle
1010
+ * @param type $haystack
1011
+ * @return boolean
1012
+ */
1013
+ public function recursive_array_search( $needle, $haystack ) {
1014
+ foreach ( $haystack as $key => $value ) {
1015
+ $current_key = $key;
1016
+ if ( $needle === $value OR ( is_array( $value ) &&
1017
+ $this->recursive_array_search( $needle, $value ) !== false) ) {
1018
+ return $current_key;
1019
+ }
1020
+ }
1021
+ return false;
1022
+ }
1023
+
1024
+ }
trunk/iubenda-cookie-class/simple_html_dom.php ADDED
@@ -0,0 +1,2351 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Website: http://sourceforge.net/projects/simplehtmldom/
4
+ * Additional projects: http://sourceforge.net/projects/debugobject/
5
+ * Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/)
6
+ *
7
+ * Licensed under The MIT License
8
+ * See the LICENSE file in the project root for more information.
9
+ *
10
+ * Authors:
11
+ * S.C. Chen
12
+ * John Schlick
13
+ * Rus Carroll
14
+ * logmanoriginal
15
+ *
16
+ * Contributors:
17
+ * Yousuke Kumakura
18
+ * Vadim Voituk
19
+ * Antcs
20
+ *
21
+ * Version Rev. 1.9 (290)
22
+ *
23
+ * @author S.C. Chen, John Schlick, Rus Carroll, logmanoriginal
24
+ * @copyright 2018-2019, iubenda s.r.l
25
+ * @license MIT License
26
+ * @version 1.9
27
+ */
28
+
29
+ define('HDOM_TYPE_ELEMENT', 1);
30
+ define('HDOM_TYPE_COMMENT', 2);
31
+ define('HDOM_TYPE_TEXT', 3);
32
+ define('HDOM_TYPE_ENDTAG', 4);
33
+ define('HDOM_TYPE_ROOT', 5);
34
+ define('HDOM_TYPE_UNKNOWN', 6);
35
+ define('HDOM_QUOTE_DOUBLE', 0);
36
+ define('HDOM_QUOTE_SINGLE', 1);
37
+ define('HDOM_QUOTE_NO', 3);
38
+ define('HDOM_INFO_BEGIN', 0);
39
+ define('HDOM_INFO_END', 1);
40
+ define('HDOM_INFO_QUOTE', 2);
41
+ define('HDOM_INFO_SPACE', 3);
42
+ define('HDOM_INFO_TEXT', 4);
43
+ define('HDOM_INFO_INNER', 5);
44
+ define('HDOM_INFO_OUTER', 6);
45
+ define('HDOM_INFO_ENDSPACE', 7);
46
+
47
+ defined('DEFAULT_TARGET_CHARSET') || define('DEFAULT_TARGET_CHARSET', 'UTF-8');
48
+ defined('DEFAULT_BR_TEXT') || define('DEFAULT_BR_TEXT', "\r\n");
49
+ defined('DEFAULT_SPAN_TEXT') || define('DEFAULT_SPAN_TEXT', ' ');
50
+ defined('MAX_FILE_SIZE') || define('MAX_FILE_SIZE', 600000);
51
+ define('HDOM_SMARTY_AS_TEXT', 1);
52
+
53
+ function file_get_html(
54
+ $url,
55
+ $use_include_path = false,
56
+ $context = null,
57
+ $offset = 0,
58
+ $maxLen = -1,
59
+ $lowercase = true,
60
+ $forceTagsClosed = true,
61
+ $target_charset = DEFAULT_TARGET_CHARSET,
62
+ $stripRN = true,
63
+ $defaultBRText = DEFAULT_BR_TEXT,
64
+ $defaultSpanText = DEFAULT_SPAN_TEXT)
65
+ {
66
+ if($maxLen <= 0) { $maxLen = MAX_FILE_SIZE; }
67
+
68
+ $dom = new simple_html_dom(
69
+ null,
70
+ $lowercase,
71
+ $forceTagsClosed,
72
+ $target_charset,
73
+ $stripRN,
74
+ $defaultBRText,
75
+ $defaultSpanText
76
+ );
77
+
78
+ /**
79
+ * For sourceforge users: uncomment the next line and comment the
80
+ * retrieve_url_contents line 2 lines down if it is not already done.
81
+ */
82
+ $contents = file_get_contents(
83
+ $url,
84
+ $use_include_path,
85
+ $context,
86
+ $offset,
87
+ $maxLen
88
+ );
89
+ // $contents = retrieve_url_contents($url);
90
+
91
+ if (empty($contents) || strlen($contents) > $maxLen) {
92
+ $dom->clear();
93
+ return false;
94
+ }
95
+
96
+ return $dom->load($contents, $lowercase, $stripRN);
97
+ }
98
+
99
+ function str_get_html(
100
+ $str,
101
+ $lowercase = true,
102
+ $forceTagsClosed = true,
103
+ $target_charset = DEFAULT_TARGET_CHARSET,
104
+ $stripRN = true,
105
+ $defaultBRText = DEFAULT_BR_TEXT,
106
+ $defaultSpanText = DEFAULT_SPAN_TEXT)
107
+ {
108
+ $dom = new simple_html_dom(
109
+ null,
110
+ $lowercase,
111
+ $forceTagsClosed,
112
+ $target_charset,
113
+ $stripRN,
114
+ $defaultBRText,
115
+ $defaultSpanText
116
+ );
117
+
118
+ if (empty($str) || strlen($str) > MAX_FILE_SIZE) {
119
+ $dom->clear();
120
+ return false;
121
+ }
122
+
123
+ return $dom->load($str, $lowercase, $stripRN);
124
+ }
125
+
126
+ function dump_html_tree($node, $show_attr = true, $deep = 0)
127
+ {
128
+ $node->dump($node);
129
+ }
130
+
131
+ class simple_html_dom_node
132
+ {
133
+ public $nodetype = HDOM_TYPE_TEXT;
134
+ public $tag = 'text';
135
+ public $attr = array();
136
+ public $children = array();
137
+ public $nodes = array();
138
+ public $parent = null;
139
+ public $_ = array();
140
+ public $tag_start = 0;
141
+ private $dom = null;
142
+
143
+ function __construct($dom)
144
+ {
145
+ $this->dom = $dom;
146
+ $dom->nodes[] = $this;
147
+ }
148
+
149
+ function __destruct()
150
+ {
151
+ $this->clear();
152
+ }
153
+
154
+ function __toString()
155
+ {
156
+ return $this->outertext();
157
+ }
158
+
159
+ function clear()
160
+ {
161
+ $this->dom = null;
162
+ $this->nodes = null;
163
+ $this->parent = null;
164
+ $this->children = null;
165
+ }
166
+
167
+ function dump($show_attr = true, $depth = 0)
168
+ {
169
+ echo str_repeat("\t", $depth) . $this->tag;
170
+
171
+ if ($show_attr && count($this->attr) > 0) {
172
+ echo '(';
173
+ foreach ($this->attr as $k => $v) {
174
+ echo "[$k]=>\"$v\", ";
175
+ }
176
+ echo ')';
177
+ }
178
+
179
+ echo "\n";
180
+
181
+ if ($this->nodes) {
182
+ foreach ($this->nodes as $node) {
183
+ $node->dump($show_attr, $depth + 1);
184
+ }
185
+ }
186
+ }
187
+
188
+ function dump_node($echo = true)
189
+ {
190
+ $string = $this->tag;
191
+
192
+ if (count($this->attr) > 0) {
193
+ $string .= '(';
194
+ foreach ($this->attr as $k => $v) {
195
+ $string .= "[$k]=>\"$v\", ";
196
+ }
197
+ $string .= ')';
198
+ }
199
+
200
+ if (count($this->_) > 0) {
201
+ $string .= ' $_ (';
202
+ foreach ($this->_ as $k => $v) {
203
+ if (is_array($v)) {
204
+ $string .= "[$k]=>(";
205
+ foreach ($v as $k2 => $v2) {
206
+ $string .= "[$k2]=>\"$v2\", ";
207
+ }
208
+ $string .= ')';
209
+ } else {
210
+ $string .= "[$k]=>\"$v\", ";
211
+ }
212
+ }
213
+ $string .= ')';
214
+ }
215
+
216
+ if (isset($this->text)) {
217
+ $string .= " text: ({$this->text})";
218
+ }
219
+
220
+ $string .= ' HDOM_INNER_INFO: ';
221
+
222
+ if (isset($node->_[HDOM_INFO_INNER])) {
223
+ $string .= "'" . $node->_[HDOM_INFO_INNER] . "'";
224
+ } else {
225
+ $string .= ' NULL ';
226
+ }
227
+
228
+ $string .= ' children: ' . count($this->children);
229
+ $string .= ' nodes: ' . count($this->nodes);
230
+ $string .= ' tag_start: ' . $this->tag_start;
231
+ $string .= "\n";
232
+
233
+ if ($echo) {
234
+ echo $string;
235
+ return;
236
+ } else {
237
+ return $string;
238
+ }
239
+ }
240
+
241
+ function parent($parent = null)
242
+ {
243
+ // I am SURE that this doesn't work properly.
244
+ // It fails to unset the current node from it's current parents nodes or
245
+ // children list first.
246
+ if ($parent !== null) {
247
+ $this->parent = $parent;
248
+ $this->parent->nodes[] = $this;
249
+ $this->parent->children[] = $this;
250
+ }
251
+
252
+ return $this->parent;
253
+ }
254
+
255
+ function has_child()
256
+ {
257
+ return !empty($this->children);
258
+ }
259
+
260
+ function children($idx = -1)
261
+ {
262
+ if ($idx === -1) {
263
+ return $this->children;
264
+ }
265
+
266
+ if (isset($this->children[$idx])) {
267
+ return $this->children[$idx];
268
+ }
269
+
270
+ return null;
271
+ }
272
+
273
+ function first_child()
274
+ {
275
+ if (count($this->children) > 0) {
276
+ return $this->children[0];
277
+ }
278
+ return null;
279
+ }
280
+
281
+ function last_child()
282
+ {
283
+ if (count($this->children) > 0) {
284
+ return end($this->children);
285
+ }
286
+ return null;
287
+ }
288
+
289
+ function next_sibling()
290
+ {
291
+ if ($this->parent === null) {
292
+ return null;
293
+ }
294
+
295
+ $idx = array_search($this, $this->parent->children, true);
296
+
297
+ if ($idx !== false && isset($this->parent->children[$idx + 1])) {
298
+ return $this->parent->children[$idx + 1];
299
+ }
300
+
301
+ return null;
302
+ }
303
+
304
+ function prev_sibling()
305
+ {
306
+ if ($this->parent === null) {
307
+ return null;
308
+ }
309
+
310
+ $idx = array_search($this, $this->parent->children, true);
311
+
312
+ if ($idx !== false && $idx > 0) {
313
+ return $this->parent->children[$idx - 1];
314
+ }
315
+
316
+ return null;
317
+ }
318
+
319
+ function find_ancestor_tag($tag)
320
+ {
321
+ global $debug_object;
322
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
323
+
324
+ if ($this->parent === null) {
325
+ return null;
326
+ }
327
+
328
+ $ancestor = $this->parent;
329
+
330
+ while (!is_null($ancestor)) {
331
+ if (is_object($debug_object)) {
332
+ $debug_object->debug_log(2, 'Current tag is: ' . $ancestor->tag);
333
+ }
334
+
335
+ if ($ancestor->tag === $tag) {
336
+ break;
337
+ }
338
+
339
+ $ancestor = $ancestor->parent;
340
+ }
341
+
342
+ return $ancestor;
343
+ }
344
+
345
+ function innertext()
346
+ {
347
+ if (isset($this->_[HDOM_INFO_INNER])) {
348
+ return $this->_[HDOM_INFO_INNER];
349
+ }
350
+
351
+ if (isset($this->_[HDOM_INFO_TEXT])) {
352
+ return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
353
+ }
354
+
355
+ $ret = '';
356
+
357
+ foreach ($this->nodes as $n) {
358
+ $ret .= $n->outertext();
359
+ }
360
+
361
+ return $ret;
362
+ }
363
+
364
+ function outertext()
365
+ {
366
+ global $debug_object;
367
+
368
+ if (is_object($debug_object)) {
369
+ $text = '';
370
+
371
+ if ($this->tag === 'text') {
372
+ if (!empty($this->text)) {
373
+ $text = ' with text: ' . $this->text;
374
+ }
375
+ }
376
+
377
+ $debug_object->debug_log(1, 'Innertext of tag: ' . $this->tag . $text);
378
+ }
379
+
380
+ if ($this->tag === 'root') {
381
+ return $this->innertext();
382
+ }
383
+
384
+ // todo: What is the use of this callback? Remove?
385
+ if ($this->dom && $this->dom->callback !== null) {
386
+ call_user_func_array($this->dom->callback, array($this));
387
+ }
388
+
389
+ if (isset($this->_[HDOM_INFO_OUTER])) {
390
+ return $this->_[HDOM_INFO_OUTER];
391
+ }
392
+
393
+ if (isset($this->_[HDOM_INFO_TEXT])) {
394
+ return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
395
+ }
396
+
397
+ $ret = '';
398
+
399
+ if ($this->dom && $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]) {
400
+ $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup();
401
+ }
402
+
403
+ if (isset($this->_[HDOM_INFO_INNER])) {
404
+ // todo: <br> should either never have HDOM_INFO_INNER or always
405
+ if ($this->tag !== 'br') {
406
+ $ret .= $this->_[HDOM_INFO_INNER];
407
+ }
408
+ } elseif ($this->nodes) {
409
+ foreach ($this->nodes as $n) {
410
+ $ret .= $this->convert_text($n->outertext());
411
+ }
412
+ }
413
+
414
+ if (isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END] != 0) {
415
+ $ret .= '</' . $this->tag . '>';
416
+ }
417
+
418
+ return $ret;
419
+ }
420
+
421
+ function text()
422
+ {
423
+ if (isset($this->_[HDOM_INFO_INNER])) {
424
+ return $this->_[HDOM_INFO_INNER];
425
+ }
426
+
427
+ switch ($this->nodetype) {
428
+ case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
429
+ case HDOM_TYPE_COMMENT: return '';
430
+ case HDOM_TYPE_UNKNOWN: return '';
431
+ }
432
+
433
+ if (strcasecmp($this->tag, 'script') === 0) { return ''; }
434
+ if (strcasecmp($this->tag, 'style') === 0) { return ''; }
435
+
436
+ $ret = '';
437
+
438
+ // In rare cases, (always node type 1 or HDOM_TYPE_ELEMENT - observed
439
+ // for some span tags, and some p tags) $this->nodes is set to NULL.
440
+ // NOTE: This indicates that there is a problem where it's set to NULL
441
+ // without a clear happening.
442
+ // WHY is this happening?
443
+ if (!is_null($this->nodes)) {
444
+ foreach ($this->nodes as $n) {
445
+ // Start paragraph after a blank line
446
+ if ($n->tag === 'p') {
447
+ $ret = trim($ret) . "\n\n";
448
+ }
449
+
450
+ $ret .= $this->convert_text($n->text());
451
+
452
+ // If this node is a span... add a space at the end of it so
453
+ // multiple spans don't run into each other. This is plaintext
454
+ // after all.
455
+ if ($n->tag === 'span') {
456
+ $ret .= $this->dom->default_span_text;
457
+ }
458
+ }
459
+ }
460
+ return $ret;
461
+ }
462
+
463
+ function xmltext()
464
+ {
465
+ $ret = $this->innertext();
466
+ $ret = str_ireplace('<![CDATA[', '', $ret);
467
+ $ret = str_replace(']]>', '', $ret);
468
+ return $ret;
469
+ }
470
+
471
+ function makeup()
472
+ {
473
+ // text, comment, unknown
474
+ if (isset($this->_[HDOM_INFO_TEXT])) {
475
+ return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
476
+ }
477
+
478
+ $ret = '<' . $this->tag;
479
+ $i = -1;
480
+
481
+ foreach ($this->attr as $key => $val) {
482
+ ++$i;
483
+
484
+ // skip removed attribute
485
+ if ($val === null || $val === false) { continue; }
486
+
487
+ $ret .= $this->_[HDOM_INFO_SPACE][$i][0];
488
+
489
+ //no value attr: nowrap, checked selected...
490
+ if ($val === true) {
491
+ $ret .= $key;
492
+ } else {
493
+ switch ($this->_[HDOM_INFO_QUOTE][$i])
494
+ {
495
+ case HDOM_QUOTE_DOUBLE: $quote = '"'; break;
496
+ case HDOM_QUOTE_SINGLE: $quote = '\''; break;
497
+ default: $quote = '';
498
+ }
499
+
500
+ $ret .= $key
501
+ . $this->_[HDOM_INFO_SPACE][$i][1]
502
+ . '='
503
+ . $this->_[HDOM_INFO_SPACE][$i][2]
504
+ . $quote
505
+ . $val
506
+ . $quote;
507
+ }
508
+ }
509
+
510
+ $ret = $this->dom->restore_noise($ret);
511
+ return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>';
512
+ }
513
+
514
+ function find($selector, $idx = null, $lowercase = false)
515
+ {
516
+ $selectors = $this->parse_selector($selector);
517
+ if (($count = count($selectors)) === 0) { return array(); }
518
+ $found_keys = array();
519
+
520
+ // find each selector
521
+ for ($c = 0; $c < $count; ++$c) {
522
+ // The change on the below line was documented on the sourceforge
523
+ // code tracker id 2788009
524
+ // used to be: if (($levle=count($selectors[0]))===0) return array();
525
+ if (($levle = count($selectors[$c])) === 0) { return array(); }
526
+ if (!isset($this->_[HDOM_INFO_BEGIN])) { return array(); }
527
+
528
+ $head = array($this->_[HDOM_INFO_BEGIN] => 1);
529
+ $cmd = ' '; // Combinator
530
+
531
+ // handle descendant selectors, no recursive!
532
+ for ($l = 0; $l < $levle; ++$l) {
533
+ $ret = array();
534
+
535
+ foreach ($head as $k => $v) {
536
+ $n = ($k === -1) ? $this->dom->root : $this->dom->nodes[$k];
537
+ //PaperG - Pass this optional parameter on to the seek function.
538
+ $n->seek($selectors[$c][$l], $ret, $cmd, $lowercase);
539
+ }
540
+
541
+ $head = $ret;
542
+ $cmd = $selectors[$c][$l][4]; // Next Combinator
543
+ }
544
+
545
+ foreach ($head as $k => $v) {
546
+ if (!isset($found_keys[$k])) {
547
+ $found_keys[$k] = 1;
548
+ }
549
+ }
550
+ }
551
+
552
+ // sort keys
553
+ ksort($found_keys);
554
+
555
+ $found = array();
556
+ foreach ($found_keys as $k => $v) {
557
+ $found[] = $this->dom->nodes[$k];
558
+ }
559
+
560
+ // return nth-element or array
561
+ if (is_null($idx)) { return $found; }
562
+ elseif ($idx < 0) { $idx = count($found) + $idx; }
563
+ return (isset($found[$idx])) ? $found[$idx] : null;
564
+ }
565
+
566
+ protected function seek($selector, &$ret, $parent_cmd, $lowercase = false)
567
+ {
568
+ global $debug_object;
569
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
570
+
571
+ list($tag, $id, $class, $attributes, $cmb) = $selector;
572
+ $nodes = array();
573
+
574
+ if ($parent_cmd === ' ') { // Descendant Combinator
575
+ // Find parent closing tag if the current element doesn't have a closing
576
+ // tag (i.e. void element)
577
+ $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0;
578
+ if ($end == 0) {
579
+ $parent = $this->parent;
580
+ while (!isset($parent->_[HDOM_INFO_END]) && $parent !== null) {
581
+ $end -= 1;
582
+ $parent = $parent->parent;
583
+ }
584
+ $end += $parent->_[HDOM_INFO_END];
585
+ }
586
+
587
+ // Get list of target nodes
588
+ $nodes_start = $this->_[HDOM_INFO_BEGIN] + 1;
589
+ $nodes_count = $end - $nodes_start;
590
+ $nodes = array_slice($this->dom->nodes, $nodes_start, $nodes_count, true);
591
+ } elseif ($parent_cmd === '>') { // Child Combinator
592
+ $nodes = $this->children;
593
+ } elseif ($parent_cmd === '+'
594
+ && $this->parent
595
+ && in_array($this, $this->parent->children)) { // Next-Sibling Combinator
596
+ $index = array_search($this, $this->parent->children, true) + 1;
597
+ if ($index < count($this->parent->children))
598
+ $nodes[] = $this->parent->children[$index];
599
+ } elseif ($parent_cmd === '~'
600
+ && $this->parent
601
+ && in_array($this, $this->parent->children)) { // Subsequent Sibling Combinator
602
+ $index = array_search($this, $this->parent->children, true);
603
+ $nodes = array_slice($this->parent->children, $index);
604
+ }
605
+
606
+ // Go throgh each element starting at this element until the end tag
607
+ // Note: If this element is a void tag, any previous void element is
608
+ // skipped.
609
+ foreach($nodes as $node) {
610
+ $pass = true;
611
+
612
+ // Skip root nodes
613
+ if(!$node->parent) {
614
+ $pass = false;
615
+ }
616
+
617
+ // Skip if node isn't a child node (i.e. text nodes)
618
+ if($pass && !in_array($node, $node->parent->children, true)) {
619
+ $pass = false;
620
+ }
621
+
622
+ // Skip if tag doesn't match
623
+ if ($pass && $tag !== '' && $tag !== $node->tag && $tag !== '*') {
624
+ $pass = false;
625
+ }
626
+
627
+ // Skip if ID doesn't exist
628
+ if ($pass && $id !== '' && !isset($node->attr['id'])) {
629
+ $pass = false;
630
+ }
631
+
632
+ // Check if ID matches
633
+ if ($pass && $id !== '' && isset($node->attr['id'])) {
634
+ // Note: Only consider the first ID (as browsers do)
635
+ $node_id = explode(' ', trim($node->attr['id']))[0];
636
+
637
+ if($id !== $node_id) { $pass = false; }
638
+ }
639
+
640
+ // Check if all class(es) exist
641
+ if ($pass && $class !== '' && is_array($class) && !empty($class)) {
642
+ if (isset($node->attr['class'])) {
643
+ $node_classes = explode(' ', $node->attr['class']);
644
+
645
+ if ($lowercase) {
646
+ $node_classes = array_map('strtolower', $node_classes);
647
+ }
648
+
649
+ foreach($class as $c) {
650
+ if(!in_array($c, $node_classes)) {
651
+ $pass = false;
652
+ break;
653
+ }
654
+ }
655
+ } else {
656
+ $pass = false;
657
+ }
658
+ }
659
+
660
+ // Check attributes
661
+ if ($pass
662
+ && $attributes !== ''
663
+ && is_array($attributes)
664
+ && !empty($attributes)) {
665
+ foreach($attributes as $a) {
666
+ list (
667
+ $att_name,
668
+ $att_expr,
669
+ $att_val,
670
+ $att_inv,
671
+ $att_case_sensitivity
672
+ ) = $a;
673
+
674
+ // Handle indexing attributes (i.e. "[2]")
675
+ /**
676
+ * Note: This is not supported by the CSS Standard but adds
677
+ * the ability to select items compatible to XPath (i.e.
678
+ * the 3rd element within it's parent).
679
+ *
680
+ * Note: This doesn't conflict with the CSS Standard which
681
+ * doesn't work on numeric attributes anyway.
682
+ */
683
+ if (is_numeric($att_name)
684
+ && $att_expr === ''
685
+ && $att_val === '') {
686
+ $count = 0;
687
+
688
+ // Find index of current element in parent
689
+ foreach ($node->parent->children as $c) {
690
+ if ($c->tag === $node->tag) ++$count;
691
+ if ($c === $node) break;
692
+ }
693
+
694
+ // If this is the correct node, continue with next
695
+ // attribute
696
+ if ($count === (int)$att_name) continue;
697
+ }
698
+
699
+ // Check attribute availability
700
+ if ($att_inv) { // Attribute should NOT be set
701
+ if (isset($node->attr[$att_name])) {
702
+ $pass = false;
703
+ break;
704
+ }
705
+ } else { // Attribute should be set
706
+ // todo: "plaintext" is not a valid CSS selector!
707
+ if ($att_name !== 'plaintext'
708
+ && !isset($node->attr[$att_name])) {
709
+ $pass = false;
710
+ break;
711
+ }
712
+ }
713
+
714
+ // Continue with next attribute if expression isn't defined
715
+ if ($att_expr === '') continue;
716
+
717
+ // If they have told us that this is a "plaintext"
718
+ // search then we want the plaintext of the node - right?
719
+ // todo "plaintext" is not a valid CSS selector!
720
+ if ($att_name === 'plaintext') {
721
+ $nodeKeyValue = $node->text();
722
+ } else {
723
+ $nodeKeyValue = $node->attr[$att_name];
724
+ }
725
+
726
+ if (is_object($debug_object)) {
727
+ $debug_object->debug_log(2,
728
+ 'testing node: '
729
+ . $node->tag
730
+ . ' for attribute: '
731
+ . $att_name
732
+ . $att_expr
733
+ . $att_val
734
+ . ' where nodes value is: '
735
+ . $nodeKeyValue
736
+ );
737
+ }
738
+
739
+ // If lowercase is set, do a case insensitive test of
740
+ // the value of the selector.
741
+ if ($lowercase) {
742
+ $check = $this->match(
743
+ $att_expr,
744
+ strtolower($att_val),
745
+ strtolower($nodeKeyValue),
746
+ $att_case_sensitivity
747
+ );
748
+ } else {
749
+ $check = $this->match(
750
+ $att_expr,
751
+ $att_val,
752
+ $nodeKeyValue,
753
+ $att_case_sensitivity
754
+ );
755
+ }
756
+
757
+ if (is_object($debug_object)) {
758
+ $debug_object->debug_log(2,
759
+ 'after match: '
760
+ . ($check ? 'true' : 'false')
761
+ );
762
+ }
763
+
764
+ if (!$check) {
765
+ $pass = false;
766
+ break;
767
+ }
768
+ }
769
+ }
770
+
771
+ // Found a match. Add to list and clear node
772
+ if ($pass) $ret[$node->_[HDOM_INFO_BEGIN]] = 1;
773
+ unset($node);
774
+ }
775
+ // It's passed by reference so this is actually what this function returns.
776
+ if (is_object($debug_object)) {
777
+ $debug_object->debug_log(1, 'EXIT - ret: ', $ret);
778
+ }
779
+ }
780
+
781
+ protected function match($exp, $pattern, $value, $case_sensitivity)
782
+ {
783
+ global $debug_object;
784
+ if (is_object($debug_object)) {$debug_object->debug_log_entry(1);}
785
+
786
+ if ($case_sensitivity === 'i') {
787
+ $pattern = strtolower($pattern);
788
+ $value = strtolower($value);
789
+ }
790
+
791
+ switch ($exp) {
792
+ case '=':
793
+ return ($value === $pattern);
794
+ case '!=':
795
+ return ($value !== $pattern);
796
+ case '^=':
797
+ return preg_match('/^' . preg_quote($pattern, '/') . '/', $value);
798
+ case '$=':
799
+ return preg_match('/' . preg_quote($pattern, '/') . '$/', $value);
800
+ case '*=':
801
+ return preg_match('/' . preg_quote($pattern, '/') . '/', $value);
802
+ case '|=':
803
+ /**
804
+ * [att|=val]
805
+ *
806
+ * Represents an element with the att attribute, its value
807
+ * either being exactly "val" or beginning with "val"
808
+ * immediately followed by "-" (U+002D).
809
+ */
810
+ return strpos($value, $pattern) === 0;
811
+ case '~=':
812
+ /**
813
+ * [att~=val]
814
+ *
815
+ * Represents an element with the att attribute whose value is a
816
+ * whitespace-separated list of words, one of which is exactly
817
+ * "val". If "val" contains whitespace, it will never represent
818
+ * anything (since the words are separated by spaces). Also if
819
+ * "val" is the empty string, it will never represent anything.
820
+ */
821
+ return in_array($pattern, explode(' ', trim($value)), true);
822
+ }
823
+ return false;
824
+ }
825
+
826
+ protected function parse_selector($selector_string)
827
+ {
828
+ global $debug_object;
829
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
830
+
831
+ /**
832
+ * Pattern of CSS selectors, modified from mootools (https://mootools.net/)
833
+ *
834
+ * Paperg: Add the colon to the attribute, so that it properly finds
835
+ * <tag attr:ibute="something" > like google does.
836
+ *
837
+ * Note: if you try to look at this attribute, you MUST use getAttribute
838
+ * since $dom->x:y will fail the php syntax check.
839
+ *
840
+ * Notice the \[ starting the attribute? and the @? following? This
841
+ * implies that an attribute can begin with an @ sign that is not
842
+ * captured. This implies that an html attribute specifier may start
843
+ * with an @ sign that is NOT captured by the expression. Farther study
844
+ * is required to determine of this should be documented or removed.
845
+ *
846
+ * Matches selectors in this order:
847
+ *
848
+ * [0] - full match
849
+ *
850
+ * [1] - tag name
851
+ * ([\w:\*-]*)
852
+ * Matches the tag name consisting of zero or more words, colons,
853
+ * asterisks and hyphens.
854
+ *
855
+ * [2] - id name
856
+ * (?:\#([\w-]+))
857
+ * Optionally matches a id name, consisting of an "#" followed by
858
+ * the id name (one or more words and hyphens).
859
+ *
860
+ * [3] - class names (including dots)
861
+ * (?:\.([\w\.-]+))?
862
+ * Optionally matches a list of classs, consisting of an "."
863
+ * followed by the class name (one or more words and hyphens)
864
+ * where multiple classes can be chained (i.e. ".foo.bar.baz")
865
+ *
866
+ * [4] - attributes
867
+ * ((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)?
868
+ * Optionally matches the attributes list
869
+ *
870
+ * [5] - separator
871
+ * ([\/, >+~]+)
872
+ * Matches the selector list separator
873
+ */
874
+ // phpcs:ignore Generic.Files.LineLength
875
+ $pattern = "/([\w:\*-]*)(?:\#([\w-]+))?(?:|\.([\w\.-]+))?((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)?([\/, >+~]+)/is";
876
+
877
+ preg_match_all(
878
+ $pattern,
879
+ trim($selector_string) . ' ', // Add final ' ' as pseudo separator
880
+ $matches,
881
+ PREG_SET_ORDER
882
+ );
883
+
884
+ if (is_object($debug_object)) {
885
+ $debug_object->debug_log(2, 'Matches Array: ', $matches);
886
+ }
887
+
888
+ $selectors = array();
889
+ $result = array();
890
+
891
+ foreach ($matches as $m) {
892
+ $m[0] = trim($m[0]);
893
+
894
+ // Skip NoOps
895
+ if ($m[0] === '' || $m[0] === '/' || $m[0] === '//') { continue; }
896
+
897
+ // Convert to lowercase
898
+ if ($this->dom->lowercase) {
899
+ $m[1] = strtolower($m[1]);
900
+ }
901
+
902
+ // Extract classes
903
+ if ($m[3] !== '') { $m[3] = explode('.', $m[3]); }
904
+
905
+ /* Extract attributes (pattern based on the pattern above!)
906
+
907
+ * [0] - full match
908
+ * [1] - attribute name
909
+ * [2] - attribute expression
910
+ * [3] - attribute value
911
+ * [4] - case sensitivity
912
+ *
913
+ * Note: Attributes can be negated with a "!" prefix to their name
914
+ */
915
+ if($m[4] !== '') {
916
+ preg_match_all(
917
+ "/\[@?(!?[\w:-]+)(?:([!*^$|~]?=)[\"']?(.*?)[\"']?)?(?:\s+?([iIsS])?)?\]/is",
918
+ trim($m[4]),
919
+ $attributes,
920
+ PREG_SET_ORDER
921
+ );
922
+
923
+ // Replace element by array
924
+ $m[4] = array();
925
+
926
+ foreach($attributes as $att) {
927
+ // Skip empty matches
928
+ if(trim($att[0]) === '') { continue; }
929
+
930
+ $inverted = (isset($att[1][0]) && $att[1][0] === '!');
931
+ $m[4][] = array(
932
+ $inverted ? substr($att[1], 1) : $att[1], // Name
933
+ (isset($att[2])) ? $att[2] : '', // Expression
934
+ (isset($att[3])) ? $att[3] : '', // Value
935
+ $inverted, // Inverted Flag
936
+ (isset($att[4])) ? strtolower($att[4]) : '', // Case-Sensitivity
937
+ );
938
+ }
939
+ }
940
+
941
+ // Sanitize Separator
942
+ if ($m[5] !== '' && trim($m[5]) === '') { // Descendant Separator
943
+ $m[5] = ' ';
944
+ } else { // Other Separator
945
+ $m[5] = trim($m[5]);
946
+ }
947
+
948
+ // Clear Separator if it's a Selector List
949
+ if ($is_list = ($m[5] === ',')) { $m[5] = ''; }
950
+
951
+ // Remove full match before adding to results
952
+ array_shift($m);
953
+ $result[] = $m;
954
+
955
+ if ($is_list) { // Selector List
956
+ $selectors[] = $result;
957
+ $result = array();
958
+ }
959
+ }
960
+
961
+ if (count($result) > 0) { $selectors[] = $result; }
962
+ return $selectors;
963
+ }
964
+
965
+ function __get($name)
966
+ {
967
+ if (isset($this->attr[$name])) {
968
+ return $this->convert_text($this->attr[$name]);
969
+ }
970
+ switch ($name) {
971
+ case 'outertext': return $this->outertext();
972
+ case 'innertext': return $this->innertext();
973
+ case 'plaintext': return $this->text();
974
+ case 'xmltext': return $this->xmltext();
975
+ default: return array_key_exists($name, $this->attr);
976
+ }
977
+ }
978
+
979
+ function __set($name, $value)
980
+ {
981
+ global $debug_object;
982
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
983
+
984
+ switch ($name) {
985
+ case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value;
986
+ case 'innertext':
987
+ if (isset($this->_[HDOM_INFO_TEXT])) {
988
+ return $this->_[HDOM_INFO_TEXT] = $value;
989
+ }
990
+ return $this->_[HDOM_INFO_INNER] = $value;
991
+ }
992
+
993
+ if (!isset($this->attr[$name])) {
994
+ $this->_[HDOM_INFO_SPACE][] = array(' ', '', '');
995
+ $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
996
+ }
997
+
998
+ $this->attr[$name] = $value;
999
+ }
1000
+
1001
+ function __isset($name)
1002
+ {
1003
+ switch ($name) {
1004
+ case 'outertext': return true;
1005
+ case 'innertext': return true;
1006
+ case 'plaintext': return true;
1007
+ }
1008
+ //no value attr: nowrap, checked selected...
1009
+ return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]);
1010
+ }
1011
+
1012
+ function __unset($name)
1013
+ {
1014
+ if (isset($this->attr[$name])) { unset($this->attr[$name]); }
1015
+ }
1016
+
1017
+ function convert_text($text)
1018
+ {
1019
+ global $debug_object;
1020
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
1021
+
1022
+ $converted_text = $text;
1023
+
1024
+ $sourceCharset = '';
1025
+ $targetCharset = '';
1026
+
1027
+ if ($this->dom) {
1028
+ $sourceCharset = strtoupper($this->dom->_charset);
1029
+ $targetCharset = strtoupper($this->dom->_target_charset);
1030
+ }
1031
+
1032
+ if (is_object($debug_object)) {
1033
+ $debug_object->debug_log(3,
1034
+ 'source charset: '
1035
+ . $sourceCharset
1036
+ . ' target charaset: '
1037
+ . $targetCharset
1038
+ );
1039
+ }
1040
+
1041
+ if (!empty($sourceCharset)
1042
+ && !empty($targetCharset)
1043
+ && (strcasecmp($sourceCharset, $targetCharset) != 0)) {
1044
+ // Check if the reported encoding could have been incorrect and the text is actually already UTF-8
1045
+ if ((strcasecmp($targetCharset, 'UTF-8') == 0)
1046
+ && ($this->is_utf8($text))) {
1047
+ $converted_text = $text;
1048
+ } else {
1049
+ $converted_text = iconv($sourceCharset, $targetCharset, $text);
1050
+ }
1051
+ }
1052
+
1053
+ // Lets make sure that we don't have that silly BOM issue with any of the utf-8 text we output.
1054
+ if ($targetCharset === 'UTF-8') {
1055
+ if (substr($converted_text, 0, 3) === "\xef\xbb\xbf") {
1056
+ $converted_text = substr($converted_text, 3);
1057
+ }
1058
+
1059
+ if (substr($converted_text, -3) === "\xef\xbb\xbf") {
1060
+ $converted_text = substr($converted_text, 0, -3);
1061
+ }
1062
+ }
1063
+
1064
+ return $converted_text;
1065
+ }
1066
+
1067
+ static function is_utf8($str)
1068
+ {
1069
+ $c = 0; $b = 0;
1070
+ $bits = 0;
1071
+ $len = strlen($str);
1072
+ for($i = 0; $i < $len; $i++) {
1073
+ $c = ord($str[$i]);
1074
+ if($c > 128) {
1075
+ if(($c >= 254)) { return false; }
1076
+ elseif($c >= 252) { $bits = 6; }
1077
+ elseif($c >= 248) { $bits = 5; }
1078
+ elseif($c >= 240) { $bits = 4; }
1079
+ elseif($c >= 224) { $bits = 3; }
1080
+ elseif($c >= 192) { $bits = 2; }
1081
+ else { return false; }
1082
+ if(($i + $bits) > $len) { return false; }
1083
+ while($bits > 1) {
1084
+ $i++;
1085
+ $b = ord($str[$i]);
1086
+ if($b < 128 || $b > 191) { return false; }
1087
+ $bits--;
1088
+ }
1089
+ }
1090
+ }
1091
+ return true;
1092
+ }
1093
+
1094
+ function get_display_size()
1095
+ {
1096
+ global $debug_object;
1097
+
1098
+ $width = -1;
1099
+ $height = -1;
1100
+
1101
+ if ($this->tag !== 'img') {
1102
+ return false;
1103
+ }
1104
+
1105
+ // See if there is aheight or width attribute in the tag itself.
1106
+ if (isset($this->attr['width'])) {
1107
+ $width = $this->attr['width'];
1108
+ }
1109
+
1110
+ if (isset($this->attr['height'])) {
1111
+ $height = $this->attr['height'];
1112
+ }
1113
+
1114
+ // Now look for an inline style.
1115
+ if (isset($this->attr['style'])) {
1116
+ // Thanks to user gnarf from stackoverflow for this regular expression.
1117
+ $attributes = array();
1118
+
1119
+ preg_match_all(
1120
+ '/([\w-]+)\s*:\s*([^;]+)\s*;?/',
1121
+ $this->attr['style'],
1122
+ $matches,
1123
+ PREG_SET_ORDER
1124
+ );
1125
+
1126
+ foreach ($matches as $match) {
1127
+ $attributes[$match[1]] = $match[2];
1128
+ }
1129
+
1130
+ // If there is a width in the style attributes:
1131
+ if (isset($attributes['width']) && $width == -1) {
1132
+ // check that the last two characters are px (pixels)
1133
+ if (strtolower(substr($attributes['width'], -2)) === 'px') {
1134
+ $proposed_width = substr($attributes['width'], 0, -2);
1135
+ // Now make sure that it's an integer and not something stupid.
1136
+ if (filter_var($proposed_width, FILTER_VALIDATE_INT)) {
1137
+ $width = $proposed_width;
1138
+ }
1139
+ }
1140
+ }
1141
+
1142
+ // If there is a width in the style attributes:
1143
+ if (isset($attributes['height']) && $height == -1) {
1144
+ // check that the last two characters are px (pixels)
1145
+ if (strtolower(substr($attributes['height'], -2)) == 'px') {
1146
+ $proposed_height = substr($attributes['height'], 0, -2);
1147
+ // Now make sure that it's an integer and not something stupid.
1148
+ if (filter_var($proposed_height, FILTER_VALIDATE_INT)) {
1149
+ $height = $proposed_height;
1150
+ }
1151
+ }
1152
+ }
1153
+
1154
+ }
1155
+
1156
+ // Future enhancement:
1157
+ // Look in the tag to see if there is a class or id specified that has
1158
+ // a height or width attribute to it.
1159
+
1160
+ // Far future enhancement
1161
+ // Look at all the parent tags of this image to see if they specify a
1162
+ // class or id that has an img selector that specifies a height or width
1163
+ // Note that in this case, the class or id will have the img subselector
1164
+ // for it to apply to the image.
1165
+
1166
+ // ridiculously far future development
1167
+ // If the class or id is specified in a SEPARATE css file thats not on
1168
+ // the page, go get it and do what we were just doing for the ones on
1169
+ // the page.
1170
+
1171
+ $result = array(
1172
+ 'height' => $height,
1173
+ 'width' => $width
1174
+ );
1175
+
1176
+ return $result;
1177
+ }
1178
+
1179
+ function save($filepath = '')
1180
+ {
1181
+ $ret = $this->outertext();
1182
+
1183
+ if ($filepath !== '') {
1184
+ file_put_contents($filepath, $ret, LOCK_EX);
1185
+ }
1186
+
1187
+ return $ret;
1188
+ }
1189
+
1190
+ function addClass($class)
1191
+ {
1192
+ if (is_string($class)) {
1193
+ $class = explode(' ', $class);
1194
+ }
1195
+
1196
+ if (is_array($class)) {
1197
+ foreach($class as $c) {
1198
+ if (isset($this->class)) {
1199
+ if ($this->hasClass($c)) {
1200
+ continue;
1201
+ } else {
1202
+ $this->class .= ' ' . $c;
1203
+ }
1204
+ } else {
1205
+ $this->class = $c;
1206
+ }
1207
+ }
1208
+ } else {
1209
+ if (is_object($debug_object)) {
1210
+ $debug_object->debug_log(2, 'Invalid type: ', gettype($class));
1211
+ }
1212
+ }
1213
+ }
1214
+
1215
+ function hasClass($class)
1216
+ {
1217
+ if (is_string($class)) {
1218
+ if (isset($this->class)) {
1219
+ return in_array($class, explode(' ', $this->class), true);
1220
+ }
1221
+ } else {
1222
+ if (is_object($debug_object)) {
1223
+ $debug_object->debug_log(2, 'Invalid type: ', gettype($class));
1224
+ }
1225
+ }
1226
+
1227
+ return false;
1228
+ }
1229
+
1230
+ function removeClass($class = null)
1231
+ {
1232
+ if (!isset($this->class)) {
1233
+ return;
1234
+ }
1235
+
1236
+ if (is_null($class)) {
1237
+ $this->removeAttribute('class');
1238
+ return;
1239
+ }
1240
+
1241
+ if (is_string($class)) {
1242
+ $class = explode(' ', $class);
1243
+ }
1244
+
1245
+ if (is_array($class)) {
1246
+ $class = array_diff(explode(' ', $this->class), $class);
1247
+ if (empty($class)) {
1248
+ $this->removeAttribute('class');
1249
+ } else {
1250
+ $this->class = implode(' ', $class);
1251
+ }
1252
+ }
1253
+ }
1254
+
1255
+ function getAllAttributes()
1256
+ {
1257
+ return $this->attr;
1258
+ }
1259
+
1260
+ function getAttribute($name)
1261
+ {
1262
+ return $this->__get($name);
1263
+ }
1264
+
1265
+ function setAttribute($name, $value)
1266
+ {
1267
+ $this->__set($name, $value);
1268
+ }
1269
+
1270
+ function hasAttribute($name)
1271
+ {
1272
+ return $this->__isset($name);
1273
+ }
1274
+
1275
+ function removeAttribute($name)
1276
+ {
1277
+ $this->__set($name, null);
1278
+ }
1279
+
1280
+ function remove()
1281
+ {
1282
+ if ($this->parent) {
1283
+ $this->parent->removeChild($this);
1284
+ }
1285
+ }
1286
+
1287
+ function removeChild($node)
1288
+ {
1289
+ $nidx = array_search($node, $this->nodes, true);
1290
+ $cidx = array_search($node, $this->children, true);
1291
+ $didx = array_search($node, $this->dom->nodes, true);
1292
+
1293
+ if ($nidx !== false && $cidx !== false && $didx !== false) {
1294
+
1295
+ foreach($node->children as $child) {
1296
+ $node->removeChild($child);
1297
+ }
1298
+
1299
+ foreach($node->nodes as $entity) {
1300
+ $enidx = array_search($entity, $node->nodes, true);
1301
+ $edidx = array_search($entity, $node->dom->nodes, true);
1302
+
1303
+ if ($enidx !== false && $edidx !== false) {
1304
+ unset($node->nodes[$enidx]);
1305
+ unset($node->dom->nodes[$edidx]);
1306
+ }
1307
+ }
1308
+
1309
+ unset($this->nodes[$nidx]);
1310
+ unset($this->children[$cidx]);
1311
+ unset($this->dom->nodes[$didx]);
1312
+
1313
+ $node->clear();
1314
+
1315
+ }
1316
+ }
1317
+
1318
+ function getElementById($id)
1319
+ {
1320
+ return $this->find("#$id", 0);
1321
+ }
1322
+
1323
+ function getElementsById($id, $idx = null)
1324
+ {
1325
+ return $this->find("#$id", $idx);
1326
+ }
1327
+
1328
+ function getElementByTagName($name)
1329
+ {
1330
+ return $this->find($name, 0);
1331
+ }
1332
+
1333
+ function getElementsByTagName($name, $idx = null)
1334
+ {
1335
+ return $this->find($name, $idx);
1336
+ }
1337
+
1338
+ function parentNode()
1339
+ {
1340
+ return $this->parent();
1341
+ }
1342
+
1343
+ function childNodes($idx = -1)
1344
+ {
1345
+ return $this->children($idx);
1346
+ }
1347
+
1348
+ function firstChild()
1349
+ {
1350
+ return $this->first_child();
1351
+ }
1352
+
1353
+ function lastChild()
1354
+ {
1355
+ return $this->last_child();
1356
+ }
1357
+
1358
+ function nextSibling()
1359
+ {
1360
+ return $this->next_sibling();
1361
+ }
1362
+
1363
+ function previousSibling()
1364
+ {
1365
+ return $this->prev_sibling();
1366
+ }
1367
+
1368
+ function hasChildNodes()
1369
+ {
1370
+ return $this->has_child();
1371
+ }
1372
+
1373
+ function nodeName()
1374
+ {
1375
+ return $this->tag;
1376
+ }
1377
+
1378
+ function appendChild($node)
1379
+ {
1380
+ $node->parent($this);
1381
+ return $node;
1382
+ }
1383
+
1384
+ }
1385
+
1386
+ class simple_html_dom
1387
+ {
1388
+ public $root = null;
1389
+ public $nodes = array();
1390
+ public $callback = null;
1391
+ public $lowercase = false;
1392
+ public $original_size;
1393
+ public $size;
1394
+
1395
+ protected $pos;
1396
+ protected $doc;
1397
+ protected $char;
1398
+
1399
+ protected $cursor;
1400
+ protected $parent;
1401
+ protected $noise = array();
1402
+ protected $token_blank = " \t\r\n";
1403
+ protected $token_equal = ' =/>';
1404
+ protected $token_slash = " />\r\n\t";
1405
+ protected $token_attr = ' >';
1406
+
1407
+ public $_charset = '';
1408
+ public $_target_charset = '';
1409
+
1410
+ protected $default_br_text = '';
1411
+
1412
+ public $default_span_text = '';
1413
+
1414
+ protected $self_closing_tags = array(
1415
+ 'area' => 1,
1416
+ 'base' => 1,
1417
+ 'br' => 1,
1418
+ 'col' => 1,
1419
+ 'embed' => 1,
1420
+ 'hr' => 1,
1421
+ 'img' => 1,
1422
+ 'input' => 1,
1423
+ 'link' => 1,
1424
+ 'meta' => 1,
1425
+ 'param' => 1,
1426
+ 'source' => 1,
1427
+ 'track' => 1,
1428
+ 'wbr' => 1
1429
+ );
1430
+ protected $block_tags = array(
1431
+ 'body' => 1,
1432
+ 'div' => 1,
1433
+ 'form' => 1,
1434
+ 'root' => 1,
1435
+ 'span' => 1,
1436
+ 'table' => 1
1437
+ );
1438
+ protected $optional_closing_tags = array(
1439
+ // Not optional, see
1440
+ // https://www.w3.org/TR/html/textlevel-semantics.html#the-b-element
1441
+ 'b' => array('b' => 1),
1442
+ 'dd' => array('dd' => 1, 'dt' => 1),
1443
+ // Not optional, see
1444
+ // https://www.w3.org/TR/html/grouping-content.html#the-dl-element
1445
+ 'dl' => array('dd' => 1, 'dt' => 1),
1446
+ 'dt' => array('dd' => 1, 'dt' => 1),
1447
+ 'li' => array('li' => 1),
1448
+ 'optgroup' => array('optgroup' => 1, 'option' => 1),
1449
+ 'option' => array('optgroup' => 1, 'option' => 1),
1450
+ 'p' => array('p' => 1),
1451
+ 'rp' => array('rp' => 1, 'rt' => 1),
1452
+ 'rt' => array('rp' => 1, 'rt' => 1),
1453
+ 'td' => array('td' => 1, 'th' => 1),
1454
+ 'th' => array('td' => 1, 'th' => 1),
1455
+ 'tr' => array('td' => 1, 'th' => 1, 'tr' => 1),
1456
+ );
1457
+
1458
+ function __construct(
1459
+ $str = null,
1460
+ $lowercase = true,
1461
+ $forceTagsClosed = true,
1462
+ $target_charset = DEFAULT_TARGET_CHARSET,
1463
+ $stripRN = true,
1464
+ $defaultBRText = DEFAULT_BR_TEXT,
1465
+ $defaultSpanText = DEFAULT_SPAN_TEXT,
1466
+ $options = 0)
1467
+ {
1468
+ if ($str) {
1469
+ if (preg_match('/^http:\/\//i', $str) || is_file($str)) {
1470
+ $this->load_file($str);
1471
+ } else {
1472
+ $this->load(
1473
+ $str,
1474
+ $lowercase,
1475
+ $stripRN,
1476
+ $defaultBRText,
1477
+ $defaultSpanText,
1478
+ $options
1479
+ );
1480
+ }
1481
+ }
1482
+ // Forcing tags to be closed implies that we don't trust the html, but
1483
+ // it can lead to parsing errors if we SHOULD trust the html.
1484
+ if (!$forceTagsClosed) {
1485
+ $this->optional_closing_array = array();
1486
+ }
1487
+
1488
+ $this->_target_charset = $target_charset;
1489
+ }
1490
+
1491
+ function __destruct()
1492
+ {
1493
+ $this->clear();
1494
+ }
1495
+
1496
+ function load(
1497
+ $str,
1498
+ $lowercase = true,
1499
+ $stripRN = true,
1500
+ $defaultBRText = DEFAULT_BR_TEXT,
1501
+ $defaultSpanText = DEFAULT_SPAN_TEXT,
1502
+ $options = 0)
1503
+ {
1504
+ global $debug_object;
1505
+
1506
+ // prepare
1507
+ $this->prepare($str, $lowercase, $defaultBRText, $defaultSpanText);
1508
+
1509
+ // Per sourceforge http://sourceforge.net/tracker/?func=detail&aid=2949097&group_id=218559&atid=1044037
1510
+ // Script tags removal now preceeds style tag removal.
1511
+ // strip out <script> tags
1512
+ $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is");
1513
+ $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is");
1514
+
1515
+ // strip out the \r \n's if we are told to.
1516
+ if ($stripRN) {
1517
+ $this->doc = str_replace("\r", ' ', $this->doc);
1518
+ $this->doc = str_replace("\n", ' ', $this->doc);
1519
+
1520
+ // set the length of content since we have changed it.
1521
+ $this->size = strlen($this->doc);
1522
+ }
1523
+
1524
+ // strip out cdata
1525
+ $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true);
1526
+ // strip out comments
1527
+ $this->remove_noise("'<!--(.*?)-->'is");
1528
+ // strip out <style> tags
1529
+ $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is");
1530
+ $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is");
1531
+ // strip out preformatted tags
1532
+ $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is");
1533
+ // strip out server side scripts
1534
+ $this->remove_noise("'(<\?)(.*?)(\?>)'s", true);
1535
+
1536
+ if($options & HDOM_SMARTY_AS_TEXT) { // Strip Smarty scripts
1537
+ $this->remove_noise("'(\{\w)(.*?)(\})'s", true);
1538
+ }
1539
+
1540
+ // parsing
1541
+ $this->parse();
1542
+ // end
1543
+ $this->root->_[HDOM_INFO_END] = $this->cursor;
1544
+ $this->parse_charset();
1545
+
1546
+ // make load function chainable
1547
+ return $this;
1548
+ }
1549
+
1550
+ function load_file()
1551
+ {
1552
+ $args = func_get_args();
1553
+
1554
+ if(($doc = call_user_func_array('file_get_contents', $args)) !== false) {
1555
+ $this->load($doc, true);
1556
+ } else {
1557
+ return false;
1558
+ }
1559
+ }
1560
+
1561
+ function set_callback($function_name)
1562
+ {
1563
+ $this->callback = $function_name;
1564
+ }
1565
+
1566
+ function remove_callback()
1567
+ {
1568
+ $this->callback = null;
1569
+ }
1570
+
1571
+ function save($filepath = '')
1572
+ {
1573
+ $ret = $this->root->innertext();
1574
+ if ($filepath !== '') { file_put_contents($filepath, $ret, LOCK_EX); }
1575
+ return $ret;
1576
+ }
1577
+
1578
+ function find($selector, $idx = null, $lowercase = false)
1579
+ {
1580
+ return $this->root->find($selector, $idx, $lowercase);
1581
+ }
1582
+
1583
+ function clear()
1584
+ {
1585
+ if (isset($this->nodes)) {
1586
+ foreach ($this->nodes as $n) {
1587
+ $n->clear();
1588
+ $n = null;
1589
+ }
1590
+ }
1591
+
1592
+ // This add next line is documented in the sourceforge repository.
1593
+ // 2977248 as a fix for ongoing memory leaks that occur even with the
1594
+ // use of clear.
1595
+ if (isset($this->children)) {
1596
+ foreach ($this->children as $n) {
1597
+ $n->clear();
1598
+ $n = null;
1599
+ }
1600
+ }
1601
+
1602
+ if (isset($this->parent)) {
1603
+ $this->parent->clear();
1604
+ unset($this->parent);
1605
+ }
1606
+
1607
+ if (isset($this->root)) {
1608
+ $this->root->clear();
1609
+ unset($this->root);
1610
+ }
1611
+
1612
+ unset($this->doc);
1613
+ unset($this->noise);
1614
+ }
1615
+
1616
+ function dump($show_attr = true)
1617
+ {
1618
+ $this->root->dump($show_attr);
1619
+ }
1620
+
1621
+ protected function prepare(
1622
+ $str, $lowercase = true,
1623
+ $defaultBRText = DEFAULT_BR_TEXT,
1624
+ $defaultSpanText = DEFAULT_SPAN_TEXT)
1625
+ {
1626
+ $this->clear();
1627
+
1628
+ $this->doc = trim($str);
1629
+ $this->size = strlen($this->doc);
1630
+ $this->original_size = $this->size; // original size of the html
1631
+ $this->pos = 0;
1632
+ $this->cursor = 1;
1633
+ $this->noise = array();
1634
+ $this->nodes = array();
1635
+ $this->lowercase = $lowercase;
1636
+ $this->default_br_text = $defaultBRText;
1637
+ $this->default_span_text = $defaultSpanText;
1638
+ $this->root = new simple_html_dom_node($this);
1639
+ $this->root->tag = 'root';
1640
+ $this->root->_[HDOM_INFO_BEGIN] = -1;
1641
+ $this->root->nodetype = HDOM_TYPE_ROOT;
1642
+ $this->parent = $this->root;
1643
+ if ($this->size > 0) { $this->char = $this->doc[0]; }
1644
+ }
1645
+
1646
+ protected function parse()
1647
+ {
1648
+ while (true) {
1649
+ // Read next tag if there is no text between current position and the
1650
+ // next opening tag.
1651
+ if (($s = $this->copy_until_char('<')) === '') {
1652
+ if($this->read_tag()) {
1653
+ continue;
1654
+ } else {
1655
+ return true;
1656
+ }
1657
+ }
1658
+
1659
+ // Add a text node for text between tags
1660
+ $node = new simple_html_dom_node($this);
1661
+ ++$this->cursor;
1662
+ $node->_[HDOM_INFO_TEXT] = $s;
1663
+ $this->link_nodes($node, false);
1664
+ }
1665
+ }
1666
+
1667
+ protected function parse_charset()
1668
+ {
1669
+ global $debug_object;
1670
+
1671
+ $charset = null;
1672
+
1673
+ if (function_exists('get_last_retrieve_url_contents_content_type')) {
1674
+ $contentTypeHeader = get_last_retrieve_url_contents_content_type();
1675
+ $success = preg_match('/charset=(.+)/', $contentTypeHeader, $matches);
1676
+ if ($success) {
1677
+ $charset = $matches[1];
1678
+ if (is_object($debug_object)) {
1679
+ $debug_object->debug_log(2,
1680
+ 'header content-type found charset of: '
1681
+ . $charset
1682
+ );
1683
+ }
1684
+ }
1685
+ }
1686
+
1687
+ if (empty($charset)) {
1688
+ // https://www.w3.org/TR/html/document-metadata.html#statedef-http-equiv-content-type
1689
+ $el = $this->root->find('meta[http-equiv=Content-Type]', 0, true);
1690
+
1691
+ if (!empty($el)) {
1692
+ $fullvalue = $el->content;
1693
+ if (is_object($debug_object)) {
1694
+ $debug_object->debug_log(2,
1695
+ 'meta content-type tag found'
1696
+ . $fullvalue
1697
+ );
1698
+ }
1699
+
1700
+ if (!empty($fullvalue)) {
1701
+ $success = preg_match(
1702
+ '/charset=(.+)/i',
1703
+ $fullvalue,
1704
+ $matches
1705
+ );
1706
+
1707
+ if ($success) {
1708
+ $charset = $matches[1];
1709
+ } else {
1710
+ // If there is a meta tag, and they don't specify the
1711
+ // character set, research says that it's typically
1712
+ // ISO-8859-1
1713
+ if (is_object($debug_object)) {
1714
+ $debug_object->debug_log(2,
1715
+ 'meta content-type tag couldn\'t be parsed. using iso-8859 default.'
1716
+ );
1717
+ }
1718
+
1719
+ $charset = 'ISO-8859-1';
1720
+ }
1721
+ }
1722
+ }
1723
+ }
1724
+
1725
+ if (empty($charset)) {
1726
+ // https://www.w3.org/TR/html/document-metadata.html#character-encoding-declaration
1727
+ if ($meta = $this->root->find('meta[charset]', 0)) {
1728
+ $charset = $meta->charset;
1729
+ if (is_object($debug_object)) {
1730
+ $debug_object->debug_log(2, 'meta charset: ' . $charset);
1731
+ }
1732
+ }
1733
+ }
1734
+
1735
+ if (empty($charset)) {
1736
+ // Try to guess the charset based on the content
1737
+ // Requires Multibyte String (mbstring) support (optional)
1738
+ if (function_exists('mb_detect_encoding')) {
1739
+ /**
1740
+ * mb_detect_encoding() is not intended to distinguish between
1741
+ * charsets, especially single-byte charsets. Its primary
1742
+ * purpose is to detect which multibyte encoding is in use,
1743
+ * i.e. UTF-8, UTF-16, shift-JIS, etc.
1744
+ *
1745
+ * -- https://bugs.php.net/bug.php?id=38138
1746
+ *
1747
+ * Adding both CP1251/ISO-8859-5 and CP1252/ISO-8859-1 will
1748
+ * always result in CP1251/ISO-8859-5 and vice versa.
1749
+ *
1750
+ * Thus, only detect if it's either UTF-8 or CP1252/ISO-8859-1
1751
+ * to stay compatible.
1752
+ */
1753
+ $encoding = mb_detect_encoding(
1754
+ $this->doc,
1755
+ array( 'UTF-8', 'CP1252', 'ISO-8859-1' )
1756
+ );
1757
+
1758
+ if ($encoding === 'CP1252' || $encoding === 'ISO-8859-1') {
1759
+ // Due to a limitation of mb_detect_encoding
1760
+ // 'CP1251'/'ISO-8859-5' will be detected as
1761
+ // 'CP1252'/'ISO-8859-1'. This will cause iconv to fail, in
1762
+ // which case we can simply assume it is the other charset.
1763
+ if (!@iconv('CP1252', 'UTF-8', $this->doc)) {
1764
+ $encoding = 'CP1251';
1765
+ }
1766
+ }
1767
+
1768
+ if ($encoding !== false) {
1769
+ $charset = $encoding;
1770
+ if (is_object($debug_object)) {
1771
+ $debug_object->debug_log(2, 'mb_detect: ' . $charset);
1772
+ }
1773
+ }
1774
+ }
1775
+ }
1776
+
1777
+ if (empty($charset)) {
1778
+ // Assume it's UTF-8 as it is the most likely charset to be used
1779
+ $charset = 'UTF-8';
1780
+ if (is_object($debug_object)) {
1781
+ $debug_object->debug_log(2, 'No match found, assume ' . $charset);
1782
+ }
1783
+ }
1784
+
1785
+ // Since CP1252 is a superset, if we get one of it's subsets, we want
1786
+ // it instead.
1787
+ if ((strtolower($charset) == 'iso-8859-1')
1788
+ || (strtolower($charset) == 'latin1')
1789
+ || (strtolower($charset) == 'latin-1')) {
1790
+ $charset = 'CP1252';
1791
+ if (is_object($debug_object)) {
1792
+ $debug_object->debug_log(2,
1793
+ 'replacing ' . $charset . ' with CP1252 as its a superset'
1794
+ );
1795
+ }
1796
+ }
1797
+
1798
+ if (is_object($debug_object)) {
1799
+ $debug_object->debug_log(1, 'EXIT - ' . $charset);
1800
+ }
1801
+
1802
+ return $this->_charset = $charset;
1803
+ }
1804
+
1805
+ protected function read_tag()
1806
+ {
1807
+ // Set end position if no further tags found
1808
+ if ($this->char !== '<') {
1809
+ $this->root->_[HDOM_INFO_END] = $this->cursor;
1810
+ return false;
1811
+ }
1812
+
1813
+ $begin_tag_pos = $this->pos;
1814
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1815
+
1816
+ // end tag
1817
+ if ($this->char === '/') {
1818
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1819
+
1820
+ // Skip whitespace in end tags (i.e. in "</ html>")
1821
+ $this->skip($this->token_blank);
1822
+ $tag = $this->copy_until_char('>');
1823
+
1824
+ // Skip attributes in end tags
1825
+ if (($pos = strpos($tag, ' ')) !== false) {
1826
+ $tag = substr($tag, 0, $pos);
1827
+ }
1828
+
1829
+ $parent_lower = strtolower($this->parent->tag);
1830
+ $tag_lower = strtolower($tag);
1831
+
1832
+ // The end tag is supposed to close the parent tag. Handle situations
1833
+ // when it doesn't
1834
+ if ($parent_lower !== $tag_lower) {
1835
+ // Parent tag does not have to be closed necessarily (optional closing tag)
1836
+ // Current tag is a block tag, so it may close an ancestor
1837
+ if (isset($this->optional_closing_tags[$parent_lower])
1838
+ && isset($this->block_tags[$tag_lower])) {
1839
+
1840
+ $this->parent->_[HDOM_INFO_END] = 0;
1841
+ $org_parent = $this->parent;
1842
+
1843
+ // Traverse ancestors to find a matching opening tag
1844
+ // Stop at root node
1845
+ while (($this->parent->parent)
1846
+ && strtolower($this->parent->tag) !== $tag_lower
1847
+ ){
1848
+ $this->parent = $this->parent->parent;
1849
+ }
1850
+
1851
+ // If we don't have a match add current tag as text node
1852
+ if (strtolower($this->parent->tag) !== $tag_lower) {
1853
+ $this->parent = $org_parent; // restore origonal parent
1854
+
1855
+ if ($this->parent->parent) {
1856
+ $this->parent = $this->parent->parent;
1857
+ }
1858
+
1859
+ $this->parent->_[HDOM_INFO_END] = $this->cursor;
1860
+ return $this->as_text_node($tag);
1861
+ }
1862
+ } elseif (($this->parent->parent)
1863
+ && isset($this->block_tags[$tag_lower])
1864
+ ) {
1865
+ // Grandparent exists and current tag is a block tag, so our
1866
+ // parent doesn't have an end tag
1867
+ $this->parent->_[HDOM_INFO_END] = 0; // No end tag
1868
+ $org_parent = $this->parent;
1869
+
1870
+ // Traverse ancestors to find a matching opening tag
1871
+ // Stop at root node
1872
+ while (($this->parent->parent)
1873
+ && strtolower($this->parent->tag) !== $tag_lower
1874
+ ) {
1875
+ $this->parent = $this->parent->parent;
1876
+ }
1877
+
1878
+ // If we don't have a match add current tag as text node
1879
+ if (strtolower($this->parent->tag) !== $tag_lower) {
1880
+ $this->parent = $org_parent; // restore origonal parent
1881
+ $this->parent->_[HDOM_INFO_END] = $this->cursor;
1882
+ return $this->as_text_node($tag);
1883
+ }
1884
+ } elseif (($this->parent->parent)
1885
+ && strtolower($this->parent->parent->tag) === $tag_lower
1886
+ ) { // Grandparent exists and current tag closes it
1887
+ $this->parent->_[HDOM_INFO_END] = 0;
1888
+ $this->parent = $this->parent->parent;
1889
+ } else { // Random tag, add as text node
1890
+ return $this->as_text_node($tag);
1891
+ }
1892
+ }
1893
+
1894
+ // Set end position of parent tag to current cursor position
1895
+ $this->parent->_[HDOM_INFO_END] = $this->cursor;
1896
+
1897
+ if ($this->parent->parent) {
1898
+ $this->parent = $this->parent->parent;
1899
+ }
1900
+
1901
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1902
+ return true;
1903
+ }
1904
+
1905
+ // start tag
1906
+ $node = new simple_html_dom_node($this);
1907
+ $node->_[HDOM_INFO_BEGIN] = $this->cursor;
1908
+ ++$this->cursor;
1909
+ $tag = $this->copy_until($this->token_slash); // Get tag name
1910
+ $node->tag_start = $begin_tag_pos;
1911
+
1912
+ // doctype, cdata & comments...
1913
+ // <!DOCTYPE html>
1914
+ // <![CDATA[ ... ]]>
1915
+ // <!-- Comment -->
1916
+ if (isset($tag[0]) && $tag[0] === '!') {
1917
+ $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>');
1918
+
1919
+ if (isset($tag[2]) && $tag[1] === '-' && $tag[2] === '-') { // Comment ("<!--")
1920
+ $node->nodetype = HDOM_TYPE_COMMENT;
1921
+ $node->tag = 'comment';
1922
+ } else { // Could be doctype or CDATA but we don't care
1923
+ $node->nodetype = HDOM_TYPE_UNKNOWN;
1924
+ $node->tag = 'unknown';
1925
+ }
1926
+
1927
+ if ($this->char === '>') { $node->_[HDOM_INFO_TEXT] .= '>'; }
1928
+
1929
+ $this->link_nodes($node, true);
1930
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1931
+ return true;
1932
+ }
1933
+
1934
+ // The start tag cannot contain another start tag, if so add as text
1935
+ // i.e. "<<html>"
1936
+ if ($pos = strpos($tag, '<') !== false) {
1937
+ $tag = '<' . substr($tag, 0, -1);
1938
+ $node->_[HDOM_INFO_TEXT] = $tag;
1939
+ $this->link_nodes($node, false);
1940
+ $this->char = $this->doc[--$this->pos]; // prev
1941
+ return true;
1942
+ }
1943
+
1944
+ // Handle invalid tag names (i.e. "<html#doc>")
1945
+ if (!preg_match('/^\w[\w:-]*$/', $tag)) {
1946
+ $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>');
1947
+
1948
+ // Next char is the beginning of a new tag, don't touch it.
1949
+ if ($this->char === '<') {
1950
+ $this->link_nodes($node, false);
1951
+ return true;
1952
+ }
1953
+
1954
+ // Next char closes current tag, add and be done with it.
1955
+ if ($this->char === '>') { $node->_[HDOM_INFO_TEXT] .= '>'; }
1956
+ $this->link_nodes($node, false);
1957
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1958
+ return true;
1959
+ }
1960
+
1961
+ // begin tag, add new node
1962
+ $node->nodetype = HDOM_TYPE_ELEMENT;
1963
+ $tag_lower = strtolower($tag);
1964
+ $node->tag = ($this->lowercase) ? $tag_lower : $tag;
1965
+
1966
+ // handle optional closing tags
1967
+ if (isset($this->optional_closing_tags[$tag_lower])) {
1968
+ // Traverse ancestors to close all optional closing tags
1969
+ while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)])) {
1970
+ $this->parent->_[HDOM_INFO_END] = 0;
1971
+ $this->parent = $this->parent->parent;
1972
+ }
1973
+ $node->parent = $this->parent;
1974
+ }
1975
+
1976
+ $guard = 0; // prevent infinity loop
1977
+
1978
+ // [0] Space between tag and first attribute
1979
+ $space = array($this->copy_skip($this->token_blank), '', '');
1980
+
1981
+ // attributes
1982
+ do {
1983
+ // Everything until the first equal sign should be the attribute name
1984
+ $name = $this->copy_until($this->token_equal);
1985
+
1986
+ if ($name === '' && $this->char !== null && $space[0] === '') {
1987
+ break;
1988
+ }
1989
+
1990
+ if ($guard === $this->pos) { // Escape infinite loop
1991
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1992
+ continue;
1993
+ }
1994
+
1995
+ $guard = $this->pos;
1996
+
1997
+ // handle endless '<'
1998
+ // Out of bounds before the tag ended
1999
+ if ($this->pos >= $this->size - 1 && $this->char !== '>') {
2000
+ $node->nodetype = HDOM_TYPE_TEXT;
2001
+ $node->_[HDOM_INFO_END] = 0;
2002
+ $node->_[HDOM_INFO_TEXT] = '<' . $tag . $space[0] . $name;
2003
+ $node->tag = 'text';
2004
+ $this->link_nodes($node, false);
2005
+ return true;
2006
+ }
2007
+
2008
+ // handle mismatch '<'
2009
+ // Attributes cannot start after opening tag
2010
+ if ($this->doc[$this->pos - 1] == '<') {
2011
+ $node->nodetype = HDOM_TYPE_TEXT;
2012
+ $node->tag = 'text';
2013
+ $node->attr = array();
2014
+ $node->_[HDOM_INFO_END] = 0;
2015
+ $node->_[HDOM_INFO_TEXT] = substr(
2016
+ $this->doc,
2017
+ $begin_tag_pos,
2018
+ $this->pos - $begin_tag_pos - 1
2019
+ );
2020
+ $this->pos -= 2;
2021
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2022
+ $this->link_nodes($node, false);
2023
+ return true;
2024
+ }
2025
+
2026
+ if ($name !== '/' && $name !== '') { // this is a attribute name
2027
+ // [1] Whitespace after attribute name
2028
+ $space[1] = $this->copy_skip($this->token_blank);
2029
+
2030
+ $name = $this->restore_noise($name); // might be a noisy name
2031
+
2032
+ if ($this->lowercase) { $name = strtolower($name); }
2033
+
2034
+ if ($this->char === '=') { // attribute with value
2035
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2036
+ $this->parse_attr($node, $name, $space); // get attribute value
2037
+ } else {
2038
+ //no value attr: nowrap, checked selected...
2039
+ $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
2040
+ $node->attr[$name] = true;
2041
+ if ($this->char != '>') { $this->char = $this->doc[--$this->pos]; } // prev
2042
+ }
2043
+
2044
+ $node->_[HDOM_INFO_SPACE][] = $space;
2045
+
2046
+ // prepare for next attribute
2047
+ $space = array(
2048
+ $this->copy_skip($this->token_blank),
2049
+ '',
2050
+ ''
2051
+ );
2052
+ } else { // no more attributes
2053
+ break;
2054
+ }
2055
+ } while ($this->char !== '>' && $this->char !== '/'); // go until the tag ended
2056
+
2057
+ $this->link_nodes($node, true);
2058
+ $node->_[HDOM_INFO_ENDSPACE] = $space[0];
2059
+
2060
+ // handle empty tags (i.e. "<div/>")
2061
+ if ($this->copy_until_char('>') === '/') {
2062
+ $node->_[HDOM_INFO_ENDSPACE] .= '/';
2063
+ $node->_[HDOM_INFO_END] = 0;
2064
+ } else {
2065
+ // reset parent
2066
+ if (!isset($this->self_closing_tags[strtolower($node->tag)])) {
2067
+ $this->parent = $node;
2068
+ }
2069
+ }
2070
+
2071
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2072
+
2073
+ // If it's a BR tag, we need to set it's text to the default text.
2074
+ // This way when we see it in plaintext, we can generate formatting that the user wants.
2075
+ // since a br tag never has sub nodes, this works well.
2076
+ if ($node->tag === 'br') {
2077
+ $node->_[HDOM_INFO_INNER] = $this->default_br_text;
2078
+ }
2079
+
2080
+ return true;
2081
+ }
2082
+
2083
+ protected function parse_attr($node, $name, &$space)
2084
+ {
2085
+ $is_duplicate = isset($node->attr[$name]);
2086
+
2087
+ if (!$is_duplicate) // Copy whitespace between "=" and value
2088
+ $space[2] = $this->copy_skip($this->token_blank);
2089
+
2090
+ switch ($this->char) {
2091
+ case '"':
2092
+ $quote_type = HDOM_QUOTE_DOUBLE;
2093
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2094
+ $value = $this->copy_until_char('"');
2095
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2096
+ break;
2097
+ case '\'':
2098
+ $quote_type = HDOM_QUOTE_SINGLE;
2099
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2100
+ $value = $this->copy_until_char('\'');
2101
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2102
+ break;
2103
+ default:
2104
+ $quote_type = HDOM_QUOTE_NO;
2105
+ $value = $this->copy_until($this->token_attr);
2106
+ }
2107
+
2108
+ $value = $this->restore_noise($value);
2109
+
2110
+ // PaperG: Attributes should not have \r or \n in them, that counts as
2111
+ // html whitespace.
2112
+ $value = str_replace("\r", '', $value);
2113
+ $value = str_replace("\n", '', $value);
2114
+
2115
+ // PaperG: If this is a "class" selector, lets get rid of the preceeding
2116
+ // and trailing space since some people leave it in the multi class case.
2117
+ if ($name === 'class') {
2118
+ $value = trim($value);
2119
+ }
2120
+
2121
+ if (!$is_duplicate) {
2122
+ $node->_[HDOM_INFO_QUOTE][] = $quote_type;
2123
+ $node->attr[$name] = $value;
2124
+ }
2125
+ }
2126
+
2127
+ protected function link_nodes(&$node, $is_child)
2128
+ {
2129
+ $node->parent = $this->parent;
2130
+ $this->parent->nodes[] = $node;
2131
+ if ($is_child) {
2132
+ $this->parent->children[] = $node;
2133
+ }
2134
+ }
2135
+
2136
+ protected function as_text_node($tag)
2137
+ {
2138
+ $node = new simple_html_dom_node($this);
2139
+ ++$this->cursor;
2140
+ $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>';
2141
+ $this->link_nodes($node, false);
2142
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2143
+ return true;
2144
+ }
2145
+
2146
+ protected function skip($chars)
2147
+ {
2148
+ $this->pos += strspn($this->doc, $chars, $this->pos);
2149
+ $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2150
+ }
2151
+
2152
+ protected function copy_skip($chars)
2153
+ {
2154
+ $pos = $this->pos;
2155
+ $len = strspn($this->doc, $chars, $pos);
2156
+ $this->pos += $len;
2157
+ $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2158
+ if ($len === 0) { return ''; }
2159
+ return substr($this->doc, $pos, $len);
2160
+ }
2161
+
2162
+ protected function copy_until($chars)
2163
+ {
2164
+ $pos = $this->pos;
2165
+ $len = strcspn($this->doc, $chars, $pos);
2166
+ $this->pos += $len;
2167
+ $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2168
+ return substr($this->doc, $pos, $len);
2169
+ }
2170
+
2171
+ protected function copy_until_char($char)
2172
+ {
2173
+ if ($this->char === null) { return ''; }
2174
+
2175
+ if (($pos = strpos($this->doc, $char, $this->pos)) === false) {
2176
+ $ret = substr($this->doc, $this->pos, $this->size - $this->pos);
2177
+ $this->char = null;
2178
+ $this->pos = $this->size;
2179
+ return $ret;
2180
+ }
2181
+
2182
+ if ($pos === $this->pos) { return ''; }
2183
+
2184
+ $pos_old = $this->pos;
2185
+ $this->char = $this->doc[$pos];
2186
+ $this->pos = $pos;
2187
+ return substr($this->doc, $pos_old, $pos - $pos_old);
2188
+ }
2189
+
2190
+ protected function remove_noise($pattern, $remove_tag = false)
2191
+ {
2192
+ global $debug_object;
2193
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
2194
+
2195
+ $count = preg_match_all(
2196
+ $pattern,
2197
+ $this->doc,
2198
+ $matches,
2199
+ PREG_SET_ORDER | PREG_OFFSET_CAPTURE
2200
+ );
2201
+
2202
+ for ($i = $count - 1; $i > -1; --$i) {
2203
+ $key = '___noise___' . sprintf('% 5d', count($this->noise) + 1000);
2204
+
2205
+ if (is_object($debug_object)) {
2206
+ $debug_object->debug_log(2, 'key is: ' . $key);
2207
+ }
2208
+
2209
+ $idx = ($remove_tag) ? 0 : 1; // 0 = entire match, 1 = submatch
2210
+ $this->noise[$key] = $matches[$i][$idx][0];
2211
+ $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0]));
2212
+ }
2213
+
2214
+ // reset the length of content
2215
+ $this->size = strlen($this->doc);
2216
+
2217
+ if ($this->size > 0) {
2218
+ $this->char = $this->doc[0];
2219
+ }
2220
+ }
2221
+
2222
+ function restore_noise($text)
2223
+ {
2224
+ global $debug_object;
2225
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
2226
+
2227
+ while (($pos = strpos($text, '___noise___')) !== false) {
2228
+ // Sometimes there is a broken piece of markup, and we don't GET the
2229
+ // pos+11 etc... token which indicates a problem outside of us...
2230
+
2231
+ // todo: "___noise___1000" (or any number with four or more digits)
2232
+ // in the DOM causes an infinite loop which could be utilized by
2233
+ // malicious software
2234
+ if (strlen($text) > $pos + 15) {
2235
+ $key = '___noise___'
2236
+ . $text[$pos + 11]
2237
+ . $text[$pos + 12]
2238
+ . $text[$pos + 13]
2239
+ . $text[$pos + 14]
2240
+ . $text[$pos + 15];
2241
+
2242
+ if (is_object($debug_object)) {
2243
+ $debug_object->debug_log(2, 'located key of: ' . $key);
2244
+ }
2245
+
2246
+ if (isset($this->noise[$key])) {
2247
+ $text = substr($text, 0, $pos)
2248
+ . $this->noise[$key]
2249
+ . substr($text, $pos + 16);
2250
+ } else {
2251
+ // do this to prevent an infinite loop.
2252
+ $text = substr($text, 0, $pos)
2253
+ . 'UNDEFINED NOISE FOR KEY: '
2254
+ . $key
2255
+ . substr($text, $pos + 16);
2256
+ }
2257
+ } else {
2258
+ // There is no valid key being given back to us... We must get
2259
+ // rid of the ___noise___ or we will have a problem.
2260
+ $text = substr($text, 0, $pos)
2261
+ . 'NO NUMERIC NOISE KEY'
2262
+ . substr($text, $pos + 11);
2263
+ }
2264
+ }
2265
+ return $text;
2266
+ }
2267
+
2268
+ function search_noise($text)
2269
+ {
2270
+ global $debug_object;
2271
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
2272
+
2273
+ foreach($this->noise as $noiseElement) {
2274
+ if (strpos($noiseElement, $text) !== false) {
2275
+ return $noiseElement;
2276
+ }
2277
+ }
2278
+ }
2279
+
2280
+ function __toString()
2281
+ {
2282
+ return $this->root->innertext();
2283
+ }
2284
+
2285
+ function __get($name)
2286
+ {
2287
+ switch ($name) {
2288
+ case 'outertext':
2289
+ return $this->root->innertext();
2290
+ case 'innertext':
2291
+ return $this->root->innertext();
2292
+ case 'plaintext':
2293
+ return $this->root->text();
2294
+ case 'charset':
2295
+ return $this->_charset;
2296
+ case 'target_charset':
2297
+ return $this->_target_charset;
2298
+ }
2299
+ }
2300
+
2301
+ function childNodes($idx = -1)
2302
+ {
2303
+ return $this->root->childNodes($idx);
2304
+ }
2305
+
2306
+ function firstChild()
2307
+ {
2308
+ return $this->root->first_child();
2309
+ }
2310
+
2311
+ function lastChild()
2312
+ {
2313
+ return $this->root->last_child();
2314
+ }
2315
+
2316
+ function createElement($name, $value = null)
2317
+ {
2318
+ return @str_get_html("<$name>$value</$name>")->firstChild();
2319
+ }
2320
+
2321
+ function createTextNode($value)
2322
+ {
2323
+ return @end(str_get_html($value)->nodes);
2324
+ }
2325
+
2326
+ function getElementById($id)
2327
+ {
2328
+ return $this->find("#$id", 0);
2329
+ }
2330
+
2331
+ function getElementsById($id, $idx = null)
2332
+ {
2333
+ return $this->find("#$id", $idx);
2334
+ }
2335
+
2336
+ function getElementByTagName($name)
2337
+ {
2338
+ return $this->find($name, 0);
2339
+ }
2340
+
2341
+ function getElementsByTagName($name, $idx = -1)
2342
+ {
2343
+ return $this->find($name, $idx);
2344
+ }
2345
+
2346
+ function loadFile()
2347
+ {
2348
+ $args = func_get_args();
2349
+ $this->load_file($args);
2350
+ }
2351
+ }
trunk/iubenda-cookie-class/test.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * test.php
4
+ *
5
+ * @author iubenda s.r.l
6
+ * @copyright 2018-2020, iubenda s.r.l
7
+ * @license GNU/GPL
8
+ *
9
+ * This program is free software: you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation, either version 3 of the License, or
12
+ * (at your option) any later version.
13
+ *
14
+ * This program is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
21
+ */
22
+
23
+ ini_set( 'max_execution_time', 300 );
24
+ ?>
25
+
26
+ <html>
27
+ <head>
28
+ <!-- Latest compiled and minified CSS -->
29
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
30
+
31
+ <!-- Optional theme -->
32
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css">
33
+ <style>
34
+ ul { margin: 0; padding: 0;}
35
+ ul li { list-style-type: none; }
36
+ </style>
37
+ </head>
38
+ <body>
39
+ <div class="container">
40
+ <div class="row">
41
+ <div class="col-md-12">
42
+ <h1>iubenda class test</h1>
43
+ <form action="" method="POST">
44
+ <strong>URL WEBSITE</strong><BR>
45
+ <input type="text" name="url">
46
+ <input type="submit" class="btn" value="Analyze">
47
+ </form>
48
+ </div>
49
+
50
+ <?php
51
+ if ( ! empty( $_POST['url'] ) )
52
+ if (substr($_POST['url'], 0, 4) == "http") {
53
+ $url = filter_var( $_POST['url'], FILTER_SANITIZE_URL );
54
+ }
55
+ else
56
+ $url = '';
57
+
58
+ if ( $url ) {
59
+
60
+ function print_stuff( $array ) {
61
+ if ( count( $array ) ) {
62
+ echo "<ul>";
63
+ foreach ( $array as $r ) {
64
+ echo "<li><pre><code>" . htmlspecialchars( $r ) . "</code></pre></li>";
65
+ }
66
+ echo "</ul>";
67
+ } else {
68
+ echo "<p>Nothing</p>";
69
+ }
70
+ }
71
+
72
+ echo '<div class="col-md-12" style="padding-bottom:150px;"><h2>RESULTS</H2>';
73
+
74
+ include_once( 'iubenda.class.php' );
75
+
76
+ $content = file_get_contents( $url );
77
+
78
+ $type = isset( $_GET['type'] ) && in_array( $_GET['type'], array( 'page', 'faster' ), true ) ? $_GET['type'] : 'page';
79
+ $iubenda = new iubendaParser( $content, array( 'type' => $type ) );
80
+ $iubenda->parse();
81
+
82
+ $iub_comments_detected = count( $iubenda->iub_comments_detected );
83
+ $scripts_detected = count( $iubenda->scripts_detected );
84
+ $iframes_detected = count( $iubenda->iframes_detected );
85
+ $iframes_converted = count( $iubenda->iframes_converted );
86
+ $script_inline_detected = count( $iubenda->scripts_inline_detected );
87
+ $script_inline_converted = count( $iubenda->scripts_inline_converted );
88
+ $script_converted = count( $iubenda->scripts_converted );
89
+
90
+ echo "<p>Iubenda comments detected: $iub_comments_detected<br>Iubenda automatic stuff<br>Iframe detected: $iframes_detected<br>Iframe autoconverted: $iframes_converted<br>Scripts detected: $scripts_detected<br>Scripts autoconverted: $script_converted<br>Inline scripts detected: $script_inline_detected<br>Inline scripts autoconverted: $script_inline_converted</p>";
91
+
92
+ echo "<H3>DETAILS</H3>";
93
+
94
+ echo "<H4>iubenda comments stuff</h4>";
95
+ print_stuff( $iubenda->iub_comments_detected );
96
+ echo "<H4>Script detected</h4>";
97
+ print_stuff( $iubenda->scripts_detected );
98
+ echo "<H4>Script converted</h4>";
99
+ print_stuff( $iubenda->scripts_converted );
100
+ echo "<H4>Script inline detected</h4>";
101
+ print_stuff( $iubenda->scripts_inline_detected );
102
+ echo "<H4>Script inline converted</h4>";
103
+ print_stuff( $iubenda->scripts_inline_converted );
104
+ echo "<H4>Iframe detected</h4>";
105
+ print_stuff( $iubenda->iframes_detected );
106
+ echo "<H4>Iframe converted</h4>";
107
+ print_stuff( $iubenda->iframes_converted );
108
+
109
+ echo "</div>";
110
+ }
111
+ ?>
112
+ </div>
113
+ </div>
114
+
115
+ </body>
116
+ </html>
trunk/iubenda-cookie-class/usage.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * usage.php
4
+ *
5
+ * @author iubenda s.r.l
6
+ * @copyright 2018-2020, iubenda s.r.l
7
+ * @license GNU/GPL
8
+ *
9
+ * This program is free software: you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation, either version 3 of the License, or
12
+ * (at your option) any later version.
13
+ *
14
+ * This program is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
21
+ */
22
+
23
+ // the "$html" parameter must contain the content of the web page with the iubenda JavaScript banner/policy included
24
+
25
+ function iubenda_system( $html, $type = 'page' ) {
26
+ if ( empty( $html ) )
27
+ return;
28
+
29
+ require_once( 'iubenda.class.php' );
30
+
31
+ // separator
32
+ if ( ! iubendaParser::consent_given() && ! iubendaParser::bot_detected() ) {
33
+ $iubenda = new iubendaParser( $html, array( 'type' => in_array( $type, array( 'page', 'faster' ), true ) ? $type : 'page' ) );
34
+ $html = $iubenda->parse();
35
+ }
36
+
37
+ // finished
38
+ return $html;
39
+ }
40
+
41
+ /**
42
+ * Example:
43
+ *
44
+ * echo iubenda_system( "<html> ...content... </html>", 'faster' );
45
+ *
46
+ */
trunk/iubenda_cookie_solution.php ADDED
@@ -0,0 +1,837 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Cookie and Consent Solution for the GDPR & ePrivacy
4
+ Plugin URI: https://www.iubenda.com
5
+ Description: An All-in-One approach developed by iubenda, which includes functionalities of two powerful solutions that help to make your website GDPR and ePrivacy compliant.
6
+ Version: 2.3.4
7
+ Author: iubenda
8
+ Author URI: https://www.iubenda.com
9
+ License: MIT License
10
+ License URI: http://opensource.org/licenses/MIT
11
+ Text Domain: iubenda
12
+ Domain Path: /languages
13
+
14
+ Cookie and Consent Solution for the GDPR & ePrivacy
15
+ Copyright (C) 2018-2020, iubenda s.r.l
16
+
17
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ */
23
+
24
+ // exit if accessed directly
25
+ if ( ! defined( 'ABSPATH' ) )
26
+ exit;
27
+
28
+ // define contants
29
+ define( 'IUB_DEBUG', false );
30
+
31
+ /**
32
+ * iubenda final class.
33
+ *
34
+ * @class iubenda
35
+ * @version 2.3.4
36
+ */
37
+ class iubenda {
38
+
39
+ private static $instance;
40
+ public $options = array();
41
+ public $defaults = array(
42
+ 'cs' => array(
43
+ 'parse' => false, // iubenda_parse
44
+ 'skip_parsing' => true, // skip_parsing
45
+ 'ctype' => true, // iubenda_ctype
46
+ 'parse' => false, // iubenda_parse
47
+ 'parser_engine' => 'new', // parser_engine
48
+ 'output_feed' => true, // iubenda_output_feed
49
+ 'output_post' => true,
50
+ 'code_default' => false, // iubenda-code-default,
51
+ 'menu_position' => 'topmenu',
52
+ 'amp_support' => false,
53
+ 'amp_source' => 'local',
54
+ 'amp_template_done' => false,
55
+ 'amp_template' => '',
56
+ 'custom_scripts' => array(),
57
+ 'custom_iframes' => array(),
58
+ 'deactivation' => false
59
+ ),
60
+ 'cons' => array(
61
+ 'public_api_key' => '',
62
+ )
63
+ );
64
+ public $base_url;
65
+ public $version = '2.3.4';
66
+ public $activation = array(
67
+ 'update_version' => 0,
68
+ 'update_notice' => true,
69
+ 'update_date' => '',
70
+ 'update_delay_date' => 0
71
+ );
72
+ public $no_html = false;
73
+ public $multilang = false;
74
+ public $languages = array();
75
+ public $lang_default = '';
76
+ public $lang_current = '';
77
+
78
+ /**
79
+ * Disable object clone.
80
+ */
81
+ private function __clone() {
82
+
83
+ }
84
+
85
+ /**
86
+ * Disable unserializing of the class.
87
+ */
88
+ private function __wakeup() {
89
+
90
+ }
91
+
92
+ /**
93
+ * Main plugin instance,
94
+ * Insures that only one instance of the plugin exists in memory at one time.
95
+ *
96
+ * @return object
97
+ */
98
+ public static function instance() {
99
+ if ( ! isset( self::$instance ) && ! ( self::$instance instanceof iubenda ) ) {
100
+
101
+ self::$instance = new iubenda;
102
+ self::$instance->define_constants();
103
+
104
+ add_action( 'plugins_loaded', array( self::$instance, 'load_textdomain' ) );
105
+ add_action( 'plugins_loaded', array( self::$instance, 'init' ) );
106
+
107
+ self::$instance->includes();
108
+
109
+ self::$instance->AMP = new iubenda_AMP();
110
+ self::$instance->forms = new iubenda_Forms();
111
+ self::$instance->settings = new iubenda_Settings();
112
+ }
113
+
114
+ return self::$instance;
115
+ }
116
+
117
+ /**
118
+ * Class constructor.
119
+ */
120
+ public function __construct() {
121
+ register_activation_hook( __FILE__, array( $this, 'activation' ) );
122
+ register_deactivation_hook( __FILE__, array( $this, 'deactivation' ) );
123
+
124
+ // settings
125
+ $cs_options = (array) get_option( 'iubenda_cookie_law_solution', $this->defaults['cs'] );
126
+ $cons_options = (array) get_option( 'iubenda_consent_solution', $this->defaults['cons'] );
127
+
128
+ // activate AMP if not available before
129
+ if ( function_exists( 'is_amp_endpoint' ) || function_exists( 'ampforwp_is_amp_endpoint' ) ) {
130
+ if ( ! isset( $cs_options['amp_support'] ) )
131
+ $this->defaults['cs']['amp_support'] = true;
132
+ }
133
+
134
+ $this->options['cs'] = array_merge( $this->defaults['cs'], $cs_options );
135
+ $this->options['cons'] = array_merge( $this->defaults['cons'], $cons_options );
136
+
137
+ $this->base_url = esc_url_raw( add_query_arg( 'page', 'iubenda', admin_url( $this->options['cs']['menu_position'] === 'submenu' ? 'options-general.php' : 'admin.php' ) ) );
138
+
139
+ // check old custom scripts
140
+ if ( ! empty( $this->options['cs']['custom_scripts'] ) && is_array( $this->options['cs']['custom_scripts'] ) && ! is_int( reset( $this->options['cs']['custom_scripts'] ) ) ) {
141
+ $data = array();
142
+
143
+ foreach ( $this->options['cs']['custom_scripts'] as $script ) {
144
+ $data[$script] = 0;
145
+ }
146
+
147
+ $this->options['cs']['custom_scripts'] = $data;
148
+ }
149
+
150
+ // check old custom iframes
151
+ if ( ! empty( $this->options['cs']['custom_iframes'] ) && is_array( $this->options['cs']['custom_iframes'] ) && ! is_int( reset( $this->options['cs']['custom_iframes'] ) ) ) {
152
+ $data = array();
153
+
154
+ foreach ( $this->options['cs']['custom_iframes'] as $iframe ) {
155
+ $data[$iframe] = 0;
156
+ }
157
+
158
+ $this->options['cs']['custom_iframes'] = $data;
159
+ }
160
+
161
+ // actions
162
+ add_action( 'after_setup_theme', array( $this, 'register_shortcode' ) );
163
+ add_action( 'wp_head', array( $this, 'wp_head_cs' ), 0 );
164
+ add_action( 'wp_head', array( $this, 'wp_head_cons' ), 1 );
165
+ add_action( 'template_redirect', array( $this, 'output_start' ), 0 );
166
+ add_action( 'shutdown', array( $this, 'output_end' ), 100 );
167
+ add_action( 'template_redirect', array( $this, 'disable_jetpack_tracking' ) );
168
+ add_action( 'admin_init', array( $this, 'maybe_do_upgrade' ) );
169
+ add_action( 'upgrader_process_complete', array( $this, 'upgrade' ), 10, 2 );
170
+ }
171
+
172
+ /**
173
+ * Setup plugin constants.
174
+ *
175
+ * @return void
176
+ */
177
+ private function define_constants() {
178
+ define( 'IUBENDA_PLUGIN_URL', plugins_url( '', __FILE__ ) );
179
+ define( 'IUBENDA_PLUGIN_REL_PATH', dirname( plugin_basename( __FILE__ ) ) . '/' );
180
+ define( 'IUBENDA_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
181
+ }
182
+
183
+ /**
184
+ * Include required files.
185
+ *
186
+ * @return void
187
+ */
188
+ private function includes() {
189
+ include_once( IUBENDA_PLUGIN_PATH . 'includes/settings.php' );
190
+ include_once( IUBENDA_PLUGIN_PATH . 'includes/forms.php' );
191
+ include_once( IUBENDA_PLUGIN_PATH . 'includes/amp.php' );
192
+ }
193
+
194
+ /**
195
+ * Initialize plugin.
196
+ *
197
+ * @return void
198
+ */
199
+ public function init() {
200
+ // check if WPML or Polylang is active
201
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
202
+
203
+ // Polylang support
204
+ if ( ( is_plugin_active( 'polylang/polylang.php' ) || is_plugin_active( 'polylang-pro/polylang.php' ) ) && function_exists( 'PLL' ) ) {
205
+ $this->multilang = true;
206
+
207
+ // get registered languages
208
+ $registered_languages = PLL()->model->get_languages_list();
209
+
210
+ if ( ! empty( $registered_languages ) ) {
211
+ foreach ( $registered_languages as $language )
212
+ $this->languages[$language->slug] = $language->name;
213
+ }
214
+
215
+ // get default language
216
+ $this->lang_default = pll_default_language();
217
+ // get current language
218
+ $this->lang_current = pll_current_language();
219
+
220
+ // WPML support
221
+ } elseif ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) && class_exists( 'SitePress' ) ) {
222
+ $this->multilang = true;
223
+
224
+ global $sitepress;
225
+
226
+ // get registered languages
227
+ $registered_languages = icl_get_languages();
228
+
229
+ if ( ! empty( $registered_languages ) ) {
230
+ foreach ( $registered_languages as $language )
231
+ $this->languages[$language['code']] = $language['display_name'];
232
+ }
233
+
234
+ // get default language
235
+ $this->lang_default = $sitepress->get_default_language();
236
+ // get current language
237
+ $this->lang_current = $sitepress->get_current_language();
238
+ }
239
+
240
+ // load iubenda parser
241
+ include_once( dirname( __FILE__ ) . '/iubenda-cookie-class/iubenda.class.php' );
242
+ }
243
+
244
+ /**
245
+ * Plugin activation.
246
+ *
247
+ * @return void
248
+ */
249
+ public function activation() {
250
+ set_transient( 'iub_activation_completed', 1, 3600 );
251
+
252
+ add_option( 'iubenda_cookie_law_solution', $this->options['cs'], '', 'no' );
253
+ add_option( 'iubenda_cookie_law_solution', $this->options['cons'], '', 'no' );
254
+ add_option( 'iubenda_cookie_law_version', $this->version, '', 'no' );
255
+ add_option( 'iubenda_activation_data', $this->activation, '', 'no' );
256
+ }
257
+
258
+ /**
259
+ * Plugin deactivation.
260
+ *
261
+ * @return void
262
+ */
263
+ public function deactivation() {
264
+ // remove options from database?
265
+ if ( $this->options['cs']['deactivation'] ) {
266
+ delete_option( 'iubenda_cookie_law_solution' );
267
+ delete_option( 'iubenda_consent_solution' );
268
+ delete_option( 'iubenda_cookie_law_version' );
269
+ delete_option( 'iubenda_activation_data' );
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Plugin upgrae.
275
+ *
276
+ * @return void
277
+ */
278
+ public function upgrade( $upgrader_object, $options ) {
279
+ // the path to our plugin's main file
280
+ $our_plugin = plugin_basename( __FILE__ );
281
+
282
+ // if an update has taken place and the updated type is plugins and the plugins element exists
283
+ if ( $options['action'] == 'update' && $options['type'] == 'plugin' && isset( $options['plugins'] ) ) {
284
+ // iterate through the plugins being updated and check if ours is there
285
+ foreach ( $options['plugins'] as $plugin ) {
286
+ if ( $plugin == $our_plugin ) {
287
+ // set a transient to record that our plugin has just been updated
288
+ set_transient( 'iub_upgrade_completed', 1, 3600 );
289
+ }
290
+ }
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Load textdomain.
296
+ *
297
+ * @return void
298
+ */
299
+ public function load_textdomain() {
300
+ load_plugin_textdomain( 'iubenda', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
301
+ }
302
+
303
+ /**
304
+ * Register shortcode function.
305
+ *
306
+ * @return void
307
+ */
308
+ public function register_shortcode() {
309
+ add_shortcode( 'iub-cookie-policy', array( $this, 'block_shortcode' ) );
310
+ add_shortcode( 'iub-cookie-block', array( $this, 'block_shortcode' ) );
311
+ add_shortcode( 'iub-cookie-skip', array( $this, 'skip_shortcode' ) );
312
+ }
313
+
314
+ /**
315
+ * Handle block shortcode function.
316
+ *
317
+ * @param array $atts
318
+ * @param mixed $content
319
+ * @return mixed
320
+ */
321
+ public function block_shortcode( $atts, $content = '' ) {
322
+ return '<!--IUB-COOKIE-BLOCK-START-->' . do_shortcode( $content ) . '<!--IUB-COOKIE-BLOCK-END-->';
323
+ }
324
+
325
+ /**
326
+ * Handle skip shortcode function.
327
+ *
328
+ * @param array $atts
329
+ * @param mixed $content
330
+ * @return mixed
331
+ */
332
+ public function skip_shortcode( $atts, $content = '' ) {
333
+ return '<!--IUB-COOKIE-BLOCK-SKIP-START-->' . do_shortcode( $content ) . '<!--IUB-COOKIE-BLOCK-SKIP-END-->';
334
+ }
335
+
336
+ /**
337
+ * Add wp_head cookie soution content.
338
+ *
339
+ * @return mixed
340
+ */
341
+ public function wp_head_cs() {
342
+
343
+ // check content type
344
+ if ( (bool) $this->options['cs']['ctype'] == true ) {
345
+ $iub_headers = headers_list();
346
+ $destroy = true;
347
+
348
+ foreach ( $iub_headers as $header ) {
349
+ if ( strpos( $header, "Content-Type: text/html" ) !== false || strpos( $header, "Content-type: text/html" ) !== false ) {
350
+ $destroy = false;
351
+ break;
352
+ }
353
+ }
354
+
355
+ if ( $destroy )
356
+ $this->no_html = true;
357
+ }
358
+
359
+ // is post or not html content type?
360
+ if ( ( $_POST && $this->options['cs']['output_post'] ) || $this->no_html )
361
+ return;
362
+
363
+ // initial head output
364
+ $iubenda_code = '';
365
+
366
+ if ( $this->multilang === true && defined( 'ICL_LANGUAGE_CODE' ) && isset( $this->options['cs']['code_' . ICL_LANGUAGE_CODE] ) ) {
367
+ $iubenda_code .= $this->options['cs']['code_' . ICL_LANGUAGE_CODE];
368
+
369
+ // no code for current language, use default
370
+ if ( ! $iubenda_code )
371
+ $iubenda_code .= $this->options['cs']['code_default'];
372
+ } else
373
+ $iubenda_code .= $this->options['cs']['code_default'];
374
+
375
+ $iubenda_code = $this->parse_code( $iubenda_code, true );
376
+
377
+ if ( $iubenda_code !== '' ) {
378
+ $iubenda_code .= "\n
379
+ <script>
380
+ var iCallback = function() {};
381
+ var _iub = _iub || {};
382
+
383
+ if ( typeof _iub.csConfiguration != 'undefined' ) {
384
+ if ( 'callback' in _iub.csConfiguration ) {
385
+ if ( 'onConsentGiven' in _iub.csConfiguration.callback )
386
+ iCallback = _iub.csConfiguration.callback.onConsentGiven;
387
+
388
+ _iub.csConfiguration.callback.onConsentGiven = function() {
389
+ iCallback();
390
+
391
+ /* separator */
392
+ jQuery('noscript._no_script_iub').each(function (a, b) { var el = jQuery(b); el.after(el.html()); });
393
+ }
394
+ }
395
+ }
396
+ </script>";
397
+
398
+ echo '<!--IUB-COOKIE-SKIP-START-->' . $iubenda_code . '<!--IUB-COOKIE-SKIP-END-->';
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Add wp_head consent solution content.
404
+ *
405
+ * @return mixed
406
+ */
407
+ public function wp_head_cons() {
408
+ if ( ! empty( $this->options['cons']['public_api_key'] ) ) {
409
+
410
+ $parameters = apply_filters( 'iubenda_cons_init_parameters', array(
411
+ 'log_level' => 'error',
412
+ 'logger' => 'console',
413
+ 'send_from_local' => true
414
+ ) );
415
+
416
+ echo '<!-- Library initialization -->
417
+ <script type="text/javascript">
418
+ var _iub = _iub || { };
419
+
420
+ _iub.cons_instructions = _iub.cons_instructions || [ ];
421
+ _iub.cons_instructions.push(
422
+ [ "init", {
423
+ api_key: "' . $this->options['cons']['public_api_key'] . '",
424
+ log_level: "' . $parameters['log_level'] . '",
425
+ logger: "' . ( ! empty( $parameters['logger'] ) && in_array( $parameters['logger'], array( 'console', 'none' ) ) ? $parameters['logger'] : 'console' ) . '",
426
+ sendFromLocalStorageAtLoad: ' . ( (bool) ( $parameters['send_from_local'] ) ? 'true' : 'false' ) . '
427
+ }, function ( ) {
428
+ // console.log( "init callBack" );
429
+ }
430
+ ]
431
+ );
432
+ </script>
433
+ <script type="text/javascript" src="//cdn.iubenda.com/cons/iubenda_cons.js" async></script>';
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Initialize html output.
439
+ *
440
+ * @return void
441
+ */
442
+ public function output_start() {
443
+ if ( ! is_admin() )
444
+ ob_start( array( $this, 'output_callback' ) );
445
+ }
446
+
447
+ /**
448
+ * Finish html output.
449
+ *
450
+ * @return void
451
+ */
452
+ public function output_end() {
453
+ if ( ! is_admin() && ob_get_level() )
454
+ ob_end_flush();
455
+ }
456
+
457
+ /**
458
+ * Handle final html output.
459
+ *
460
+ * @param mixed $output
461
+ * @return mixed
462
+ */
463
+ public function output_callback( $output ) {
464
+ // check whether to run parser or not
465
+ // bail on ajax, xmlrpc or iub_no_parse request
466
+ if (
467
+ ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) || isset( $_SERVER["HTTP_X_REQUESTED_WITH"] ) || isset( $_GET['iub_no_parse'] )
468
+ )
469
+ return $output;
470
+
471
+ // bail on admin side
472
+ if ( is_admin() )
473
+ return $output;
474
+
475
+ // bail on rss feed
476
+ if ( is_feed() && $this->options['cs']['output_feed'] )
477
+ return $output;
478
+
479
+ if ( strpos( $output, "<html" ) === false )
480
+ return $output;
481
+ elseif ( strpos( $output, "<html" ) > 200 )
482
+ return $output;
483
+
484
+ // bail if skripts blocking disabled
485
+ if ( ! $this->options['cs']['parse'] )
486
+ return $output;
487
+
488
+ // bail if consent given and skip parsing enabled
489
+ if ( iubendaParser::consent_given() && $this->options['cs']['skip_parsing'] )
490
+ return $output;
491
+
492
+ // bail on POST request
493
+ if ( $_POST && $this->options['cs']['output_post'] )
494
+ return $output;
495
+
496
+ // bail if bot detectd, no html in output or it's a post request
497
+ if ( iubendaParser::bot_detected() || $this->no_html )
498
+ return $output;
499
+
500
+ // google recaptcha v3 compatibility
501
+ if ( class_exists( 'WPCF7' ) && (int) WPCF7::get_option( 'iqfix_recaptcha' ) === 0 && ! iubendaParser::consent_given() )
502
+ $this->options['cs']['custom_scripts']['grecaptcha'] = 2;
503
+
504
+ // Jetpack compatibility
505
+ if ( class_exists( 'Jetpack' ) )
506
+ $this->options['cs']['custom_scripts']['stats.wp.com'] = 5;
507
+
508
+ $startime = microtime( true );
509
+ $output = apply_filters( 'iubenda_initial_output', $output );
510
+
511
+ // prepare scripts and iframes
512
+ $scripts = $this->prepare_custom_data( $this->options['cs']['custom_scripts'] );
513
+ $iframes = $this->prepare_custom_data( $this->options['cs']['custom_iframes'] );
514
+
515
+ // experimental class
516
+ if ( $this->options['cs']['parser_engine'] == 'new' ) {
517
+ $iubenda = new iubendaParser( mb_convert_encoding( $output, 'HTML-ENTITIES', 'UTF-8' ), array(
518
+ 'type' => 'faster',
519
+ 'amp' => $this->options['cs']['amp_support'],
520
+ 'scripts' => $scripts,
521
+ 'iframes' => $iframes
522
+ ) );
523
+
524
+ // render output
525
+ $output = $iubenda->parse();
526
+
527
+ // append signature
528
+ $output .= '<!-- Parsed with iubenda experimental class in ' . round( microtime( true ) - $startime, 4 ) . ' sec. -->';
529
+ // default class
530
+ } else {
531
+ $iubenda = new iubendaParser( $output, array(
532
+ 'type' => 'page',
533
+ 'amp' => $this->options['cs']['amp_support'],
534
+ 'scripts' => $scripts,
535
+ 'iframes' => $iframes
536
+ ) );
537
+
538
+ // render output
539
+ $output = $iubenda->parse();
540
+
541
+ // append signature
542
+ $output .= '<!-- Parsed with iubenda default class in ' . round( microtime( true ) - $startime, 4 ) . ' sec. -->';
543
+ }
544
+
545
+ return apply_filters( 'iubenda_final_output', $output );
546
+ }
547
+
548
+ /**
549
+ * Prepare scripts/iframes.
550
+ *
551
+ * @param array $data
552
+ * @return array
553
+ */
554
+ public function prepare_custom_data( $data ) {
555
+ $newdata = array();
556
+
557
+ foreach ( $data as $script => $type ) {
558
+ if ( ! array_key_exists( $type, $newdata ) )
559
+ $newdata[$type] = array();
560
+
561
+ $newdata[$type][] = $script;
562
+ }
563
+
564
+ return $newdata;
565
+ }
566
+
567
+ /**
568
+ * Parse iubenda code.
569
+ *
570
+ * @param string $source
571
+ * @param bool $display
572
+ * @return string
573
+ */
574
+ public function parse_code( $source, $display = false ) {
575
+ // return $source;
576
+ $source = trim( $source );
577
+
578
+ preg_match_all( '/(\"(?:html|content)\"(?:\s+)?\:(?:\s+)?)\"((?:.*?)(?:[^\\\\]))\"/s', $source, $matches );
579
+
580
+ // found subgroup?
581
+ if ( ! empty( $matches[1] ) && ! empty( $matches[2] ) ) {
582
+ foreach ( $matches[2] as $no => $match ) {
583
+ $source = str_replace( $matches[0][$no], $matches[1][$no] . '[[IUBENDA_TAG_START]]' . $match . '[[IUBENDA_TAG_END]]', $source );
584
+ }
585
+
586
+ // kses it
587
+ $source = wp_kses( $source, $this->get_allowed_html() );
588
+
589
+ preg_match_all( '/\[\[IUBENDA_TAG_START\]\](.*?)\[\[IUBENDA_TAG_END\]\]/s', $source, $matches_tags );
590
+
591
+ if ( ! empty( $matches_tags[1] ) ) {
592
+ foreach ( $matches_tags[1] as $no => $match ) {
593
+ $source = str_replace( $matches_tags[0][$no], '"' . ( $display ? str_replace( '</', '<\/', $matches[2][$no] ) : $matches[2][$no] ) . '"', $source );
594
+ }
595
+ }
596
+ }
597
+
598
+ return $source;
599
+ }
600
+
601
+ /**
602
+ * Disable Jetpack tracking on AMO cached pages.
603
+ *
604
+ * @return void
605
+ */
606
+ public function disable_jetpack_tracking() {
607
+ // bail no Jetpack active
608
+ if ( ! class_exists( 'Jetpack' ) )
609
+ return;
610
+
611
+ // disable if it's not AMP cached request
612
+ if ( ! class_exists( 'Jetpack_AMP_Support' ) || ! Jetpack_AMP_Support::is_amp_request() )
613
+ return;
614
+
615
+ // if ( is_feed() || is_robots() || is_trackback() || is_preview() || jetpack_is_dnt_enabled() )
616
+ // bail if skripts blocking disabled
617
+ if ( ! $this->options['cs']['parse'] )
618
+ return;
619
+
620
+ // bail if consent given and skip parsing enabled
621
+ if ( iubendaParser::consent_given() && $this->options['cs']['skip_parsing'] )
622
+ return;
623
+
624
+ remove_action( 'wp_head', 'stats_add_shutdown_action' );
625
+ remove_action( 'wp_footer', 'stats_footer', 101 );
626
+ }
627
+
628
+ /**
629
+ * Perform actions on plugin installation/upgrade.
630
+ *
631
+ * @return void
632
+ */
633
+ public function maybe_do_upgrade() {
634
+ if ( ! current_user_can( 'install_plugins' ) )
635
+ return;
636
+
637
+ // bail if no activation or upgrade transient is set
638
+ if ( ! get_transient( 'iub_upgrade_completed' ) && ! get_transient( 'iub_activation_completed' ) )
639
+ return;
640
+
641
+ // delete the activation transient
642
+ delete_transient( 'iub_activation_completed' );
643
+ // delete the upgrade transient
644
+ delete_transient( 'iub_upgrade_completed' );
645
+
646
+ // bail if activating from network, or bulk, or within an iFrame
647
+ if ( is_network_admin() || isset( $_GET['activate-multi'] ) || defined( 'IFRAME_REQUEST' ) )
648
+ return;
649
+
650
+ // generate AMP template file if AMP plugins available
651
+ if ( function_exists( 'is_amp_endpoint' ) || function_exists( 'ampforwp_is_amp_endpoint' ) ) {
652
+ iubenda()->AMP->generate_amp_template();
653
+ }
654
+ }
655
+
656
+ /**
657
+ * Get configuration data parsed from iubenda code
658
+ *
659
+ * @param type $iubenda_code
660
+ * @param type $args
661
+ * @return type
662
+ */
663
+ public function parse_configuration( $code, $args = array() ) {
664
+ $configuration = array();
665
+ $defaults = array(
666
+ 'mode' => 'basic',
667
+ 'parse' => false
668
+ );
669
+
670
+ // parse incoming $args into an array and merge it with $defaults
671
+ $args = wp_parse_args( $args, $defaults );
672
+
673
+ if ( empty( $code ) )
674
+ return $configuration;
675
+
676
+ // parse code if needed
677
+ $parsed_code = $args['parse'] === true ? $this->parse_code( $code, true ) : $code;
678
+
679
+ // get script
680
+ $parsed_script = '';
681
+
682
+ preg_match_all( '/src\=(?:[\"|\'])(.*?)(?:[\"|\'])/', $parsed_code, $matches );
683
+
684
+ // find the iubenda script url
685
+ if ( ! empty( $matches[1] ) ) {
686
+ foreach ( $matches[1] as $found_script ) {
687
+ if ( wp_http_validate_url( $found_script ) && strpos( $found_script, 'iubenda_cs.js' ) ) {
688
+ $parsed_script = $found_script;
689
+ continue;
690
+ }
691
+ }
692
+ }
693
+
694
+ // strip tags
695
+ $parsed_code = wp_kses( $parsed_code, array() );
696
+
697
+ // get configuration
698
+ preg_match( '/_iub.csConfiguration *= *{(.*?)\};/', $parsed_code, $matches );
699
+
700
+ if ( ! empty( $matches[1] ) )
701
+ $parsed_code = '{' . $matches[1] . '}';
702
+
703
+ // decode
704
+ $decoded = json_decode( $parsed_code, true );
705
+
706
+ if ( ! empty( $decoded ) && is_array( $decoded ) ) {
707
+
708
+ $decoded['script'] = $parsed_script;
709
+
710
+ // basic mode
711
+ if ( $args['mode'] === 'basic' ) {
712
+ if ( isset( $decoded['banner'] ) )
713
+ unset( $decoded['banner'] );
714
+ if ( isset( $decoded['callback'] ) )
715
+ unset( $decoded['callback'] );
716
+ if ( isset( $decoded['perPurposeConsent'] ) )
717
+ unset( $decoded['perPurposeConsent'] );
718
+ }
719
+
720
+ $configuration = $decoded;
721
+ }
722
+
723
+ return $configuration;
724
+ }
725
+
726
+ /**
727
+ * Domain info helper function.
728
+ *
729
+ * @param type $domainb
730
+ * @return type
731
+ */
732
+ public function domain( $domainb ) {
733
+ $bits = explode( '/', $domainb );
734
+ if ( $bits[0] == 'http:' || $bits[0] == 'https:' ) {
735
+ $domainb = $bits[2];
736
+ } else {
737
+ $domainb = $bits[0];
738
+ }
739
+ unset( $bits );
740
+ $bits = explode( '.', $domainb );
741
+ $idz = 0;
742
+ while ( isset( $bits[$idz] ) ) {
743
+ $idz += 1;
744
+ }
745
+ $idz -= 3;
746
+ $idy = 0;
747
+ while ( $idy < $idz ) {
748
+ unset( $bits[$idy] );
749
+ $idy += 1;
750
+ }
751
+ $part = array();
752
+ foreach ( $bits AS $bit ) {
753
+ $part[] = $bit;
754
+ }
755
+ unset( $bit );
756
+ unset( $bits );
757
+ unset( $domainb );
758
+ $domainb = '';
759
+
760
+ if ( strlen( $part[1] ) > 3 ) {
761
+ unset( $part[0] );
762
+ }
763
+ foreach ( $part AS $bit ) {
764
+ $domainb .= $bit . '.';
765
+ }
766
+ unset( $bit );
767
+
768
+ return preg_replace( '/(.*)\./', '$1', $domainb );
769
+ }
770
+
771
+ /**
772
+ * Check if file exists helper function.
773
+ *
774
+ * @param type $file
775
+ */
776
+ public function file_exists( $file ) {
777
+ $file_headers = @get_headers( $file );
778
+
779
+ if ( ! $file_headers || $file_headers[0] == 'HTTP/1.1 404 Not Found' ) {
780
+ $exists = false;
781
+ } else {
782
+ $exists = true;
783
+ }
784
+ }
785
+
786
+ /**
787
+ * Get allowed iubenda script HTML.
788
+ *
789
+ * @return array
790
+ */
791
+ public function get_allowed_html() {
792
+ // Jetpack fix
793
+ remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'filter' ), 11 );
794
+
795
+ $html = array_merge(
796
+ wp_kses_allowed_html( 'post' ), array(
797
+ 'script' => array(
798
+ 'type' => array(),
799
+ 'src' => array(),
800
+ 'charset' => array(),
801
+ 'async' => array()
802
+ ),
803
+ 'noscript' => array(),
804
+ 'style' => array(
805
+ 'type' => array()
806
+ ),
807
+ 'iframe' => array(
808
+ 'src' => array(),
809
+ 'height' => array(),
810
+ 'width' => array(),
811
+ 'frameborder' => array(),
812
+ 'allowfullscreen' => array()
813
+ )
814
+ )
815
+ );
816
+
817
+ return apply_filters( 'iub_code_allowed_html', $html );
818
+ }
819
+
820
+ }
821
+
822
+ /**
823
+ * Initialise iubenda Cookie Solution
824
+ *
825
+ * @return object
826
+ */
827
+ function iubenda() {
828
+ static $instance;
829
+
830
+ // first call to instance() initializes the plugin
831
+ if ( $instance === null || ! ( $instance instanceof iubenda ) )
832
+ $instance = iubenda::instance();
833
+
834
+ return $instance;
835
+ }
836
+
837
+ $iubenda = iubenda();
trunk/js/admin.js ADDED
@@ -0,0 +1,282 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ( function ( $ ) {
2
+
3
+ $( document ).ready( function () {
4
+ // parse args
5
+ var args = $.parseJSON( iubAdminArgs );
6
+
7
+ // parser options
8
+ $( '#iub_parse' ).change( function () {
9
+ if ( $( this ).is( ':checked' ) ) {
10
+ $( '#iub_parser_engine_container' ).slideDown( 'fast' );
11
+ } else {
12
+ $( '#iub_parser_engine_container' ).slideUp( 'fast' );
13
+ }
14
+ } );
15
+
16
+ // amp options
17
+ $( '#iub_amp_support' ).change( function () {
18
+ if ( $( this ).is( ':checked' ) ) {
19
+ $( '#iub_amp_options_container' ).slideDown( 'fast' );
20
+ } else {
21
+ $( '#iub_amp_options_container' ).slideUp( 'fast' );
22
+ }
23
+ } );
24
+
25
+ // amp options
26
+ $( 'input.iub_amp_source' ).change( function () {
27
+ var value = $( 'input.iub_amp_source:checked' ).val();
28
+
29
+ if ( value === 'remote' ) {
30
+ $( '#iub_amp_template-local' ).fadeOut( 'fast', function () {
31
+ $( '#iub_amp_template-remote' ).fadeIn( 'fast' );
32
+ } );
33
+ } else {
34
+ $( '#iub_amp_template-remote' ).fadeOut( 'fast', function () {
35
+ $( '#iub_amp_template-local' ).fadeIn( 'fast' );
36
+ } );
37
+ }
38
+ } );
39
+
40
+ // move notices
41
+ var errors = $( '.settings-error' ).detach();
42
+
43
+ $( '.iubenda-link' ).after( errors );
44
+
45
+ // Help tabs
46
+ $( '.contextual-help-tabs a' ).off( 'click' ).click( function ( e ) {
47
+ var link = $( this ),
48
+ panel,
49
+ panelParent;
50
+
51
+ e.preventDefault();
52
+
53
+ // don't do anything if the click is for the tab already showing.
54
+ if ( link.is( '.active a' ) )
55
+ return false;
56
+
57
+ panelParent = link.closest( '.contextual-help-wrap' );
58
+
59
+ // links
60
+ $( panelParent ).find( '.contextual-help-tabs .active' ).removeClass( 'active' );
61
+ link.parent( 'li' ).addClass( 'active' );
62
+
63
+ panel = $( link.attr( 'href' ) );
64
+
65
+ // panels
66
+ $( panelParent ).find( '.help-tab-content' ).not( panel ).removeClass( 'active' ).hide();
67
+ panel.addClass( 'active' ).show();
68
+ } );
69
+
70
+ // Preferences fields
71
+ var preferencesID = $( '.preferences-field' ).length;
72
+
73
+ // Add new preferences field
74
+ $( document ).on( 'click', '.add-preferences-field', function ( e ) {
75
+ e.preventDefault();
76
+
77
+ $( '#postbox-container-2' ).change();
78
+
79
+ var html = $( '#preferences-field-template' ).html();
80
+ html = html.replace( /__PREFERENCE_ID__/g, preferencesID++ );
81
+
82
+ $( '.preferences-table .add-preferences-field' ).closest( 'tr' ).before( '<tr class="preferences-field options-field" style="display: none;">' + html + '</tr>' );
83
+
84
+ var last = $( '.preferences-field' ).last();
85
+
86
+ last.fadeIn( 300 );
87
+ } );
88
+
89
+ // Remove preferences field
90
+ $( document ).on( 'click', '.remove-preferences-field', function ( e ) {
91
+ e.preventDefault();
92
+
93
+ $( '#postbox-container-2' ).change();
94
+
95
+ $( this ).closest( '.preferences-field' ).fadeOut( 300, function () {
96
+ $( this ).remove();
97
+ } );
98
+ } );
99
+
100
+ // Exclude fields
101
+ var excludeID = $( '.exclude-field' ).length;
102
+
103
+ // Add new preferences field
104
+ $( document ).on( 'click', '.add-exclude-field', function ( e ) {
105
+ e.preventDefault();
106
+
107
+ console.log( this );
108
+
109
+ $( '#postbox-container-2' ).change();
110
+
111
+ var html = $( '#exclude-field-template' ).html();
112
+ html = html.replace( /__EXCLUDE_ID__/g, excludeID++ );
113
+
114
+ $( '.exclude-table .add-exclude-field' ).closest( 'tr' ).before( '<tr class="exclude-field options-field" style="display: none;">' + html + '</tr>' );
115
+
116
+ var last = $( '.exclude-field' ).last();
117
+
118
+ last.fadeIn( 300 );
119
+ } );
120
+
121
+ // Remove exclude field
122
+ $( document ).on( 'click', '.remove-exclude-field', function ( e ) {
123
+ e.preventDefault();
124
+
125
+ $( '#postbox-container-2' ).change();
126
+
127
+ $( this ).closest( '.exclude-field' ).fadeOut( 300, function () {
128
+ $( this ).remove();
129
+ } );
130
+ } );
131
+
132
+ // Legal notices fields
133
+ var legalNoticesID = $( '.legal_notices-field' ).length;
134
+
135
+ // Add new preferences field
136
+ $( document ).on( 'click', '.add-legal_notices-field', function ( e ) {
137
+ e.preventDefault();
138
+
139
+ $( '#postbox-container-2' ).change();
140
+
141
+ var html = $( '#legal_notices-field-template' ).html();
142
+ html = html.replace( /__LEGAL_NOTICE_ID__/g, legalNoticesID++ );
143
+
144
+ console.log( html );
145
+
146
+ $( '.legal_notices-table .add-legal_notices-field' ).closest( 'tr' ).before( '<tr class="legal_notices-field options-field" style="display: none;">' + html + '</tr>' );
147
+
148
+ var last = $( '.legal_notices-field' ).last();
149
+
150
+ last.fadeIn( 300 );
151
+ } );
152
+
153
+ // Remove legal notices field
154
+ $( document ).on( 'click', '.remove-legal_notices-field', function ( e ) {
155
+ e.preventDefault();
156
+
157
+ $( '#postbox-container-2' ).change();
158
+
159
+ $( this ).closest( '.legal_notices-field' ).fadeOut( 300, function () {
160
+ $( this ).remove();
161
+ } );
162
+ } );
163
+
164
+ // add new script field
165
+ $( document ).on( 'click', '.add-custom-script-field', function( e ) {
166
+ e.preventDefault();
167
+
168
+ $( this ).before( '<div class="custom-script-field" style="display: none;">' + $( '#custom-script-field-template' ).html() + '</div>' );
169
+ $( '#tab-panel-scripts' ).find( '.custom-script-field' ).last().fadeIn( 300 );
170
+ } );
171
+
172
+ // remove custom script field
173
+ $( document ).on( 'click', '.remove-custom-script-field', function( e ) {
174
+ e.preventDefault();
175
+
176
+ $( this ).closest( '.custom-script-field' ).fadeOut( 300, function() {
177
+ $( this ).remove();
178
+ } );
179
+ } );
180
+
181
+ // add new iframe field
182
+ $( document ).on( 'click', '.add-custom-iframe-field', function( e ) {
183
+ e.preventDefault();
184
+
185
+ $( this ).before( '<div class="custom-iframe-field" style="display: none;">' + $( '#custom-iframe-field-template' ).html() + '</div>' );
186
+ $( '#tab-panel-iframes' ).find( '.custom-iframe-field' ).last().fadeIn( 300 );
187
+ } );
188
+
189
+ // remove custom iframe field
190
+ $( document ).on( 'click', '.remove-custom-iframe-field', function( e ) {
191
+ e.preventDefault();
192
+
193
+ $( this ).closest( '.custom-iframe-field' ).fadeOut( 300, function() {
194
+ $( this ).remove();
195
+ } );
196
+ } );
197
+
198
+ // Remove template fields on save
199
+ $( document ).on( 'click', '#publish', function () {
200
+ $( '#preferences-field-template' ).remove();
201
+ $( '#exclude-field-template' ).remove();
202
+ $( '#legal_notices-field-template' ).remove();
203
+ } );
204
+
205
+ // Confirm form delete
206
+ $( document ).on( 'click', '#iubenda-consent-forms .delete-form', function () {
207
+ return confirm( args.deleteForm );
208
+ } );
209
+
210
+ // Handle form fields data
211
+ $( document ).on( 'change', '#postbox-container-2', function() {
212
+ var fields = {},
213
+ fieldsTypes = [ 'subject', 'preferences', 'exclude' ];
214
+
215
+ if ( args.formId > 0 ) {
216
+ // get all fields
217
+ fields.all = $( '.subject-fields-select.select-id option:not([value=""])' ).map( function() { return $( this ).val(); } ).get();
218
+
219
+ // get specific fields
220
+ $.each( fieldsTypes, function( index, fieldType ) {
221
+ fields[fieldType] = [];
222
+
223
+ var fieldItems = $( '.' + fieldType + '-field select' );
224
+
225
+ // get selected values
226
+ $.each( fieldItems, function( index, item ) {
227
+ if ( $( item ).val() != '' )
228
+ fields[fieldType].push( $( item ).val() );
229
+ } );
230
+
231
+ fields.fieldType = $.unique( fields[fieldType] );
232
+
233
+ // remove available fields if needed
234
+ if ( fields[fieldType].length > 0 ) {
235
+
236
+ // get options count
237
+ var templateItemsCount = $( '.template-field .' + fieldType + '-fields-select option:disabled' ).length;
238
+
239
+ // update if options count changed
240
+ if ( templateItemsCount !== 0 && fields[fieldType].length != templateItemsCount ) {
241
+ // console.log( fields[fieldType] );
242
+ }
243
+
244
+ // disable add button if needed
245
+ if ( fields.all.length == fields[fieldType].length ) {
246
+ $( '.add-' + fieldType + '-field' ).attr( 'disabled', 'disabled' );
247
+ } else {
248
+ $( '.add-' + fieldType + '-field' ).attr( 'disabled', false );
249
+ }
250
+
251
+ // adjust disabled options
252
+ $.each( fields.all, function( index, fieldName ) {
253
+ if ( $.inArray( fieldName, fields[fieldType] ) < 0 ) {
254
+ // options field
255
+ $( '.' + fieldType + '-fields-select option:not(:checked)[value="' + fieldName + '"]' ).attr( 'disabled', false );
256
+ // template field
257
+ $( '.template-field .' + fieldType + '-fields-select option[value="' + fieldName + '"]' ).attr( 'disabled', false );
258
+ } else {
259
+ $( '.' + fieldType + '-fields-select option:not(:checked)[value="' + fieldName + '"]' ).attr( 'disabled', 'disabled' );
260
+ $( '.template-field .' + fieldType + '-fields-select option[value="' + fieldName + '"]' ).attr( 'disabled', 'disabled' );
261
+ }
262
+ } );
263
+ }
264
+ } );
265
+
266
+ // console.log( fields );
267
+ }
268
+
269
+ } );
270
+
271
+ // Force trigger change on document ready
272
+ $( document ).on( 'ready', function() {
273
+ $( '#postbox-container-2' ).change();
274
+ } );
275
+
276
+ $( document ).on( 'mouseenter mouseleave', '#postbox-container-2 .options-field, #postbox-container-2 .submit-field', function() {
277
+ $( '#postbox-container-2' ).change();
278
+ } );
279
+
280
+ } );
281
+
282
+ } )( jQuery );
trunk/js/frontend.js ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ( function ( $ ) {
2
+
3
+ $( document ).ready( function () {
4
+
5
+ var iubendaConsentSolution = new function () {
6
+ var _this = this;
7
+
8
+ // parse args
9
+ var args = $.parseJSON( iubForms );
10
+
11
+ // console.log( args );
12
+
13
+ // get forms
14
+ this.init = function () {
15
+ // loop though plugins
16
+ if ( $( args ).length > 0 ) {
17
+ $.each( args, function( source, forms ) {
18
+ // loop through forms
19
+ if ( $( forms ).length > 0 ) {
20
+ $.each( forms, function( id, form ) {
21
+ // console.log( form );
22
+
23
+ // get corresponding html form id
24
+ switch ( source ) {
25
+
26
+ // WooCommerce Checkout Form
27
+ case 'woocommerce' :
28
+ var htmlFormContainer = $( '.woocommerce-checkout' );
29
+
30
+ // form exists, let's use it
31
+ if ( htmlFormContainer.length > 0 ) {
32
+ // setup vars
33
+ formArgs = {
34
+ submitElement: null,
35
+ form: {
36
+ selector: document.querySelectorAll( 'form.woocommerce-checkout' )[0],
37
+ map: form.form.map
38
+ }
39
+ };
40
+
41
+ // handle ajax submit
42
+ $( htmlFormContainer ).on( 'checkout_place_order', function( e ) {
43
+ _this.submitForm( form, formArgs );
44
+
45
+ _iub.cons.sendData();
46
+ // don't send before page refresh
47
+ // on succcessfull submit it will be sent automatically
48
+ // _iub.cons.sendFromLocalStorage();
49
+ } );
50
+ }
51
+
52
+ break;
53
+
54
+ // WordPress Comment Form
55
+ case 'wp_comment_form' :
56
+ var htmlFormContainer = $( '#commentform' );
57
+
58
+ // form exists, let's use it
59
+ if ( htmlFormContainer.length > 0 ) {
60
+ // adjust submit element id
61
+ var submitElement = document.getElementById( htmlFormContainer.attr( 'id' ) ).querySelectorAll( 'input[type=submit]' )[0];
62
+
63
+ /* id="submit" override
64
+ if ( typeof submitElement !== 'undefined' && submitElement.name == 'submit' ) {
65
+ submitElement.id = 'wp-comment-submit';
66
+ submitElement.name = 'wp-comment-submit';
67
+ }
68
+ */
69
+
70
+ // setup vars
71
+ formArgs = {
72
+ // submitElement: submitElement,
73
+ submitElement: null,
74
+ form: {
75
+ selector: document.getElementById( htmlFormContainer.attr( 'id' ) ),
76
+ map: form.form.map
77
+ }
78
+ };
79
+
80
+ $( submitElement ).on( 'click touchstart', function( e ) {
81
+ _this.submitForm( form, formArgs );
82
+
83
+ _iub.cons.sendData();
84
+ // don't send before page refresh
85
+ // on succcessfull submit it will be sent automatically
86
+ // _iub.cons.sendFromLocalStorage();
87
+ } );
88
+ }
89
+
90
+ break;
91
+
92
+ // Contact Form 7
93
+ case 'wpcf7' :
94
+ // var regex = new RegExp( '^wpcf7-f([0-9]*)-' );
95
+ var htmlFormContainer = $( 'div[id^="wpcf7-f' + id + '-"]' );
96
+
97
+ // form exists, let's use it
98
+ if ( htmlFormContainer.length > 0 ) {
99
+ var selector = document.getElementById( htmlFormContainer.attr( 'id' ) ).getElementsByClassName( 'wpcf7-form' )[0];
100
+
101
+ // handle ajax submit
102
+ $( document ).on( 'wpcf7mailsent', selector, function( e ) {
103
+ // setup vars
104
+ formArgs = {
105
+ // submitElement: document.getElementById( htmlFormContainer.attr( 'id' ) ).getElementsByClassName( 'wpcf7-submit' )[0],
106
+ submitElement: null,
107
+ form: {
108
+ selector: selector,
109
+ map: form.form.map
110
+ }
111
+ };
112
+
113
+ // send only if specific form has been submitted
114
+ if ( selector.parentElement.id == e.target.id ) {
115
+ _this.submitForm( form, formArgs );
116
+
117
+ _iub.cons.sendData();
118
+ _iub.cons.sendFromLocalStorage();
119
+ }
120
+ } );
121
+
122
+ };
123
+
124
+ break;
125
+
126
+ // WP Forms
127
+ case 'wpforms' :
128
+ var htmlFormContainer = $( 'div[id^="wpforms-' + id + '"]' );
129
+
130
+ // form exists, let's use it
131
+ if ( htmlFormContainer.length > 0 ) {
132
+ var selector = document.getElementById( 'wpforms-form-' + id );
133
+ var isAjax = $( '#wpforms-form-' + id ).hasClass( 'wpforms-ajax-form' );
134
+
135
+ // handle ajax submit
136
+ $( document ).on( 'wpformsAjaxSubmitSuccess', selector, function( e ) {
137
+ // setup vars
138
+ formArgs = {
139
+ submitElement: ( isAjax ? null : document.getElementById( 'wpforms-submit-' + id ) ),
140
+ form: {
141
+ selector: selector,
142
+ map: form.form.map
143
+ }
144
+ };
145
+
146
+ // send only if specific form has been submitted
147
+ if ( selector.id == e.target.id ) {
148
+ _this.submitForm( form, formArgs );
149
+
150
+ _iub.cons.sendData();
151
+ _iub.cons.sendFromLocalStorage();
152
+ }
153
+ } );
154
+ };
155
+
156
+ break;
157
+ }
158
+
159
+ // console.log( source );
160
+
161
+ } );
162
+ }
163
+ } );
164
+ }
165
+ };
166
+
167
+ // submit form
168
+ this.submitForm = function ( form, formArgs ) {
169
+ // push consent vars
170
+ if ( typeof form.consent !== 'undefined' && form.consent.legal_notices.length > 0 ) {
171
+ formArgs.consent = {};
172
+ formArgs.consent.legal_notices = form.consent.legal_notices;
173
+ }
174
+
175
+ console.log( formArgs );
176
+
177
+ // build form consent data
178
+ _iub.cons_instructions.push( [ 'load', formArgs ] );
179
+ };
180
+
181
+ };
182
+
183
+ // initialize
184
+ iubendaConsentSolution.init();
185
+
186
+ } );
187
+
188
+ } )( jQuery );
trunk/languages/iubenda-cookie-law-solution-it_IT.mo ADDED
Binary file
trunk/languages/iubenda-cookie-law-solution-it_IT.po ADDED
@@ -0,0 +1,859 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: Iubenda Cookie Solution\n"
4
+ "POT-Creation-Date: 2020-02-06 13:33+0100\n"
5
+ "PO-Revision-Date: 2020-02-06 13:34+0100\n"
6
+ "Last-Translator: \n"
7
+ "Language-Team: \n"
8
+ "Language: it\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 2.3\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
15
+ "X-Poedit-SourceCharset: UTF-8\n"
16
+ "X-Poedit-KeywordsList: __\n"
17
+ "X-Poedit-SearchPath-0: .\n"
18
+
19
+ #: includes/amp.php:126
20
+ msgid "Loading"
21
+ msgstr ""
22
+
23
+ #: includes/amp.php:258
24
+ msgid "AMP Cookie Consent"
25
+ msgstr ""
26
+
27
+ #: includes/forms-list-table.php:92
28
+ msgid "Form Title"
29
+ msgstr "Nome del form"
30
+
31
+ #: includes/forms-list-table.php:93
32
+ msgid "Form ID"
33
+ msgstr "ID del form"
34
+
35
+ #: includes/forms-list-table.php:94
36
+ #, fuzzy
37
+ #| msgid "Source"
38
+ msgid "Form Source"
39
+ msgstr "Fonte"
40
+
41
+ #: includes/forms-list-table.php:95
42
+ msgid "Fields"
43
+ msgstr "Campi"
44
+
45
+ #: includes/forms-list-table.php:96
46
+ msgid "Date"
47
+ msgstr "Data"
48
+
49
+ #: includes/forms-list-table.php:165
50
+ msgid "Edit"
51
+ msgstr "Modifica"
52
+
53
+ #: includes/forms-list-table.php:166
54
+ msgid "Delete"
55
+ msgstr "Elimina"
56
+
57
+ #: includes/forms-list-table.php:277
58
+ msgid "Filter"
59
+ msgstr "Filtra"
60
+
61
+ #: includes/forms-list-table.php:294
62
+ msgid "Filter by source"
63
+ msgstr "Filtra per fonte"
64
+
65
+ #: includes/forms-list-table.php:296
66
+ msgid "All form sources"
67
+ msgstr "Tutte le fonti"
68
+
69
+ #: includes/forms-list-table.php:364
70
+ msgid "No forms found."
71
+ msgstr "Nessun form trovato."
72
+
73
+ #: includes/forms.php:149 includes/settings.php:138
74
+ msgid "Forms"
75
+ msgstr "Form"
76
+
77
+ #: includes/forms.php:150
78
+ msgid "Form"
79
+ msgstr "Form"
80
+
81
+ #: includes/forms.php:566 includes/forms.php:580
82
+ msgid "First name"
83
+ msgstr "Nome"
84
+
85
+ #: includes/forms.php:572 includes/forms.php:592
86
+ msgid "Last name"
87
+ msgstr "Cognome"
88
+
89
+ #: includes/forms.php:586
90
+ msgid "Middle name"
91
+ msgstr "Secondo nome"
92
+
93
+ #: includes/settings.php:43 includes/settings.php:44 includes/settings.php:45
94
+ #: includes/settings.php:46 includes/settings.php:47
95
+ msgid "string"
96
+ msgstr "stringa"
97
+
98
+ #: includes/settings.php:59 includes/settings.php:183
99
+ msgid "Cookie Solution"
100
+ msgstr "Cookie Solution"
101
+
102
+ #: includes/settings.php:65 includes/settings.php:184
103
+ msgid "Consent Solution"
104
+ msgstr "Consent Solution"
105
+
106
+ #: includes/settings.php:73
107
+ msgid "Not set"
108
+ msgstr ""
109
+
110
+ #: includes/settings.php:74
111
+ msgid "Strictly necessary"
112
+ msgstr ""
113
+
114
+ #: includes/settings.php:75
115
+ msgid "Basic interactions & functionalities"
116
+ msgstr ""
117
+
118
+ #: includes/settings.php:76
119
+ #, fuzzy
120
+ #| msgid "Experimental (enhances performance)"
121
+ msgid "Experience enhancement"
122
+ msgstr "Sperimentale (performance migliorata)"
123
+
124
+ #: includes/settings.php:77
125
+ msgid "Analytics"
126
+ msgstr ""
127
+
128
+ #: includes/settings.php:78
129
+ msgid "Targeting & Advertising"
130
+ msgstr ""
131
+
132
+ #: includes/settings.php:125
133
+ msgid "Code"
134
+ msgstr "Codice"
135
+
136
+ #: includes/settings.php:126
137
+ msgid "Google AMP"
138
+ msgstr ""
139
+
140
+ #: includes/settings.php:127
141
+ #, fuzzy
142
+ #| msgid "Scripts blocking"
143
+ msgid "Script blocking"
144
+ msgstr "Blocco preventivo dei codici"
145
+
146
+ #: includes/settings.php:128
147
+ msgid "Custom scripts"
148
+ msgstr "Script personalizzati"
149
+
150
+ #: includes/settings.php:129
151
+ msgid "Content type"
152
+ msgstr "Tipo di contenuto"
153
+
154
+ #: includes/settings.php:130
155
+ msgid "RSS feed"
156
+ msgstr "Feed RSS"
157
+
158
+ #: includes/settings.php:131
159
+ msgid "POST requests"
160
+ msgstr "Richieste POST"
161
+
162
+ #: includes/settings.php:132
163
+ msgid "Menu position"
164
+ msgstr "Posizione menu"
165
+
166
+ #: includes/settings.php:133
167
+ msgid "Deactivation"
168
+ msgstr "Disattivazione"
169
+
170
+ #: includes/settings.php:139
171
+ #, fuzzy
172
+ #| msgid "Public API Key"
173
+ msgid "Public Api Key"
174
+ msgstr "Chiave API pubblica"
175
+
176
+ #: includes/settings.php:142 includes/settings.php:146
177
+ msgid "Field Mapping"
178
+ msgstr "Mapping dei campi"
179
+
180
+ #: includes/settings.php:206
181
+ msgid "Are you sure you want to delete this form?"
182
+ msgstr "Sei sicuro di voler eliminare questo form?"
183
+
184
+ #: includes/settings.php:541
185
+ msgid "You don't have permission to access this page."
186
+ msgstr "Non disponi dell'autorizzazione per accedere a questa pagina."
187
+
188
+ #: includes/settings.php:567
189
+ #, fuzzy
190
+ #| msgid ""
191
+ #| "This plugin is the easiest and most comprehensive way to adapt your "
192
+ #| "WordPress site to the European cookie law. Upon your user's first visit, "
193
+ #| "the plugin will take care of collecting their consent, of blocking the "
194
+ #| "most popular among the scripts that install cookies and subsequently "
195
+ #| "reactivate these scripts as soon as consent is provided. The basic "
196
+ #| "settings include obtaining consent by a simple scroll action (the most "
197
+ #| "effective method) and script reactivation without refreshing the page."
198
+ msgid ""
199
+ "This plugin is the easiest and most comprehensive way to adapt your "
200
+ "WordPress site to the ePrivacy (EU Cookie Law). Upon your users’ first "
201
+ "visit, the plugin will take care of collecting their consent, blocking the "
202
+ "most popular cookie-scripts and subsequently reactivating these scripts as "
203
+ "soon as consent is provided. The basic settings include obtaining consent by "
204
+ "a simple scroll action (the most effective method) and script reactivation "
205
+ "without refreshing the page (asynchronous script reactivation)."
206
+ msgstr ""
207
+ "Questo plugin è il modo più semplice e completo per adeguare il tuo sito "
208
+ "WordPress alla Direttiva ePrivacy (Cookie Law). Alla prima visita "
209
+ "dell'utente il plugin si occuperà di raccoglierne il consenso, bloccare gli "
210
+ "script più popolari che installano cookie e riattivarli non appena il "
211
+ "consenso viene fornito. Le impostazioni di base includono la raccolta del "
212
+ "consenso tramite il semplice scroll (il metodo più efficace) e la "
213
+ "riattivazione senza il refresh della pagina."
214
+
215
+ #: includes/settings.php:570
216
+ msgid ""
217
+ "Does the Cookie Solution support IAB’s Transparency and Consent Framework?"
218
+ msgstr ""
219
+ "La Cookie Solution supporta il Transparency e Consent Framework di IAB?"
220
+
221
+ #: includes/settings.php:571
222
+ #, fuzzy, php-format
223
+ #| msgid ""
224
+ #| "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">plugin "
225
+ #| "page.</a>"
226
+ msgid ""
227
+ "Yes it does. You can read more about it <a href=\"%s\" class=\"iubenda-url\" "
228
+ "target=\"_blank\">here.</a>"
229
+ msgstr ""
230
+ "Sì. Visita <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">questa "
231
+ "pagina</a> per maggiori dettagli."
232
+
233
+ #: includes/settings.php:574
234
+ #, fuzzy
235
+ #| msgid "Would you like to know more about the Cookie Law?"
236
+ msgid "Would you like to know more about the cookie law?"
237
+ msgstr "Vuoi saperne di più sulla Cookie Law?"
238
+
239
+ #: includes/settings.php:575
240
+ #, fuzzy, php-format
241
+ #| msgid ""
242
+ #| "Read our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">complete "
243
+ #| "guide to the Cookie Law</a>."
244
+ msgid ""
245
+ "Read our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">complete "
246
+ "guide to the cookie law.</a>"
247
+ msgstr ""
248
+ "Leggi la nostra <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">guida "
249
+ "completa alla Cookie Law</a>."
250
+
251
+ #: includes/settings.php:578
252
+ msgid "What is the full functionality of the plugin?"
253
+ msgstr "Quali sono le funzionalità del plugin?"
254
+
255
+ #: includes/settings.php:579
256
+ #, fuzzy, php-format
257
+ #| msgid ""
258
+ #| "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">plugin "
259
+ #| "page</a>."
260
+ msgid ""
261
+ "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">plugin page."
262
+ "</a>"
263
+ msgstr ""
264
+ "Visita la <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">pagina "
265
+ "dedicata</a> al plugin."
266
+
267
+ #: includes/settings.php:582
268
+ msgid "Enter the iubenda code for the Cookie Solution below."
269
+ msgstr "Inserisci qui sotto il codice di iubenda per la Cookie Solution."
270
+
271
+ #: includes/settings.php:583
272
+ #, php-format
273
+ msgid ""
274
+ "In order to run the plugin, you need to enter the iubenda code that "
275
+ "activates the cookie law banner and the cookie policy in the form below. "
276
+ "This code can be generated on www.iubenda.com, following <a href=\"%s\" "
277
+ "class=\"iubenda-url\" target=\"_blank\">this guide.</a>"
278
+ msgstr ""
279
+ "Per far funzionare il plugin, è necessario inserire nel form sottostante il "
280
+ "codice di iubenda che attiva il cookie banner e la cookie policy. Questo "
281
+ "codice può essere generato su www.iubenda.com seguendo le istruzioni "
282
+ "contenute in <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">questa "
283
+ "guida</a>"
284
+
285
+ #: includes/settings.php:588
286
+ #, fuzzy
287
+ #| msgid ""
288
+ #| "Maintaining comprehensive records of consent is a vital part of privacy "
289
+ #| "compliance in general but is specifically required under the GDPR. These "
290
+ #| "records should include a way of identifying the user, store proof of "
291
+ #| "consent, record of the consenting action, and the legal documents "
292
+ #| "available to the user at the time of consent, among other things. You can "
293
+ #| "read about the <a href=\"https://www.iubenda.com/en/help/5428#records-of-"
294
+ #| "consent\" target=\"_blank\">full requirements here</a>."
295
+ msgid ""
296
+ "Maintaining comprehensive records of consent is a vital part of privacy "
297
+ "compliance in general but is specifically required under the GDPR. These "
298
+ "records should include a way of identifying the user, store proof of "
299
+ "consent, record of the consenting action, and the legal documents available "
300
+ "to the user at the time of consent, among other things. You can read about "
301
+ "the <a href=\"https://www.iubenda.com/en/help/5428-gdpr-guide#records-of-"
302
+ "consent\" target=\"_blank\">full requirements here</a>."
303
+ msgstr ""
304
+ "Oltre ad essere un elemento vitale per il rispetto della privacy in "
305
+ "generale, il mantenimento di un registro dei consensi è specificamente "
306
+ "richiesto dal GDPR. Tra le altre cose, tale registro dovrebbe includere un "
307
+ "modo per identificare l'utente, la prova del consenso, la registrazione "
308
+ "dell'azione di consenso e i documenti legali messi a disposizione "
309
+ "dell'utente al momento del consenso. <a href=\"https://www.iubenda.com/it/"
310
+ "help/5424#registro-consensi\" target=\"_blank\">Trovi tutti i requisiti qui</"
311
+ "a>."
312
+
313
+ #: includes/settings.php:613
314
+ #, php-format
315
+ msgid ""
316
+ "If you are using per-purpose script blocking or Reject option please disable "
317
+ "the \"Leave scripts untouched on the page if the user has already given "
318
+ "consent\" option. <a href=\"%s\" target=\"_self\">Disable now</a>"
319
+ msgstr ""
320
+
321
+ #: includes/settings.php:638
322
+ msgid ""
323
+ "AMP configuration file requires HTTPS. Make sure your SSL Certificate is "
324
+ "configured correctly."
325
+ msgstr ""
326
+
327
+ #: includes/settings.php:660
328
+ #, php-format
329
+ msgid ""
330
+ "This plugin drastically reduces the need for direct interventions in the "
331
+ "code of the site by integrating with iubenda’s Cookie Solution. It provides "
332
+ "a fully customizable cookie banner, dynamically generates a cookie policy <a "
333
+ "href=\"%s\" target=\"_blank\">to match the services in use on your site</a>, "
334
+ "and, fully manages cookie-related consent – including the blocking of the "
335
+ "most common widgets and third-party cookies before consent is received – in "
336
+ "order to comply with the GDPR and ePrivacy."
337
+ msgstr ""
338
+ "Grazie all'integrazione con la Cookie Solution di iubenda, questo plugin "
339
+ "riduce drasticamente la necessità di interventi diretti sul codice del sito. "
340
+ "Prevede un cookie banner completamente personalizzabile, genera una cookie "
341
+ "policy che <a href=\"%s\" target=\"_blank\">rispecchia i servizi in uso dal "
342
+ "tuo sito web</a> e gestisce il consenso ai cookie (incluso il blocco "
343
+ "automatico dei widget e dei cookie di terza parte più diffusi) in modo da "
344
+ "permetterti di rispettare il GDPR e la Direttiva ePrivacy."
345
+
346
+ #: includes/settings.php:662
347
+ msgid ""
348
+ "Maintaining valid records of consent is a vital part of privacy compliance "
349
+ "in general, and it is specifically required under the GDPR. These records "
350
+ "should include a userid, timestamp, consent proof, record of the consenting "
351
+ "action, and the legal documents available to the user at the time of "
352
+ "consent, among other things. This plugin is THE most complete solution for "
353
+ "recording, sorting and maintaining GDPR records of consent*. The plugin also "
354
+ "boasts built-in compatibility with WordPress comment form, Contact Form 7 "
355
+ "and WP Forms plugins for your convenience, but can be manually integrated "
356
+ "with any type of web-form and can even store consent proofs for consents "
357
+ "collected offline (e.g in-store sign-ups) via WP media upload."
358
+ msgstr ""
359
+ "Il mantenimento di un valido registro dei consensi è un elemento vitale per "
360
+ "il rispetto della privacy, ed è specificamente richiesto dal GDPR. Tra le "
361
+ "altre cose, questo registro dovrebbe includere l'identificativo dell'utente, "
362
+ "il timestamp, la prova del consenso, la registrazione dell'azione di "
363
+ "consenso e i documenti legali messi a disposizione dell'utente nel momento "
364
+ "in cui il consenso è stato acquisito. Questo plugin è la soluzione più "
365
+ "completa per la creazione e la gestione di un registro dei consensi*. Il "
366
+ "plugin è compatibile con il modulo dei commenti WordPress e i plugin Contact "
367
+ "Form 7 e WP Forms, può essere integrato manualmente con qualsiasi form e può "
368
+ "memorizzare la prova del consenso anche per i consensi raccolti offline (ad "
369
+ "esempio, le iscrizioni in-store) tramite l'upload dei media WP."
370
+
371
+ #: includes/settings.php:680
372
+ msgid "Reset to defaults"
373
+ msgstr "Ripristina le impostazioni di default"
374
+
375
+ #: includes/settings.php:692
376
+ msgid "Need support for this plugin?"
377
+ msgstr "Serve aiuto per questo plugin?"
378
+
379
+ #: includes/settings.php:693
380
+ #, php-format
381
+ msgid ""
382
+ "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">support "
383
+ "forum.</a>"
384
+ msgstr ""
385
+ "Visita il nostro <a href=\"%s\" class=\"iubenda-url\" target=\"_blank"
386
+ "\">forum di supporto</a>"
387
+
388
+ #: includes/settings.php:737
389
+ #, php-format
390
+ msgid "Enter the iubenda code for %s."
391
+ msgstr "Inserisci il codice di iubenda per %s."
392
+
393
+ #: includes/settings.php:748
394
+ msgid "Enter the iubenda code."
395
+ msgstr "Inserisci il codice di iubenda."
396
+
397
+ #: includes/settings.php:775
398
+ #, fuzzy
399
+ #| msgid "Enter a list of custom scripts (one per line)."
400
+ msgid ""
401
+ "Provide a list of custom scripts you’d like to block and assign their "
402
+ "purpose."
403
+ msgstr "Elenca gli script personalizzati (uno per riga)."
404
+
405
+ #: includes/settings.php:777 includes/settings.php:784
406
+ #, fuzzy
407
+ #| msgid "Custom scripts"
408
+ msgid "Enter custom script"
409
+ msgstr "Script personalizzati"
410
+
411
+ #: includes/settings.php:777 includes/settings.php:784
412
+ #: includes/settings.php:795 includes/settings.php:802
413
+ #: includes/settings.php:1178 includes/settings.php:1205
414
+ #: includes/settings.php:1246 includes/settings.php:1274
415
+ #: includes/settings.php:1325 includes/settings.php:1341
416
+ msgid "Remove"
417
+ msgstr "Elimina"
418
+
419
+ #: includes/settings.php:793
420
+ #, fuzzy
421
+ #| msgid "Enter a list of custom iframes (one per line)."
422
+ msgid ""
423
+ "Provide a list of custom iframes you’d like to block and assign their "
424
+ "purpose. "
425
+ msgstr "Elenca gli iframe personalizzati (uno per riga)."
426
+
427
+ #: includes/settings.php:795 includes/settings.php:802
428
+ msgid "Enter custom iframe"
429
+ msgstr ""
430
+
431
+ #: includes/settings.php:840
432
+ #, fuzzy
433
+ #| msgid "Automatically block scripts detected by the plugin."
434
+ msgid "Automatically block scripts detected by the plugin"
435
+ msgstr "Blocca automaticamente gli script rilevati dal plugin."
436
+
437
+ #: includes/settings.php:841
438
+ #, php-format
439
+ msgid ""
440
+ "see <a href=\"%s\" target=\"_blank\">our documentation</a> for the list of "
441
+ "detected scripts."
442
+ msgstr ""
443
+ "visita <a href=\"%s\" target=\"_blank\">la nostra documentazione</a> per la "
444
+ "lista degli script rilevati automaticamente dal plugin."
445
+
446
+ #: includes/settings.php:844
447
+ msgid "Primary"
448
+ msgstr "Primario"
449
+
450
+ #: includes/settings.php:845
451
+ msgid "Secondary"
452
+ msgstr "Secondario"
453
+
454
+ #: includes/settings.php:846
455
+ msgid "Select parsing engine."
456
+ msgstr "Seleziona il motore di parsing."
457
+
458
+ #: includes/settings.php:849
459
+ msgid ""
460
+ "Leave scripts untouched on the page if the user has already given consent"
461
+ msgstr ""
462
+ "Lascia gli script intatti sulla pagina se l'utente ha già prestato il "
463
+ "consenso"
464
+
465
+ #: includes/settings.php:850
466
+ #, fuzzy
467
+ #| msgid ""
468
+ #| "improves performance, highly recommended, to be deactivated only if your "
469
+ #| "site uses a caching system"
470
+ msgid ""
471
+ "improves performance, highly recommended, to be deactivated only if your "
472
+ "site uses a caching system or if you're collecting per-category consent."
473
+ msgstr ""
474
+ "migliora le prestazioni, altamente consigliato, da disattivare solo qualora "
475
+ "il tuo sito utilizzi un sistema di cache"
476
+
477
+ #: includes/settings.php:864
478
+ msgid ""
479
+ "Restrict the plugin to run only for requests that have \"Content-type: "
480
+ "text / html\" (recommended)"
481
+ msgstr ""
482
+ "Restringi l'esecuzione del plugin alle sole richieste che presentano "
483
+ "\"Content-type: text/html\" (consigliato)"
484
+
485
+ #: includes/settings.php:876
486
+ msgid "Do not run the plugin inside the RSS feed (recommended)"
487
+ msgstr "Non eseguire il plugin all'interno dei Feed RSS (consigliato)"
488
+
489
+ #: includes/settings.php:888
490
+ #, fuzzy
491
+ #| msgid "Do not run the plugin inside the RSS feed (recommended)"
492
+ msgid "Do not run the plugin on POST requests (recommended)"
493
+ msgstr "Non eseguire il plugin per richieste POST (consigliato)"
494
+
495
+ #: includes/settings.php:900
496
+ msgid "Top menu"
497
+ msgstr "Menu principale"
498
+
499
+ #: includes/settings.php:901
500
+ msgid "Submenu"
501
+ msgstr "Sottomenu"
502
+
503
+ #: includes/settings.php:902
504
+ msgid ""
505
+ "Select whether to display iubenda in a top admin menu or the Settings "
506
+ "submenu."
507
+ msgstr ""
508
+ "Scegli se visualizzare iubenda in una voce di menu principale del pannello "
509
+ "admin o in un sottomenu della scheda Impostazioni."
510
+
511
+ #: includes/settings.php:914
512
+ msgid "Enable Google AMP support."
513
+ msgstr ""
514
+
515
+ #: includes/settings.php:915
516
+ #, php-format
517
+ msgid ""
518
+ "This feature enables iubenda on AMP pages via the <a href=\"%s\" target="
519
+ "\"_blank\">AMP</a> and <a href=\"%s\" target=\"_blank\">AMP for WP</a> "
520
+ "plugins. AMP requires specific configuration parameters and a page hosted on "
521
+ "your domain where the configuration is loaded from. <a href=\"%s\" target="
522
+ "\"_blank\">Learn more on iubenda and AMP</a>."
523
+ msgstr ""
524
+
525
+ #: includes/settings.php:918
526
+ msgid "Auto-generated configuration file"
527
+ msgstr ""
528
+
529
+ #: includes/settings.php:919
530
+ msgid "Custom configuration file"
531
+ msgstr ""
532
+
533
+ #: includes/settings.php:920
534
+ msgid "Select the iubenda AMP configuration file location."
535
+ msgstr ""
536
+
537
+ #: includes/settings.php:925
538
+ msgid ""
539
+ "No file available. Save changes to generate iubenda AMP configuration file."
540
+ msgstr ""
541
+
542
+ #: includes/settings.php:953
543
+ msgid ""
544
+ "If you're experiencing issues with AMP setup download the generated iubenda "
545
+ "AMP configuration file, upload it to any SSL server and paste the file link "
546
+ "to the field above."
547
+ msgstr ""
548
+
549
+ #: includes/settings.php:955
550
+ #, php-format
551
+ msgid ""
552
+ "Seeing the AMP cookie notice when testing from Google but not when visiting "
553
+ "your AMP pages directly? <a href=\"%s\" target=\"_blank\">Learn how to fix "
554
+ "it</a>."
555
+ msgstr ""
556
+
557
+ #: includes/settings.php:968
558
+ msgid "Delete all plugin data upon deactivation"
559
+ msgstr "Vuoi eliminare tutti i dati del plugin al momento della disattivazione"
560
+
561
+ #: includes/settings.php:981
562
+ msgid "Enter your iubenda Javascript library public API key."
563
+ msgstr ""
564
+ "Inserisci la chiave API pubblica per la libreria JavaScript di iubenda."
565
+
566
+ #: includes/settings.php:997
567
+ msgid ""
568
+ "This section lists the forms available for field mapping. The plugin "
569
+ "currently supports & detects: WordPress Comment, Contact Form 7, WooCommerce "
570
+ "Checkout and WP Forms."
571
+ msgstr ""
572
+ "Questa sezione elenca i form disponibili al mapping. Al momento il plugin "
573
+ "supporta e rileva: Commenti WordPress, Contact Form 7, WooCommerce Checkout "
574
+ "e WP Forms."
575
+
576
+ #: includes/settings.php:1058
577
+ #, php-format
578
+ msgid "%s form title."
579
+ msgstr "%s nome del form."
580
+
581
+ #: includes/settings.php:1058
582
+ msgid "Unknown"
583
+ msgstr "Sconosciuto"
584
+
585
+ #: includes/settings.php:1060
586
+ msgid "Available form fields:"
587
+ msgstr "Campi disponibili:"
588
+
589
+ #: includes/settings.php:1066
590
+ msgid "Publish"
591
+ msgstr "Pubblica"
592
+
593
+ #: includes/settings.php:1071
594
+ msgid "Status"
595
+ msgstr "Stato"
596
+
597
+ #: includes/settings.php:1084
598
+ msgid "Cancel"
599
+ msgstr "Annulla"
600
+
601
+ #: includes/settings.php:1089
602
+ msgid "Save"
603
+ msgstr "Salva"
604
+
605
+ #: includes/settings.php:1102
606
+ msgid "Map fields"
607
+ msgstr "Mappa i campi"
608
+
609
+ #: includes/settings.php:1108
610
+ msgid "Subject fields"
611
+ msgstr "Utente"
612
+
613
+ #: includes/settings.php:1109
614
+ #, fuzzy
615
+ #| msgid ""
616
+ #| "Subject fields allow you to store a series of identifying values about "
617
+ #| "your individual subjects/users. Please map the subject field with the "
618
+ #| "corresponding form fields where applicable."
619
+ msgid ""
620
+ "Subject fields allow you to store a series of identifying values about your "
621
+ "individual subjects/users. Please map the subject field with the "
622
+ "corresponding form fields where applicable."
623
+ msgstr ""
624
+ "Questi campi ti permettono di memorizzare una serie di valori identificativi "
625
+ "dell'utente. Associa gli attributi dell'utente ai corrispondenti campi del "
626
+ "form (quando applicabile)."
627
+
628
+ #: includes/settings.php:1114
629
+ msgid "Subject field"
630
+ msgstr "Attributo"
631
+
632
+ #: includes/settings.php:1115 includes/settings.php:1159
633
+ msgid "Form field"
634
+ msgstr "Campo del form"
635
+
636
+ #: includes/settings.php:1121
637
+ msgid "Autogenerated"
638
+ msgstr "Generato automaticamente"
639
+
640
+ #: includes/settings.php:1121
641
+ msgid "None"
642
+ msgstr "Nessuno"
643
+
644
+ #: includes/settings.php:1152
645
+ msgid "Preferences fields"
646
+ msgstr "Preferenze"
647
+
648
+ #: includes/settings.php:1153
649
+ msgid ""
650
+ "Preferences fields allow you to store a record of the various opt-ins points "
651
+ "at which the user has agreed or given consent, such as fields for agreeing "
652
+ "to terms and conditions, newsletter, profiling, etc. *Please create at least "
653
+ "one preference field."
654
+ msgstr ""
655
+ "Questi campi ti permettono di memorizzare a cosa l'utente ha prestato il "
656
+ "proprio consenso, come ad esempio i termini e condizioni, la newsletter la "
657
+ "profilazione, ecc. *Si prega di creare almeno un campo."
658
+
659
+ #: includes/settings.php:1158
660
+ msgid "Preferences field"
661
+ msgstr "Campo delle preferenze"
662
+
663
+ #: includes/settings.php:1164 includes/settings.php:1190
664
+ #: includes/settings.php:1315 includes/settings.php:1325
665
+ #: includes/settings.php:1341
666
+ msgid "Enter field name"
667
+ msgstr "Aggiungi il nome di un campo"
668
+
669
+ #: includes/settings.php:1214
670
+ msgid "Add New Preference"
671
+ msgstr "Aggiungi nuova preferenza"
672
+
673
+ #: includes/settings.php:1221
674
+ msgid "Exclude fields"
675
+ msgstr "Esclusioni"
676
+
677
+ #: includes/settings.php:1222
678
+ msgid ""
679
+ "Exclude fields allow you to create a list of fields that you would like to "
680
+ "exclude from your Consent Solution recorded proofs (for e.g. password or "
681
+ "other fields not related to the consent)."
682
+ msgstr ""
683
+ "Qui puoi creare una lista dei campi che desideri escludere dalle prove del "
684
+ "consenso memorizzate dalla Consent Solution (ad es. password o altri campi "
685
+ "non correlati)."
686
+
687
+ #: includes/settings.php:1227
688
+ msgid "Exclude field"
689
+ msgstr "Campi esclusi"
690
+
691
+ #: includes/settings.php:1284
692
+ msgid "Add New Exclude"
693
+ msgstr "Aggiungi una nuova esclusione"
694
+
695
+ #: includes/settings.php:1294
696
+ msgid "Legal Notices"
697
+ msgstr "Note legali"
698
+
699
+ #: includes/settings.php:1300
700
+ msgid "Legal documents"
701
+ msgstr "Documenti legali"
702
+
703
+ #: includes/settings.php:1301
704
+ msgid ""
705
+ "In general, it’s important that you declare which legal documents are being "
706
+ "agreed upon when each consent is collected. However, if you use iubenda for "
707
+ "your legal documents, it is *required* that you identify the documents by "
708
+ "selecting them here."
709
+ msgstr ""
710
+ "In generale, è importante dichiarare quali documenti legali vengono "
711
+ "accettati al momento del conferimento del consenso. Se usi iubenda per le "
712
+ "tue informative, *devi* identificare tali documenti selezionandoli qui."
713
+
714
+ #: includes/settings.php:1306
715
+ msgid "Identifier"
716
+ msgstr "Identificatore"
717
+
718
+ #: includes/settings.php:1315
719
+ msgid "Please select each legal document available on your site."
720
+ msgstr "Seleziona tutti i documenti legali presenti sul tuo sito."
721
+
722
+ #: includes/settings.php:1331
723
+ msgid "Alternatively, you may add your own custom document identifiers."
724
+ msgstr "In alternativa, puoi aggiungere degli identificatori personalizzati."
725
+
726
+ #: includes/settings.php:1350
727
+ msgid "Add New Document"
728
+ msgstr "Aggiungi un nuovo documento"
729
+
730
+ #: includes/settings.php:1471 includes/settings.php:1503
731
+ #: includes/settings.php:1688
732
+ msgid "Settings saved."
733
+ msgstr "Impostazioni salvate."
734
+
735
+ #: includes/settings.php:1483 includes/settings.php:1508
736
+ msgid "Settings restored to defaults."
737
+ msgstr "Impostazioni di default ripristinate."
738
+
739
+ #: includes/settings.php:1543
740
+ #, php-format
741
+ msgid ""
742
+ "Please enable comments cookies opt-in checkbox in the <a href=\"%s\" target="
743
+ "\"_blank\">Discussion settings</a>."
744
+ msgstr ""
745
+ "Abilita per i commenti la possibilità di attivare o disattivare la "
746
+ "memorizzazione dei dati personali in un cookie. Per farlo, vai su <a href="
747
+ "\"%s\" target=\"_blank\">Impostazioni discussione</a>."
748
+
749
+ #: includes/settings.php:1563
750
+ msgid "No forms or form changes detected."
751
+ msgstr "Nessun form o modifica rilevati."
752
+
753
+ #: includes/settings.php:1623
754
+ msgid "Form saving failed. Please fill the Subject and Preferences fields."
755
+ msgstr "Salvataggio del form fallito. Compila i campi Utente e Preferenze."
756
+
757
+ #: includes/settings.php:1647
758
+ #, fuzzy
759
+ #| msgid "Settings applied successfully"
760
+ msgid "Form saved successfully - form status changed to Mapped."
761
+ msgstr "Form salvato con successo - Stato aggiornato a Mappato."
762
+
763
+ #: includes/settings.php:1650
764
+ msgid "Form updated successfully."
765
+ msgstr "Form aggiornato con successo."
766
+
767
+ #: includes/settings.php:1653
768
+ msgid "Form saving failed."
769
+ msgstr "Salvataggio del form fallito."
770
+
771
+ #: includes/settings.php:1670
772
+ #, fuzzy
773
+ #| msgid "Settings applied successfully"
774
+ msgid "Form deleted successfully."
775
+ msgstr "Form eliminato con successo."
776
+
777
+ #: includes/settings.php:1672
778
+ msgid "Form delete failed."
779
+ msgstr "Eliminazione del form fallita."
780
+
781
+ #: includes/settings.php:1748
782
+ msgid "Dismiss this notice."
783
+ msgstr "Chiudi questo avviso."
784
+
785
+ #, fuzzy
786
+ #~| msgid "Settings applied successfully"
787
+ #~ msgid "Forms detected successfully."
788
+ #~ msgstr "Impostazioni salvate con successo."
789
+
790
+ #, fuzzy
791
+ #~| msgid "Content type"
792
+ #~ msgid "Contents"
793
+ #~ msgstr "Tipo di contenuto"
794
+
795
+ #~ msgid "Want to try a beta version of this plugin with the latest features?"
796
+ #~ msgstr ""
797
+ #~ "Vuoi provare una versione Beta di questo plugin, con le funzionalità più "
798
+ #~ "recenti?"
799
+
800
+ #~ msgid ""
801
+ #~ "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank"
802
+ #~ "\">documentation pages</a> and follow the instructions to install a beta "
803
+ #~ "version."
804
+ #~ msgstr ""
805
+ #~ "Visita la <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">nostra "
806
+ #~ "documentazione</a> e segui le istruzioni per installare una versione Beta."
807
+
808
+ #~ msgid "Default"
809
+ #~ msgstr "Default"
810
+
811
+ #~ msgid "Experimental"
812
+ #~ msgstr "Sperimentale"
813
+
814
+ #~ msgid "What’s the full functionality of the plugin?"
815
+ #~ msgstr "Quali sono le funzionalità del plugin?"
816
+
817
+ #~ msgid "Select a language to correctly pair it with your script"
818
+ #~ msgstr "Seleziona una lingua a cui associare il tuo codice"
819
+
820
+ #~ msgid "Automatically blocks scripts detected by the plugin"
821
+ #~ msgstr "Effettua il blocco automatico degli script rilevati dal plugin"
822
+
823
+ #~ msgid ""
824
+ #~ "see <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">our "
825
+ #~ "documentation</a> for the list of detected scripts."
826
+ #~ msgstr ""
827
+ #~ "consulta la <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">nostra "
828
+ #~ "documentazione</a> per la lista di script rilevati."
829
+
830
+ #~ msgid "Parsing engine"
831
+ #~ msgstr "Parsing engine"
832
+
833
+ #~ msgid ""
834
+ #~ "Leaves scripts untouched on the page if the user has already given consent"
835
+ #~ msgstr ""
836
+ #~ "Lascia intatti gli script della pagina se l'utente ha già dato il consenso"
837
+
838
+ #~ msgid "Applies special optimizations in cases with faulty output"
839
+ #~ msgstr "Applica ottimizzazioni speciali in caso di errori con l'output"
840
+
841
+ #~ msgid ""
842
+ #~ "only select this option if you had performance problems or if you notice "
843
+ #~ "that the blocking of code is run several times"
844
+ #~ msgstr ""
845
+ #~ "attiva questa opzione solo qualora avessi problemi di performance o "
846
+ #~ "notassi che il blocco dei codici viene applicato più volte"
847
+
848
+ #~ msgid "Parsed with iubenda experimental class in %s sec."
849
+ #~ msgstr "Parsed with iubenda experimental class in %s sec."
850
+
851
+ #~ msgid "Parsed with iubenda default class in %s sec."
852
+ #~ msgstr "Parsed with iubenda default class in %s sec."
853
+
854
+ #~ msgid ""
855
+ #~ "see <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">our "
856
+ #~ "documentation</a> for the list of detected scripts this guide."
857
+ #~ msgstr ""
858
+ #~ "consulta la <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">nostra "
859
+ #~ "documentazione</a> per la lista di script rilevati."
trunk/languages/iubenda-cookie-law-solution.pot ADDED
@@ -0,0 +1,647 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #, fuzzy
2
+ msgid ""
3
+ msgstr ""
4
+ "Project-Id-Version: Iubenda Cookie Solution\n"
5
+ "POT-Creation-Date: 2020-02-06 13:33+0100\n"
6
+ "PO-Revision-Date: 2015-08-12 10:36+0200\n"
7
+ "Last-Translator: \n"
8
+ "Language-Team: \n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 2.3\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
15
+ "X-Poedit-SourceCharset: UTF-8\n"
16
+ "X-Poedit-KeywordsList: __\n"
17
+ "X-Poedit-SearchPath-0: .\n"
18
+
19
+ #: includes/amp.php:126
20
+ msgid "Loading"
21
+ msgstr ""
22
+
23
+ #: includes/amp.php:258
24
+ msgid "AMP Cookie Consent"
25
+ msgstr ""
26
+
27
+ #: includes/forms-list-table.php:92
28
+ msgid "Form Title"
29
+ msgstr ""
30
+
31
+ #: includes/forms-list-table.php:93
32
+ msgid "Form ID"
33
+ msgstr ""
34
+
35
+ #: includes/forms-list-table.php:94
36
+ msgid "Form Source"
37
+ msgstr ""
38
+
39
+ #: includes/forms-list-table.php:95
40
+ msgid "Fields"
41
+ msgstr ""
42
+
43
+ #: includes/forms-list-table.php:96
44
+ msgid "Date"
45
+ msgstr ""
46
+
47
+ #: includes/forms-list-table.php:165
48
+ msgid "Edit"
49
+ msgstr ""
50
+
51
+ #: includes/forms-list-table.php:166
52
+ msgid "Delete"
53
+ msgstr ""
54
+
55
+ #: includes/forms-list-table.php:277
56
+ msgid "Filter"
57
+ msgstr ""
58
+
59
+ #: includes/forms-list-table.php:294
60
+ msgid "Filter by source"
61
+ msgstr ""
62
+
63
+ #: includes/forms-list-table.php:296
64
+ msgid "All form sources"
65
+ msgstr ""
66
+
67
+ #: includes/forms-list-table.php:364
68
+ msgid "No forms found."
69
+ msgstr ""
70
+
71
+ #: includes/forms.php:149 includes/settings.php:138
72
+ msgid "Forms"
73
+ msgstr ""
74
+
75
+ #: includes/forms.php:150
76
+ msgid "Form"
77
+ msgstr ""
78
+
79
+ #: includes/forms.php:566 includes/forms.php:580
80
+ msgid "First name"
81
+ msgstr ""
82
+
83
+ #: includes/forms.php:572 includes/forms.php:592
84
+ msgid "Last name"
85
+ msgstr ""
86
+
87
+ #: includes/forms.php:586
88
+ msgid "Middle name"
89
+ msgstr ""
90
+
91
+ #: includes/settings.php:43 includes/settings.php:44 includes/settings.php:45
92
+ #: includes/settings.php:46 includes/settings.php:47
93
+ msgid "string"
94
+ msgstr ""
95
+
96
+ #: includes/settings.php:59 includes/settings.php:183
97
+ msgid "Cookie Solution"
98
+ msgstr ""
99
+
100
+ #: includes/settings.php:65 includes/settings.php:184
101
+ msgid "Consent Solution"
102
+ msgstr ""
103
+
104
+ #: includes/settings.php:73
105
+ msgid "Not set"
106
+ msgstr ""
107
+
108
+ #: includes/settings.php:74
109
+ msgid "Strictly necessary"
110
+ msgstr ""
111
+
112
+ #: includes/settings.php:75
113
+ msgid "Basic interactions & functionalities"
114
+ msgstr ""
115
+
116
+ #: includes/settings.php:76
117
+ msgid "Experience enhancement"
118
+ msgstr ""
119
+
120
+ #: includes/settings.php:77
121
+ msgid "Analytics"
122
+ msgstr ""
123
+
124
+ #: includes/settings.php:78
125
+ msgid "Targeting & Advertising"
126
+ msgstr ""
127
+
128
+ #: includes/settings.php:125
129
+ msgid "Code"
130
+ msgstr ""
131
+
132
+ #: includes/settings.php:126
133
+ msgid "Google AMP"
134
+ msgstr ""
135
+
136
+ #: includes/settings.php:127
137
+ msgid "Script blocking"
138
+ msgstr ""
139
+
140
+ #: includes/settings.php:128
141
+ msgid "Custom scripts"
142
+ msgstr ""
143
+
144
+ #: includes/settings.php:129
145
+ msgid "Content type"
146
+ msgstr ""
147
+
148
+ #: includes/settings.php:130
149
+ msgid "RSS feed"
150
+ msgstr ""
151
+
152
+ #: includes/settings.php:131
153
+ msgid "POST requests"
154
+ msgstr ""
155
+
156
+ #: includes/settings.php:132
157
+ msgid "Menu position"
158
+ msgstr ""
159
+
160
+ #: includes/settings.php:133
161
+ msgid "Deactivation"
162
+ msgstr ""
163
+
164
+ #: includes/settings.php:139
165
+ msgid "Public Api Key"
166
+ msgstr ""
167
+
168
+ #: includes/settings.php:142 includes/settings.php:146
169
+ msgid "Field Mapping"
170
+ msgstr ""
171
+
172
+ #: includes/settings.php:206
173
+ msgid "Are you sure you want to delete this form?"
174
+ msgstr ""
175
+
176
+ #: includes/settings.php:541
177
+ msgid "You don't have permission to access this page."
178
+ msgstr ""
179
+
180
+ #: includes/settings.php:567
181
+ msgid ""
182
+ "This plugin is the easiest and most comprehensive way to adapt your "
183
+ "WordPress site to the ePrivacy (EU Cookie Law). Upon your users’ first "
184
+ "visit, the plugin will take care of collecting their consent, blocking the "
185
+ "most popular cookie-scripts and subsequently reactivating these scripts as "
186
+ "soon as consent is provided. The basic settings include obtaining consent "
187
+ "by a simple scroll action (the most effective method) and script "
188
+ "reactivation without refreshing the page (asynchronous script reactivation)."
189
+ msgstr ""
190
+
191
+ #: includes/settings.php:570
192
+ msgid ""
193
+ "Does the Cookie Solution support IAB’s Transparency and Consent Framework?"
194
+ msgstr ""
195
+
196
+ #: includes/settings.php:571
197
+ #, php-format
198
+ msgid ""
199
+ "Yes it does. You can read more about it <a href=\"%s\" class=\"iubenda-url"
200
+ "\" target=\"_blank\">here.</a>"
201
+ msgstr ""
202
+
203
+ #: includes/settings.php:574
204
+ msgid "Would you like to know more about the cookie law?"
205
+ msgstr ""
206
+
207
+ #: includes/settings.php:575
208
+ #, php-format
209
+ msgid ""
210
+ "Read our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">complete "
211
+ "guide to the cookie law.</a>"
212
+ msgstr ""
213
+
214
+ #: includes/settings.php:578
215
+ msgid "What is the full functionality of the plugin?"
216
+ msgstr ""
217
+
218
+ #: includes/settings.php:579
219
+ #, php-format
220
+ msgid ""
221
+ "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">plugin "
222
+ "page.</a>"
223
+ msgstr ""
224
+
225
+ #: includes/settings.php:582
226
+ msgid "Enter the iubenda code for the Cookie Solution below."
227
+ msgstr ""
228
+
229
+ #: includes/settings.php:583
230
+ #, php-format
231
+ msgid ""
232
+ "In order to run the plugin, you need to enter the iubenda code that "
233
+ "activates the cookie law banner and the cookie policy in the form below. "
234
+ "This code can be generated on www.iubenda.com, following <a href=\"%s\" "
235
+ "class=\"iubenda-url\" target=\"_blank\">this guide.</a>"
236
+ msgstr ""
237
+
238
+ #: includes/settings.php:588
239
+ msgid ""
240
+ "Maintaining comprehensive records of consent is a vital part of privacy "
241
+ "compliance in general but is specifically required under the GDPR. These "
242
+ "records should include a way of identifying the user, store proof of "
243
+ "consent, record of the consenting action, and the legal documents available "
244
+ "to the user at the time of consent, among other things. You can read about "
245
+ "the <a href=\"https://www.iubenda.com/en/help/5428-gdpr-guide#records-of-"
246
+ "consent\" target=\"_blank\">full requirements here</a>."
247
+ msgstr ""
248
+
249
+ #: includes/settings.php:613
250
+ #, php-format
251
+ msgid ""
252
+ "If you are using per-purpose script blocking or Reject option please "
253
+ "disable the \"Leave scripts untouched on the page if the user has already "
254
+ "given consent\" option. <a href=\"%s\" target=\"_self\">Disable now</a>"
255
+ msgstr ""
256
+
257
+ #: includes/settings.php:638
258
+ msgid ""
259
+ "AMP configuration file requires HTTPS. Make sure your SSL Certificate is "
260
+ "configured correctly."
261
+ msgstr ""
262
+
263
+ #: includes/settings.php:660
264
+ #, php-format
265
+ msgid ""
266
+ "This plugin drastically reduces the need for direct interventions in the "
267
+ "code of the site by integrating with iubenda’s Cookie Solution. It provides "
268
+ "a fully customizable cookie banner, dynamically generates a cookie policy "
269
+ "<a href=\"%s\" target=\"_blank\">to match the services in use on your site</"
270
+ "a>, and, fully manages cookie-related consent – including the blocking of "
271
+ "the most common widgets and third-party cookies before consent is received "
272
+ "– in order to comply with the GDPR and ePrivacy."
273
+ msgstr ""
274
+
275
+ #: includes/settings.php:662
276
+ msgid ""
277
+ "Maintaining valid records of consent is a vital part of privacy compliance "
278
+ "in general, and it is specifically required under the GDPR. These records "
279
+ "should include a userid, timestamp, consent proof, record of the consenting "
280
+ "action, and the legal documents available to the user at the time of "
281
+ "consent, among other things. This plugin is THE most complete solution for "
282
+ "recording, sorting and maintaining GDPR records of consent*. The plugin "
283
+ "also boasts built-in compatibility with WordPress comment form, Contact "
284
+ "Form 7 and WP Forms plugins for your convenience, but can be manually "
285
+ "integrated with any type of web-form and can even store consent proofs for "
286
+ "consents collected offline (e.g in-store sign-ups) via WP media upload."
287
+ msgstr ""
288
+
289
+ #: includes/settings.php:680
290
+ msgid "Reset to defaults"
291
+ msgstr ""
292
+
293
+ #: includes/settings.php:692
294
+ msgid "Need support for this plugin?"
295
+ msgstr ""
296
+
297
+ #: includes/settings.php:693
298
+ #, php-format
299
+ msgid ""
300
+ "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">support "
301
+ "forum.</a>"
302
+ msgstr ""
303
+
304
+ #: includes/settings.php:737
305
+ #, php-format
306
+ msgid "Enter the iubenda code for %s."
307
+ msgstr ""
308
+
309
+ #: includes/settings.php:748
310
+ msgid "Enter the iubenda code."
311
+ msgstr ""
312
+
313
+ #: includes/settings.php:775
314
+ msgid ""
315
+ "Provide a list of custom scripts you’d like to block and assign their "
316
+ "purpose."
317
+ msgstr ""
318
+
319
+ #: includes/settings.php:777 includes/settings.php:784
320
+ msgid "Enter custom script"
321
+ msgstr ""
322
+
323
+ #: includes/settings.php:777 includes/settings.php:784
324
+ #: includes/settings.php:795 includes/settings.php:802
325
+ #: includes/settings.php:1178 includes/settings.php:1205
326
+ #: includes/settings.php:1246 includes/settings.php:1274
327
+ #: includes/settings.php:1325 includes/settings.php:1341
328
+ msgid "Remove"
329
+ msgstr ""
330
+
331
+ #: includes/settings.php:793
332
+ msgid ""
333
+ "Provide a list of custom iframes you’d like to block and assign their "
334
+ "purpose. "
335
+ msgstr ""
336
+
337
+ #: includes/settings.php:795 includes/settings.php:802
338
+ msgid "Enter custom iframe"
339
+ msgstr ""
340
+
341
+ #: includes/settings.php:840
342
+ msgid "Automatically block scripts detected by the plugin"
343
+ msgstr ""
344
+
345
+ #: includes/settings.php:841
346
+ #, php-format
347
+ msgid ""
348
+ "see <a href=\"%s\" target=\"_blank\">our documentation</a> for the list of "
349
+ "detected scripts."
350
+ msgstr ""
351
+
352
+ #: includes/settings.php:844
353
+ msgid "Primary"
354
+ msgstr ""
355
+
356
+ #: includes/settings.php:845
357
+ msgid "Secondary"
358
+ msgstr ""
359
+
360
+ #: includes/settings.php:846
361
+ msgid "Select parsing engine."
362
+ msgstr ""
363
+
364
+ #: includes/settings.php:849
365
+ msgid ""
366
+ "Leave scripts untouched on the page if the user has already given consent"
367
+ msgstr ""
368
+
369
+ #: includes/settings.php:850
370
+ msgid ""
371
+ "improves performance, highly recommended, to be deactivated only if your "
372
+ "site uses a caching system or if you're collecting per-category consent."
373
+ msgstr ""
374
+
375
+ #: includes/settings.php:864
376
+ msgid ""
377
+ "Restrict the plugin to run only for requests that have \"Content-type: "
378
+ "text / html\" (recommended)"
379
+ msgstr ""
380
+
381
+ #: includes/settings.php:876
382
+ msgid "Do not run the plugin inside the RSS feed (recommended)"
383
+ msgstr ""
384
+
385
+ #: includes/settings.php:888
386
+ msgid "Do not run the plugin on POST requests (recommended)"
387
+ msgstr ""
388
+
389
+ #: includes/settings.php:900
390
+ msgid "Top menu"
391
+ msgstr ""
392
+
393
+ #: includes/settings.php:901
394
+ msgid "Submenu"
395
+ msgstr ""
396
+
397
+ #: includes/settings.php:902
398
+ msgid ""
399
+ "Select whether to display iubenda in a top admin menu or the Settings "
400
+ "submenu."
401
+ msgstr ""
402
+
403
+ #: includes/settings.php:914
404
+ msgid "Enable Google AMP support."
405
+ msgstr ""
406
+
407
+ #: includes/settings.php:915
408
+ #, php-format
409
+ msgid ""
410
+ "This feature enables iubenda on AMP pages via the <a href=\"%s\" target="
411
+ "\"_blank\">AMP</a> and <a href=\"%s\" target=\"_blank\">AMP for WP</a> "
412
+ "plugins. AMP requires specific configuration parameters and a page hosted "
413
+ "on your domain where the configuration is loaded from. <a href=\"%s\" "
414
+ "target=\"_blank\">Learn more on iubenda and AMP</a>."
415
+ msgstr ""
416
+
417
+ #: includes/settings.php:918
418
+ msgid "Auto-generated configuration file"
419
+ msgstr ""
420
+
421
+ #: includes/settings.php:919
422
+ msgid "Custom configuration file"
423
+ msgstr ""
424
+
425
+ #: includes/settings.php:920
426
+ msgid "Select the iubenda AMP configuration file location."
427
+ msgstr ""
428
+
429
+ #: includes/settings.php:925
430
+ msgid ""
431
+ "No file available. Save changes to generate iubenda AMP configuration file."
432
+ msgstr ""
433
+
434
+ #: includes/settings.php:953
435
+ msgid ""
436
+ "If you're experiencing issues with AMP setup download the generated iubenda "
437
+ "AMP configuration file, upload it to any SSL server and paste the file link "
438
+ "to the field above."
439
+ msgstr ""
440
+
441
+ #: includes/settings.php:955
442
+ #, php-format
443
+ msgid ""
444
+ "Seeing the AMP cookie notice when testing from Google but not when visiting "
445
+ "your AMP pages directly? <a href=\"%s\" target=\"_blank\">Learn how to fix "
446
+ "it</a>."
447
+ msgstr ""
448
+
449
+ #: includes/settings.php:968
450
+ msgid "Delete all plugin data upon deactivation"
451
+ msgstr ""
452
+
453
+ #: includes/settings.php:981
454
+ msgid "Enter your iubenda Javascript library public API key."
455
+ msgstr ""
456
+
457
+ #: includes/settings.php:997
458
+ msgid ""
459
+ "This section lists the forms available for field mapping. The plugin "
460
+ "currently supports & detects: WordPress Comment, Contact Form 7, "
461
+ "WooCommerce Checkout and WP Forms."
462
+ msgstr ""
463
+
464
+ #: includes/settings.php:1058
465
+ #, php-format
466
+ msgid "%s form title."
467
+ msgstr ""
468
+
469
+ #: includes/settings.php:1058
470
+ msgid "Unknown"
471
+ msgstr ""
472
+
473
+ #: includes/settings.php:1060
474
+ msgid "Available form fields:"
475
+ msgstr ""
476
+
477
+ #: includes/settings.php:1066
478
+ msgid "Publish"
479
+ msgstr ""
480
+
481
+ #: includes/settings.php:1071
482
+ msgid "Status"
483
+ msgstr ""
484
+
485
+ #: includes/settings.php:1084
486
+ msgid "Cancel"
487
+ msgstr ""
488
+
489
+ #: includes/settings.php:1089
490
+ msgid "Save"
491
+ msgstr ""
492
+
493
+ #: includes/settings.php:1102
494
+ msgid "Map fields"
495
+ msgstr ""
496
+
497
+ #: includes/settings.php:1108
498
+ msgid "Subject fields"
499
+ msgstr ""
500
+
501
+ #: includes/settings.php:1109
502
+ msgid ""
503
+ "Subject fields allow you to store a series of identifying values about your "
504
+ "individual subjects/users. Please map the subject field with the "
505
+ "corresponding form fields where applicable."
506
+ msgstr ""
507
+
508
+ #: includes/settings.php:1114
509
+ msgid "Subject field"
510
+ msgstr ""
511
+
512
+ #: includes/settings.php:1115 includes/settings.php:1159
513
+ msgid "Form field"
514
+ msgstr ""
515
+
516
+ #: includes/settings.php:1121
517
+ msgid "Autogenerated"
518
+ msgstr ""
519
+
520
+ #: includes/settings.php:1121
521
+ msgid "None"
522
+ msgstr ""
523
+
524
+ #: includes/settings.php:1152
525
+ msgid "Preferences fields"
526
+ msgstr ""
527
+
528
+ #: includes/settings.php:1153
529
+ msgid ""
530
+ "Preferences fields allow you to store a record of the various opt-ins "
531
+ "points at which the user has agreed or given consent, such as fields for "
532
+ "agreeing to terms and conditions, newsletter, profiling, etc. *Please "
533
+ "create at least one preference field."
534
+ msgstr ""
535
+
536
+ #: includes/settings.php:1158
537
+ msgid "Preferences field"
538
+ msgstr ""
539
+
540
+ #: includes/settings.php:1164 includes/settings.php:1190
541
+ #: includes/settings.php:1315 includes/settings.php:1325
542
+ #: includes/settings.php:1341
543
+ msgid "Enter field name"
544
+ msgstr ""
545
+
546
+ #: includes/settings.php:1214
547
+ msgid "Add New Preference"
548
+ msgstr ""
549
+
550
+ #: includes/settings.php:1221
551
+ msgid "Exclude fields"
552
+ msgstr ""
553
+
554
+ #: includes/settings.php:1222
555
+ msgid ""
556
+ "Exclude fields allow you to create a list of fields that you would like to "
557
+ "exclude from your Consent Solution recorded proofs (for e.g. password or "
558
+ "other fields not related to the consent)."
559
+ msgstr ""
560
+
561
+ #: includes/settings.php:1227
562
+ msgid "Exclude field"
563
+ msgstr ""
564
+
565
+ #: includes/settings.php:1284
566
+ msgid "Add New Exclude"
567
+ msgstr ""
568
+
569
+ #: includes/settings.php:1294
570
+ msgid "Legal Notices"
571
+ msgstr ""
572
+
573
+ #: includes/settings.php:1300
574
+ msgid "Legal documents"
575
+ msgstr ""
576
+
577
+ #: includes/settings.php:1301
578
+ msgid ""
579
+ "In general, it’s important that you declare which legal documents are being "
580
+ "agreed upon when each consent is collected. However, if you use iubenda for "
581
+ "your legal documents, it is *required* that you identify the documents by "
582
+ "selecting them here."
583
+ msgstr ""
584
+
585
+ #: includes/settings.php:1306
586
+ msgid "Identifier"
587
+ msgstr ""
588
+
589
+ #: includes/settings.php:1315
590
+ msgid "Please select each legal document available on your site."
591
+ msgstr ""
592
+
593
+ #: includes/settings.php:1331
594
+ msgid "Alternatively, you may add your own custom document identifiers."
595
+ msgstr ""
596
+
597
+ #: includes/settings.php:1350
598
+ msgid "Add New Document"
599
+ msgstr ""
600
+
601
+ #: includes/settings.php:1471 includes/settings.php:1503
602
+ #: includes/settings.php:1688
603
+ msgid "Settings saved."
604
+ msgstr ""
605
+
606
+ #: includes/settings.php:1483 includes/settings.php:1508
607
+ msgid "Settings restored to defaults."
608
+ msgstr ""
609
+
610
+ #: includes/settings.php:1543
611
+ #, php-format
612
+ msgid ""
613
+ "Please enable comments cookies opt-in checkbox in the <a href=\"%s\" target="
614
+ "\"_blank\">Discussion settings</a>."
615
+ msgstr ""
616
+
617
+ #: includes/settings.php:1563
618
+ msgid "No forms or form changes detected."
619
+ msgstr ""
620
+
621
+ #: includes/settings.php:1623
622
+ msgid "Form saving failed. Please fill the Subject and Preferences fields."
623
+ msgstr ""
624
+
625
+ #: includes/settings.php:1647
626
+ msgid "Form saved successfully - form status changed to Mapped."
627
+ msgstr ""
628
+
629
+ #: includes/settings.php:1650
630
+ msgid "Form updated successfully."
631
+ msgstr ""
632
+
633
+ #: includes/settings.php:1653
634
+ msgid "Form saving failed."
635
+ msgstr ""
636
+
637
+ #: includes/settings.php:1670
638
+ msgid "Form deleted successfully."
639
+ msgstr ""
640
+
641
+ #: includes/settings.php:1672
642
+ msgid "Form delete failed."
643
+ msgstr ""
644
+
645
+ #: includes/settings.php:1748
646
+ msgid "Dismiss this notice."
647
+ msgstr ""
trunk/readme.txt ADDED
@@ -0,0 +1,444 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === iubenda - Cookie and Consent Solution for the GDPR & ePrivacy ===
2
+ Contributors: iubenda
3
+ Donate link:
4
+ Tags: cookies, cookie law, cookie policy, cookie banner, privacy policy, cookie consent, privacy, gdpr, eprivacy
5
+ Requires at least: 4.0
6
+ Requires PHP: 5.2.4
7
+ Tested up to: 5.3.2
8
+ Stable tag: 2.3.4
9
+ License: MIT License
10
+ License URI: http://opensource.org/licenses/MIT
11
+
12
+ An All-in-One approach developed by iubenda, which includes functionalities of two powerful solutions that help to make your website GDPR and ePrivacy compliant.
13
+
14
+ == Description ==
15
+
16
+ This plugin is an All-in-One approach developed by iubenda, which includes functionalities of two powerful solutions (see below) that help to make your website GDPR and ePrivacy compliant. The plugin lets you automate the implementation of ePrivacy (Cookie Law) and GDPR requirements by providing a fully customizable cookie banner, blocking scripts, and by managing all aspects of cookie consent. It also allows you to record, review, and maintain comprehensive GDPR records of consent for your web-forms.
17
+
18
+ == Cookie Solution ==
19
+
20
+ This plugin drastically reduces the need for direct interventions in the code of the site by integrating with iubenda’s Cookie Solution. It provides a fully customizable cookie banner, dynamically generates a cookie policy to [match the services in use on your site](https://www.iubenda.com/en/help/19004-how-to-use-the-site-scanner-from-within-the-generator), and, fully manages cookie-related consent – including the blocking of the most common widgets and third-party cookies before consent is received – in order to comply with the GDPR and ePrivacy.
21
+
22
+ **Key features:**
23
+
24
+ * The plugin automatically inserts the iubenda code in the head of every page of the site
25
+ * Allows you to automatically or manually block scripts that can install cookies prior to consent, without the need of direct intervention on the code
26
+ * Allows you to autodetect and limit prior-blocking and cookie consent requests only to users from the EU – where this is a legal requirement – while running cookies scripts normally in regions where you are still legally allowed to do so.
27
+ * Asynchronously re-activates cookie scripts once consent is collected.
28
+ * Handles the display of the cookie banner and cookie policy, allowing you to fully customize the banner to match the look and colors of your site if needed
29
+ * California Consumer Privacy Act [(CCPA) Support](https://www.iubenda.com/en/help/21165-ccpa-how-to-add-a-notice-of-collection-and-a-do-not-sell-link)
30
+ * Saves user preferences about the use of cookies and displays a clean page (without banner) to users who have already provided their consent
31
+ * Integrates with IAB’s [Transparency and Consent Framework](https://www.iubenda.com/en/help/7440-enable-preference-management-iab-framework#revenue) (TCF)
32
+ * Allows you to provide you users with granular, per-category preference control (e.g. basic functionalities, experience enhancement, targeting & advertising)
33
+ * Compatible with Google's Accelerated Mobile Pages (AMP)
34
+ * Features an easy-to-use interface for entering custom scripts and iframes
35
+ * Detects bots/spiders and serves them a clean page so that your SEO efforts are never compromised
36
+
37
+ **The plugin is currently capable of automatically detecting and blocking the following scripts:**
38
+
39
+ * Google Analytics
40
+ * Google Maps
41
+ * Google AdSense
42
+ * Google ReCaptcha
43
+ * Google Site Search
44
+ * Google Tag Manager
45
+ * Google oAuth
46
+ * Google+ widgets
47
+ * Twitter widgets
48
+ * Facebook widgets
49
+ * Facebook Comments
50
+ * YouTube
51
+ * Vimeo
52
+ * Linkedin widgets
53
+ * ShareThis widgets
54
+ * Instagram widgets
55
+ * AddThis widgets
56
+ * Pinterest widgets
57
+ * PayPal widgets
58
+ * Disqus
59
+ * Optimizely
60
+ * Neodata
61
+ * Criteo
62
+ * Outbrain
63
+ * Headway
64
+ * Codepen
65
+ * Freshchat
66
+ * Uservoice
67
+ * AdRoll
68
+ * Olark
69
+ * Segment
70
+ * Kissmetrics
71
+ * Mixpanel
72
+ * Pingdom
73
+ * Bing
74
+ * Elevio
75
+
76
+ == Consent Solution ==
77
+
78
+ Maintaining valid records of consent is a vital part of privacy compliance in general, and it is specifically required under the GDPR. These records should include a userid, timestamp, consent proof, record of the consenting action, and the legal documents available to the user at the time of consent, among other things. This plugin **is THE most complete solution for recording, sorting and maintaining GDPR records of consent**. The plugin also boasts built-in compatibility with WordPress comment form, Contact Form 7 and WP Forms plugins for your convenience, but can be manually integrated with any type of web-form and can even store consent proofs for consents collected offline (e.g in-store sign-ups) via WP media upload.
79
+
80
+ **Key features:**
81
+
82
+ * The plugin detects and identifies all supported forms that are embedded in the website
83
+ * It’s auto-compatible with and allows super easy mapping of Contact Form 7, WP Forms, WordPress comment and WooCommerce checkout forms
84
+ * It allows manual integration with any type of web-form
85
+ * For each consent, track the form/wording the user was prompted with
86
+ * Flexibly upload any form of proof of consent or legal notice, including a PDF if consent was collected offline
87
+ * It provides a high granularity: map individual form fields, exclude fields (like password inputs), add legal notices available at the time of consent collection, indicate double opt-in, set preferences and more
88
+ * REST HTTP API and JS SDK, to give you total control and how and when consent is stored
89
+ * Store multiple preferences for each user (e.g. if you have multiple newsletters or opt-ins)
90
+ * Features an easy-to-use interface for entering custom scripts and iframes
91
+ * It provides API input field for quick and easy activation
92
+
93
+ **Some background information**
94
+
95
+ If you potentially have any European users, you must comply with laws like the [GDPR](https://www.iubenda.com/en/help/5428-gdpr-guide#consent) and [ePrivacy](https://www.iubenda.com/en/help/6293-cookie-consent-management-faq). These laws are precise in their requirements and technical implementation can be pretty complicated. We've tried to make this process as painless as possible for website and app owners with our suite of compliance software solutions.
96
+ Our Cookie and Consent Solution plugin for WordPress simplifies and manages these compliance requirements within a few clicks. This extension works with the iubenda [Cookie Solution](https://www.iubenda.com/en/cookie-solution) and [Consent Solution](https://www.iubenda.com/en/consent-solution).
97
+
98
+ **Which languages does iubenda work in currently?**
99
+
100
+ * English
101
+ * Italian
102
+ * French
103
+ * Spanish
104
+ * Portuguese (Brazilian)
105
+ * German
106
+ * Dutch
107
+ * Russian
108
+
109
+ == Installation ==
110
+
111
+ * Search in your WordPress plugins admin panel for “iubenda Cookie and Consent Solution”, install it;
112
+ * Once the plugin is installed and activated, go to the Admin Panel → iubenda menu where you can select either the Cookie Solution or Consent Solution (depending on which you’d like to set up first).
113
+ * **For the Cookie Solution**, you will be asked to paste your script into that field – the script is generated from your iubenda account dashboard when you activate the solution. For more information on how to activate the Cookie Solution, see this article (https://www.iubenda.com/en/help/1177-cookie-solution-getting-started#banner).
114
+ * At this point the plugin will begin to show your banner on which displays the legal text, the consent options and your cookie policy (link) to users who visit the site for the first time. No need for other configurations;
115
+ * Furthermore, the plugin automatically recognizes and blocks cookies that get installed via an extensive list of services such as the YouTube video player, social widgets (e.g the Facebook Like Box) etc. on your site. The full list is included in the “details” above.
116
+ * Important note: Scripts can only be automatically blocked when generated from the server side (therefore processed by PHP via WordPress). Scripts that are added to the page via Javascript after page load must be blocked manually. Thankfully, this is fairly easy to do via the Custom Scripts field in the plugin console. Simply enter the custom script or iframe sources you'd like to block within the field, and click on the save changes button. You can find details, examples and further information [here](https://www.iubenda.com/en/help/1215-cookie-solution-wordpress-plugin-installation-guide#blocking-custom-scripts).
117
+ * If you’d like to manually block a specific script using a manual “wrap” method, you can use the following:
118
+ `<!--IUB-COOKIE-BLOCK-START-->
119
+ <iframe src="...
120
+ <img src="...
121
+ <!--IUB-COOKIE-BLOCK-END-->`
122
+ * For elements installed directly within WordPress posts (as opposed to elements integrated at the template level – example footer.php) there are shortcodes available:
123
+ `[iub-cookie-policy]
124
+ [/iub-cookie-policy]`
125
+ * In case you’re querying WordPress via API, you can disable our plugin by using the iub_no_parse=true URL parameter, like this: www.example.com/api/get_recent_posts?iub_no_parse=true (http://www.example.com/api/get_recent_posts?iub_no_parse=true).
126
+ * **For the Consent Solution**, you will need to paste in your Consent Solution API key. Once you’ve activated the Consent Solution in your iubenda dashboard, you can find your public API key in your dashboard (https://www.iubenda.com/en/dashboard) at [Your website] > Consent Solution > Embed).
127
+
128
+ == Frequently Asked Questions ==
129
+
130
+ **Where can I find help?**
131
+ You can find a dedicated support forum thread here [Uservoice forum](https://support.iubenda.com/support/discussions/forums/42000118028) or we're happy to answer at info@iubenda.com.
132
+
133
+ **Do you have more guidance, or a demo?**
134
+ Here’s a [quick video](https://iubenda.wistia.com/medias/02ie8av6kt) on what the cookie banner looks like and how you can configure it. More details on how to fully set up the Cookie Solution for wordpress [here](https://www.iubenda.com/en/help/1215-cookie-solution-wordpress-plugin-installation-guide).
135
+
136
+ Here’s a [quick look](https://iubenda.wistia.com/medias/fsbr465bku) at the Consent Solution dashboard. More details on how to fully set up the Consent Solution for wordpress [here](https://www.iubenda.com/en/help/13083-consent-solution-wordpress-contact-form-7) .
137
+
138
+ **Bug reports**
139
+ The best way you can help us is by providing as much information as possible, including the use of [wp_debug](https://wordpress.org/support/article/debugging-in-wordpress/).
140
+ We will be very happy to receive feedback here: [Uservoice forum](https://support.iubenda.com/support/discussions/forums/42000115771)
141
+
142
+ == Screenshots ==
143
+
144
+ 1. It's as simple as copy-pasting the code from iubenda into the plugin form.
145
+ 2. Simply enter you API key and click on autodetect to see all forms eligible for mapping.
146
+ 3. The visual configurator lets you fully customize the look and feel of your banner, wording, and consent collection options.
147
+ 4. When clicking on the cookie policy link, the user gets a view of the entire cookie policy, where they ultimately can give their consent.
148
+ 5. IAB Transparency and consent framework integrated.
149
+ 6. IAB Transparency and consent framework integrated.
150
+
151
+ == Changelog ==
152
+
153
+ = 2.3.4 =
154
+ * Security Fix: limit url sanitize to http protocols
155
+
156
+ = 2.3.3 =
157
+ * Fix: AddThis purpose category
158
+
159
+ = 2.3.2 =
160
+ * Fix: Configuration regular expression issue in some edge cases
161
+
162
+ = 2.3.1 =
163
+ * Fix: Error on AMP configuration during install in some edge cases
164
+ * Fix: Invalid www detection during AMP configuration generation process
165
+ * Fix: Regex for iubenda script url in AMP configuration
166
+ * Tweak: Added noindex for generated AMP configuration file
167
+
168
+ = 2.3.0 =
169
+ * Fix: Multiple consent forms per page support
170
+ * Fix: WP Forms checkbox field compatibility
171
+ * Tweak: AMP consent geolocation support
172
+
173
+ = 2.2.0 =
174
+ * Fix: Undefined notice during plugin update
175
+
176
+ = 2.1.0 =
177
+ * New: Per-purpose script blocking support
178
+ * New: "Reject" button support
179
+ * New: Google AMP compatibility option
180
+ * Tweak: Improved regular expression on per-purpose feature detection
181
+ * Fix: Safari unrecognized expression on CSS wildcards
182
+
183
+ = 2.1.4-beta =
184
+ * New: Multilingual support from AMP
185
+
186
+ = 2.1.3-beta =
187
+ * Tweak: Block tracking code from WP AMP plugins
188
+
189
+ = 2.1.2-beta =
190
+ * New: Google AMP compatibility option
191
+
192
+ = 2.1.1-beta =
193
+ * Tweak: Improved regular expression on per-purpose feature detection
194
+ * Fix: Safari unrecognized expression on CSS wildcards
195
+
196
+ = 2.1.0-beta =
197
+ * New: Per-purpose script blocking support
198
+ * New: "Reject" button support
199
+
200
+ = 2.0.2 =
201
+ * Fix: initialize iubenda CS on POST requests not working
202
+ * Tweak: iubenda generic menu icon switched to iubenda logo
203
+
204
+ = 2.0.1 =
205
+ * New: Jetpack tracking blocking support
206
+ * Fix: add_submenu_page and add_menu_page called incorrectly in WP 5.3
207
+
208
+ = 2.0.0 =
209
+ * New: Introducing iubenda Consent Solution integration
210
+ * Tweak: Simple HTML Dom update to 1.9
211
+
212
+ = 2.0.3-beta =
213
+ * New: Introducing WooCommerce checkout form field mapping compatibility
214
+
215
+ = 2.0.2-beta =
216
+ * New: Introducing wildcard support for scripts and iframes
217
+
218
+ = 2.0.1-beta =
219
+ * New: Option to initialize iubenda CS on POST requests
220
+ * Tweak: Update Cookie Solution and Consent Solution copy
221
+
222
+ = 2.0-beta =
223
+ * New: Introducing iubenda Consent Solution integration
224
+ * Tweak: Simple HTML Dom update to 1.9
225
+
226
+ = 1.15.8 =
227
+ * New: Introducing a way to skip specific script parsing
228
+ * Fix: Google ReCaptcha with Contact Form 7 initialization issue
229
+ * Fix: Improved handling of iubenda script HTML
230
+ * Tweak: Support links update
231
+
232
+ = 1.15.7 =
233
+ * Fix: Google ReCaptcha loading issue with Contact Form 7
234
+ * Tweak: Improved Youtube and Google Maps script blocking
235
+
236
+ = 1.15.6 =
237
+ * Fix: iubenda script tags removed when Jetpack is active
238
+
239
+ = 1.15.5 =
240
+ * Fix: Skip parsing engine when scripts blocking is disabled
241
+ * Tweak: Update iubenda logo
242
+
243
+ = 1.15.4 =
244
+ * New: Option to block custom scripts and iframes
245
+ * Tweak: Update and extend the list of blocked scripts including Google Site Search, Google oAuth, Linkedin widgets, PayPal widgets, Freshchat, Uservoice
246
+ , AdRoll, Olark, Segment, Kissmetrics, Mixpanel, Pingdom, Bing and Elevio
247
+
248
+ = 1.15.3 =
249
+ * Tweak: Update and extend the list of blocked scripts including Pinterest, AddThis, Disqus, Optimizely, Neodata, Criteo, Outbrain, Headway and Codepen
250
+
251
+ = 1.15.2 =
252
+ * Tweak: Update and unify iubenda parsing engine
253
+ * Tweak: Polylang Pro support
254
+
255
+ = 1.15.1 =
256
+ * Fix: iubenda code field removing HTML tags on save
257
+ * Tweak: Adjusted the script blocking regex in shortcode
258
+
259
+ = 1.15.0 =
260
+ * New: Option to select iubenda menu position
261
+ * Tweak: iubenda faster class regex update
262
+ * Tweak: Enable style tag in iubenda code field
263
+ * Tweak: Changed default parser method
264
+
265
+ = 1.14.2 =
266
+ * New: iubenda_initial_output filter hook
267
+
268
+ = 1.14.2-beta1 =
269
+ * Fix: repository issues breaking the update
270
+
271
+ = 1.14.1 =
272
+ * New: Option to delete all plugin data upon deactivation
273
+ * Fix: Code script attributes stripped from default code block
274
+ * Fix: Updated plugin help links
275
+ * Fix: Italian language files not loading properly
276
+
277
+ = 1.14.0 =
278
+ * New: i18 support
279
+ * New: Polylang support
280
+ * Fix: Multiple classes no longer being added to script tags
281
+ * Fix: Buffering action hooks adjustments
282
+ * General rewrite using WordPress coding standards
283
+ * Turned into OOP
284
+
285
+ = 1.11.1 =
286
+ * New: Created a new option that disables the plugin on RSS feeds
287
+ * New: Improved the control that checks if the request content type is HTML
288
+ * Fixed an issue with the banner script
289
+ * Fixed a series of conflicts with UTF-8 special characters caused by the experimental parsing engine
290
+
291
+ = 1.11.0 =
292
+ * New: Introduced a MUCH FASTER experimental parsing engine (visit the plugin options and select the experimental parsing engine)
293
+ * New: Created a new option that allow users to enable/disable the parsing engine and to select the parsing engine between stable and experimental
294
+ * New: Created a new option that filters the output buffer level to get only the first level ()
295
+ * Fixed a series of conflicts with AJAX requests, which were conflicting with Contact Form 7, BackWPUp and other plugins
296
+ * Added filter that only activates the plugin when the Content Type is text/html, enabled by default
297
+ * Loads of bug fixes and speed improvements
298
+
299
+ = 1.10.21 =
300
+ * Rolling back to 1.10.11
301
+
302
+ = 1.10.20 =
303
+ * Hotfix: moved "is_user_logged_in" method control after the “template_redirect” hook.
304
+
305
+ = 1.10.19 =
306
+ * Fixed a series of conflicts with AJAX requests, which were conflicting with Contact Form 7 and other plugins
307
+
308
+ = 1.10.18 =
309
+ * More bugs fixed
310
+ * The content-type restriction option is now on by default
311
+
312
+ = 1.10.17 =
313
+ * Added filter that only activates the plugin when the Content Type is text/html
314
+ * Loads of bug fixes and speed improvements
315
+
316
+ = 1.10.11 =
317
+ * iub_no_parse parameter reintroduced
318
+ * added XMLRPC control
319
+
320
+ = 1.10.10 =
321
+ * French and Portuguese languages fixed when used with WPML
322
+
323
+ = 1.10.9 =
324
+ * Further bugfixing
325
+
326
+ = 1.10.9 =
327
+ * Further bugfixing
328
+
329
+ = 1.10.8 =
330
+ * Fixed problems with WPML and with using the shortcode
331
+
332
+ = 1.10.7 =
333
+ * Further work on resolving any conflicts with other plugins
334
+ * Fixed a problem with the Media library
335
+
336
+ = 1.10.5 =
337
+ * Reverting the parsing method to 1.9.19, slower but more stable
338
+
339
+ = 1.10.4 =
340
+ * Fixed compatibility with the Yoast SEO plugin (and possibly others)
341
+ * Fixed preference saving after update from 1.9.19
342
+
343
+ = 1.10.3 =
344
+ * Fixed the WPML activation, which now detects the language of the embedding code and places it in the right tab
345
+ * The first tab when WPML is activated is now activated automatically
346
+ * The iubenda shortcode has been improved to be more flexible
347
+
348
+ = 1.10.2 =
349
+ * Fixed an encoding issue
350
+
351
+ = 1.10.1 =
352
+ * Fixed a bug that forced users to re-insert their cookie law code
353
+
354
+ = 1.10.0 =
355
+ * New: Multi-language support with WPML integration
356
+ * New: AdSense auto-matching/blocking has been redone and now works properly
357
+ * New: Addthis and Sharethis are now also automatically blocked
358
+ * Loads of small fixes and improvements
359
+
360
+ = 1.9.28 =
361
+ * Fixed some bugs about i18n, created .pot files for translations. Now is true i18n friendly. Tested.
362
+
363
+ = 1.9.27 =
364
+ * i18n friendly
365
+
366
+ = 1.9.26 =
367
+ * Associate cookie policy for installation before/after WPML
368
+
369
+ = 1.9.25 =
370
+ * Hiding E_NOTICE messages
371
+
372
+ = 1.9.24 =
373
+ * skip parsing if XML-RPC request
374
+ * skip parsing if is admin page
375
+ * added multilanguage
376
+
377
+ = 1.9.19 =
378
+ * new iframe src according to the new doc
379
+
380
+ = 1.9.18 =
381
+ * bug on all iframe, suppressedsrc is not null anymore
382
+
383
+ = 1.9.17 =
384
+ * added another url of google maps embed
385
+
386
+ = 1.9.16 =
387
+ * skip parsing page if bot/crawler + added checkbox to autoparse (or not) the page if the user have already given the consent
388
+
389
+ = 1.9.15 =
390
+ * include bug + google maps
391
+
392
+ = 1.9.14 =
393
+ * Autoconvert iframe vimeo + facebook likebox
394
+
395
+ = 1.9.13 =
396
+ * Now the plugin use iubenda.class.php + fix bug on it.
397
+
398
+ = 1.9.12 =
399
+ * Add iub__no_parse get parameter to skip parsing page
400
+
401
+ = 1.9.11 =
402
+ * Add iub__no_parse get parameter to skip parsing page
403
+
404
+ = 1.9.10 =
405
+ * Another adsense script blocked, another fix on simple html dom
406
+
407
+ = 1.9.9 =
408
+ * Bugs page 60000 chars
409
+
410
+ = 1.9.8 =
411
+ * Added Google Maps & Google Adsense + better shortcode handling
412
+
413
+ = 1.9.7 =
414
+ * minor bugfix
415
+
416
+ = 1.9.6 =
417
+ * bugfix: custom banner now allowed
418
+
419
+ = 1.9.5 =
420
+ * no refresh page needed to activate scripts inside IUB tags.
421
+
422
+ = 1.9.4 =
423
+ * wp-admin blank page bug fix
424
+
425
+ = 1.9.3 =
426
+ * G+ platform bug, typo: _iub_cs_activate_inline vs _iub_cs_activate-inline
427
+
428
+ = 1.9.2 =
429
+ * G+ platform bug
430
+
431
+ = 1.9.1 =
432
+ * Minor improvements
433
+
434
+ = 1.9 =
435
+ * Improved parsing without regex
436
+ * No parsing if the user have already given the consent
437
+
438
+ = 1.0 =
439
+ * First plugin version.
440
+
441
+ == Upgrade Notice ==
442
+
443
+ = 2.3.4 =
444
+ * Security Fix: limit url sanitize to http protocols