iubenda Cookie Solution for GDPR - Version 2.0-beta

Version Description

  • New: Introducing iubenda Consent Solution integration
  • Tweak: Simple HTML Dom update to 1.9
Download this release

Release Info

Developer dfactory
Plugin Icon 128x128 iubenda Cookie Solution for GDPR
Version 2.0-beta
Comparing to
See all releases

Code changes from version 1.15.8 to 2.0-beta

css/admin.css CHANGED
@@ -1,14 +1,5 @@
1
- #iubenda-view {
2
- display: table;
3
-
4
- width: 90%;
5
- margin: 50px auto;
6
- padding: 50px 6%;
7
- box-sizing: border-box;
8
-
9
- border-radius: 2px;
10
- background-color: #FFFFFF;
11
- box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.1)
12
  }
13
  .iubenda-title {
14
  margin-top: 10px;
@@ -16,12 +7,32 @@
16
  }
17
  .iubenda-link {
18
  display: table;
19
- margin: 0 auto 40px;
20
  }
21
  .iubenda-text {
22
  margin: 10px auto;
23
  color: #434149
24
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  #iubenda-tabs {
26
  margin: 30px auto 20px;
27
  }
@@ -54,4 +65,28 @@
54
  #iubenda-tabs .help-tab-content textarea {
55
  margin-top: 18px;
56
  width: 100%;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
1
+ #iubenda-header {
2
+ margin-bottom: 30px;
 
 
 
 
 
 
 
 
 
3
  }
4
  .iubenda-title {
5
  margin-top: 10px;
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
  }
65
  #iubenda-tabs .help-tab-content textarea {
66
  margin-top: 18px;
67
  width: 100%;
68
+ }
69
+ #iubenda-tabs .postbox-container .widefat {
70
+ border: none;
71
+ box-shadow: none;
72
+ }
73
+ #iubenda-tabs .postbox-container .widefat h4 {
74
+ margin: 8px 0;
75
+ }
76
+ #iubenda-tabs .postbox-container .widefat select {
77
+ min-width: 50%;
78
+ }
79
+ #iubenda-tabs .postbox-container .widefat thead .label {
80
+ font-weight: bold;
81
+ }
82
+ #iubenda-tabs .postbox-container .widefat .table-label {
83
+ min-width: 25%;
84
+ }
85
+ #iubenda-tabs .postbox-container .widefat thead td {
86
+ border: none;
87
+ width: 50%;
88
+ }
89
+ #iubenda-tabs .postbox-container .widefat .widefat tbody td {
90
+ padding-top: 5px;
91
+ padding-bottom: 5px;
92
  }
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
+ }
includes/forms.php ADDED
@@ -0,0 +1,665 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 Form';
35
+
36
+ // check if Contact Form 7 is active
37
+ if ( class_exists( 'WPCF7' ) ) {
38
+ $this->sources['wpcf7'] = 'Contact Form 7';
39
+ }
40
+
41
+ $this->sources = apply_filters( 'iub_supported_form_sources', $this->sources );
42
+
43
+ $this->statuses = array(
44
+ 'publish' => _x( 'To Map', 'post status', 'iubenda' ),
45
+ 'mapped' => _x( 'Mapped', 'post status', 'iubenda' ),
46
+ 'needs_update' => _x( 'Needs Update', 'post status', 'iubenda' ),
47
+ // 'trash' => _x( 'Ignored', 'post status', 'iubenda' )
48
+ );
49
+ }
50
+
51
+ /**
52
+ * Enqueue frontend script.
53
+ */
54
+ public function wp_enqueue_scripts() {
55
+ if ( ! empty( iubenda()->options['cons']['public_api_key'] ) ) {
56
+ wp_register_script( 'iubenda-forms', IUBENDA_PLUGIN_URL . '/js/frontend.js', array( 'jquery' ), iubenda()->version, true );
57
+
58
+ $args = array();
59
+
60
+ $form_args = array(
61
+ 'post_status' => array( 'mapped', 'needs_update' )
62
+ );
63
+
64
+ $forms = iubenda()->forms->get_forms( $form_args );
65
+
66
+ if ( ! empty( $forms ) ) {
67
+ // required form parameters
68
+ $form_parameters = array(
69
+ 'subject',
70
+ 'preferences',
71
+ 'exclude',
72
+ 'legal_notices'
73
+ );
74
+ // loop through forms
75
+ foreach ( $forms as $form ) {
76
+ // bail if user is logged in and source is WP comment form
77
+ if ( $form->form_source == 'wp_comment_form' && is_user_logged_in() )
78
+ continue;
79
+
80
+ // we need unique identifier for the html form
81
+ // by default it's object id, used in form html id
82
+ $args[$form->form_source][$form->object_id] = array();
83
+
84
+ foreach ( $form_parameters as $parameter ) {
85
+ $parameter_name = 'form_' . $parameter;
86
+ $parameter_value = ! empty( $form->$parameter_name ) ? $form->$parameter_name : '';
87
+
88
+ switch ( $parameter ) {
89
+ case 'legal_notices' :
90
+ if ( $parameter_value && is_array( $parameter_value ) ) {
91
+ foreach( $parameter_value as $value ) {
92
+ $args[$form->form_source][$form->object_id]['consent']['legal_notices'][] = array( 'identifier' => $value );
93
+ }
94
+ }
95
+ break;
96
+ default :
97
+ if ( $parameter_value )
98
+ $args[$form->form_source][$form->object_id]['form']['map'][$parameter] = $parameter_value;
99
+ break;
100
+ }
101
+ }
102
+ }
103
+ }
104
+
105
+ // echo '<pre>'; print_r( json_encode( $args ) ); echo '</pre>'; exit;
106
+
107
+ wp_localize_script(
108
+ 'iubenda-forms',
109
+ 'iubForms',
110
+ json_encode( $args )
111
+ );
112
+
113
+ wp_enqueue_script( 'iubenda-forms' );
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Register iubenda form post type.
119
+ */
120
+ public function register_post_type() {
121
+ register_post_type( 'iubenda_form', array(
122
+ 'labels' => array(
123
+ 'name' => __( 'Forms', 'iubenda' ),
124
+ 'singular_name' => __( 'Form', 'iubenda' ),
125
+ ),
126
+ 'rewrite' => false,
127
+ 'query_var' => false,
128
+ 'public' => false,
129
+ 'capability_type' => 'page'
130
+ ) );
131
+ }
132
+
133
+ /**
134
+ * Register iubenda form post status.
135
+ */
136
+ public function register_post_status() {
137
+ foreach ( $this->statuses as $name => $label ) {
138
+ if ( $name === 'publish' )
139
+ continue;
140
+
141
+ register_post_status( $name, array(
142
+ 'label' => $label,
143
+ 'public' => true,
144
+ 'exclude_from_search' => false,
145
+ 'show_in_admin_all_list' => true,
146
+ 'show_in_admin_status_list' => true,
147
+ 'post_type' => array( 'iubenda_form' ),
148
+ // 'label_count' => _n_noop( 'Mapped <span class="count">(%s)</span>', 'Mapped <span class="count">(%s)</span>', 'iubenda' ),
149
+ ) );
150
+ }
151
+
152
+ }
153
+
154
+ /**
155
+ * Get iubenda forms function.
156
+ *
157
+ * @param type $args
158
+ * @return array
159
+ */
160
+ public function get_forms( $args = array() ) {
161
+ $defaults = array(
162
+ 'post_status' => 'any',
163
+ 'posts_per_page' => -1,
164
+ 'offset' => 0,
165
+ 'orderby' => 'ID',
166
+ 'order' => 'ASC',
167
+ 'form_source' => 'any'
168
+ );
169
+
170
+ $args = wp_parse_args( $args, $defaults );
171
+
172
+ $args['post_type'] = 'iubenda_form';
173
+
174
+ // specific sources only
175
+ if ( $args['form_source'] != 'any' && ( is_string( $args['form_source'] ) || is_array( $args['form_source'] ) ) ) {
176
+ $args['meta_query'] = array(
177
+ array(
178
+ 'key' => '_iub_form_source',
179
+ 'value' => $args['form_source'],
180
+ 'compare' => 'IN',
181
+ ),
182
+ );
183
+ }
184
+
185
+ $q = new WP_Query();
186
+
187
+ $posts = $q->query( $args );
188
+
189
+ $metakeys = array(
190
+ 'form_source',
191
+ 'object_type',
192
+ 'object_id',
193
+ 'form_fields',
194
+ 'form_subject',
195
+ 'form_preferences',
196
+ 'form_exclude',
197
+ 'form_legal_notices'
198
+ );
199
+
200
+ if ( ! empty( $posts ) ) {
201
+ foreach ( $posts as $index => $post ) {
202
+ // get form data
203
+ $metadata_raw = get_metadata( 'post', $post->ID );
204
+
205
+ foreach ( $metakeys as $metakey ) {
206
+ $metadata = ! empty( $metadata_raw['_iub_' . $metakey][0] ) ? maybe_unserialize( $metadata_raw['_iub_' . $metakey][0] ) : '';
207
+
208
+ if ( ! empty( $metadata ) ) {
209
+ // unset empty values
210
+ if ( is_array( $metadata ) ) {
211
+ foreach ( $metadata as $metadata_key => $metadata_value ) {
212
+ if ( empty( $metadata_value ) && ! in_array( $metakey, array( 'form_legal_notices' ) ) )
213
+ unset( $metadata[$metadata_key] );
214
+ }
215
+ }
216
+
217
+ $posts[$index]->{$metakey} = $metadata;
218
+ }
219
+ /* object id needs to ba an integer
220
+ } elseif ( in_array( $metakey, array( 'object_id' ) ) ) {
221
+ $posts[$index]->{$metakey} = ! empty( $metadata ) ? absint( $metadata ) : 0;
222
+ }
223
+ */
224
+ }
225
+ }
226
+ }
227
+
228
+ return $posts;
229
+ }
230
+
231
+ /**
232
+ * Get form function.
233
+ *
234
+ * @param int
235
+ * @return object
236
+ */
237
+ public function get_form( $id ) {
238
+ $form_id = ! empty( $id ) ? absint( $id ) : 0;
239
+
240
+ if ( ! $form_id )
241
+ return false;
242
+
243
+ $form = get_post( $form_id );
244
+
245
+ if ( ! $form )
246
+ return false;
247
+
248
+ $metakeys = array(
249
+ 'form_source',
250
+ 'object_type',
251
+ 'object_id',
252
+ 'form_fields',
253
+ 'form_subject',
254
+ 'form_preferences',
255
+ 'form_exclude',
256
+ 'form_legal_notices'
257
+ );
258
+
259
+ // get form data
260
+ $metadata = get_metadata( 'post', $form->ID );
261
+
262
+ foreach ( $metakeys as $metakey ) {
263
+ $form->{$metakey} = ! empty( $metadata['_iub_' . $metakey][0] ) ? maybe_unserialize( $metadata['_iub_' . $metakey][0] ) : '';
264
+ }
265
+
266
+ return $form;
267
+ }
268
+
269
+ /**
270
+ * Delete form function.
271
+ *
272
+ * @param int
273
+ * @return int
274
+ */
275
+ public function delete_form( $id ) {
276
+ $form_id = ! empty( $id ) ? absint( $id ) : 0;
277
+
278
+ if ( ! $form_id )
279
+ return false;
280
+
281
+ $form = get_post( $form_id );
282
+
283
+ if ( ! $form )
284
+ return false;
285
+
286
+ $result = wp_delete_post( $id, true );
287
+
288
+ return $result;
289
+ }
290
+
291
+ /**
292
+ * Insert form function.
293
+ *
294
+ * @param array $args
295
+ * @return int
296
+ */
297
+ public function save_form( $args = array() ) {
298
+ $defaults = array(
299
+ 'ID' => 0,
300
+ 'status' => 'publish',
301
+ 'object_type' => 'post', // object type where the form data is stored
302
+ 'object_id' => 0, // unique object id
303
+ 'form_source' => '', // source slug
304
+ 'form_title' => '', // form title
305
+ 'form_date' => current_time( 'mysql' ), // form last modified date
306
+ 'form_fields' => array(), // form field names array
307
+ 'form_subject' => array(), // mapped form with iubenda consent subject param
308
+ 'form_preferences' => array(), // mapped form with iubenda consent preferences param
309
+ 'form_exclude' => array(), // mapped form with iubenda consent exclude param
310
+ 'form_legal_notices' => array() // form legal notices
311
+ );
312
+
313
+ $args = wp_parse_args( $args, $defaults );
314
+
315
+ // sanitize args
316
+ $args['ID'] = ! empty( $args['ID'] ) ? (int) $args['ID'] : 0;
317
+ $args['status'] = ! empty( $args['status'] ) && in_array( $args['status'], array_keys( $this->statuses ) ) ? $args['status'] : 'publish';
318
+ $args['object_type'] = 'post';
319
+ $args['object_id'] = ! empty( $args['object_id'] ) ? (int) $args['object_id'] : 0;
320
+ $args['form_source'] = ! empty( $args['form_source'] ) && in_array( $args['form_source'], array_keys( $this->sources ) ) ? $args['form_source'] : '';
321
+ $args['form_title'] = ! empty( $args['form_title'] ) ? esc_html( $args['form_title'] ) : '';
322
+ $args['form_date'] = date( 'Y-m-d H:i:s', ( ! empty( $args['form_date'] ) ? strtotime( $args['form_date'] ) : current_time( 'mysql' ) ) );
323
+ $args['form_fields'] = ! empty( $args['form_fields'] ) && is_array( $args['form_fields'] ) ? array_map( 'esc_attr', $args['form_fields'] ) : array();
324
+ $args['form_subject'] = ! empty( $args['form_subject'] ) && is_array( $args['form_subject'] ) ? array_map( 'esc_attr', $args['form_subject'] ) : array();
325
+ $args['form_preferences'] = ! empty( $args['form_preferences'] ) && is_array( $args['form_preferences'] ) ? array_map( 'esc_attr', $args['form_preferences'] ) : array();
326
+ $args['form_exclude'] = ! empty( $args['form_exclude'] ) && is_array( $args['form_exclude'] ) ? array_map( 'esc_attr', $args['form_exclude'] ) : array();
327
+ $args['form_legal_notices'] = ! empty( $args['form_legal_notices'] ) && is_array( $args['form_legal_notices'] ) ? array_map( 'esc_attr', $args['form_legal_notices'] ) : array();
328
+
329
+ // bail if any issues
330
+ if ( ! $args['form_source'] || ! $args['form_fields'] )
331
+ return false;
332
+
333
+ $post = get_post( (int) $args['ID'] );
334
+ $update = ! $post ? false : true;
335
+
336
+ // insert new form
337
+ if ( ! $update ) {
338
+ $post_id = wp_insert_post( array(
339
+ 'post_type' => 'iubenda_form',
340
+ 'post_status' => $args['status'],
341
+ 'post_title' => $args['form_title'],
342
+ 'post_content' => '',
343
+ 'post_date' => $args['form_date'],
344
+ 'post_modified' => $args['form_date']
345
+ ) );
346
+ // update form
347
+ } else {
348
+ $post_id = wp_update_post( array(
349
+ 'ID' => $args['ID'],
350
+ 'post_status' => $args['status'],
351
+ 'post_modified' => $args['form_date']
352
+ ) );
353
+ }
354
+
355
+ // save form source
356
+ if ( isset( $args['form_source'] ) )
357
+ update_post_meta( $post_id, '_iub_form_source', $args['form_source'] );
358
+
359
+ // save object type
360
+ if ( isset( $args['object_type'] ) )
361
+ update_post_meta( $post_id, '_iub_object_type', $args['object_type'] );
362
+
363
+ // save object id
364
+ if ( isset( $args['object_id'] ) )
365
+ update_post_meta( $post_id, '_iub_object_id', absint( $args['object_id'] ) );
366
+
367
+ // save form fields
368
+ if ( isset( $args['form_fields'] ) )
369
+ update_post_meta( $post_id, '_iub_form_fields', $args['form_fields'] );
370
+
371
+ // save form subject
372
+ if ( isset( $args['form_subject'] ) )
373
+ update_post_meta( $post_id, '_iub_form_subject', $args['form_subject'] );
374
+
375
+ // save form preferences
376
+ if ( isset( $args['form_preferences'] ) )
377
+ update_post_meta( $post_id, '_iub_form_preferences', $args['form_preferences'] );
378
+
379
+ // save form exclude
380
+ if ( isset( $args['form_exclude'] ) )
381
+ update_post_meta( $post_id, '_iub_form_exclude', $args['form_exclude'] );
382
+
383
+ // save legal notices
384
+ if ( isset( $args['form_legal_notices'] ) )
385
+ update_post_meta( $post_id, '_iub_form_legal_notices', $args['form_legal_notices'] );
386
+
387
+ return $post_id;
388
+ }
389
+
390
+ /**
391
+ * Autodetect forms action.
392
+ *
393
+ * @return bool
394
+ */
395
+ public function autodetect_forms() {
396
+ $found_forms = $new_forms = array();
397
+
398
+ // get forms from active sources
399
+ if ( ! empty( $this->sources ) ) {
400
+ foreach ( $this->sources as $source => $source_name ) {
401
+ $found_forms[$source] = call_user_func( array( $this, 'get_source_forms' ), $source );
402
+ }
403
+ }
404
+
405
+ // insert forms
406
+ if ( ! empty( $found_forms ) ) {
407
+ foreach ( $found_forms as $source => $source_forms ) {
408
+ if ( ! empty( $source_forms ) ) {
409
+
410
+ foreach ( $source_forms as $formdata ) {
411
+
412
+ $exists = $this->get_form_by_object_id( array(
413
+ 'id' => $formdata['object_id'],
414
+ 'source' => $formdata['form_source']
415
+ ) );
416
+
417
+ // form does not exist
418
+ if ( ! $exists ) {
419
+ $result = $this->save_form( $formdata );
420
+
421
+ if ( $result )
422
+ $new_forms['new'] = $result;
423
+ } else {
424
+ // check for fields changes
425
+ $new_fields = array_merge( array_diff( $formdata['form_fields'], $exists->form_fields ), array_diff( $exists->form_fields, $formdata['form_fields'] ) );
426
+
427
+ if ( $new_fields ) {
428
+ $new_forms['updated'] = $exists->ID;
429
+
430
+ // update form
431
+ $formdata['ID'] = $exists->ID;
432
+
433
+ // update to need status if form is already mapped
434
+ if ( $exists->post_status == 'mapped' )
435
+ $formdata['status'] = 'needs_update';
436
+
437
+ // echo '<pre>'; print_r( $formdata ); echo '</pre>'; exit;
438
+
439
+ $result = $this->save_form( $formdata );
440
+ }
441
+ }
442
+ }
443
+ }
444
+ }
445
+ }
446
+
447
+ // echo '<pre>'; print_r( $found_forms ); echo '</pre>'; exit;
448
+
449
+ return ! empty( $new_forms ) ? $new_forms : array();
450
+ }
451
+
452
+ /**
453
+ * Get source forms.
454
+ *
455
+ * @param string
456
+ * @return array
457
+ */
458
+ public function get_source_forms( $source = '' ) {
459
+ $source = ! empty( $source ) && in_array( $source, array_keys( $this->sources ) ) ? $source : '';
460
+ $forms = array();
461
+
462
+ $restricted_fields = apply_filters( "iub_{$source}_restricted_fields", array(
463
+ 'submit',
464
+ 'file',
465
+ 'quiz'
466
+ ) );
467
+
468
+ switch ( $source ) {
469
+ case 'wpcf7' :
470
+ $args = array(
471
+ 'post_type' => 'wpcf7_contact_form',
472
+ 'posts_per_page' => -1
473
+ );
474
+ $posts = get_posts( $args );
475
+
476
+ if ( ! empty( $posts ) ) {
477
+ foreach ( $posts as $post ) {
478
+ // get form data
479
+ $contact_form = class_exists( 'WPCF7_ContactForm' ) ? WPCF7_ContactForm::get_instance( $post->ID ) : false;
480
+
481
+ if ( ! empty( $contact_form ) ) {
482
+ $formdata = array(
483
+ 'object_type' => 'post', // object type where the form data is stored
484
+ 'object_id' => $post->ID, // unique object id
485
+ 'form_source' => $source, // source slug
486
+ 'form_title' => $post->post_title, // form title
487
+ 'form_date' => $post->post_modified, // form last modified date
488
+ 'form_fields' => array() // form field names array
489
+ );
490
+
491
+ $fields_raw = $contact_form->scan_form_tags();
492
+
493
+ // echo '<pre>'; print_r( $fields_raw ); echo '</pre>'; exit;
494
+
495
+ if ( ! empty( $fields_raw ) ) {
496
+ foreach ( $fields_raw as $field ) {
497
+ // specific field types only
498
+ if ( ! empty( $field['basetype'] ) && ! in_array( $field['basetype'], $restricted_fields ) ) {
499
+ $formdata['form_fields'][] = $field['name'];
500
+ }
501
+ }
502
+ }
503
+
504
+ $forms[] = $formdata;
505
+ }
506
+
507
+ // echo '<pre>'; print_r( $contact_form ); echo '</pre>'; exit;
508
+ }
509
+ }
510
+
511
+ break;
512
+
513
+ case 'wp_comment_form' :
514
+ $comment_form = '';
515
+
516
+ // get comment form for logged out user
517
+ $current_user_id = get_current_user_id();
518
+
519
+ // get first post
520
+ $post_args = array(
521
+ 'numberposts' => 1,
522
+ 'orderby' => 'ID',
523
+ 'order' => 'ASC',
524
+ 'fields' => 'ids'
525
+ );
526
+
527
+ $posts = get_posts( $post_args );
528
+
529
+ // get comment form
530
+ if ( ! empty( $posts ) ) {
531
+ wp_set_current_user( 0 );
532
+
533
+ ob_start();
534
+
535
+ comment_form( array(), $posts[0] );
536
+
537
+ $comment_form = ob_get_contents();
538
+ ob_end_clean();
539
+
540
+ wp_set_current_user( $current_user_id );
541
+ }
542
+
543
+ if ( ! empty( $comment_form ) ) {
544
+ $formdata = array(
545
+ 'object_type' => 'custom', // object type where the form data is stored
546
+ 'object_id' => 0, // unique object id
547
+ 'form_source' => $source, // source slug
548
+ 'form_title' => $this->sources[$source], // form title
549
+ 'form_date' => current_time( 'mysql' ), // form last modified date
550
+ 'form_fields' => array() // form field names array
551
+ );
552
+
553
+ $input_fields = array(
554
+ 'input',
555
+ 'textarea',
556
+ 'select'
557
+ );
558
+
559
+ // DOMDoc parser
560
+ if ( iubenda()->options['cs']['parser_engine'] == 'new' ) {
561
+ libxml_use_internal_errors( true );
562
+
563
+ $document = new DOMDocument();
564
+
565
+ // set document arguments
566
+ $document->formatOutput = true;
567
+ $document->preserveWhiteSpace = false;
568
+
569
+ // load HTML
570
+ $document->loadHTML( $comment_form );
571
+
572
+ // search for nodes
573
+ foreach ( $input_fields as $input_field ) {
574
+ $fields_raw = $document->getElementsByTagName( $input_field );
575
+
576
+ if ( ! empty( $fields_raw ) && is_object( $fields_raw ) ) {
577
+ foreach ( $fields_raw as $field ) {
578
+ $field_name = $field->getAttribute( 'name' );
579
+ $field_type = $field->getAttribute( 'type' );
580
+
581
+ // exclude submit
582
+ if ( ! empty( $field_type ) && ! in_array( $field_type, array( 'submit' ) ) )
583
+ $formdata['form_fields'][] = $field->getAttribute( 'name' );
584
+ }
585
+ }
586
+ }
587
+
588
+ $forms[] = $formdata;
589
+
590
+ libxml_use_internal_errors( false );
591
+
592
+ // Simple HTML Dom parser
593
+ } else {
594
+ $html = str_get_html( $comment_form, $lowercase = true, $force_tags_closed = true, $strip = false );
595
+
596
+ if ( is_object( $html ) ) {
597
+ // search for nodes
598
+ foreach ( $input_fields as $input_field ) {
599
+ $fields_raw = $html->find( $input_field );
600
+
601
+ if ( is_array( $fields_raw ) ) {
602
+ foreach ( $fields_raw as $field ) {
603
+ $field_name = $field->name;
604
+ $field_type = $field->type;
605
+
606
+ // exclude submit
607
+ if ( ! empty( $field_type ) && ! in_array( $field_type, array( 'submit' ) ) )
608
+ $formdata['form_fields'][] = $field->getAttribute( 'name' );
609
+ }
610
+ }
611
+ }
612
+
613
+ $forms[] = $formdata;
614
+
615
+ }
616
+ }
617
+ }
618
+
619
+ break;
620
+ }
621
+
622
+ return $forms;
623
+ }
624
+
625
+ /**
626
+ * Get Post object by post_meta query
627
+ *
628
+ * @return array
629
+ */
630
+ public function get_form_by_object_id( $args = array() ) {
631
+ // parse incoming $args into an array and merge it with $defaults
632
+ $args = wp_parse_args( $args );
633
+
634
+ // grab page
635
+ $args = array(
636
+ 'meta_query' => array(
637
+ array(
638
+ 'key' => '_iub_object_id',
639
+ 'value' => $args['id'],
640
+ ),
641
+ array(
642
+ 'key' => '_iub_form_source',
643
+ 'value' => $args['source'],
644
+ )
645
+ ),
646
+ 'post_type' => 'iubenda_form',
647
+ 'post_status' => 'any',
648
+ 'posts_per_page' => '1',
649
+ 'fields' => 'ids'
650
+ );
651
+
652
+ // run query
653
+ $posts = get_posts( $args );
654
+
655
+ // check result
656
+ if ( ! $posts || is_wp_error( $posts ) )
657
+ return false;
658
+
659
+ $form = $this->get_form( $posts[0] );
660
+
661
+ // kick back results
662
+ return $form;
663
+ }
664
+
665
+ }
includes/settings.php ADDED
@@ -0,0 +1,1319 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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' ) );
26
+ add_action( 'admin_menu', array( $this, 'admin_menu_options' ) );
27
+ add_action( 'admin_notices', array( $this, 'settings_errors' ) );
28
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
29
+ add_action( 'admin_print_styles', array( $this, 'admin_print_styles' ) );
30
+ // add_action( 'admin_footer-options-discussion.php', array( $this, 'admin_footer' ) );
31
+
32
+ // filters
33
+ add_filter( 'submenu_file', array( $this, 'submenu_file' ), 10, 2 );
34
+ }
35
+
36
+ /**
37
+ * Load default settings.
38
+ */
39
+ public function load_defaults() {
40
+ $this->subject_fields = array(
41
+ 'id' => __( 'string', 'iubenda' ),
42
+ 'email' => __( 'string', 'iubenda' ),
43
+ 'first_name' => __( 'string', 'iubenda' ),
44
+ 'last_name' => __( 'string', 'iubenda' ),
45
+ 'full_name' => __( 'string', 'iubenda' ),
46
+ // 'verified' => __( 'boolean', 'iubenda' ),
47
+ );
48
+
49
+ $this->legal_notices = array(
50
+ 'privacy_policy',
51
+ 'cookie_policy',
52
+ 'terms'
53
+ );
54
+
55
+ $this->tabs = array(
56
+ 'cs' => array(
57
+ 'name' => __( 'Cookie Solution', 'iubenda' ),
58
+ 'key' => 'iubenda_cookie_law_solution',
59
+ 'submit' => 'save_iubenda_options',
60
+ 'reset' => 'reset_iubenda_options'
61
+ ),
62
+ 'cons' => array(
63
+ 'name' => __( 'Consent Solution', 'iubenda' ),
64
+ 'key' => 'iubenda_consent_solution',
65
+ 'submit' => 'save_consent_options',
66
+ 'reset' => 'reset_consent_options'
67
+ )
68
+ );
69
+
70
+ $links = array(
71
+ 'en' => array(
72
+ 'guide' => 'https://www.iubenda.com/en/iubenda-cookie-law-solution',
73
+ 'plugin_page' => 'https://www.iubenda.com/en/help/posts/1215',
74
+ 'generating_code' => 'https://www.iubenda.com/en/help/posts/1177',
75
+ 'support_forum' => 'https://support.iubenda.com/support/home',
76
+ 'documentation' => 'https://www.iubenda.com/en/help/posts/1215'
77
+ ),
78
+ 'it' => array(
79
+ 'guide' => 'https://www.iubenda.com/it/soluzione-cookie-law',
80
+ 'plugin_page' => 'https://www.iubenda.com/it/help/posts/810',
81
+ 'generating_code' => 'https://www.iubenda.com/it/help/posts/680',
82
+ 'support_forum' => 'https://support.iubenda.com/support/home',
83
+ 'documentation' => 'https://www.iubenda.com/it/help/posts/810',
84
+ )
85
+ );
86
+
87
+ $locale = explode( '_', get_locale() );
88
+ $locale_code = $locale[0];
89
+
90
+ // assign links
91
+ $this->links = in_array( $locale_code, array_keys( $links ) ) ? $links[$locale_code] : $links['en'];
92
+
93
+ // handle actions
94
+ if ( ! empty( $_POST['save'] ) ) {
95
+ // update item action
96
+ $this->action = 'save';
97
+ } else {
98
+ $this->action = isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] ? esc_attr( $_REQUEST['action'] ) : '';
99
+ $this->action = isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] ? esc_attr( $_REQUEST['action2'] ) : $this->action;
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Register plugin options.
105
+ *
106
+ * @return void
107
+ */
108
+ public function register_options() {
109
+ register_setting( 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution', array( $this, 'save_cookie_law_options' ) );
110
+
111
+ add_settings_section( 'iubenda_cookie_law_solution', '', '', 'iubenda_cookie_law_solution' );
112
+ add_settings_field( 'iub_code', __( 'Code', 'iubenda' ), array( $this, 'iub_code' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
113
+ add_settings_field( 'iub_parse', __( 'Scripts blocking', 'iubenda' ), array( $this, 'iub_parse' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
114
+ add_settings_field( 'iub_custom_scripts', __( 'Custom scripts', 'iubenda' ), array( $this, 'iub_custom_scripts' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
115
+ add_settings_field( 'iub_ctype', __( 'Content type', 'iubenda' ), array( $this, 'iub_ctype' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
116
+ add_settings_field( 'iub_output_feed', __( 'RSS feed', 'iubenda' ), array( $this, 'iub_output_feed' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
117
+ add_settings_field( 'iub_menu_position', __( 'Menu position', 'iubenda' ), array( $this, 'iub_menu_position' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
118
+ add_settings_field( 'iub_deactivation', __( 'Deactivation', 'iubenda' ), array( $this, 'iub_deactivation' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
119
+
120
+ // forms list
121
+ if ( ! in_array( $this->action, array( 'save', 'edit' ) ) ) {
122
+ register_setting( 'iubenda_consent_solution', 'iubenda_consent_solution', array( $this, 'save_consent_options' ) );
123
+ add_settings_section( 'iubenda_consent_solution', __( 'Forms', 'iubenda' ), '', 'iubenda_consent_solution' );
124
+ add_settings_field( 'iub_public_api_key', __( 'Public Api Key', 'iubenda' ), array( $this, 'iub_public_api_key' ), 'iubenda_consent_solution', 'iubenda_consent_solution' );
125
+ // only if api key is given
126
+ if ( ! empty( iubenda()->options['cons']['public_api_key'] ) )
127
+ add_settings_section( 'iubenda_consent_forms', __( 'Fields Mapping', 'iubenda' ), array( $this, 'iubenda_consent_forms' ), 'iubenda_consent_solution' );
128
+ // single form
129
+ } else {
130
+ register_setting( 'iubenda_consent_solution', 'iubenda_consent_forms' );
131
+ add_settings_section( 'iubenda_consent_form', __( 'Fields Mapping', 'iubenda' ), array( $this, 'iubenda_consent_form' ), 'iubenda_consent_solution' );
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Display errors and notices.
137
+ *
138
+ * @global string $pagenow
139
+ */
140
+ public function settings_errors() {
141
+ global $pagenow;
142
+
143
+ // force display notices in top menu settings page
144
+ if ( $pagenow == 'options-general.php' )
145
+ return;
146
+
147
+ $tab_key = ! empty( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'cs';
148
+
149
+ settings_errors( "{$tab_key}_settings_errors" );
150
+ }
151
+
152
+ /**
153
+ * Add submenu.
154
+ *
155
+ * @return void
156
+ */
157
+ public function admin_menu_options() {
158
+ if ( iubenda()->options['cs']['menu_position'] === 'submenu' ) {
159
+ // sub menu
160
+ add_submenu_page(
161
+ 'options-general.php', 'iubenda', 'iubenda', apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ), 'iubenda', array( $this, 'options_page' ), 'none'
162
+ );
163
+ } else {
164
+ // top menu
165
+ add_menu_page(
166
+ 'iubenda', 'iubenda', apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ), 'iubenda', array( $this, 'options_page' ), 'none'
167
+ );
168
+ add_submenu_page( 'iubenda', __( 'Cookie Solution', 'iubenda' ), __( 'Cookie Solution', 'iubenda' ), apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ), 'iubenda', array( $this, 'options_page' ) );
169
+ 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' ) );
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Load admin scripts and styles.
175
+ *
176
+ * @param string $page
177
+ * @return void
178
+ */
179
+ public function admin_enqueue_scripts( $page ) {
180
+ if ( ! in_array( $page, array( 'toplevel_page_iubenda', 'settings_page_iubenda' ) ) )
181
+ return;
182
+
183
+ wp_enqueue_script(
184
+ 'iubenda-admin', IUBENDA_PLUGIN_URL . '/js/admin.js', array( 'jquery' )
185
+ );
186
+
187
+ $args = array(
188
+ 'formId' => 0,
189
+ 'deleteForm' => __( 'Are you sure you want to delete this form?', 'iubenda' )
190
+ );
191
+
192
+ // get form data on edit screen
193
+ if ( in_array( $this->action, array( 'edit' ) ) ) {
194
+ $form_id = ! empty( $_GET['form_id'] ) ? absint( $_GET['form_id'] ) : 0;
195
+ $form = ! empty( $form_id ) ? iubenda()->forms->get_form( $form_id ) : array();
196
+
197
+ $args['formId'] = $form_id;
198
+ }
199
+
200
+ wp_localize_script(
201
+ 'iubenda-admin',
202
+ 'iubAdminArgs',
203
+ json_encode( $args )
204
+ );
205
+
206
+ wp_enqueue_style( 'iubenda-admin', IUBENDA_PLUGIN_URL . '/css/admin.css' );
207
+ }
208
+
209
+ /**
210
+ * Load admin style inline, for menu icon only.
211
+ *
212
+ * @return mixed
213
+ */
214
+ public function admin_print_styles() {
215
+ echo '
216
+ <style>
217
+ a.toplevel_page_iubenda .wp-menu-image {
218
+ background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj48c3ZnIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAyMzIgNTAzIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zOnNlcmlmPSJodHRwOi8vd3d3LnNlcmlmLmNvbS8iIHN0eWxlPSJmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6MS40MTQyMTsiPiAgICA8ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDEzNi4yNDcsMjY4LjgzMSkiPiAgICAgICAgPHBhdGggZD0iTTAsLTM1LjgxTC0zNi4zLDAuNDg5TC0zNi4zLDE0MC45NzhMMCwxNDAuOTc4TDAsLTM1LjgxWk0tMjAuOTM4LC0xMjkuODAyQy02LjI4NywtMTI5LjgwMiA1LjU4NywtMTQxLjU2NSA1LjU4NywtMTU2LjA2QzUuNTg3LC0xNzAuNTU2IC02LjI4NywtMTgyLjMwOCAtMjAuOTM4LC0xODIuMzA4Qy0zNS42LC0xODIuMzA4IC00Ny40NzQsLTE3MC41NTYgLTQ3LjQ3NCwtMTU2LjA2Qy00Ny40NzQsLTE0MS41NjUgLTM1LjYsLTEyOS44MDIgLTIwLjkzOCwtMTI5LjgwMk04OS4zNiwtMTU0LjQxNkM4OS4zNiwtMTI3LjgyNSA3OS41NzUsLTEwMy40OTkgNjMuMjY5LC04NC42NzJMODYuNjk0LDIyNi42MjhMLTEyMi43MjgsMjI2LjYyOEwtMTAwLjAyNCwtNzkuMjI5Qy0xMTkuMzUxLC05OC42NjggLTEzMS4yNDcsLTEyNS4xNTkgLTEzMS4yNDcsLTE1NC40MTZDLTEzMS4yNDcsLTIxNC4wODYgLTgxLjg3NCwtMjYyLjQzOCAtMjAuOTM4LC0yNjIuNDM4QzM5Ljk5OSwtMjYyLjQzOCA4OS4zNiwtMjE0LjA4NiA4OS4zNiwtMTU0LjQxNiIgc3R5bGU9ImZpbGw6d2hpdGU7ZmlsbC1ydWxlOm5vbnplcm87Ii8+ICAgIDwvZz48L3N2Zz4=);
219
+ background-position: center center;
220
+ background-repeat: no-repeat;
221
+ background-size: 7px auto;
222
+ }
223
+ </style>
224
+ ';
225
+ }
226
+
227
+ /**
228
+ * Highlight comments cookies opt-in checkbox option.
229
+ *
230
+ * @return mixed
231
+ */
232
+ public function admin_footer() {
233
+ if ( ! empty( $_GET['iub-highlight'] ) ) {
234
+ echo '
235
+ <style>
236
+ label[for=show_comments_cookies_opt_in] {
237
+ border: 1px dashed red;
238
+ }
239
+ </style>
240
+ ';
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Redirect to the correct urle after switching menu position.
246
+ *
247
+ * @global string $pagenow
248
+ * @return void
249
+ */
250
+ public function admin_page_redirect() {
251
+ if ( ! empty( $_GET['settings-updated'] ) && ! empty( $_GET['page'] ) && in_array( $_GET['page'], array( 'iubenda' ) ) ) {
252
+ global $pagenow;
253
+
254
+ // no redirect by default
255
+ $redirect_to = false;
256
+
257
+ if ( iubenda()->options['cs']['menu_position'] === 'submenu' && $pagenow === 'admin.php' ) {
258
+ // sub menu
259
+ $redirect_to = admin_url( 'options-general.php?page=iubenda' );
260
+ } elseif ( iubenda()->options['cs']['menu_position'] === 'topmenu' && $pagenow === 'options-general.php' ) {
261
+ // top menu
262
+ $redirect_to = admin_url( 'admin.php?page=iubenda' );
263
+ }
264
+
265
+ if ( $redirect_to ) {
266
+ // make sure it's current host location
267
+ wp_safe_redirect( add_query_arg( 'settings-updated', true, $redirect_to ) );
268
+ exit;
269
+ }
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Plugin options migration for versions < 1.14.0
275
+ *
276
+ * @return void
277
+ */
278
+ public function update_plugin() {
279
+ if ( ! current_user_can( 'install_plugins' ) )
280
+ return;
281
+
282
+ $db_version = get_option( 'iubenda_cookie_law_version' );
283
+ $db_version = ! $db_version ? '1.13.0' : $db_version;
284
+
285
+ if ( $db_version != false ) {
286
+ if ( version_compare( $db_version, '1.14.0', '<' ) ) {
287
+ $options = array();
288
+
289
+ $old_new = array(
290
+ 'iubenda_parse' => 'parse',
291
+ 'skip_parsing' => 'skip_parsing',
292
+ 'iubenda_ctype' => 'ctype',
293
+ 'iubenda_parse' => 'parse',
294
+ 'parser_engine' => 'parser_engine',
295
+ 'iubenda_output_feed' => 'output_feed',
296
+ 'iubenda-code-default' => 'code_default',
297
+ 'default_skip_parsing' => '',
298
+ 'default_iubendactype' => '',
299
+ 'default_iubendaparse' => '',
300
+ 'default_parser_engine' => '',
301
+ 'iub_code' => '',
302
+ );
303
+
304
+ foreach ( $old_new as $old => $new ) {
305
+ if ( $new ) {
306
+ $options[$new] = get_option( $old );
307
+ }
308
+ delete_option( $old );
309
+ }
310
+
311
+ // multilang support
312
+ if ( ! empty( iubenda()->languages ) ) {
313
+ foreach ( iubenda()->languages as $lang ) {
314
+ $code = get_option( 'iubenda-code-' . $lang );
315
+
316
+ if ( ! empty( $code ) ) {
317
+ $options['code_' . $lang] = $code;
318
+
319
+ delete_option( 'iubenda-code-' . $lang );
320
+ }
321
+ }
322
+ }
323
+
324
+ add_option( 'iubenda_cookie_law_solution', $options, '', 'no' );
325
+ add_option( 'iubenda_cookie_law_version', iubenda()->version, '', 'no' );
326
+ }
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Load admin options page.
332
+ *
333
+ * @return void
334
+ */
335
+ public function options_page() {
336
+ if ( ! current_user_can( apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ) ) ) {
337
+ wp_die( __( "You don't have permission to access this page.", 'iubenda' ) );
338
+ }
339
+
340
+ $tab_key = ! empty( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'cs';
341
+ ?>
342
+ <div class="wrap">
343
+
344
+ <div id="iubenda-header">
345
+ <?php
346
+ echo '
347
+ <a class="iubenda-link" href="http://iubenda.com" title="iubenda" title="_blank">
348
+ <img id="iubenda-logo" alt="iubenda logo" width="300" height="90" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNjM3LjggMjgzLjUiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDYzNy44IDI4My41OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHN0eWxlIHR5cGU9InRleHQvY3NzIj4uc3Qwe2ZpbGw6IzFDQzY5MTt9LnN0MXtmaWxsOiM1MTUyNTQ7fTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MCIgZD0iTTE3OC45LDk5LjljMCw4LjItMywxNS42LTgsMjEuNGw3LjIsOTUuNGgtNjQuMmw3LTkzLjhjLTUuOS02LTkuNi0xNC4xLTkuNi0yMy4xYzAtMTguMywxNS4xLTMzLjEsMzMuOC0zMy4xUzE3OC45LDgxLjYsMTc4LjksOTkuOSBNMTQ1LjEsMTA3LjRjNC41LDAsOC4xLTMuNiw4LjEtOC4xcy0zLjYtOC04LjEtOGMtNC41LDAtOC4xLDMuNi04LjEsOFMxNDAuNiwxMDcuNCwxNDUuMSwxMDcuNCBNMTUxLjUsMTM2LjJsLTExLjEsMTEuMXY0My4xaDExLjFWMTM2LjJ6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTI2NS40LDE3OC42Yy0yLjMsMS4yLTQuNywxLjgtNy4yLDEuOGMtMi44LDAtNS4zLTAuOC03LjQtMi40Yy0yLjEtMS42LTMuNS0zLjctNC4zLTYuMmMtMC44LTIuNS0xLjItNi4xLTEuMi0xMC44di0xOC4yYzAsMCwwLTAuOSwwLTIuOGMwLTAuNSwwLTIuOC0xLjUtMy41Yy0wLjItMC4xLTAuNi0wLjItMS4yLTAuM2MtMC40LDAtMC44LTAuNC0wLjgtMC44bDAtMi40YzAtMC41LDAuNC0wLjksMC44LTAuOWg5LjNjMS4zLDAsMi40LDEuMSwyLjQsMi40VjE0N2wwLDE1LjVjMCw0LjYsMC44LDcuNywyLjUsOS4xYzEuNiwxLjUsMy42LDIuMiw1LjksMi4yYzEuNiwwLDMuNC0wLjUsNS40LTEuNWMyLTEsNS4zLTIuOCw4LjEtNS42bDAtMi40bDAtMjIuMlYxNDBjMC0wLjUsMC0yLjgtMS40LTMuNWMtMC4yLTAuMS0wLjYtMC4yLTEuMS0wLjNjLTAuNC0wLjEtMC44LTAuNC0wLjgtMC44bDAtMi40YzAtMC41LDAuNC0wLjksMC45LTAuOWg5LjJjMS4zLDAsMi40LDEuMSwyLjQsMi40djhjMCwwLjEsMCwwLjEsMCwwLjJ2MTYuNmMwLDMuOCwwLDcuNCwwLDEwLjZjMCwwLjcsMCwxLjIsMCwxLjJjMCwwLjUtMC4xLDMuMSwxLjQsMy44YzAuMiwwLjEsMC42LDAuMiwxLjIsMC4zYzAuNCwwLDAuOCwwLjQsMC44LDAuOGwwLDIuNGMwLDAuNS0wLjQsMC44LTAuOSwwLjloLTkuMmMtMS4zLDAtMi40LTEuMS0yLjQtMi40bDAtNC41bDAtMi41QzI3MS45LDE3NC41LDI2Ny43LDE3Ny40LDI2NS40LDE3OC42Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTMwOS4yLDE3NmMxLjksMC45LDMuOSwxLjMsNiwxLjNjMy4yLDAsNi4zLTEuNyw5LTUuMmMyLjgtMy41LDQuMi04LjUsNC4yLTE1LjJjMC02LjEtMS40LTEwLjgtNC4yLTE0LjFjLTIuOC0zLjMtNi00LjktOS41LTQuOWMtMS45LDAtMy44LDAuNS01LjcsMS40Yy0xLjIsMC42LTIuOCwxLjgtNC43LDMuNGMtMC41LDAuNS0wLjgsMS4xLTAuOCwxLjhWMTcxYzAsMC43LDAuMywxLjQsMC44LDEuOEMzMDYsMTc0LjIsMzA3LjYsMTc1LjMsMzA5LjIsMTc2IE0yOTQuOCwxMThjMC0wLjUsMC0yLjctMS40LTMuNGMtMC4yLTAuMS0wLjMtMC4xLTAuNi0wLjJjLTAuNC0wLjEtMC42LTAuNC0wLjYtMC44bDAtMi4zYzAtMC41LDAuNC0wLjgsMC45LTAuOWgxLjhoNi41YzEuMywwLDIuMywxLDIuMywyLjNsMCwxMnYxNS40YzQuNy02LjQsOS44LTkuNiwxNS4zLTkuNmM1LDAsOS40LDIuMSwxMy4xLDYuM2MzLjcsNC4yLDUuNiw5LjksNS42LDE3LjJjMCw4LjUtMi45LDE1LjMtOC42LDIwLjVjLTQuOSw0LjQtMTAuNSw2LjctMTYuNSw2LjdjLTIuOCwwLTUuNy0wLjUtOC43LTEuNWMtMi41LTAuOS01LjEtMi4xLTcuNy0zLjdjLTAuOC0wLjUtMS4zLTEuNC0xLjMtMi40di00NmMwLTAuOSwwLTIsMC0zLjNMMjk0LjgsMTE4eiIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0zODkuMywxNzkuMWMtMC41LDAtMC45LTAuNC0wLjktMC45bDAtMi4zYzAtMC40LDAuMy0wLjgsMC43LTAuOGMwLjUtMC4xLDAuOC0wLjEsMS0wLjJjMS40LTAuNywxLjQtMi45LDEuNC0zLjR2LTIuN2MwLDAsMC01LjgsMC0xNy41YzAtMS45LDAtMy44LDAuMS01LjVsMC00LjZjMC0wLjUsMC0xLDAtMS41YzAtMC42LDAtMi44LTEuNC0zLjVjLTAuMS0wLjEtMC4zLTAuMS0wLjUtMC4yYy0wLjQtMC4xLTAuNi0wLjQtMC42LTAuOGwwLTIuM2MwLTAuNSwwLjQtMC44LDAuOS0wLjloOC4xYzEuMywwLDIuMywxLDIuMywyLjN2My40YzAsMCwwLDAuNiwwLDEuOGMwLDAuMywwLjIsMC42LDAuNiwwLjZjMC4yLDAsMC4zLTAuMSwwLjQtMC4yYzUuNC01LjksMTIuMy04LjgsMTcuMi04LjhjMi43LDAsNSwwLjYsNi45LDEuOWMxLjksMS4zLDMuNCwzLjQsNC42LDYuM2MwLjgsMi4xLDEuMiw1LjIsMS4yLDkuNHYxNi41bDAsNi4zYzAsMC41LDAsMi43LDEuNCwzLjRjMC4yLDAuMSwwLjQsMC4yLDAuOCwwLjJjMC40LDAuMSwwLjcsMC40LDAuNywwLjhsMCwyLjNjMCwwLjUtMC40LDAuOC0wLjgsMC45Yy0wLjgsMC0xLjUsMC0yLDBoLTYuNWMtMC4xLDAtMC4zLDAtMC40LDBoLTMuMWMtMS4xLDAtMi0wLjktMi0yYzAtMSwwLjctMS45LDEuNi0yLjJjMC4xLDAsMC4xLDAsMC4yLTAuMWMxLTAuNSwxLjMtMS44LDEuNC0yLjd2LTcuNGwwLTE1LjJjMC00LjMtMC42LTcuNC0xLjctOS4zYy0xLjItMS45LTMuMS0yLjktNS44LTIuOWMtNC4yLDAtMTAuMywyLjItMTQuNCw2Ljd2MjAuOHYwLjNsMCw2LjRjMCwwLjUsMCwyLjgsMS40LDMuNWMwLjEsMCwwLjEsMCwwLjIsMC4xYzEsMC4zLDEuNiwxLjIsMS42LDIuMmMwLDEuMS0wLjksMi0yLDJIMzk0QzM5NCwxNzkuMSwzOTIuNCwxNzkuMSwzODkuMywxNzkuMSIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik01MTUsMTUzLjRjLTYuNiwxLjMtMTAuNCwyLjItMTEuNCwyLjVjLTMuNywxLjItNi42LDIuNi02LjgsOC43Yy0wLjEsMi41LDAuOCw0LjcsMi4zLDYuM2MxLjUsMS43LDMuMywyLjUsNS4zLDIuNWMyLjUsMCw1LjctMS44LDkuNi00LjhjMC43LTAuNSwxLjEtMS4zLDEuMS0yLjJWMTUzLjR6IE01MjMuOCwxNzAuOGMwLDAuMSwwLDAuMiwwLDAuMmMwLDAuMiwwLDAuMywwLDAuNGMwLjEsMS40LDAuNiwyLjQsMS40LDIuOGMwLjIsMC4xLDAuNCwwLjIsMC42LDAuMmMwLjQsMC4xLDAuNywwLjQsMC43LDAuOGwwLDIuNGMwLDAuNS0wLjQsMC44LTAuOSwwLjloLTguM2MtMS4zLDAtMi4zLTEtMi4zLTIuM3YtNC41Yy01LDMuOS04LjIsNi4xLTkuNSw2LjdjLTEuOSwwLjktNCwxLjMtNi4xLDEuM2MtMy40LDAtNi4yLTEuMi04LjQtMy40Yy0yLjItMi4zLTMuMy01LjMtMy4zLTkuMWMwLTIuNCwwLjUtNC40LDEuNi02LjJjMS41LTIuNCwzLjctNS4yLDcuNi02LjhjNC0xLjYsNy4zLTIsMTgtNC40YzAtMC4zLDAtNCwwLTQuM2MwLTQuNS0wLjgtOS4yLTguNC04LjdjLTUuMywwLjMtMTAuMiwyLTE0LjcsNWMtMC40LDAuMy0wLjksMC4yLTEuMi0wLjJjLTAuMS0wLjEtMC4xLTAuMy0wLjEtMC41di0yLjhjMC0xLjUsMC4zLTIuNCwwLjktMi45YzMuMS0yLjUsMTAuOS01LjUsMTguNS01YzguNCwwLjYsMTEuNCw0LDEyLjksOS4zYzAuNSwxLjYsMSwyLjgsMSw3LjV2MTQuNWMwLDIsMCw0LDAsNS44VjE3MC44eiIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik00NjUuNCwxMzcuOGMtMS43LTEtMy40LTEuNS01LTEuNWMtMywwLTUuOCwxLjMtOC4zLDMuOGMtMi43LDIuOC00LjYsNi41LTQuNiwxMy41YzAsNywxLjUsMTIuNCw0LjYsMTYuMmMzLDMuNyw2LjQsNS42LDEwLjIsNS42YzIuNywwLDUuMy0xLjEsNy44LTMuNGMwLjktMC44LDEuNC0xLjksMS40LTN2LTIwLjhDNDcxLjQsMTQzLjksNDY5LjEsMTQwLDQ2NS40LDEzNy44IE00ODEuMywxNzQuNmMwLjEsMC4xLDAuMywwLjEsMC41LDAuMmMwLjQsMC4xLDAuNiwwLjQsMC42LDAuOGwwLDIuM2MwLDAuNS0wLjQsMC44LTAuOSwwLjloLThjLTEuMiwwLTIuMy0xLTIuMy0yLjJ2LTIuMmMtMi4zLDIuNC00LjYsNC4yLTYuOCw1LjNjLTIuMiwxLjEtNC42LDEuNi03LjEsMS42Yy01LjIsMC05LjctMi4yLTEzLjYtNi42Yy0zLjktNC40LTUuOC0xMC01LjgtMTYuOXMyLjEtMTMuMSw2LjQtMTguOGM0LjMtNS43LDkuOC04LjUsMTYuNS04LjVjNC4yLDAsNy42LDEuMywxMC40LDR2LTE2LjdjMC0wLjUsMC0yLjctMS40LTMuNGMtMC4xLTAuMS0wLjMtMC4xLTAuNS0wLjJjLTAuNC0wLjEtMC42LTAuNC0wLjYtMC44bDAtMi40YzAtMC41LDAuNC0wLjksMC45LTAuOWg3LjljMS4yLDAsMi4zLDEsMi4zLDIuMnY1OC45QzQ3OS45LDE3MS44LDQ3OS45LDE3My45LDQ4MS4zLDE3NC42Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTM1MCwxNTAuMmMwLDAuMSwwLDAuMywwLjEsMC4zYzAuMSwwLjEsMC4yLDAuMSwwLjQsMC4xaDIzLjljMC4zLDAsMC41LTAuMiwwLjUtMC40YzAuMy0yLjUsMC40LTctMy4zLTEwLjhjLTEuOC0xLjktNC4xLTIuOC04LjMtMi44QzM1NS43LDEzNi42LDM1MC44LDE0My45LDM1MCwxNTAuMiBNMzQ3LjUsMTc0LjljLTMuOS00LjMtNS45LTExLjMtNS45LTE4LjJjMC03LjMsMi4zLTEzLjksNi40LTE4LjdjNC4zLTUsMTAuMi03LjcsMTcuMS03LjdjNS44LDAsMTAuMiwyLDEzLjIsNS44YzIuNywzLjYsNC4xLDguOCw0LjEsMTUuNGMwLDAuOCwwLDEuOS0wLjEsMy4zYy0wLjEsMC45LTAuOCwxLjYtMS43LDEuNmgtMjkuOGMtMC4xLDAtMC4zLDAuMS0wLjQsMC4xYy0wLjEsMC4xLTAuMSwwLjItMC4xLDAuNGMwLjEsNS40LDEuOCwxMCw1LDEzLjJjMy4xLDMuMiw3LjQsNC45LDEyLjQsNC45YzMuNywwLDguNi0xLDEyLjQtMi4xYzAuNS0wLjIsMS4xLDAuMSwxLjMsMC43YzAuMSwwLjIsMC4xLDAuNCwwLDAuNWwtMC41LDEuOWMtMC4yLDAuNy0wLjcsMS4zLTEuMywxLjZjLTMuNywxLjgtOS4zLDMuNS0xNSwzLjVDMzU3LjYsMTgxLjIsMzUxLjYsMTc5LjUsMzQ3LjUsMTc0LjkiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNMjMxLjEsMTM1Ljl2MzYuOWMwLDEsMC42LDEuOSwxLjQsMi4zYzAuOSwwLjQsMS40LDEuMywxLjQsMi4zdjAuN2MwLDAuOC0wLjYsMS40LTEuNCwxLjRIMjIwYy0wLjgsMC0xLjQtMC42LTEuNC0xLjR2LTAuN2MwLTEsMC42LTEuOSwxLjQtMi4zYzAuOS0wLjQsMS40LTEuMywxLjQtMi4zdi0zNS43YzAtMC41LTAuNC0wLjktMC45LTAuOXMtMC45LTAuNC0wLjktMC45di0xLjJjMC0xLjIsMC45LTIuMSwyLjEtMi4xaDUuNkMyMjkuNCwxMzIsMjMxLjEsMTMzLjcsMjMxLjEsMTM1LjkiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNMjI2LjMsMTEwLjhjMy4zLDAsNiwyLjcsNiw1LjljMCwzLjMtMi43LDUuOS02LDUuOXMtNi0yLjctNi01LjlDMjIwLjMsMTEzLjUsMjIzLDExMC44LDIyNi4zLDExMC44Ii8+PC9zdmc+"/>
349
+ </a>';
350
+
351
+ if ( $tab_key === 'cs' ) {
352
+ echo '
353
+ <p class="iubenda-text">
354
+ ' . __( "This plugin is the easiest and most comprehensive way to adapt your WordPress site to the European cookie law. Upon your user's first visit, the plugin will take care of collecting their consent, of blocking the most popular among the scripts that install cookies and subsequently reactivate 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.", 'iubenda' ) . '
355
+ </p>
356
+ <p class="iubenda-text">
357
+ <span class="iubenda-title">' . __( "Would you like to know more about the cookie law?", 'iubenda' ) . '</span><br />
358
+ ' . sprintf( __( "Read our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">complete guide to the cookie law.</a>", 'iubenda' ), $this->links['guide'] ) . '
359
+ </p>
360
+ <p class="iubenda-text">
361
+ <span class="iubenda-title">' . __( "What is the full functionality of the plugin?", 'iubenda' ) . '</span><br />
362
+ ' . sprintf( __( "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">plugin page.</a>", 'iubenda' ), $this->links['plugin_page'] ) . '
363
+ </p>
364
+ <p class="iubenda-text">
365
+ <span class="iubenda-title">' . __( "Enter the iubenda code for the Cookie Solution below.", 'iubenda' ) . '</span><br />
366
+ ' . 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'] ) . '
367
+ </p>';
368
+ } else {
369
+ echo '
370
+ <p class="iubenda-text">
371
+ ' . __( 'Maintaining comprehensive records of consent are a vital part of privacy compliance in general but are specifically required under the GDPR. These records should include a way of identifying the user, 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' ) . '
372
+ </p>';
373
+ }
374
+ ?>
375
+ </div>
376
+
377
+ <?php
378
+ // render custom notices
379
+ $this->print_notices();
380
+ ?>
381
+
382
+ <h2 style="display: none;"></h2>
383
+ <h2 class="nav-tab-wrapper iubenda-tab-wrapper">
384
+ <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>
385
+ <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>
386
+ </h2>
387
+
388
+ <div id="iubenda-settings">
389
+ <form id="iubenda-tabs" action="options.php" method="post">
390
+ <?php
391
+ settings_fields( $this->tabs[$tab_key]['key'] );
392
+ do_settings_sections( $this->tabs[$tab_key]['key'] );
393
+
394
+ if ( ! in_array( $this->action, array( 'save', 'edit' ) ) ) {
395
+ echo ' <p class="submit submit-' . $tab_key . '">';
396
+
397
+ // consent solution tab only
398
+ if ( $tab_key != 'cs' && ! empty( iubenda()->options['cons']['public_api_key'] ) ) {
399
+ 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>';
400
+ echo '<br />';
401
+ }
402
+ submit_button( '', 'primary', $this->tabs[$tab_key]['submit'], false );
403
+ echo ' ';
404
+ submit_button( __( 'Reset to defaults', 'iubenda' ), 'secondary', $this->tabs[$tab_key]['reset'], false );
405
+ echo ' </p>';
406
+ }
407
+ ?>
408
+ </form>
409
+ </div>
410
+
411
+ <div id="iubenda-footer">
412
+ <?php echo '
413
+ <p class="iubenda-text">
414
+ <span class="iubenda-title">' . __( 'Need support for this plugin?', 'iubenda' ) . '</span><br />
415
+ ' . sprintf( __( "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">support forum.</a>", 'iubenda' ), $this->links['support_forum'] ) . '
416
+ </p>';
417
+ ?>
418
+ </div>
419
+
420
+ <div class="clear"></div>
421
+ </div>
422
+ <?php
423
+ }
424
+
425
+ /**
426
+ * Code option.
427
+ *
428
+ * @return mixed
429
+ */
430
+ public function iub_code() {
431
+ // multilang support
432
+ if ( iubenda()->multilang && ! empty( iubenda()->languages ) ) {
433
+ echo '
434
+ <div id="contextual-help-wrap" class="contextual-help-wrap hidden" tabindex="-1" style="display: block;">
435
+ <div id="contextual-help-back" class="contextual-help-back"></div>
436
+ <div id="contextual-help-columns" class="contextual-help-columns">
437
+ <div class="contextual-help-tabs">
438
+ <ul>';
439
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
440
+ echo '
441
+ <li class="' . ( iubenda()->lang_default == $lang_id ? 'active' : '' ) . '">
442
+ <a href="#tab-panel-' . $lang_id . '" aria-controls="tab-panel-' . $lang_id . '">' . $lang_name . '</a>
443
+ </li>';
444
+ }
445
+ echo '
446
+ </ul>
447
+ </div>
448
+
449
+ <div id="contextual-help-tabs-wrap" class="contextual-help-tabs-wrap">';
450
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
451
+ // get code for the language
452
+ $code = ! empty( iubenda()->options['cs']['code_' . $lang_id] ) ? html_entity_decode( iubenda()->parse_code( iubenda()->options['cs']['code_' . $lang_id] ) ) : '';
453
+ // handle default, if empty
454
+ $code = empty( $code ) && $lang_id == iubenda()->lang_default ? html_entity_decode( iubenda()->parse_code( iubenda()->options['cs']['code_default'] ) ) : $code;
455
+
456
+ echo '
457
+ <div id="tab-panel-' . $lang_id . '" class="help-tab-content' . ( iubenda()->lang_default == $lang_id ? ' active' : '' ) . '">
458
+ <textarea name="iubenda_cookie_law_solution[code_' . $lang_id . ']" class="large-text" cols="50" rows="10">' . $code . '</textarea>
459
+ <p class="description">' . sprintf( __( 'Enter the iubenda code for %s.', 'iubenda' ), $lang_name ) . '</p>
460
+ </div>';
461
+ }
462
+ echo '
463
+ </div>
464
+ </div>
465
+ </div>';
466
+ } else {
467
+ echo '
468
+ <div id="iub_code_default">
469
+ <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>
470
+ <p class="description">' . __( 'Enter the iubenda code.', 'iubenda' ) . '</p>
471
+ </div>';
472
+ }
473
+ }
474
+
475
+ /**
476
+ * Custom scripts option.
477
+ *
478
+ * @return void
479
+ */
480
+ public function iub_custom_scripts() {
481
+ echo '
482
+ <div id="contextual-help-wrap-2" class="contextual-help-wrap hidden" tabindex="-1" style="display: block;">
483
+ <div id="contextual-help-back-2" class="contextual-help-back"></div>
484
+ <div id="contextual-help-columns-2" class="contextual-help-columns">
485
+ <div class="contextual-help-tabs">
486
+ <ul>
487
+ <li class="active">
488
+ <a href="#tab-panel-scripts" aria-controls="tab-panel-scripts">' . esc_html__( 'Scripts', 'iubenda' ) . '</a>
489
+ </li>
490
+ <li>
491
+ <a href="#tab-panel-iframes" aria-controls="tab-panel-iframes">' . esc_html__( 'Iframes', 'iubenda' ) . '</a>
492
+ </li>
493
+ </ul>
494
+ </div>
495
+ <div id="contextual-help-tabs-wrap-2" class="contextual-help-tabs-wrap">
496
+ <div id="tab-panel-scripts" class="help-tab-content active">
497
+ <textarea name="iubenda_cookie_law_solution[custom_scripts]" class="large-text" cols="50" rows="10">' . esc_textarea( implode( "\n", iubenda()->options['cs']['custom_scripts'] ) ) . '</textarea>
498
+ <p class="description">' . __( 'Enter a list of custom scripts (one per line).', 'iubenda' ) . '</p>
499
+ </div>
500
+ <div id="tab-panel-iframes" class="help-tab-content">
501
+ <textarea name="iubenda_cookie_law_solution[custom_iframes]" class="large-text" cols="50" rows="10">' . esc_textarea( implode( "\n", iubenda()->options['cs']['custom_iframes'] ) ) . '</textarea>
502
+ <p class="description">' . __( 'Enter a list of custom iframes (one per line).', 'iubenda' ) . '</p>
503
+ </div>
504
+ </div>
505
+ </div>
506
+ </div>';
507
+ }
508
+
509
+ /**
510
+ * Parsing option.
511
+ *
512
+ * @return mixed
513
+ */
514
+ public function iub_parse() {
515
+ echo '
516
+ <div id="iub_parse_container">
517
+ <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>
518
+ <p class="description">' . '(' . sprintf( __( "see <a href=\"%s\" target=\"_blank\">our documentation</a> for the list of detected scripts.", 'iubenda' ), $this->links['documentation'] ) . ')' . '</p>
519
+ <div id="iub_parser_engine_container"' . ( iubenda()->options['cs']['parse'] === false ? ' style="display: none;"' : '' ) . '>
520
+ <div>
521
+ <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>
522
+ <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>
523
+ <p class="description">' . __( 'Select parsing engine.', 'iubenda' ) . '</p>
524
+ </div>
525
+ <div>
526
+ <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>
527
+ <p class="description">(' . __( "improves performance, highly recommended, to be deactivated only if your site uses a caching system", 'iubenda' ) . ')</p>
528
+ </div>
529
+ </div>
530
+ </div>';
531
+ }
532
+
533
+ /**
534
+ * Ctype option.
535
+ *
536
+ * @return mixed
537
+ */
538
+ public function iub_ctype() {
539
+ echo '
540
+ <div id="iub_ctype_container">
541
+ <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>
542
+ </div>';
543
+ }
544
+
545
+ /**
546
+ * RSS feed option.
547
+ *
548
+ * @return mixed
549
+ */
550
+ public function iub_output_feed() {
551
+ echo '
552
+ <div id="iub_output_feed_container">
553
+ <label><input id="iub_ctype" 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>
554
+ </div>';
555
+ }
556
+
557
+ /**
558
+ * Menu option.
559
+ *
560
+ * @return mixed
561
+ */
562
+ public function iub_menu_position() {
563
+ echo '
564
+ <div id="iub_menu_position_container">
565
+ <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>
566
+ <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>
567
+ <p class="description">' . __( 'Select whether to display iubenda in a top admin menu or the Settings submenu.', 'iubenda' ) . '</p>
568
+ </div>';
569
+ }
570
+
571
+ /**
572
+ * Deactivation option.
573
+ *
574
+ * @return mixed
575
+ */
576
+ public function iub_deactivation() {
577
+ echo '
578
+ <div id="iub_deactivation_container">
579
+ <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>
580
+ </div>';
581
+ }
582
+
583
+ /**
584
+ * Public API Key option.
585
+ *
586
+ * @return mixed
587
+ */
588
+ public function iub_public_api_key() {
589
+ echo '
590
+ <div id="iub_public_api_key_container">
591
+ <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>
592
+ <p class="description">' . __( 'Enter your iubenda Javascript library public API key.', 'iubenda' ) . '</p>
593
+ </div>';
594
+ }
595
+
596
+ /**
597
+ * Forms list.
598
+ *
599
+ * @return mixed
600
+ */
601
+ public function iubenda_consent_forms() {
602
+ $form_id = ! empty( $_GET['form_id'] ) ? absint( $_GET['form_id'] ) : 0;
603
+ $form = ! empty( $form_id ) ? iubenda()->forms->get_form( $form_id ) : false;
604
+
605
+ $supported_forms = iubenda()->forms->sources;
606
+
607
+ echo '
608
+ <p class="description">' . sprintf( __( 'A list forms of available for field mapping. Currently supports: %s', 'iubenda' ), implode( ', ', $supported_forms ) ) . '</p>';
609
+
610
+ // list screen
611
+ if ( ! class_exists( 'WP_List_Table' ) )
612
+ include_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
613
+
614
+ include_once( IUBENDA_PLUGIN_PATH . '/includes/forms-list-table.php' );
615
+
616
+ $list_table = new iubenda_List_Table_Forms();
617
+
618
+ echo '
619
+ <div id="iubenda-consent-forms">';
620
+ $list_table->views();
621
+ $list_table->prepare_items();
622
+ $list_table->display();
623
+
624
+ echo '
625
+ </div>';
626
+ }
627
+
628
+ /**
629
+ * Single form.
630
+ *
631
+ * @return mixed
632
+ */
633
+ public function iubenda_consent_form() {
634
+ $form_id = ! empty( $_GET['form_id'] ) ? absint( $_GET['form_id'] ) : 0;
635
+ $form = ! empty( $form_id ) ? iubenda()->forms->get_form( $form_id ) : false;
636
+
637
+ if ( ! $form )
638
+ return;
639
+
640
+ $status = isset( $form->post_status ) && in_array( $form->post_status, array_keys( iubenda()->forms->statuses ) ) ? esc_attr( $form->post_status ) : 'publish';
641
+ $subject = isset( $form->form_subject ) && is_array( $form->form_subject ) ? array_map( 'esc_attr', $form->form_subject ) : array();
642
+ $preferences = isset( $form->form_preferences ) && is_array( $form->form_preferences ) ? array_map( 'esc_attr', $form->form_preferences ) : array();
643
+ $exclude = isset( $form->form_exclude ) && is_array( $form->form_exclude ) ? array_map( 'esc_attr', $form->form_exclude ) : array();
644
+ $legal_notices = isset( $form->form_legal_notices ) && is_array( $form->form_legal_notices ) ? array_map( 'esc_attr', $form->form_legal_notices ) : array();
645
+
646
+ // print_r( $form );
647
+
648
+ echo '
649
+ <div id="poststuff">
650
+ <div id="post-body" class="metabox-holder columns-2">
651
+ <div id="post-body-content">
652
+ <div id="titlediv">
653
+ <div id="titlewrap">
654
+ <h1>' . $form->post_title . '</h1>
655
+ </div>
656
+ <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>
657
+
658
+ <div style="margin-top: 18px"><strong>' . __( 'Available form fields:', 'iubenda' ) . '</strong><br /><p class="description">' . implode( ', ', $form->form_fields ) . '</p></div>
659
+ </div>
660
+ </div>
661
+ <div id="postbox-container-1" class="postbox-container">
662
+ <div id="side-sortables" class="">
663
+ <div id="submitdiv" class="postbox ">
664
+ <h3 class="hndle"><span>' . __( 'Publish' ) . '</span></h3>
665
+ <div class="inside">
666
+ <div id="submitpost" class="submitbox">
667
+ <div id="minor-publishing">
668
+ <div class="misc-pub-section misc-pub-post-status">
669
+ <label for="status">' . __( 'Status' ) . ':</label>
670
+ <div id="status-select" class="" style="margin: 3px 0 0;">
671
+ <select id="status" name="status">';
672
+ foreach ( iubenda()->forms->statuses as $name => $label ) {
673
+ echo '
674
+ <option value="' . $name . '"' . selected( $form->post_status, $name, true ) . '>' . $label . '</option>';
675
+ }
676
+ echo '
677
+ </select>
678
+ </div>
679
+ </div>
680
+ <div id="major-publishing-actions">
681
+ <div id="delete-action">
682
+ <a class="submitdelete deletion" href="' . esc_url( add_query_arg( array( 'tab' => 'cons' ), iubenda()->base_url ) ) . '">' . __( 'Cancel' ) . '</a>
683
+ </div>
684
+ <div id="publishing-action">
685
+ <span class="spinner"></span>
686
+ <input type="hidden" value="' . $form->ID . '" name="form_id">
687
+ <input id="publish" class="button button-primary button-large" type="submit" value="' . __( 'Save' ) . '" name="save">
688
+ </div>
689
+ <div class="clear"></div>
690
+ </div>
691
+ </div>
692
+ </div>
693
+ </div>
694
+ </div>
695
+ </div>
696
+ </div>
697
+ <div id="postbox-container-2" class="postbox-container">
698
+ <div id="normal-sortables" class="meta-box-sortables">
699
+ <div id="map-fields" class="postbox">
700
+ <h3 class="hndle ui-sortable-handle"><span>' . __( 'Map fields', 'iubenda' ) . '</span></h3>
701
+ <div class="inside">
702
+ <table class="widefat">
703
+ <tbody>
704
+ <tr>
705
+ <td class="label table-label">
706
+ <h4>' . __( 'Subject fields', 'iubenda' ) . ' <span class="required">(required)</span></h4>
707
+ <p class="description">' . __( 'Subject fields allows you to store a series of values saved about your subjects/users. Please map the subject/user data with the corresponding form fields.', 'iubenda' ) . '</p>
708
+ </td>
709
+ <td>
710
+ <table class="widefat subject-table">
711
+ <thead>
712
+ <td class="label">' . __( 'Subject field', 'iubenda' ) . '</td>
713
+ <td class="label">' . __( 'Form field', 'iubenda' ) . '</td>
714
+ </thead>
715
+ <tbody>';
716
+
717
+ foreach ( $this->subject_fields as $field_name => $field_label ) {
718
+ $selected = isset( $subject[$field_name] ) ? $subject[$field_name] : '';
719
+ $none = $field_name == 'id' ? __( 'Autogenerated', 'iubenda' ) : __( 'None', 'iubenda' );
720
+
721
+ echo '
722
+ <tr class="subject-field options-field">
723
+ <td>' . $field_name . ' (' . $field_label . ')' . '</td>
724
+ <td>
725
+ <select class="subject-fields-select select-' . $field_name . '" name="subject[' . $field_name . ']">
726
+ <option value="" ' . selected( $selected, '', false ) . '>' . $none . '</option>';
727
+ if ( ! empty( $form->form_fields ) ) {
728
+ foreach ( $form->form_fields as $form_field ) {
729
+ echo '<option value="' . $form_field . '" ' . selected( $selected, $form_field, false ) . '>' . $form_field . '</option>';
730
+ }
731
+ }
732
+ echo '
733
+ </select>
734
+ </td>
735
+ </tr>
736
+ ';
737
+ }
738
+ echo '
739
+ </tbody>
740
+ </table>
741
+ </td>
742
+ </tr>
743
+ <tr>
744
+ <td class="label table-label">
745
+ <h4>' . __( 'Preferences fields', 'iubenda' ) . ' <span class="required">(required)</span></h4>
746
+ <p class="description">' . __( 'Preferences fields allows you to save the various opt-ins the user has agreed to, such as terms and conditions, newsletter, profiling, etc. Please create at least one preferences field.', 'iubenda' ) . '</p>
747
+ </td>
748
+ <td>
749
+ <table class="widefat preferences-table">
750
+ <thead>
751
+ <td class="label">' . __( 'Preferences field', 'iubenda' ) . '</td>
752
+ <td class="label">' . __( 'Form field', 'iubenda' ) . '</td>
753
+ </thead>
754
+ <tbody>';
755
+ echo '
756
+ <tr id="preferences-field-template" class="template-field" style="display: none;">
757
+ <td><input type="text" class="regular-text" value="" name="preferences[__PREFERENCE_ID__][field]" placeholder="' . __( 'Enter field name', 'iubenda' ) . '" /></td>
758
+ <td>
759
+ <select class="preferences-fields-select select-' . $field_name . '" name="preferences[__PREFERENCE_ID__][value]">';
760
+ if ( ! empty( $form->form_fields ) ) {
761
+ foreach ( $form->form_fields as $index => $form_field ) {
762
+ echo '<option value="' . $form_field . '">' . $form_field . '</option>';
763
+ }
764
+ }
765
+ echo '
766
+ </select>
767
+ <a href="javascript:void(0)" class="remove-preferences-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
768
+ </td>
769
+ </tr>';
770
+
771
+ if ( $preferences ) {
772
+ $index = 0;
773
+
774
+ foreach ( $preferences as $field_name => $field_value ) {
775
+ $selected = isset( $preferences[$field_name] ) ? $preferences[$field_name] : '';
776
+
777
+ echo '
778
+ <tr class="preferences-field options-field">
779
+ <td><input type="text" class="regular-text" value="' . $field_name . '" name="preferences[' . $index . '][field]" placeholder="' . __( 'Enter field name', 'iubenda' ) . '" /></td>
780
+ <td>
781
+ <select class="preferences-fields-select select-' . $field_name . '" name="preferences[' . $index . '][value]">';
782
+ if ( ! empty( $form->form_fields ) ) {
783
+ foreach ( $form->form_fields as $form_field ) {
784
+ echo '<option value="' . $form_field . '" ' . selected( $selected, $form_field, false ) . '>' . $form_field . '</option>';
785
+ }
786
+ }
787
+ echo '
788
+ </select>
789
+ <a href="javascript:void(0)" class="remove-preferences-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
790
+ </td>
791
+ </tr>';
792
+
793
+ $index++;
794
+ }
795
+ }
796
+
797
+ echo '
798
+ <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>
799
+ </tbody>
800
+ </table>
801
+ </td>
802
+ </tr>
803
+ <tr>
804
+ <td class="label table-label">
805
+ <h4>' . __( 'Exclude fields', 'iubenda' ) . '</h4>
806
+ <p class="description">' . __( 'Exclude fields allows you to create a list of field names that you would like to exclude from proofs (for e.g. password or other fields not related to the consent).', 'iubenda' ) . '</p>
807
+ </td>
808
+ <td>
809
+ <table class="widefat exclude-table">
810
+ <thead>
811
+ <td class="label">' . __( 'Exclude field', 'iubenda' ) . '</td>
812
+ <td class="label"></td>
813
+ </thead>
814
+ <tbody>';
815
+ echo '
816
+ <tr id="exclude-field-template" class="template-field" style="display: none;">
817
+ <td>
818
+ <select class="exclude-fields-select select-' . $field_name . '" name="exclude[__EXCLUDE_ID__][field]">';
819
+ if ( ! empty( $form->form_fields ) ) {
820
+ foreach ( $form->form_fields as $index => $form_field ) {
821
+ echo '<option value="' . $form_field . '">' . $form_field . '</option>';
822
+ }
823
+ }
824
+ echo '
825
+ </select>
826
+ <a href="javascript:void(0)" class="remove-exclude-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
827
+ </td>
828
+ <td></td>
829
+
830
+ </tr>';
831
+
832
+ if ( $exclude ) {
833
+ $index = 0;
834
+
835
+ foreach ( $exclude as $index => $field_name ) {
836
+ $selected = isset( $exclude[$index] ) ? $exclude[$index] : '';
837
+
838
+ echo '
839
+ <tr class="exclude-field options-field">
840
+ <td>
841
+ <select class="exclude-fields-select select-' . $field_name . '" name="exclude[' . $index . '][field]">';
842
+ if ( ! empty( $form->form_fields ) ) {
843
+ foreach ( $form->form_fields as $form_field ) {
844
+ echo '<option value="' . $form_field . '" ' . selected( $selected, $form_field, false ) . '>' . $form_field . '</option>';
845
+ }
846
+ }
847
+ echo '
848
+ </select>
849
+ <a href="javascript:void(0)" class="remove-exclude-field button-secondary" title="' . __( 'Remove', 'iubenda' ) . '">-</a>
850
+ </td>
851
+ <td></td>
852
+ </tr>';
853
+
854
+ $index++;
855
+ }
856
+ }
857
+
858
+ echo '
859
+ <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>
860
+ </tbody>
861
+ </table>
862
+ </td>
863
+ </tr>
864
+ </tbody>
865
+ </table>
866
+ </div>
867
+ </div>
868
+ <div id="legal-notices" class="postbox">
869
+ <h3 class="hndle ui-sortable-handle"><span>' . __( 'Legal Notices', 'iubenda' ) . '</span></h3>
870
+ <div class="inside">
871
+ <table class="widefat">
872
+ <tbody>
873
+ <tr>
874
+ <td class="label table-label">
875
+ <h4>' . __( 'Legal documents', 'iubenda' ) . '</h4>
876
+ <p class="description">' . __( 'If you use iubenda for your legal documents it is required for you to declare which of them are being agreed upon on each consent creation.', 'iubenda' ) . '</p>
877
+ </td>
878
+ <td>
879
+ <table class="widefat legal_notices-table">
880
+ <thead>
881
+ <td class="label">' . __( 'Identifier', 'iubenda' ) . '</td>
882
+ <td class="label"></td>
883
+ </thead>
884
+ <tbody>';
885
+
886
+ // default identifiers
887
+ foreach ( $this->legal_notices as $index => $field_name ) {
888
+ echo '
889
+ <tr class="legal_notices-field default-field">
890
+ <td>' . ( $index === 0 ? '<p class="description">' . __( 'Please check the legal notices you are using.', '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>
891
+ <td></td>
892
+ </tr>';
893
+ }
894
+
895
+ $index++;
896
+
897
+ // custom identifiers
898
+ echo '
899
+ <tr id="legal_notices-field-template" class="template-field" style="display: none;">
900
+ <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>
901
+ <td></td>
902
+ </tr>';
903
+
904
+ echo '
905
+ <tr>
906
+ <td colspan="2"><p class="description" style="margin-bottom: 0;">' . __( 'Optionally add your custom document identifiers.', 'iubenda' ) . '</p></td>
907
+ </tr>';
908
+
909
+ if ( $legal_notices ) {
910
+ foreach ( $legal_notices as $field_name ) {
911
+ if ( in_array( $field_name, $this->legal_notices, true ) )
912
+ continue;
913
+
914
+ echo '
915
+ <tr class="legal_notices-field options-field">
916
+ <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>
917
+ <td></td>
918
+ </tr>';
919
+
920
+ $index++;
921
+ }
922
+ }
923
+
924
+ echo '
925
+ <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>';
926
+ echo '
927
+ </tbody>
928
+ </table>
929
+ </td>
930
+ </tr>
931
+ </tbody>
932
+ </table>
933
+ </div>
934
+ </div>
935
+ </div>
936
+ </div>
937
+ </div>
938
+ </div>
939
+ <div class="clear"></div>';
940
+
941
+ // echo '<pre>'; print_r( $form ); echo '</pre>';
942
+ }
943
+
944
+ /**
945
+ * Save cookie solution options.
946
+ *
947
+ * @return void
948
+ */
949
+ public function save_cookie_law_options( $input ) {
950
+ if ( ! current_user_can( apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ) ) )
951
+ return $input;
952
+
953
+ // save options
954
+ if ( isset( $_POST['save_iubenda_options'] ) ) {
955
+ $input['parse'] = (bool) isset( $input['parse'] );
956
+ $input['parser_engine'] = isset( $input['parser_engine'] ) && in_array( $input['parser_engine'], array( 'default', 'new' ) ) ? $input['parser_engine'] : iubenda()->defaults['cs']['parser_engine'];
957
+ $input['skip_parsing'] = (bool) isset( $input['skip_parsing'] );
958
+ $input['ctype'] = (bool) isset( $input['ctype'] );
959
+ $input['output_feed'] = (bool) isset( $input['output_feed'] );
960
+ $input['menu_position'] = isset( $input['menu_position'] ) && in_array( $input['menu_position'], array( 'topmenu', 'submenu' ) ) ? $input['menu_position'] : iubenda()->defaults['cs']['menu_position'];
961
+ $input['deactivation'] = (bool) isset( $input['deactivation'] );
962
+
963
+ // multilang support
964
+ if ( iubenda()->multilang && ! empty( iubenda()->languages ) ) {
965
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
966
+ $input['code_' . $lang_id] = ! empty( $input['code_' . $lang_id] ) ? iubenda()->parse_code( $input['code_' . $lang_id] ) : '';
967
+
968
+ // handle default lang too
969
+ if ( $lang_id == iubenda()->lang_default ) {
970
+ $input['code_default'] = ! empty( $input['code_' . $lang_id] ) ? iubenda()->parse_code( $input['code_' . $lang_id] ) : iubenda()->options['cs']['code_default'];
971
+ }
972
+ }
973
+ } else
974
+ $input['code_default'] = ! empty( $input['code_default'] ) ? iubenda()->parse_code( $input['code_default'] ) : '';
975
+
976
+ // scripts
977
+ if ( isset( $input['custom_scripts'] ) ) {
978
+ $input['custom_scripts'] = trim( $input['custom_scripts'] );
979
+
980
+ if ( ! empty( $input['custom_scripts'] ) )
981
+ $input['custom_scripts'] = array_map( 'trim', explode( "\n", str_replace( "\r", '', $input['custom_scripts'] ) ) );
982
+ else
983
+ $input['custom_scripts'] = array();
984
+ } else
985
+ $input['custom_scripts'] = array();
986
+
987
+ // iframes
988
+ if ( isset( $input['custom_iframes'] ) ) {
989
+ $input['custom_iframes'] = trim( $input['custom_iframes'] );
990
+
991
+ if ( ! empty( $input['custom_iframes'] ) )
992
+ $input['custom_iframes'] = array_map( 'trim', explode( "\n", str_replace( "\r", '', $input['custom_iframes'] ) ) );
993
+ else
994
+ $input['custom_iframes'] = array();
995
+ } else
996
+ $input['custom_iframes'] = array();
997
+
998
+ add_settings_error( 'cs_settings_errors', 'iub_cs_settings_updated', __( 'Settings saved.', 'iubenda' ), 'updated' );
999
+ // reset options
1000
+ } elseif ( isset( $_POST['reset_iubenda_options'] ) ) {
1001
+ $input = iubenda()->defaults['cs'];
1002
+
1003
+ // multilang support
1004
+ if ( iubenda()->multilang && ! empty( iubenda()->languages ) ) {
1005
+ foreach ( iubenda()->languages as $lang_id => $lang_name ) {
1006
+ $input['code_' . $lang_id] = '';
1007
+ }
1008
+ }
1009
+
1010
+ add_settings_error( 'cs_settings_errors', 'iub_cs_settings_restored', __( 'Settings restored to defaults.', 'iubenda' ), 'updated' );
1011
+ }
1012
+
1013
+ return $input;
1014
+ }
1015
+
1016
+ /**
1017
+ * Save consent solution options.
1018
+ *
1019
+ * @return void
1020
+ */
1021
+ public function save_consent_options( $input ) {
1022
+
1023
+ if ( ! current_user_can( apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ) ) )
1024
+ return $input;
1025
+
1026
+ // save options
1027
+ if ( isset( $_POST['save_consent_options'] ) ) {
1028
+ $input['public_api_key'] = isset( $input['public_api_key'] ) ? esc_attr( $input['public_api_key'] ) : '';
1029
+
1030
+ add_settings_error( 'cons_settings_errors', 'iub_cons_settings_updated', __( 'Settings saved.', 'iubenda' ), 'updated' );
1031
+ // reset options
1032
+ } elseif ( isset( $_POST['reset_consent_options'] ) ) {
1033
+ $input = iubenda()->defaults['cons'];
1034
+
1035
+ add_settings_error( 'cons_settings_errors', 'iub_cons_settings_restored', __( 'Settings restored to defaults.', 'iubenda' ), 'updated' );
1036
+ }
1037
+
1038
+ return $input;
1039
+ }
1040
+
1041
+ /**
1042
+ * Process the bulk actions
1043
+ *
1044
+ * @return void
1045
+ */
1046
+ public function process_actions() {
1047
+ $page = ! empty( $_POST['option_page'] ) ? esc_attr( $_POST['option_page'] ) : ( ! empty( $_GET['page'] ) ? esc_attr( $_GET['page'] ) : '' );
1048
+ $id = isset( $_REQUEST['form_id'] ) ? ( is_array( $_REQUEST['form_id'] ) ? array_map( 'ansint', $_REQUEST['form_id'] ) : absint( $_REQUEST['form_id'] ) ) : false;
1049
+ $tab_key = ! empty( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'cs';
1050
+
1051
+ if ( ! $page )
1052
+ return;
1053
+
1054
+ // add comments cookie option notice
1055
+ if ( $tab_key != 'cs' && ! empty( iubenda()->options['cons']['public_api_key'] ) ) {
1056
+ $cookies_enabled = get_option( 'show_comments_cookies_opt_in' );
1057
+
1058
+ if ( ! $cookies_enabled ) {
1059
+ iubenda()->settings->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' );
1060
+ }
1061
+ }
1062
+
1063
+ $result = null;
1064
+
1065
+ switch ( $this->action ) {
1066
+ case 'autodetect' :
1067
+ $result = iubenda()->forms->autodetect_forms();
1068
+
1069
+ // new forms notice
1070
+ if ( ! empty( $result['new'] ) )
1071
+ iubenda()->settings->add_notice( 'iub_autodetect_success', sprintf( _n( '%d form detected successfully.', '%d forms detected successfully.', count( $result['new'] ), 'iubenda' ), $result ), 'success' );
1072
+
1073
+ // forms changed notice
1074
+ if ( ! empty( $result['updated'] ) )
1075
+ iubenda()->settings->add_notice( 'iub_autodetect_success', sprintf( _n( '%d form change detected.', '%d form changes detected.', count( $result['updated'] ), 'iubenda' ), $result ), 'success' );
1076
+
1077
+ // no changes notice
1078
+ if ( empty( $result['new'] ) && empty( $result['updated'] ) )
1079
+ iubenda()->settings->add_notice( 'iub_autodetect_success', __( 'No forms or form changes detected.', 'iubenda' ), 'error' );
1080
+
1081
+ if ( iubenda()->options['cs']['menu_position'] === 'submenu' && $pagenow === 'admin.php' ) {
1082
+ // sub menu
1083
+ $redirect_to = admin_url( 'options-general.php?page=iubenda&tab=cons' );
1084
+ } else {
1085
+ // top menu
1086
+ $redirect_to = admin_url( 'admin.php?page=iubenda&tab=cons' );
1087
+ }
1088
+
1089
+ // make sure it's current host location
1090
+ wp_safe_redirect( $redirect_to );
1091
+ exit;
1092
+
1093
+ break;
1094
+
1095
+ case 'save' :
1096
+ if ( ! $id )
1097
+ return;
1098
+
1099
+ $form = iubenda()->forms->get_form( $id );
1100
+
1101
+ if ( $form->ID != $id )
1102
+ return;
1103
+
1104
+ $status = isset( $_POST['status'] ) && in_array( $_POST['status'], array_keys( iubenda()->forms->statuses ) ) ? esc_attr( $_POST['status'] ) : 'publish';
1105
+ $subject = isset( $_POST['subject'] ) && is_array( $_POST['subject'] ) ? array_map( 'esc_attr', $_POST['subject'] ) : array();
1106
+ $preferences = array();
1107
+ $exclude = array();
1108
+ $legal_notices = array();
1109
+
1110
+ $preferences_raw = isset( $_POST['preferences'] ) && is_array( $_POST['preferences'] ) ? array_map( array( $this, 'array_map_callback' ), $_POST['preferences'] ) : array();
1111
+ $exclude_raw = isset( $_POST['exclude'] ) && is_array( $_POST['exclude'] ) ? array_map( array( $this, 'array_map_callback' ), $_POST['exclude'] ) : array();
1112
+ $legal_notices_raw = isset( $_POST['legal_notices'] ) && is_array( $_POST['legal_notices'] ) ? array_map( array( $this, 'array_map_callback' ), $_POST['legal_notices'] ) : array();
1113
+
1114
+ // format preferences data
1115
+ if ( ! empty( $preferences_raw ) && is_array( $preferences_raw ) ) {
1116
+ foreach ( $preferences_raw as $index => $data ) {
1117
+ if ( ! empty( $data['field'] ) && ! empty( $data['value'] ) )
1118
+ $preferences[ sanitize_key( $data['field'] ) ] = $data['value'];
1119
+ }
1120
+ }
1121
+
1122
+ // format exclude data
1123
+ if ( ! empty( $exclude_raw ) && is_array( $exclude_raw ) ) {
1124
+ foreach ( $exclude_raw as $index => $data ) {
1125
+ if ( ! empty( $data['field'] ) )
1126
+ $exclude[] = $data['field'];
1127
+ }
1128
+ }
1129
+
1130
+ // format legal notices data
1131
+ if ( ! empty( $legal_notices_raw ) && is_array( $legal_notices_raw ) ) {
1132
+ foreach ( $legal_notices_raw as $index => $data ) {
1133
+ if ( ! empty( $data['field'] ) )
1134
+ $legal_notices[] = $data['field'];
1135
+ }
1136
+ }
1137
+
1138
+ // form first save, update status to mapped automatically
1139
+ if ( empty( $form->form_subject ) && empty( $form->form_preferences ) ) {
1140
+ $status = 'mapped';
1141
+ }
1142
+
1143
+ // echo '<pre>'; print_r( $_POST ); echo '</pre>'; exit;
1144
+
1145
+ // bail if empty fields
1146
+ if ( empty( $subject ) || empty( $preferences ) ) {
1147
+ iubenda()->settings->add_notice( 'iub_form_fields_missing', __( 'Form saving failed. Please fill the Subject and Preferences fields.', 'iubenda' ), 'error' );
1148
+ return;
1149
+ }
1150
+
1151
+ $args = array(
1152
+ 'ID' => $form->ID,
1153
+ 'status' => $status,
1154
+ 'object_type' => $form->object_type,
1155
+ 'object_id' => $form->object_id,
1156
+ 'form_source' => $form->form_source,
1157
+ 'form_title' => $form->post_title,
1158
+ 'form_date' => $form->post_modified,
1159
+ 'form_fields' => $form->form_fields,
1160
+ 'form_subject' => $subject,
1161
+ 'form_preferences' => $preferences,
1162
+ 'form_exclude' => $exclude,
1163
+ 'form_legal_notices' => $legal_notices
1164
+ );
1165
+
1166
+ $result = iubenda()->forms->save_form( $args );
1167
+
1168
+ if ( $result ) {
1169
+ // form save, inform about form status update
1170
+ if ( empty( $form->form_subject ) && empty( $form->form_preferences ) ) {
1171
+ iubenda()->settings->add_notice( 'iub_form_saved', __( 'Form saved successfully - form status changed to Mapped.', 'iubenda' ), 'success' );
1172
+ // form update
1173
+ } else {
1174
+ iubenda()->settings->add_notice( 'iub_form_updated', __( 'Form updated successfully.', 'iubenda' ), 'success' );
1175
+ }
1176
+ } else {
1177
+ iubenda()->settings->add_notice( 'iub_form_failed', __( 'Form saving failed.', 'iubenda' ), 'error' );
1178
+ }
1179
+
1180
+ break;
1181
+
1182
+ case 'delete' :
1183
+ if ( ! $id )
1184
+ return;
1185
+
1186
+ $form = iubenda()->forms->get_form( $id );
1187
+
1188
+ if ( empty( $form ) )
1189
+ return;
1190
+
1191
+ $result = iubenda()->forms->delete_form( $id );
1192
+
1193
+ if ( $result )
1194
+ iubenda()->settings->add_notice( 'iub_form_deleted', __( 'Form deleted successfully.', 'iubenda' ), 'success' );
1195
+ else
1196
+ iubenda()->settings->add_notice( 'iub_form_delete_failed', __( 'Form delete failed.', 'iubenda' ), 'error' );
1197
+
1198
+ $redirect_to = admin_url( 'admin.php?page=iubenda&tab=cons' );
1199
+
1200
+ // make sure it's current host location
1201
+ wp_safe_redirect( $redirect_to );
1202
+
1203
+ break;
1204
+
1205
+ default :
1206
+ return;
1207
+ }
1208
+
1209
+ if ( ! empty ( $result ) ) {
1210
+ //
1211
+ } else {
1212
+ //
1213
+ }
1214
+ }
1215
+
1216
+ /**
1217
+ * Add admin notice.
1218
+ *
1219
+ * @param mixed $message
1220
+ * @param string $notice_type
1221
+ */
1222
+ public function add_notice( $key, $message, $notice_type = 'notice' ) {
1223
+ $key = ! empty( $key ) ? sanitize_key( $key ) : '';
1224
+ $message = ! empty( $message ) ? wp_kses_post( $message ) : '';
1225
+ $notice_type = ! empty( $notice_type ) && in_array( $notice_type, $this->notice_types ) ? $notice_type : 'notice';
1226
+
1227
+ if ( ! $key || ! $message )
1228
+ return;
1229
+
1230
+ $notices = get_transient( 'iubenda_dashboard_notices' );
1231
+
1232
+ if ( empty( $notices ) || ! array_key_exists( $key, $notices[$notice_type] ) ) {
1233
+ $notices[$notice_type][$key] = $message;
1234
+
1235
+ set_transient( 'iubenda_dashboard_notices', $notices, 2 * MINUTE_IN_SECONDS );
1236
+ }
1237
+ }
1238
+
1239
+ /**
1240
+ * Display admin notices.
1241
+ *
1242
+ * @return mixed
1243
+ */
1244
+ public function print_notices() {
1245
+ $notices = get_transient( 'iubenda_dashboard_notices' );
1246
+ $notices_array = array();
1247
+
1248
+ foreach ( $this->notice_types as $notice_type ) {
1249
+ if ( $this->notice_count( $notices, $notice_type ) > 0 ) {
1250
+ echo '<div class="notice notice-' . ( $notice_type === 'notice' ? 'info' : $notice_type ) . ' below-h2 is-dismissible">';
1251
+
1252
+ foreach ( $notices[$notice_type] as $key => $notice ) {
1253
+ echo '<p><strong>' . wp_kses_post( $notice ) . '</strong></p>';
1254
+ }
1255
+
1256
+ echo '<button type="button" class="notice-dismiss"><span class="screen-reader-text">' . __( 'Dismiss this notice.' ) . '</span></button>';
1257
+
1258
+ echo '</div>';
1259
+ }
1260
+ }
1261
+
1262
+ delete_transient( 'iubenda_dashboard_notices' );
1263
+ }
1264
+
1265
+ /**
1266
+ * Count notices function.
1267
+ *
1268
+ * @param string $notice_type
1269
+ * @return int
1270
+ */
1271
+ public function notice_count( $all_notices = array(), $notice_type = '' ) {
1272
+ $notice_count = 0;
1273
+
1274
+ if ( isset( $all_notices[$notice_type] ) ) {
1275
+ $notice_count = absint( sizeof( $all_notices[$notice_type] ) );
1276
+ } elseif ( empty( $notice_type ) ) {
1277
+ foreach ( $all_notices as $notices ) {
1278
+ $notice_count += absint( sizeof( $all_notices ) );
1279
+ }
1280
+ }
1281
+
1282
+ return $notice_count;
1283
+ }
1284
+
1285
+ /**
1286
+ * Adjust highlighted menu.
1287
+ *
1288
+ * @param type $file
1289
+ * @return type
1290
+ */
1291
+ public function submenu_file( $submenu_file, $parent_file ) {
1292
+ global $menu, $submenu;
1293
+
1294
+ if ( $parent_file == 'iubenda' ) {
1295
+ $tab_key = ! empty( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'cs';
1296
+
1297
+ if ( $tab_key == 'cons' ) {
1298
+ $submenu_file = 'admin.php?page=iubenda&tab=cons';
1299
+ $submenu['iubenda'][1][2] = 'admin.php?page=iubenda&tab=cons';
1300
+ }
1301
+ }
1302
+
1303
+ return $submenu_file;
1304
+ }
1305
+
1306
+ /**
1307
+ * Sanitize array helper function.
1308
+ *
1309
+ * @param array $array
1310
+ * @return array
1311
+ */
1312
+ public function array_map_callback( $array ) {
1313
+ if ( ! is_array( $array ) )
1314
+ return array();
1315
+
1316
+ return array_map( 'esc_attr', $array );
1317
+ }
1318
+
1319
+ }
iubenda-cookie-class/simple_html_dom.php CHANGED
@@ -1,113 +1,128 @@
1
  <?php
2
  /**
3
  * Website: http://sourceforge.net/projects/simplehtmldom/
4
- * Additional projects that may be used: http://sourceforge.net/projects/debugobject/
5
  * Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/)
6
- * Contributions by:
7
- * Yousuke Kumakura (Attribute filters)
8
- * Vadim Voituk (Negative indexes supports of "find" method)
9
- * Antcs (Constructor with automatically load contents either text or file/url)
10
  *
11
- * all affected sections have comments starting with "PaperG"
12
- *
13
- * Paperg - Added case insensitive testing of the value of the selector.
14
- * Paperg - Added tag_start for the starting index of tags - NOTE: This works but not accurately.
15
- * This tag_start gets counted AFTER \r\n have been crushed out, and after the remove_noice calls so it will not reflect the REAL position of the tag in the source,
16
- * it will almost always be smaller by some amount.
17
- * We use this to determine how far into the file the tag in question is. This "percentage will never be accurate as the $dom->size is the "real" number of bytes the dom was created from.
18
- * but for most purposes, it's a really good estimation.
19
- * Paperg - Added the forceTagsClosed to the dom constructor. Forcing tags closed is great for malformed html, but it CAN lead to parsing errors.
20
- * Allow the user to tell us how much they trust the html.
21
- * Paperg add the text and plaintext to the selectors for the find syntax. plaintext implies text in the innertext of a node. text implies that the tag is a text node.
22
- * This allows for us to find tags based on the text they contain.
23
- * Create find_ancestor_tag to see if a tag is - at any level - inside of another specific tag.
24
- * Paperg: added parse_charset so that we know about the character set of the source document.
25
- * NOTE: If the user's system has a routine called get_last_retrieve_url_contents_content_type availalbe, we will assume it's returning the content-type header from the
26
- * last transfer or curl_exec, and we will parse that and use it in preference to any other method of charset detection.
27
  *
28
- * Found infinite loop in the case of broken html in restore_noise. Rewrote to protect from that.
29
- * PaperG (John Schlick) Added get_display_size for "IMG" tags.
 
 
 
30
  *
31
- * Licensed under The MIT License
32
- * Redistributions of files must retain the above copyright notice.
 
 
33
  *
34
- * @author S.C. Chen <me578022@gmail.com>
35
- * @author John Schlick
36
- * @author Rus Carroll
37
- * @version 1.5 ($Rev: 210 $)
38
- * @package PlaceLocalInclude
39
- * @subpackage simple_html_dom
40
  */
41
 
42
- /**
43
- * All of the Defines for the classes below.
44
- * @author S.C. Chen <me578022@gmail.com>
45
- */
46
  define('HDOM_TYPE_ELEMENT', 1);
47
  define('HDOM_TYPE_COMMENT', 2);
48
- define('HDOM_TYPE_TEXT', 3);
49
- define('HDOM_TYPE_ENDTAG', 4);
50
- define('HDOM_TYPE_ROOT', 5);
51
  define('HDOM_TYPE_UNKNOWN', 6);
52
  define('HDOM_QUOTE_DOUBLE', 0);
53
  define('HDOM_QUOTE_SINGLE', 1);
54
- define('HDOM_QUOTE_NO', 3);
55
- define('HDOM_INFO_BEGIN', 0);
56
- define('HDOM_INFO_END', 1);
57
- define('HDOM_INFO_QUOTE', 2);
58
- define('HDOM_INFO_SPACE', 3);
59
- define('HDOM_INFO_TEXT', 4);
60
- define('HDOM_INFO_INNER', 5);
61
- define('HDOM_INFO_OUTER', 6);
62
- define('HDOM_INFO_ENDSPACE',7);
63
- // helper functions
64
- // -----------------------------------------------------------------------------
65
- // get html dom from file
66
- // $maxlen is defined in the code as PHP_STREAM_COPY_ALL which is defined as -1.
67
- function file_get_html($url, $use_include_path = false, $context=null, $offset = -1, $maxLen=-1, $lowercase = true, $forceTagsClosed=true, $stripRN=true)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  {
69
- // We DO force the tags to be terminated.
70
- $dom = new simple_html_dom(null, $lowercase, $forceTagsClosed, $stripRN, $defaultBRText, $defaultSpanText);
71
- // For sourceforge users: uncomment the next line and comment the retreive_url_contents line 2 lines down if it is not already done.
72
- $contents = file_get_contents($url, $use_include_path, $context, $offset);
73
- // Paperg - use our own mechanism for getting the contents as we want to control the timeout.
74
- //$contents = retrieve_url_contents($url);
75
- if (empty($contents))
76
- {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  return false;
78
  }
79
- // The second parameter can force the selectors to all be lowercase.
80
- $dom->load($contents, $lowercase, $stripRN);
81
- return $dom;
82
  }
83
 
84
- // get html dom from string
85
- function str_get_html($str, $lowercase=true, $forceTagsClosed=true, $stripRN=true)
 
 
 
 
 
 
86
  {
87
- $dom = new simple_html_dom(null, $lowercase, $forceTagsClosed, $stripRN);
88
- if (empty($str))
89
- {
 
 
 
 
 
 
 
 
90
  $dom->clear();
91
  return false;
92
  }
93
- $dom->load($str, $lowercase, $stripRN);
94
- return $dom;
95
  }
96
 
97
- // dump html dom tree
98
- function dump_html_tree($node, $show_attr=true, $deep=0)
99
  {
100
  $node->dump($node);
101
  }
102
 
103
-
104
- /**
105
- * simple html dom node
106
- * PaperG - added ability for "find" routine to lowercase the value of the selector.
107
- * PaperG - added $tag_start to track the start position of the tag in the total byte index
108
- *
109
- * @package PlaceLocalInclude
110
- */
111
  class simple_html_dom_node
112
  {
113
  public $nodetype = HDOM_TYPE_TEXT;
@@ -116,7 +131,6 @@ class simple_html_dom_node
116
  public $children = array();
117
  public $nodes = array();
118
  public $parent = null;
119
- // The "info" array - see HDOM_INFO_... for what each element contains.
120
  public $_ = array();
121
  public $tag_start = 0;
122
  private $dom = null;
@@ -137,7 +151,6 @@ class simple_html_dom_node
137
  return $this->outertext();
138
  }
139
 
140
- // clean up memory due to php5 circular references memory leak...
141
  function clear()
142
  {
143
  $this->dom = null;
@@ -146,104 +159,86 @@ class simple_html_dom_node
146
  $this->children = null;
147
  }
148
 
149
- // dump node's tree
150
- function dump($show_attr=true, $deep=0)
151
  {
152
- $lead = str_repeat(' ', $deep);
153
 
154
- echo $lead.$this->tag;
155
- if ($show_attr && count($this->attr)>0)
156
- {
157
  echo '(';
158
- foreach ($this->attr as $k=>$v)
159
- echo "[$k]=>\"".$this->$k.'", ';
 
160
  echo ')';
161
  }
 
162
  echo "\n";
163
 
164
- if ($this->nodes)
165
- {
166
- foreach ($this->nodes as $c)
167
- {
168
- $c->dump($show_attr, $deep+1);
169
  }
170
  }
171
  }
172
 
173
-
174
- // Debugging function to dump a single dom node with a bunch of information about it.
175
- function dump_node($echo=true)
176
  {
177
-
178
  $string = $this->tag;
179
- if (count($this->attr)>0)
180
- {
181
  $string .= '(';
182
- foreach ($this->attr as $k=>$v)
183
- {
184
- $string .= "[$k]=>\"".$this->$k.'", ';
185
  }
186
  $string .= ')';
187
  }
188
- if (count($this->_)>0)
189
- {
190
  $string .= ' $_ (';
191
- foreach ($this->_ as $k=>$v)
192
- {
193
- if (is_array($v))
194
- {
195
  $string .= "[$k]=>(";
196
- foreach ($v as $k2=>$v2)
197
- {
198
- $string .= "[$k2]=>\"".$v2.'", ';
199
  }
200
- $string .= ")";
201
  } else {
202
- $string .= "[$k]=>\"".$v.'", ';
203
  }
204
  }
205
- $string .= ")";
206
  }
207
 
208
- if (isset($this->text))
209
- {
210
- $string .= " text: (" . $this->text . ")";
211
  }
212
 
213
- $string .= " HDOM_INNER_INFO: '";
214
- if (isset($node->_[HDOM_INFO_INNER]))
215
- {
216
- $string .= $node->_[HDOM_INFO_INNER] . "'";
217
- }
218
- else
219
- {
220
  $string .= ' NULL ';
221
  }
222
 
223
- $string .= " children: " . count($this->children);
224
- $string .= " nodes: " . count($this->nodes);
225
- $string .= " tag_start: " . $this->tag_start;
226
  $string .= "\n";
227
 
228
- if ($echo)
229
- {
230
  echo $string;
231
  return;
232
- }
233
- else
234
- {
235
  return $string;
236
  }
237
  }
238
 
239
- // returns the parent of node
240
- // If a node is passed in, it will reset the parent of the current node to that one.
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 children list first.
245
- if ($parent !== null)
246
- {
247
  $this->parent = $parent;
248
  $this->parent->nodes[] = $this;
249
  $this->parent->children[] = $this;
@@ -252,204 +247,210 @@ class simple_html_dom_node
252
  return $this->parent;
253
  }
254
 
255
- // verify that node has children
256
  function has_child()
257
  {
258
  return !empty($this->children);
259
  }
260
 
261
- // returns children of node
262
- function children($idx=-1)
263
  {
264
- if ($idx===-1)
265
- {
266
  return $this->children;
267
  }
268
- if (isset($this->children[$idx]))
269
- {
270
  return $this->children[$idx];
271
  }
 
272
  return null;
273
  }
274
 
275
- // returns the first child of node
276
  function first_child()
277
  {
278
- if (count($this->children)>0)
279
- {
280
  return $this->children[0];
281
  }
282
  return null;
283
  }
284
 
285
- // returns the last child of node
286
  function last_child()
287
  {
288
- if (($count=count($this->children))>0)
289
- {
290
- return $this->children[$count-1];
291
  }
292
  return null;
293
  }
294
 
295
- // returns the next sibling of node
296
  function next_sibling()
297
  {
298
- if ($this->parent===null)
299
- {
300
  return null;
301
  }
302
 
303
- $idx = 0;
304
- $count = count($this->parent->children);
305
- while ($idx<$count && $this!==$this->parent->children[$idx])
306
- {
307
- ++$idx;
308
- }
309
- if (++$idx>=$count)
310
- {
311
- return null;
312
  }
313
- return $this->parent->children[$idx];
 
314
  }
315
 
316
- // returns the previous sibling of node
317
  function prev_sibling()
318
  {
319
- if ($this->parent===null) return null;
320
- $idx = 0;
321
- $count = count($this->parent->children);
322
- while ($idx<$count && $this!==$this->parent->children[$idx])
323
- ++$idx;
324
- if (--$idx<0) return null;
325
- return $this->parent->children[$idx];
 
 
 
 
326
  }
327
 
328
- // function to locate a specific ancestor tag in the path to the root.
329
  function find_ancestor_tag($tag)
330
  {
331
  global $debug_object;
332
  if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
333
 
334
- // Start by including ourselves in the comparison.
335
- $returnDom = $this;
 
336
 
337
- while (!is_null($returnDom))
338
- {
339
- if (is_object($debug_object)) { $debug_object->debug_log(2, "Current tag is: " . $returnDom->tag); }
 
 
 
340
 
341
- if ($returnDom->tag == $tag)
342
- {
343
  break;
344
  }
345
- $returnDom = $returnDom->parent;
 
346
  }
347
- return $returnDom;
 
348
  }
349
 
350
- // get dom node's inner html
351
  function innertext()
352
  {
353
- if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER];
354
- if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
 
 
 
 
 
355
 
356
  $ret = '';
357
- foreach ($this->nodes as $n)
 
358
  $ret .= $n->outertext();
 
 
359
  return $ret;
360
  }
361
 
362
- // get dom node's outer text (with tag)
363
  function outertext()
364
  {
365
  global $debug_object;
366
- if (is_object($debug_object))
367
- {
368
  $text = '';
369
- if ($this->tag == 'text')
370
- {
371
- if (!empty($this->text))
372
- {
373
- $text = " with text: " . $this->text;
374
  }
375
  }
 
376
  $debug_object->debug_log(1, 'Innertext of tag: ' . $this->tag . $text);
377
  }
378
 
379
- if ($this->tag==='root') return $this->innertext();
 
 
380
 
381
- // trigger callback
382
- if ($this->dom && $this->dom->callback!==null)
383
- {
384
  call_user_func_array($this->dom->callback, array($this));
385
  }
386
 
387
- if (isset($this->_[HDOM_INFO_OUTER])) return $this->_[HDOM_INFO_OUTER];
388
- if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
 
389
 
390
- // render begin tag
391
- if ($this->dom && $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]])
392
- {
 
 
 
 
393
  $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup();
394
- } else {
395
- $ret = "";
396
  }
397
 
398
- // render inner text
399
- if (isset($this->_[HDOM_INFO_INNER]))
400
- {
401
- // If it's a br tag... don't return the HDOM_INNER_INFO that we may or may not have added.
402
- if ($this->tag != "br")
403
- {
404
  $ret .= $this->_[HDOM_INFO_INNER];
405
  }
406
- } else {
407
- if ($this->nodes)
408
- {
409
- foreach ($this->nodes as $n)
410
- {
411
- $ret .= $this->convert_text($n->outertext());
412
- }
413
  }
414
  }
415
 
416
- // render end tag
417
- if (isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END]!=0)
418
- $ret .= '</'.$this->tag.'>';
 
419
  return $ret;
420
  }
421
 
422
- // get dom node's plain text
423
  function text()
424
  {
425
- if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER];
426
- switch ($this->nodetype)
427
- {
 
 
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
- if (strcasecmp($this->tag, 'script')===0) return '';
433
- if (strcasecmp($this->tag, 'style')===0) return '';
 
434
 
435
  $ret = '';
436
- // In rare cases, (always node type 1 or HDOM_TYPE_ELEMENT - observed for some span tags, and some p tags) $this->nodes is set to NULL.
437
- // NOTE: This indicates that there is a problem where it's set to NULL without a clear happening.
 
 
 
438
  // WHY is this happening?
439
- if (!is_null($this->nodes))
440
- {
441
- foreach ($this->nodes as $n)
442
- {
 
 
 
443
  $ret .= $this->convert_text($n->text());
444
- }
445
 
446
- // If this node is a span... add a space at the end of it so multiple spans don't run into each other. This is plaintext after all.
447
- if ($this->tag == "span")
448
- {
449
- $ret .= $this->dom->default_span_text;
 
 
450
  }
451
-
452
-
453
  }
454
  return $ret;
455
  }
@@ -462,76 +463,82 @@ class simple_html_dom_node
462
  return $ret;
463
  }
464
 
465
- // build node's text with tag
466
  function makeup()
467
  {
468
  // text, comment, unknown
469
- if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
 
 
470
 
471
- $ret = '<'.$this->tag;
472
  $i = -1;
473
 
474
- foreach ($this->attr as $key=>$val)
475
- {
476
  ++$i;
477
 
478
  // skip removed attribute
479
- if ($val===null || $val===false)
480
- continue;
481
 
482
  $ret .= $this->_[HDOM_INFO_SPACE][$i][0];
 
483
  //no value attr: nowrap, checked selected...
484
- if ($val===true)
485
  $ret .= $key;
486
- else {
487
  switch ($this->_[HDOM_INFO_QUOTE][$i])
488
  {
489
  case HDOM_QUOTE_DOUBLE: $quote = '"'; break;
490
  case HDOM_QUOTE_SINGLE: $quote = '\''; break;
491
  default: $quote = '';
492
  }
493
- $ret .= $key.$this->_[HDOM_INFO_SPACE][$i][1].'='.$this->_[HDOM_INFO_SPACE][$i][2].$quote.$val.$quote;
 
 
 
 
 
 
 
494
  }
495
  }
 
496
  $ret = $this->dom->restore_noise($ret);
497
  return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>';
498
  }
499
 
500
- // find elements by css selector
501
- //PaperG - added ability for find to lowercase the value of the selector.
502
- function find($selector, $idx=null, $lowercase=false)
503
  {
504
  $selectors = $this->parse_selector($selector);
505
- if (($count=count($selectors))===0) return array();
506
  $found_keys = array();
507
 
508
  // find each selector
509
- for ($c=0; $c<$count; ++$c)
510
- {
511
- // The change on the below line was documented on the sourceforge code tracker id 2788009
512
  // used to be: if (($levle=count($selectors[0]))===0) return array();
513
- if (($levle=count($selectors[$c]))===0) return array();
514
- if (!isset($this->_[HDOM_INFO_BEGIN])) return array();
515
 
516
- $head = array($this->_[HDOM_INFO_BEGIN]=>1);
 
517
 
518
  // handle descendant selectors, no recursive!
519
- for ($l=0; $l<$levle; ++$l)
520
- {
521
  $ret = array();
522
- foreach ($head as $k=>$v)
523
- {
524
- $n = ($k===-1) ? $this->dom->root : $this->dom->nodes[$k];
525
  //PaperG - Pass this optional parameter on to the seek function.
526
- $n->seek($selectors[$c][$l], $ret, $lowercase);
527
  }
 
528
  $head = $ret;
 
529
  }
530
 
531
- foreach ($head as $k=>$v)
532
- {
533
- if (!isset($found_keys[$k]))
534
- {
535
  $found_keys[$k] = 1;
536
  }
537
  }
@@ -541,192 +548,421 @@ class simple_html_dom_node
541
  ksort($found_keys);
542
 
543
  $found = array();
544
- foreach ($found_keys as $k=>$v)
545
  $found[] = $this->dom->nodes[$k];
 
546
 
547
  // return nth-element or array
548
- if (is_null($idx)) return $found;
549
- else if ($idx<0) $idx = count($found) + $idx;
550
  return (isset($found[$idx])) ? $found[$idx] : null;
551
  }
552
 
553
- // seek for given conditions
554
- // PaperG - added parameter to allow for case insensitive testing of the value of a selector.
555
- protected function seek($selector, &$ret, $lowercase=false)
556
  {
557
  global $debug_object;
558
  if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
559
 
560
- list($tag, $key, $val, $exp, $no_key) = $selector;
561
-
562
- // xpath index
563
- if ($tag && $key && is_numeric($key))
564
- {
565
- $count = 0;
566
- foreach ($this->children as $c)
567
- {
568
- if ($tag==='*' || $tag===$c->tag) {
569
- if (++$count==$key) {
570
- $ret[$c->_[HDOM_INFO_BEGIN]] = 1;
571
- return;
572
- }
573
  }
 
574
  }
575
- return;
576
- }
577
 
578
- $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0;
579
- if ($end==0) {
580
- $parent = $this->parent;
581
- while (!isset($parent->_[HDOM_INFO_END]) && $parent!==null) {
582
- $end -= 1;
583
- $parent = $parent->parent;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
584
  }
585
- $end += $parent->_[HDOM_INFO_END];
586
- }
587
 
588
- for ($i=$this->_[HDOM_INFO_BEGIN]+1; $i<$end; ++$i) {
589
- $node = $this->dom->nodes[$i];
 
 
590
 
591
- $pass = true;
 
 
 
592
 
593
- if ($tag==='*' && !$key) {
594
- if (in_array($node, $this->children, true))
595
- $ret[$i] = 1;
596
- continue;
597
  }
598
 
599
- // compare tag
600
- if ($tag && $tag!=$node->tag && $tag!=='*') {$pass=false;}
601
- // compare key
602
- if ($pass && $key) {
603
- if ($no_key) {
604
- if (isset($node->attr[$key])) $pass=false;
605
- } else {
606
- if (($key != "plaintext") && !isset($node->attr[$key])) $pass=false;
607
- }
608
  }
609
- // compare value
610
- if ($pass && $key && $val && $val!=='*') {
611
- // If they have told us that this is a "plaintext" search then we want the plaintext of the node - right?
612
- if ($key == "plaintext") {
613
- // $node->plaintext actually returns $node->text();
614
- $nodeKeyValue = $node->text();
615
- } else {
616
- // this is a normal search, we want the value of that attribute of the tag.
617
- $nodeKeyValue = $node->attr[$key];
618
- }
619
- if (is_object($debug_object)) {$debug_object->debug_log(2, "testing node: " . $node->tag . " for attribute: " . $key . $exp . $val . " where nodes value is: " . $nodeKeyValue);}
620
 
621
- //PaperG - If lowercase is set, do a case insensitive test of the value of the selector.
622
- if ($lowercase) {
623
- $check = $this->match($exp, strtolower($val), strtolower($nodeKeyValue));
 
 
 
 
 
 
 
 
 
 
 
 
624
  } else {
625
- $check = $this->match($exp, $val, $nodeKeyValue);
626
  }
627
- if (is_object($debug_object)) {$debug_object->debug_log(2, "after match: " . ($check ? "true" : "false"));}
628
-
629
- // handle multiple class
630
- if (!$check && strcasecmp($key, 'class')===0) {
631
- foreach (explode(' ',$node->attr[$key]) as $k) {
632
- // Without this, there were cases where leading, trailing, or double spaces lead to our comparing blanks - bad form.
633
- if (!empty($k)) {
634
- if ($lowercase) {
635
- $check = $this->match($exp, strtolower($val), strtolower($k));
636
- } else {
637
- $check = $this->match($exp, $val, $k);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
  }
639
- if ($check) break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
640
  }
641
  }
642
- }
643
- if (!$check) $pass = false;
644
  }
645
- if ($pass) $ret[$i] = 1;
 
 
646
  unset($node);
647
  }
648
  // It's passed by reference so this is actually what this function returns.
649
- if (is_object($debug_object)) {$debug_object->debug_log(1, "EXIT - ret: ", $ret);}
 
 
650
  }
651
 
652
- protected function match($exp, $pattern, $value) {
 
653
  global $debug_object;
654
  if (is_object($debug_object)) {$debug_object->debug_log_entry(1);}
655
 
 
 
 
 
 
656
  switch ($exp) {
657
  case '=':
658
- return ($value===$pattern);
659
  case '!=':
660
- return ($value!==$pattern);
661
  case '^=':
662
- return preg_match("/^".preg_quote($pattern,'/')."/", $value);
663
  case '$=':
664
- return preg_match("/".preg_quote($pattern,'/')."$/", $value);
665
  case '*=':
666
- if ($pattern[0]=='/') {
667
- return preg_match($pattern, $value);
668
- }
669
- return preg_match("/".$pattern."/i", $value);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
670
  }
671
  return false;
672
  }
673
 
674
- protected function parse_selector($selector_string) {
 
675
  global $debug_object;
676
- if (is_object($debug_object)) {$debug_object->debug_log_entry(1);}
677
 
678
- // pattern of CSS selectors, modified from mootools
679
- // Paperg: Add the colon to the attrbute, so that it properly finds <tag attr:ibute="something" > like google does.
680
- // Note: if you try to look at this attribute, yo MUST use getAttribute since $dom->x:y will fail the php syntax check.
681
- // Notice the \[ starting the attbute? and the @? following? This implies that an attribute can begin with an @ sign that is not captured.
682
- // This implies that an html attribute specifier may start with an @ sign that is NOT captured by the expression.
683
- // farther study is required to determine of this should be documented or removed.
684
- // $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
685
- $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-:]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
686
- preg_match_all($pattern, trim($selector_string).' ', $matches, PREG_SET_ORDER);
687
- if (is_object($debug_object)) {$debug_object->debug_log(2, "Matches Array: ", $matches);}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
688
 
689
  $selectors = array();
690
  $result = array();
691
- //print_r($matches);
692
 
693
  foreach ($matches as $m) {
694
  $m[0] = trim($m[0]);
695
- if ($m[0]==='' || $m[0]==='/' || $m[0]==='//') continue;
696
- // for browser generated xpath
697
- if ($m[1]==='tbody') continue;
698
-
699
- list($tag, $key, $val, $exp, $no_key) = array($m[1], null, null, '=', false);
700
- if (!empty($m[2])) {$key='id'; $val=$m[2];}
701
- if (!empty($m[3])) {$key='class'; $val=$m[3];}
702
- if (!empty($m[4])) {$key=$m[4];}
703
- if (!empty($m[5])) {$exp=$m[5];}
704
- if (!empty($m[6])) {$val=$m[6];}
705
-
706
- // convert to lowercase
707
- if ($this->dom->lowercase) {$tag=strtolower($tag); $key=strtolower($key);}
708
- //elements that do NOT have the specified attribute
709
- if (isset($key[0]) && $key[0]==='!') {$key=substr($key, 1); $no_key=true;}
710
-
711
- $result[] = array($tag, $key, $val, $exp, $no_key);
712
- if (trim($m[7])===',') {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
713
  $selectors[] = $result;
714
  $result = array();
715
  }
716
  }
717
- if (count($result)>0)
718
- $selectors[] = $result;
719
  return $selectors;
720
  }
721
 
722
  function __get($name)
723
  {
724
- if (isset($this->attr[$name]))
725
- {
726
  return $this->convert_text($this->attr[$name]);
727
  }
728
- switch ($name)
729
- {
730
  case 'outertext': return $this->outertext();
731
  case 'innertext': return $this->innertext();
732
  case 'plaintext': return $this->text();
@@ -738,27 +974,28 @@ class simple_html_dom_node
738
  function __set($name, $value)
739
  {
740
  global $debug_object;
741
- if (is_object($debug_object)) {$debug_object->debug_log_entry(1);}
742
 
743
- switch ($name)
744
- {
745
  case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value;
746
  case 'innertext':
747
- if (isset($this->_[HDOM_INFO_TEXT])) return $this->_[HDOM_INFO_TEXT] = $value;
 
 
748
  return $this->_[HDOM_INFO_INNER] = $value;
749
  }
750
- if (!isset($this->attr[$name]))
751
- {
752
  $this->_[HDOM_INFO_SPACE][] = array(' ', '', '');
753
  $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
754
  }
 
755
  $this->attr[$name] = $value;
756
  }
757
 
758
  function __isset($name)
759
  {
760
- switch ($name)
761
- {
762
  case 'outertext': return true;
763
  case 'innertext': return true;
764
  case 'plaintext': return true;
@@ -767,51 +1004,54 @@ class simple_html_dom_node
767
  return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]);
768
  }
769
 
770
- function __unset($name) {
771
- if (isset($this->attr[$name]))
772
- unset($this->attr[$name]);
773
  }
774
 
775
- // PaperG - Function to convert the text from one character set to another if the two sets are not the same.
776
  function convert_text($text)
777
  {
778
  global $debug_object;
779
- if (is_object($debug_object)) {$debug_object->debug_log_entry(1);}
780
 
781
  $converted_text = $text;
782
 
783
- $sourceCharset = "";
784
- $targetCharset = "";
785
 
786
- if ($this->dom)
787
- {
788
  $sourceCharset = strtoupper($this->dom->_charset);
789
  $targetCharset = strtoupper($this->dom->_target_charset);
790
  }
791
- if (is_object($debug_object)) {$debug_object->debug_log(3, "source charset: " . $sourceCharset . " target charaset: " . $targetCharset);}
792
 
793
- if (!empty($sourceCharset) && !empty($targetCharset) && (strcasecmp($sourceCharset, $targetCharset) != 0))
794
- {
 
 
 
 
 
 
 
 
 
 
795
  // Check if the reported encoding could have been incorrect and the text is actually already UTF-8
796
- if ((strcasecmp($targetCharset, 'UTF-8') == 0) && ($this->is_utf8($text)))
797
- {
798
  $converted_text = $text;
799
- }
800
- else
801
- {
802
  $converted_text = iconv($sourceCharset, $targetCharset, $text);
803
  }
804
  }
805
 
806
  // Lets make sure that we don't have that silly BOM issue with any of the utf-8 text we output.
807
- if ($targetCharset == 'UTF-8')
808
- {
809
- if (substr($converted_text, 0, 3) == "\xef\xbb\xbf")
810
- {
811
  $converted_text = substr($converted_text, 3);
812
  }
813
- if (substr($converted_text, -3) == "\xef\xbb\xbf")
814
- {
815
  $converted_text = substr($converted_text, 0, -3);
816
  }
817
  }
@@ -819,57 +1059,33 @@ class simple_html_dom_node
819
  return $converted_text;
820
  }
821
 
822
- /**
823
- * Returns true if $string is valid UTF-8 and false otherwise.
824
- *
825
- * @param mixed $str String to be tested
826
- * @return boolean
827
- */
828
  static function is_utf8($str)
829
  {
830
- $c=0; $b=0;
831
- $bits=0;
832
- $len=strlen($str);
833
- for($i=0; $i<$len; $i++)
834
- {
835
- $c=ord($str[$i]);
836
- if($c > 128)
837
- {
838
- if(($c >= 254)) return false;
839
- elseif($c >= 252) $bits=6;
840
- elseif($c >= 248) $bits=5;
841
- elseif($c >= 240) $bits=4;
842
- elseif($c >= 224) $bits=3;
843
- elseif($c >= 192) $bits=2;
844
- else return false;
845
- if(($i+$bits) > $len) return false;
846
- while($bits > 1)
847
- {
848
  $i++;
849
- $b=ord($str[$i]);
850
- if($b < 128 || $b > 191) return false;
851
  $bits--;
852
  }
853
  }
854
  }
855
  return true;
856
  }
857
- /*
858
- function is_utf8($string)
859
- {
860
- //this is buggy
861
- return (utf8_encode(utf8_decode($string)) == $string);
862
- }
863
- */
864
 
865
- /**
866
- * Function to try a few tricks to determine the displayed size of an img on the page.
867
- * NOTE: This will ONLY work on an IMG tag. Returns FALSE on all other tag types.
868
- *
869
- * @author John Schlick
870
- * @version April 19 2012
871
- * @return array an array containing the 'height' and 'width' of the image on the page or -1 if we can't figure it out.
872
- */
873
  function get_display_size()
874
  {
875
  global $debug_object;
@@ -877,57 +1093,54 @@ class simple_html_dom_node
877
  $width = -1;
878
  $height = -1;
879
 
880
- if ($this->tag !== 'img')
881
- {
882
  return false;
883
  }
884
 
885
  // See if there is aheight or width attribute in the tag itself.
886
- if (isset($this->attr['width']))
887
- {
888
  $width = $this->attr['width'];
889
  }
890
 
891
- if (isset($this->attr['height']))
892
- {
893
  $height = $this->attr['height'];
894
  }
895
 
896
  // Now look for an inline style.
897
- if (isset($this->attr['style']))
898
- {
899
  // Thanks to user gnarf from stackoverflow for this regular expression.
900
  $attributes = array();
901
- preg_match_all("/([\w-]+)\s*:\s*([^;]+)\s*;?/", $this->attr['style'], $matches, PREG_SET_ORDER);
 
 
 
 
 
 
 
902
  foreach ($matches as $match) {
903
- $attributes[$match[1]] = $match[2];
904
  }
905
 
906
  // If there is a width in the style attributes:
907
- if (isset($attributes['width']) && $width == -1)
908
- {
909
  // check that the last two characters are px (pixels)
910
- if (strtolower(substr($attributes['width'], -2)) == 'px')
911
- {
912
  $proposed_width = substr($attributes['width'], 0, -2);
913
  // Now make sure that it's an integer and not something stupid.
914
- if (filter_var($proposed_width, FILTER_VALIDATE_INT))
915
- {
916
  $width = $proposed_width;
917
  }
918
  }
919
  }
920
 
921
  // If there is a width in the style attributes:
922
- if (isset($attributes['height']) && $height == -1)
923
- {
924
  // check that the last two characters are px (pixels)
925
- if (strtolower(substr($attributes['height'], -2)) == 'px')
926
- {
927
  $proposed_height = substr($attributes['height'], 0, -2);
928
  // Now make sure that it's an integer and not something stupid.
929
- if (filter_var($proposed_height, FILTER_VALIDATE_INT))
930
- {
931
  $height = $proposed_height;
932
  }
933
  }
@@ -936,62 +1149,248 @@ class simple_html_dom_node
936
  }
937
 
938
  // Future enhancement:
939
- // Look in the tag to see if there is a class or id specified that has a height or width attribute to it.
 
940
 
941
  // Far future enhancement
942
- // Look at all the parent tags of this image to see if they specify a class or id that has an img selector that specifies a height or width
943
- // Note that in this case, the class or id will have the img subselector for it to apply to the image.
 
 
944
 
945
  // ridiculously far future development
946
- // If the class or id is specified in a SEPARATE css file thats not on the page, go get it and do what we were just doing for the ones on the page.
 
 
 
 
 
 
 
947
 
948
- $result = array('height' => $height,
949
- 'width' => $width);
950
  return $result;
951
  }
952
 
953
- // camel naming conventions
954
- function getAllAttributes() {return $this->attr;}
955
- function getAttribute($name) {return $this->__get($name);}
956
- function setAttribute($name, $value) {$this->__set($name, $value);}
957
- function hasAttribute($name) {return $this->__isset($name);}
958
- function removeAttribute($name) {$this->__set($name, null);}
959
- function getElementById($id) {return $this->find("#$id", 0);}
960
- function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);}
961
- function getElementByTagName($name) {return $this->find($name, 0);}
962
- function getElementsByTagName($name, $idx=null) {return $this->find($name, $idx);}
963
- function parentNode() {return $this->parent();}
964
- function childNodes($idx=-1) {return $this->children($idx);}
965
- function firstChild() {return $this->first_child();}
966
- function lastChild() {return $this->last_child();}
967
- function nextSibling() {return $this->next_sibling();}
968
- function previousSibling() {return $this->prev_sibling();}
969
- function hasChildNodes() {return $this->has_child();}
970
- function nodeName() {return $this->tag;}
971
- function appendChild($node) {$node->parent($this); return $node;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
972
 
973
  }
974
 
975
- /**
976
- * simple html dom parser
977
- * Paperg - in the find routine: allow us to specify that we want case insensitive testing of the value of the selector.
978
- * Paperg - change $size from protected to public so we can easily access it
979
- * Paperg - added ForceTagsClosed in the constructor which tells us whether we trust the html or not. Default is to NOT trust it.
980
- *
981
- * @package PlaceLocalInclude
982
- */
983
  class simple_html_dom
984
  {
985
  public $root = null;
986
  public $nodes = array();
987
  public $callback = null;
988
  public $lowercase = false;
989
- // Used to keep track of how large the text was when we started.
990
  public $original_size;
991
  public $size;
 
992
  protected $pos;
993
  protected $doc;
994
  protected $char;
 
995
  protected $cursor;
996
  protected $parent;
997
  protected $noise = array();
@@ -999,49 +1398,89 @@ class simple_html_dom
999
  protected $token_equal = ' =/>';
1000
  protected $token_slash = " />\r\n\t";
1001
  protected $token_attr = ' >';
1002
- // Note that this is referenced by a child node, and so it needs to be public for that node to see this information.
1003
  public $_charset = '';
1004
  public $_target_charset = '';
1005
- protected $default_br_text = "";
1006
- public $default_span_text = "";
1007
-
1008
- // use isset instead of in_array, performance boost about 30%...
1009
- protected $self_closing_tags = array('img'=>1, 'br'=>1, 'input'=>1, 'meta'=>1, 'link'=>1, 'hr'=>1, 'base'=>1, 'embed'=>1, 'spacer'=>1);
1010
- protected $block_tags = array('root'=>1, 'body'=>1, 'form'=>1, 'div'=>1, 'span'=>1, 'table'=>1);
1011
- // Known sourceforge issue #2977341
1012
- // B tags that are not closed cause us to return everything to the end of the document.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1013
  protected $optional_closing_tags = array(
1014
- 'tr'=>array('tr'=>1, 'td'=>1, 'th'=>1),
1015
- 'th'=>array('th'=>1),
1016
- 'td'=>array('td'=>1),
1017
- 'li'=>array('li'=>1),
1018
- 'dt'=>array('dt'=>1, 'dd'=>1),
1019
- 'dd'=>array('dd'=>1, 'dt'=>1),
1020
- 'dl'=>array('dd'=>1, 'dt'=>1),
1021
- 'p'=>array('p'=>1),
1022
- 'nobr'=>array('nobr'=>1),
1023
- 'b'=>array('b'=>1),
1024
- 'option'=>array('option'=>1),
 
 
 
 
 
 
1025
  );
1026
 
1027
- function __construct($str=null, $lowercase=true, $forceTagsClosed=true, $stripRN=true)
 
 
 
 
 
 
 
 
1028
  {
1029
- if ($str)
1030
- {
1031
- if (preg_match("/^http:\/\//i",$str) || is_file($str))
1032
- {
1033
  $this->load_file($str);
1034
- }
1035
- else
1036
- {
1037
- $this->load($str, $lowercase, $stripRN, $defaultBRText, $defaultSpanText);
 
 
 
 
 
1038
  }
1039
  }
1040
- // Forcing tags to be closed implies that we don't trust the html, but it can lead to parsing errors if we SHOULD trust the html.
 
1041
  if (!$forceTagsClosed) {
1042
- $this->optional_closing_array=array();
1043
  }
1044
- $this->_target_charset = 'UTF-8';
 
1045
  }
1046
 
1047
  function __destruct()
@@ -1049,22 +1488,38 @@ class simple_html_dom
1049
  $this->clear();
1050
  }
1051
 
1052
- // load html from string
1053
- function load($str, $lowercase=true, $stripRN=true)
 
 
 
 
 
1054
  {
1055
  global $debug_object;
1056
 
1057
  // prepare
1058
- $this->prepare($str, $lowercase, $stripRN, '', '');
1059
- // strip out cdata
1060
- $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true);
1061
- // strip out comments
1062
- $this->remove_noise("'<!--(.*?)-->'is");
1063
  // Per sourceforge http://sourceforge.net/tracker/?func=detail&aid=2949097&group_id=218559&atid=1044037
1064
  // Script tags removal now preceeds style tag removal.
1065
  // strip out <script> tags
1066
  $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is");
1067
  $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1068
  // strip out <style> tags
1069
  $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is");
1070
  $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is");
@@ -1072,299 +1527,408 @@ class simple_html_dom
1072
  $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is");
1073
  // strip out server side scripts
1074
  $this->remove_noise("'(<\?)(.*?)(\?>)'s", true);
1075
- // strip smarty scripts
1076
- $this->remove_noise("'(\{\w)(.*?)(\})'s", true);
 
 
1077
 
1078
  // parsing
1079
- while ($this->parse());
1080
  // end
1081
  $this->root->_[HDOM_INFO_END] = $this->cursor;
1082
  $this->parse_charset();
1083
 
1084
  // make load function chainable
1085
  return $this;
1086
-
1087
  }
1088
 
1089
- // load html from file
1090
  function load_file()
1091
  {
1092
  $args = func_get_args();
1093
- $this->load(call_user_func_array('file_get_contents', $args), true);
1094
- // Throw an error if we can't properly load the dom.
1095
- if (($error=error_get_last())!==null) {
1096
- $this->clear();
1097
  return false;
1098
  }
1099
  }
1100
 
1101
- // set callback function
1102
  function set_callback($function_name)
1103
  {
1104
  $this->callback = $function_name;
1105
  }
1106
 
1107
- // remove callback function
1108
  function remove_callback()
1109
  {
1110
  $this->callback = null;
1111
  }
1112
 
1113
- // save dom as string
1114
- function save($filepath='')
1115
  {
1116
  $ret = $this->root->innertext();
1117
- if ($filepath!=='') file_put_contents($filepath, $ret, LOCK_EX);
1118
  return $ret;
1119
  }
1120
 
1121
- // find dom node by css selector
1122
- // Paperg - allow us to specify that we want case insensitive testing of the value of the selector.
1123
- function find($selector, $idx=null, $lowercase=false)
1124
  {
1125
  return $this->root->find($selector, $idx, $lowercase);
1126
  }
1127
 
1128
- // clean up memory due to php5 circular references memory leak...
1129
  function clear()
1130
  {
1131
- foreach ($this->nodes as $n) {$n->clear(); $n = null;}
1132
- // This add next line is documented in the sourceforge repository. 2977248 as a fix for ongoing memory leaks that occur even with the use of clear.
1133
- if (isset($this->children)) foreach ($this->children as $n) {$n->clear(); $n = null;}
1134
- if (isset($this->parent)) {$this->parent->clear(); unset($this->parent);}
1135
- if (isset($this->root)) {$this->root->clear(); unset($this->root);}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1136
  unset($this->doc);
1137
  unset($this->noise);
1138
  }
1139
 
1140
- function dump($show_attr=true)
1141
  {
1142
  $this->root->dump($show_attr);
1143
  }
1144
 
1145
- // prepare HTML data and init everything
1146
- protected function prepare($str, $lowercase=true, $stripRN=true)
 
 
1147
  {
1148
  $this->clear();
1149
 
1150
- // set the length of content before we do anything to it.
1151
- $this->size = strlen($str);
1152
- // Save the original size of the html that we got in. It might be useful to someone.
1153
- $this->original_size = $this->size;
1154
-
1155
- //before we save the string as the doc... strip out the \r \n's if we are told to.
1156
- $stripRN = false;
1157
-
1158
- $this->doc = $str;
1159
  $this->pos = 0;
1160
  $this->cursor = 1;
1161
  $this->noise = array();
1162
  $this->nodes = array();
1163
  $this->lowercase = $lowercase;
1164
- $this->default_br_text = "\r\n";
1165
- $this->default_span_text = " ";
1166
  $this->root = new simple_html_dom_node($this);
1167
  $this->root->tag = 'root';
1168
  $this->root->_[HDOM_INFO_BEGIN] = -1;
1169
  $this->root->nodetype = HDOM_TYPE_ROOT;
1170
  $this->parent = $this->root;
1171
- //if ($this->size>0) $this->char = $this->doc[0];
1172
  }
1173
 
1174
- // parse html content
1175
  protected function parse()
1176
  {
1177
- if (($s = $this->copy_until_char('<'))==='')
1178
- {
1179
- return $this->read_tag();
1180
- }
 
 
 
 
 
 
1181
 
1182
- // text
1183
- $node = new simple_html_dom_node($this);
1184
- ++$this->cursor;
1185
- $node->_[HDOM_INFO_TEXT] = $s;
1186
- $this->link_nodes($node, false);
1187
- return true;
1188
  }
1189
 
1190
- // PAPERG - dkchou - added this to try to identify the character set of the page we have just parsed so we know better how to spit it out later.
1191
- // NOTE: IF you provide a routine called get_last_retrieve_url_contents_content_type which returns the CURLINFO_CONTENT_TYPE from the last curl_exec
1192
- // (or the content_type header from the last transfer), we will parse THAT, and if a charset is specified, we will use it over any other mechanism.
1193
  protected function parse_charset()
1194
  {
1195
  global $debug_object;
1196
 
1197
  $charset = null;
1198
 
1199
- if (function_exists('get_last_retrieve_url_contents_content_type'))
1200
- {
1201
  $contentTypeHeader = get_last_retrieve_url_contents_content_type();
1202
  $success = preg_match('/charset=(.+)/', $contentTypeHeader, $matches);
1203
- if ($success)
1204
- {
1205
  $charset = $matches[1];
1206
- if (is_object($debug_object)) {$debug_object->debug_log(2, 'header content-type found charset of: ' . $charset);}
 
 
 
 
 
1207
  }
1208
-
1209
  }
1210
 
1211
- if (empty($charset))
1212
- {
1213
- $el = $this->root->find('meta[http-equiv=Content-Type]',0, true);
1214
- if (!empty($el))
1215
- {
1216
  $fullvalue = $el->content;
1217
- if (is_object($debug_object)) {$debug_object->debug_log(2, 'meta content-type tag found' . $fullvalue);}
 
 
 
 
 
1218
 
1219
- if (!empty($fullvalue))
1220
- {
1221
- $success = preg_match('/charset=(.+)/i', $fullvalue, $matches);
1222
- if ($success)
1223
- {
 
 
 
1224
  $charset = $matches[1];
1225
- }
1226
- else
1227
- {
1228
- // If there is a meta tag, and they don't specify the character set, research says that it's typically ISO-8859-1
1229
- if (is_object($debug_object)) {$debug_object->debug_log(2, 'meta content-type tag couldn\'t be parsed. using iso-8859 default.');}
 
 
 
 
 
1230
  $charset = 'ISO-8859-1';
1231
  }
1232
  }
1233
  }
1234
  }
1235
 
1236
- // If we couldn't find a charset above, then lets try to detect one based on the text we got...
1237
- if (empty($charset))
1238
- {
1239
- // Use this in case mb_detect_charset isn't installed/loaded on this machine.
1240
- $charset = false;
1241
- if (function_exists('mb_detect_encoding'))
1242
- {
1243
- // Have php try to detect the encoding from the text given to us.
1244
- $charset = mb_detect_encoding($this->root->plaintext . "ascii", $encoding_list = array( "UTF-8", "CP1252" ) );
1245
- if (is_object($debug_object)) {$debug_object->debug_log(2, 'mb_detect found: ' . $charset);}
1246
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1247
 
1248
- // and if this doesn't work... then we need to just wrongheadedly assume it's UTF-8 so that we can move on - cause this will usually give us most of what we need...
1249
- if ($charset === false)
1250
- {
1251
- if (is_object($debug_object)) {$debug_object->debug_log(2, 'since mb_detect failed - using default of utf-8');}
1252
- $charset = 'UTF-8';
 
1253
  }
1254
  }
1255
 
1256
- // Since CP1252 is a superset, if we get one of it's subsets, we want it instead.
1257
- if ((strtolower($charset) == strtolower('ISO-8859-1')) || (strtolower($charset) == strtolower('Latin1')) || (strtolower($charset) == strtolower('Latin-1')))
1258
- {
1259
- if (is_object($debug_object)) {$debug_object->debug_log(2, 'replacing ' . $charset . ' with CP1252 as its a superset');}
 
 
 
 
 
 
 
 
 
1260
  $charset = 'CP1252';
 
 
 
 
 
1261
  }
1262
 
1263
- if (is_object($debug_object)) {$debug_object->debug_log(1, 'EXIT - ' . $charset);}
 
 
1264
 
1265
  return $this->_charset = $charset;
1266
  }
1267
 
1268
- // read tag info
1269
  protected function read_tag()
1270
  {
1271
- if ($this->char!=='<')
1272
- {
1273
  $this->root->_[HDOM_INFO_END] = $this->cursor;
1274
  return false;
1275
  }
 
1276
  $begin_tag_pos = $this->pos;
1277
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1278
 
1279
  // end tag
1280
- if ($this->char==='/')
1281
- {
1282
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1283
- // This represents the change in the simple_html_dom trunk from revision 180 to 181.
1284
- // $this->skip($this->token_blank_t);
1285
  $this->skip($this->token_blank);
1286
  $tag = $this->copy_until_char('>');
1287
 
1288
- // skip attributes in end tag
1289
- if (($pos = strpos($tag, ' '))!==false)
1290
  $tag = substr($tag, 0, $pos);
 
1291
 
1292
  $parent_lower = strtolower($this->parent->tag);
1293
  $tag_lower = strtolower($tag);
1294
 
1295
- if ($parent_lower!==$tag_lower)
1296
- {
1297
- if (isset($this->optional_closing_tags[$parent_lower]) && isset($this->block_tags[$tag_lower]))
1298
- {
 
 
 
 
1299
  $this->parent->_[HDOM_INFO_END] = 0;
1300
  $org_parent = $this->parent;
1301
 
1302
- while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower)
 
 
 
 
1303
  $this->parent = $this->parent->parent;
 
1304
 
1305
- if (strtolower($this->parent->tag)!==$tag_lower) {
 
1306
  $this->parent = $org_parent; // restore origonal parent
1307
- if ($this->parent->parent) $this->parent = $this->parent->parent;
 
 
 
 
1308
  $this->parent->_[HDOM_INFO_END] = $this->cursor;
1309
  return $this->as_text_node($tag);
1310
  }
1311
- }
1312
- else if (($this->parent->parent) && isset($this->block_tags[$tag_lower]))
1313
- {
1314
- $this->parent->_[HDOM_INFO_END] = 0;
 
 
1315
  $org_parent = $this->parent;
1316
 
1317
- while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower)
 
 
 
 
1318
  $this->parent = $this->parent->parent;
 
1319
 
1320
- if (strtolower($this->parent->tag)!==$tag_lower)
1321
- {
1322
  $this->parent = $org_parent; // restore origonal parent
1323
  $this->parent->_[HDOM_INFO_END] = $this->cursor;
1324
  return $this->as_text_node($tag);
1325
  }
1326
- }
1327
- else if (($this->parent->parent) && strtolower($this->parent->parent->tag)===$tag_lower)
1328
- {
1329
  $this->parent->_[HDOM_INFO_END] = 0;
1330
  $this->parent = $this->parent->parent;
1331
- }
1332
- else
1333
  return $this->as_text_node($tag);
 
1334
  }
1335
 
 
1336
  $this->parent->_[HDOM_INFO_END] = $this->cursor;
1337
- if ($this->parent->parent) $this->parent = $this->parent->parent;
1338
 
1339
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
 
 
 
 
1340
  return true;
1341
  }
1342
 
 
1343
  $node = new simple_html_dom_node($this);
1344
  $node->_[HDOM_INFO_BEGIN] = $this->cursor;
1345
  ++$this->cursor;
1346
- $tag = $this->copy_until($this->token_slash);
1347
  $node->tag_start = $begin_tag_pos;
1348
 
1349
  // doctype, cdata & comments...
1350
- if (isset($tag[0]) && $tag[0]==='!') {
 
 
 
1351
  $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>');
1352
 
1353
- if (isset($tag[2]) && $tag[1]==='-' && $tag[2]==='-') {
1354
  $node->nodetype = HDOM_TYPE_COMMENT;
1355
  $node->tag = 'comment';
1356
- } else {
1357
  $node->nodetype = HDOM_TYPE_UNKNOWN;
1358
  $node->tag = 'unknown';
1359
  }
1360
- if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>';
 
 
1361
  $this->link_nodes($node, true);
1362
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1363
  return true;
1364
  }
1365
 
1366
- // text
1367
- if ($pos=strpos($tag, '<')!==false) {
 
1368
  $tag = '<' . substr($tag, 0, -1);
1369
  $node->_[HDOM_INFO_TEXT] = $tag;
1370
  $this->link_nodes($node, false);
@@ -1372,29 +1936,32 @@ class simple_html_dom
1372
  return true;
1373
  }
1374
 
1375
- if (!preg_match("/^[\w-:]+$/", $tag)) {
 
1376
  $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>');
1377
- if ($this->char==='<') {
 
 
1378
  $this->link_nodes($node, false);
1379
  return true;
1380
  }
1381
 
1382
- if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>';
 
1383
  $this->link_nodes($node, false);
1384
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1385
  return true;
1386
  }
1387
 
1388
- // begin tag
1389
  $node->nodetype = HDOM_TYPE_ELEMENT;
1390
  $tag_lower = strtolower($tag);
1391
  $node->tag = ($this->lowercase) ? $tag_lower : $tag;
1392
 
1393
  // handle optional closing tags
1394
- if (isset($this->optional_closing_tags[$tag_lower]) )
1395
- {
1396
- while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)]))
1397
- {
1398
  $this->parent->_[HDOM_INFO_END] = 0;
1399
  $this->parent = $this->parent->parent;
1400
  }
@@ -1402,157 +1969,179 @@ class simple_html_dom
1402
  }
1403
 
1404
  $guard = 0; // prevent infinity loop
 
 
1405
  $space = array($this->copy_skip($this->token_blank), '', '');
1406
 
1407
  // attributes
1408
- do
1409
- {
1410
- if ($this->char!==null && $space[0]==='')
1411
- {
 
1412
  break;
1413
  }
1414
- $name = $this->copy_until($this->token_equal);
1415
- if ($guard===$this->pos)
1416
- {
1417
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1418
  continue;
1419
  }
 
1420
  $guard = $this->pos;
1421
 
1422
  // handle endless '<'
1423
- if ($this->pos>=$this->size-1 && $this->char!=='>') {
 
1424
  $node->nodetype = HDOM_TYPE_TEXT;
1425
  $node->_[HDOM_INFO_END] = 0;
1426
- $node->_[HDOM_INFO_TEXT] = '<'.$tag . $space[0] . $name;
1427
  $node->tag = 'text';
1428
  $this->link_nodes($node, false);
1429
  return true;
1430
  }
1431
 
1432
  // handle mismatch '<'
1433
- if ($this->doc[$this->pos-1]=='<') {
 
1434
  $node->nodetype = HDOM_TYPE_TEXT;
1435
  $node->tag = 'text';
1436
  $node->attr = array();
1437
  $node->_[HDOM_INFO_END] = 0;
1438
- $node->_[HDOM_INFO_TEXT] = substr($this->doc, $begin_tag_pos, $this->pos-$begin_tag_pos-1);
 
 
 
 
1439
  $this->pos -= 2;
1440
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1441
  $this->link_nodes($node, false);
1442
  return true;
1443
  }
1444
 
1445
- if ($name!=='/' && $name!=='') {
 
1446
  $space[1] = $this->copy_skip($this->token_blank);
1447
- $name = $this->restore_noise($name);
1448
- if ($this->lowercase) $name = strtolower($name);
1449
- if ($this->char==='=') {
1450
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1451
- $this->parse_attr($node, $name, $space);
1452
- }
1453
- else {
 
 
1454
  //no value attr: nowrap, checked selected...
1455
  $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
1456
  $node->attr[$name] = true;
1457
- if ($this->char!='>') $this->char = $this->doc[--$this->pos]; // prev
1458
  }
 
1459
  $node->_[HDOM_INFO_SPACE][] = $space;
1460
- $space = array($this->copy_skip($this->token_blank), '', '');
1461
- }
1462
- else
 
 
 
 
 
1463
  break;
1464
- } while ($this->char!=='>' && $this->char!=='/');
 
1465
 
1466
  $this->link_nodes($node, true);
1467
  $node->_[HDOM_INFO_ENDSPACE] = $space[0];
1468
 
1469
- // check self closing
1470
- if ($this->copy_until_char_escape('>')==='/')
1471
- {
1472
  $node->_[HDOM_INFO_ENDSPACE] .= '/';
1473
  $node->_[HDOM_INFO_END] = 0;
1474
- }
1475
- else
1476
- {
1477
  // reset parent
1478
- if (!isset($this->self_closing_tags[strtolower($node->tag)])) $this->parent = $node;
 
 
1479
  }
1480
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
 
1481
 
1482
  // If it's a BR tag, we need to set it's text to the default text.
1483
  // This way when we see it in plaintext, we can generate formatting that the user wants.
1484
  // since a br tag never has sub nodes, this works well.
1485
- if ($node->tag == "br")
1486
- {
1487
  $node->_[HDOM_INFO_INNER] = $this->default_br_text;
1488
  }
1489
 
1490
  return true;
1491
  }
1492
 
1493
- // parse attributes
1494
  protected function parse_attr($node, $name, &$space)
1495
  {
1496
- // Per sourceforge: http://sourceforge.net/tracker/?func=detail&aid=3061408&group_id=218559&atid=1044037
1497
- // If the attribute is already defined inside a tag, only pay atetntion to the first one as opposed to the last one.
1498
- if (isset($node->attr[$name]))
1499
- {
1500
- return;
1501
- }
1502
 
1503
- $space[2] = $this->copy_skip($this->token_blank);
1504
  switch ($this->char) {
1505
  case '"':
1506
- $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
1507
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1508
- $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('"'));
1509
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1510
  break;
1511
  case '\'':
1512
- $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_SINGLE;
1513
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1514
- $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('\''));
1515
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1516
  break;
1517
  default:
1518
- $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
1519
- $node->attr[$name] = $this->restore_noise($this->copy_until($this->token_attr));
 
 
 
 
 
 
 
 
 
 
 
 
 
1520
  }
1521
- // PaperG: Attributes should not have \r or \n in them, that counts as html whitespace.
1522
- $node->attr[$name] = str_replace("\r", "", $node->attr[$name]);
1523
- $node->attr[$name] = str_replace("\n", "", $node->attr[$name]);
1524
- // PaperG: If this is a "class" selector, lets get rid of the preceeding and trailing space since some people leave it in the multi class case.
1525
- if ($name == "class") {
1526
- $node->attr[$name] = trim($node->attr[$name]);
1527
  }
1528
  }
1529
 
1530
- // link node's parent
1531
  protected function link_nodes(&$node, $is_child)
1532
  {
1533
  $node->parent = $this->parent;
1534
  $this->parent->nodes[] = $node;
1535
- if ($is_child)
1536
- {
1537
  $this->parent->children[] = $node;
1538
  }
1539
  }
1540
 
1541
- // as a text node
1542
  protected function as_text_node($tag)
1543
  {
1544
  $node = new simple_html_dom_node($this);
1545
  ++$this->cursor;
1546
  $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>';
1547
  $this->link_nodes($node, false);
1548
- $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1549
  return true;
1550
  }
1551
 
1552
  protected function skip($chars)
1553
  {
1554
  $this->pos += strspn($this->doc, $chars, $this->pos);
1555
- $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1556
  }
1557
 
1558
  protected function copy_skip($chars)
@@ -1560,8 +2149,8 @@ class simple_html_dom
1560
  $pos = $this->pos;
1561
  $len = strspn($this->doc, $chars, $pos);
1562
  $this->pos += $len;
1563
- $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1564
- if ($len===0) return '';
1565
  return substr($this->doc, $pos, $len);
1566
  }
1567
 
@@ -1570,132 +2159,119 @@ class simple_html_dom
1570
  $pos = $this->pos;
1571
  $len = strcspn($this->doc, $chars, $pos);
1572
  $this->pos += $len;
1573
- $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
1574
  return substr($this->doc, $pos, $len);
1575
  }
1576
 
1577
  protected function copy_until_char($char)
1578
  {
1579
- if ($this->char===null) return '';
1580
 
1581
- if (($pos = strpos($this->doc, $char, $this->pos))===false) {
1582
- $ret = substr($this->doc, $this->pos, $this->size-$this->pos);
1583
  $this->char = null;
1584
  $this->pos = $this->size;
1585
  return $ret;
1586
  }
1587
 
1588
- if ($pos===$this->pos) return '';
 
1589
  $pos_old = $this->pos;
1590
  $this->char = $this->doc[$pos];
1591
  $this->pos = $pos;
1592
- return substr($this->doc, $pos_old, $pos-$pos_old);
1593
  }
1594
 
1595
- protected function copy_until_char_escape($char)
1596
  {
1597
- if ($this->char===null) return '';
 
1598
 
1599
- $start = $this->pos;
1600
- while (1)
1601
- {
1602
- if (($pos = strpos($this->doc, $char, $start))===false)
1603
- {
1604
- $ret = substr($this->doc, $this->pos, $this->size-$this->pos);
1605
- $this->char = null;
1606
- $this->pos = $this->size;
1607
- return $ret;
1608
- }
1609
 
1610
- if ($pos===$this->pos) return '';
 
1611
 
1612
- if ($this->doc[$pos-1]==='\\') {
1613
- $start = $pos+1;
1614
- continue;
1615
  }
1616
 
1617
- $pos_old = $this->pos;
1618
- $this->char = $this->doc[$pos];
1619
- $this->pos = $pos;
1620
- return substr($this->doc, $pos_old, $pos-$pos_old);
1621
- }
1622
- }
1623
-
1624
- // remove noise from html content
1625
- // save the noise in the $this->noise array.
1626
- protected function remove_noise($pattern, $remove_tag=false)
1627
- {
1628
- global $debug_object;
1629
- if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
1630
-
1631
- $count = preg_match_all($pattern, $this->doc, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
1632
-
1633
- for ($i=$count-1; $i>-1; --$i)
1634
- {
1635
- $key = '___noise___'.sprintf('% 5d', count($this->noise)+1000);
1636
- if (is_object($debug_object)) { $debug_object->debug_log(2, 'key is: ' . $key); }
1637
- $idx = ($remove_tag) ? 0 : 1;
1638
  $this->noise[$key] = $matches[$i][$idx][0];
1639
  $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0]));
1640
  }
1641
 
1642
  // reset the length of content
1643
-
1644
  $this->size = strlen($this->doc);
1645
- if ($this->size>0){
1646
- if(is_string($this->doc)){
1647
- $this->char = $this->doc[0];
1648
- }
1649
  }
1650
  }
1651
 
1652
- // restore noise to html content
1653
  function restore_noise($text)
1654
  {
1655
  global $debug_object;
1656
  if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
1657
 
1658
- while (($pos=strpos($text, '___noise___'))!==false)
1659
- {
1660
- // Sometimes there is a broken piece of markup, and we don't GET the pos+11 etc... token which indicates a problem outside of us...
1661
- if (strlen($text) > $pos+15)
1662
- {
1663
- $key = '___noise___'.$text[$pos+11].$text[$pos+12].$text[$pos+13].$text[$pos+14].$text[$pos+15];
1664
- if (is_object($debug_object)) { $debug_object->debug_log(2, 'located key of: ' . $key); }
1665
-
1666
- if (isset($this->noise[$key]))
1667
- {
1668
- $text = substr($text, 0, $pos).$this->noise[$key].substr($text, $pos+16);
 
 
 
 
 
 
1669
  }
1670
- else
1671
- {
 
 
 
 
1672
  // do this to prevent an infinite loop.
1673
- $text = substr($text, 0, $pos).'UNDEFINED NOISE FOR KEY: '.$key . substr($text, $pos+16);
 
 
 
1674
  }
1675
- }
1676
- else
1677
- {
1678
- // There is no valid key being given back to us... We must get rid of the ___noise___ or we will have a problem.
1679
- $text = substr($text, 0, $pos).'NO NUMERIC NOISE KEY' . substr($text, $pos+11);
 
1680
  }
1681
  }
1682
  return $text;
1683
  }
1684
 
1685
- // Sometimes we NEED one of the noise elements.
1686
  function search_noise($text)
1687
  {
1688
  global $debug_object;
1689
  if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
1690
 
1691
- foreach($this->noise as $noiseElement)
1692
- {
1693
- if (strpos($noiseElement, $text)!==false)
1694
- {
1695
  return $noiseElement;
1696
  }
1697
  }
1698
  }
 
1699
  function __toString()
1700
  {
1701
  return $this->root->innertext();
@@ -1703,11 +2279,10 @@ class simple_html_dom
1703
 
1704
  function __get($name)
1705
  {
1706
- switch ($name)
1707
- {
1708
- case 'outer text':
1709
  return $this->root->innertext();
1710
- case 'inner text':
1711
  return $this->root->innertext();
1712
  case 'plaintext':
1713
  return $this->root->text();
@@ -1718,15 +2293,54 @@ class simple_html_dom
1718
  }
1719
  }
1720
 
1721
- // camel naming conventions
1722
- function childNodes($idx=-1) {return $this->root->childNodes($idx);}
1723
- function firstChild() {return $this->root->first_child();}
1724
- function lastChild() {return $this->root->last_child();}
1725
- function createElement($name, $value=null) {return @str_get_html("<$name>$value</$name>")->first_child();}
1726
- function createTextNode($value) {return @end(str_get_html($value)->nodes);}
1727
- function getElementById($id) {return $this->find("#$id", 0);}
1728
- function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);}
1729
- function getElementByTagName($name) {return $this->find($name, 0);}
1730
- function getElementsByTagName($name, $idx=-1) {return $this->find($name, $idx);}
1731
- function loadFile() {$args = func_get_args();$this->load_file($args);}
1732
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
 
 
 
 
 
24
  define('HDOM_TYPE_ELEMENT', 1);
25
  define('HDOM_TYPE_COMMENT', 2);
26
+ define('HDOM_TYPE_TEXT', 3);
27
+ define('HDOM_TYPE_ENDTAG', 4);
28
+ define('HDOM_TYPE_ROOT', 5);
29
  define('HDOM_TYPE_UNKNOWN', 6);
30
  define('HDOM_QUOTE_DOUBLE', 0);
31
  define('HDOM_QUOTE_SINGLE', 1);
32
+ define('HDOM_QUOTE_NO', 3);
33
+ define('HDOM_INFO_BEGIN', 0);
34
+ define('HDOM_INFO_END', 1);
35
+ define('HDOM_INFO_QUOTE', 2);
36
+ define('HDOM_INFO_SPACE', 3);
37
+ define('HDOM_INFO_TEXT', 4);
38
+ define('HDOM_INFO_INNER', 5);
39
+ define('HDOM_INFO_OUTER', 6);
40
+ define('HDOM_INFO_ENDSPACE', 7);
41
+
42
+ defined('DEFAULT_TARGET_CHARSET') || define('DEFAULT_TARGET_CHARSET', 'UTF-8');
43
+ defined('DEFAULT_BR_TEXT') || define('DEFAULT_BR_TEXT', "\r\n");
44
+ defined('DEFAULT_SPAN_TEXT') || define('DEFAULT_SPAN_TEXT', ' ');
45
+ defined('MAX_FILE_SIZE') || define('MAX_FILE_SIZE', 600000);
46
+ define('HDOM_SMARTY_AS_TEXT', 1);
47
+
48
+ function file_get_html(
49
+ $url,
50
+ $use_include_path = false,
51
+ $context = null,
52
+ $offset = 0,
53
+ $maxLen = -1,
54
+ $lowercase = true,
55
+ $forceTagsClosed = true,
56
+ $target_charset = DEFAULT_TARGET_CHARSET,
57
+ $stripRN = true,
58
+ $defaultBRText = DEFAULT_BR_TEXT,
59
+ $defaultSpanText = DEFAULT_SPAN_TEXT)
60
  {
61
+ if($maxLen <= 0) { $maxLen = MAX_FILE_SIZE; }
62
+
63
+ $dom = new simple_html_dom(
64
+ null,
65
+ $lowercase,
66
+ $forceTagsClosed,
67
+ $target_charset,
68
+ $stripRN,
69
+ $defaultBRText,
70
+ $defaultSpanText
71
+ );
72
+
73
+ /**
74
+ * For sourceforge users: uncomment the next line and comment the
75
+ * retrieve_url_contents line 2 lines down if it is not already done.
76
+ */
77
+ $contents = file_get_contents(
78
+ $url,
79
+ $use_include_path,
80
+ $context,
81
+ $offset,
82
+ $maxLen
83
+ );
84
+ // $contents = retrieve_url_contents($url);
85
+
86
+ if (empty($contents) || strlen($contents) > $maxLen) {
87
+ $dom->clear();
88
  return false;
89
  }
90
+
91
+ return $dom->load($contents, $lowercase, $stripRN);
 
92
  }
93
 
94
+ function str_get_html(
95
+ $str,
96
+ $lowercase = true,
97
+ $forceTagsClosed = true,
98
+ $target_charset = DEFAULT_TARGET_CHARSET,
99
+ $stripRN = true,
100
+ $defaultBRText = DEFAULT_BR_TEXT,
101
+ $defaultSpanText = DEFAULT_SPAN_TEXT)
102
  {
103
+ $dom = new simple_html_dom(
104
+ null,
105
+ $lowercase,
106
+ $forceTagsClosed,
107
+ $target_charset,
108
+ $stripRN,
109
+ $defaultBRText,
110
+ $defaultSpanText
111
+ );
112
+
113
+ if (empty($str) || strlen($str) > MAX_FILE_SIZE) {
114
  $dom->clear();
115
  return false;
116
  }
117
+
118
+ return $dom->load($str, $lowercase, $stripRN);
119
  }
120
 
121
+ function dump_html_tree($node, $show_attr = true, $deep = 0)
 
122
  {
123
  $node->dump($node);
124
  }
125
 
 
 
 
 
 
 
 
 
126
  class simple_html_dom_node
127
  {
128
  public $nodetype = HDOM_TYPE_TEXT;
131
  public $children = array();
132
  public $nodes = array();
133
  public $parent = null;
 
134
  public $_ = array();
135
  public $tag_start = 0;
136
  private $dom = null;
151
  return $this->outertext();
152
  }
153
 
 
154
  function clear()
155
  {
156
  $this->dom = null;
159
  $this->children = null;
160
  }
161
 
162
+ function dump($show_attr = true, $depth = 0)
 
163
  {
164
+ echo str_repeat("\t", $depth) . $this->tag;
165
 
166
+ if ($show_attr && count($this->attr) > 0) {
 
 
167
  echo '(';
168
+ foreach ($this->attr as $k => $v) {
169
+ echo "[$k]=>\"$v\", ";
170
+ }
171
  echo ')';
172
  }
173
+
174
  echo "\n";
175
 
176
+ if ($this->nodes) {
177
+ foreach ($this->nodes as $node) {
178
+ $node->dump($show_attr, $depth + 1);
 
 
179
  }
180
  }
181
  }
182
 
183
+ function dump_node($echo = true)
 
 
184
  {
 
185
  $string = $this->tag;
186
+
187
+ if (count($this->attr) > 0) {
188
  $string .= '(';
189
+ foreach ($this->attr as $k => $v) {
190
+ $string .= "[$k]=>\"$v\", ";
 
191
  }
192
  $string .= ')';
193
  }
194
+
195
+ if (count($this->_) > 0) {
196
  $string .= ' $_ (';
197
+ foreach ($this->_ as $k => $v) {
198
+ if (is_array($v)) {
 
 
199
  $string .= "[$k]=>(";
200
+ foreach ($v as $k2 => $v2) {
201
+ $string .= "[$k2]=>\"$v2\", ";
 
202
  }
203
+ $string .= ')';
204
  } else {
205
+ $string .= "[$k]=>\"$v\", ";
206
  }
207
  }
208
+ $string .= ')';
209
  }
210
 
211
+ if (isset($this->text)) {
212
+ $string .= " text: ({$this->text})";
 
213
  }
214
 
215
+ $string .= ' HDOM_INNER_INFO: ';
216
+
217
+ if (isset($node->_[HDOM_INFO_INNER])) {
218
+ $string .= "'" . $node->_[HDOM_INFO_INNER] . "'";
219
+ } else {
 
 
220
  $string .= ' NULL ';
221
  }
222
 
223
+ $string .= ' children: ' . count($this->children);
224
+ $string .= ' nodes: ' . count($this->nodes);
225
+ $string .= ' tag_start: ' . $this->tag_start;
226
  $string .= "\n";
227
 
228
+ if ($echo) {
 
229
  echo $string;
230
  return;
231
+ } else {
 
 
232
  return $string;
233
  }
234
  }
235
 
236
+ function parent($parent = null)
 
 
237
  {
238
  // I am SURE that this doesn't work properly.
239
+ // It fails to unset the current node from it's current parents nodes or
240
+ // children list first.
241
+ if ($parent !== null) {
242
  $this->parent = $parent;
243
  $this->parent->nodes[] = $this;
244
  $this->parent->children[] = $this;
247
  return $this->parent;
248
  }
249
 
 
250
  function has_child()
251
  {
252
  return !empty($this->children);
253
  }
254
 
255
+ function children($idx = -1)
 
256
  {
257
+ if ($idx === -1) {
 
258
  return $this->children;
259
  }
260
+
261
+ if (isset($this->children[$idx])) {
262
  return $this->children[$idx];
263
  }
264
+
265
  return null;
266
  }
267
 
 
268
  function first_child()
269
  {
270
+ if (count($this->children) > 0) {
 
271
  return $this->children[0];
272
  }
273
  return null;
274
  }
275
 
 
276
  function last_child()
277
  {
278
+ if (count($this->children) > 0) {
279
+ return end($this->children);
 
280
  }
281
  return null;
282
  }
283
 
 
284
  function next_sibling()
285
  {
286
+ if ($this->parent === null) {
 
287
  return null;
288
  }
289
 
290
+ $idx = array_search($this, $this->parent->children, true);
291
+
292
+ if ($idx !== false && isset($this->parent->children[$idx + 1])) {
293
+ return $this->parent->children[$idx + 1];
 
 
 
 
 
294
  }
295
+
296
+ return null;
297
  }
298
 
 
299
  function prev_sibling()
300
  {
301
+ if ($this->parent === null) {
302
+ return null;
303
+ }
304
+
305
+ $idx = array_search($this, $this->parent->children, true);
306
+
307
+ if ($idx !== false && $idx > 0) {
308
+ return $this->parent->children[$idx - 1];
309
+ }
310
+
311
+ return null;
312
  }
313
 
 
314
  function find_ancestor_tag($tag)
315
  {
316
  global $debug_object;
317
  if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
318
 
319
+ if ($this->parent === null) {
320
+ return null;
321
+ }
322
 
323
+ $ancestor = $this->parent;
324
+
325
+ while (!is_null($ancestor)) {
326
+ if (is_object($debug_object)) {
327
+ $debug_object->debug_log(2, 'Current tag is: ' . $ancestor->tag);
328
+ }
329
 
330
+ if ($ancestor->tag === $tag) {
 
331
  break;
332
  }
333
+
334
+ $ancestor = $ancestor->parent;
335
  }
336
+
337
+ return $ancestor;
338
  }
339
 
 
340
  function innertext()
341
  {
342
+ if (isset($this->_[HDOM_INFO_INNER])) {
343
+ return $this->_[HDOM_INFO_INNER];
344
+ }
345
+
346
+ if (isset($this->_[HDOM_INFO_TEXT])) {
347
+ return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
348
+ }
349
 
350
  $ret = '';
351
+
352
+ foreach ($this->nodes as $n) {
353
  $ret .= $n->outertext();
354
+ }
355
+
356
  return $ret;
357
  }
358
 
 
359
  function outertext()
360
  {
361
  global $debug_object;
362
+
363
+ if (is_object($debug_object)) {
364
  $text = '';
365
+
366
+ if ($this->tag === 'text') {
367
+ if (!empty($this->text)) {
368
+ $text = ' with text: ' . $this->text;
 
369
  }
370
  }
371
+
372
  $debug_object->debug_log(1, 'Innertext of tag: ' . $this->tag . $text);
373
  }
374
 
375
+ if ($this->tag === 'root') {
376
+ return $this->innertext();
377
+ }
378
 
379
+ // todo: What is the use of this callback? Remove?
380
+ if ($this->dom && $this->dom->callback !== null) {
 
381
  call_user_func_array($this->dom->callback, array($this));
382
  }
383
 
384
+ if (isset($this->_[HDOM_INFO_OUTER])) {
385
+ return $this->_[HDOM_INFO_OUTER];
386
+ }
387
 
388
+ if (isset($this->_[HDOM_INFO_TEXT])) {
389
+ return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
390
+ }
391
+
392
+ $ret = '';
393
+
394
+ if ($this->dom && $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]) {
395
  $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup();
 
 
396
  }
397
 
398
+ if (isset($this->_[HDOM_INFO_INNER])) {
399
+ // todo: <br> should either never have HDOM_INFO_INNER or always
400
+ if ($this->tag !== 'br') {
 
 
 
401
  $ret .= $this->_[HDOM_INFO_INNER];
402
  }
403
+ } elseif ($this->nodes) {
404
+ foreach ($this->nodes as $n) {
405
+ $ret .= $this->convert_text($n->outertext());
 
 
 
 
406
  }
407
  }
408
 
409
+ if (isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END] != 0) {
410
+ $ret .= '</' . $this->tag . '>';
411
+ }
412
+
413
  return $ret;
414
  }
415
 
 
416
  function text()
417
  {
418
+ if (isset($this->_[HDOM_INFO_INNER])) {
419
+ return $this->_[HDOM_INFO_INNER];
420
+ }
421
+
422
+ switch ($this->nodetype) {
423
  case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
424
  case HDOM_TYPE_COMMENT: return '';
425
  case HDOM_TYPE_UNKNOWN: return '';
426
  }
427
+
428
+ if (strcasecmp($this->tag, 'script') === 0) { return ''; }
429
+ if (strcasecmp($this->tag, 'style') === 0) { return ''; }
430
 
431
  $ret = '';
432
+
433
+ // In rare cases, (always node type 1 or HDOM_TYPE_ELEMENT - observed
434
+ // for some span tags, and some p tags) $this->nodes is set to NULL.
435
+ // NOTE: This indicates that there is a problem where it's set to NULL
436
+ // without a clear happening.
437
  // WHY is this happening?
438
+ if (!is_null($this->nodes)) {
439
+ foreach ($this->nodes as $n) {
440
+ // Start paragraph after a blank line
441
+ if ($n->tag === 'p') {
442
+ $ret = trim($ret) . "\n\n";
443
+ }
444
+
445
  $ret .= $this->convert_text($n->text());
 
446
 
447
+ // If this node is a span... add a space at the end of it so
448
+ // multiple spans don't run into each other. This is plaintext
449
+ // after all.
450
+ if ($n->tag === 'span') {
451
+ $ret .= $this->dom->default_span_text;
452
+ }
453
  }
 
 
454
  }
455
  return $ret;
456
  }
463
  return $ret;
464
  }
465
 
 
466
  function makeup()
467
  {
468
  // text, comment, unknown
469
+ if (isset($this->_[HDOM_INFO_TEXT])) {
470
+ return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
471
+ }
472
 
473
+ $ret = '<' . $this->tag;
474
  $i = -1;
475
 
476
+ foreach ($this->attr as $key => $val) {
 
477
  ++$i;
478
 
479
  // skip removed attribute
480
+ if ($val === null || $val === false) { continue; }
 
481
 
482
  $ret .= $this->_[HDOM_INFO_SPACE][$i][0];
483
+
484
  //no value attr: nowrap, checked selected...
485
+ if ($val === true) {
486
  $ret .= $key;
487
+ } else {
488
  switch ($this->_[HDOM_INFO_QUOTE][$i])
489
  {
490
  case HDOM_QUOTE_DOUBLE: $quote = '"'; break;
491
  case HDOM_QUOTE_SINGLE: $quote = '\''; break;
492
  default: $quote = '';
493
  }
494
+
495
+ $ret .= $key
496
+ . $this->_[HDOM_INFO_SPACE][$i][1]
497
+ . '='
498
+ . $this->_[HDOM_INFO_SPACE][$i][2]
499
+ . $quote
500
+ . $val
501
+ . $quote;
502
  }
503
  }
504
+
505
  $ret = $this->dom->restore_noise($ret);
506
  return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>';
507
  }
508
 
509
+ function find($selector, $idx = null, $lowercase = false)
 
 
510
  {
511
  $selectors = $this->parse_selector($selector);
512
+ if (($count = count($selectors)) === 0) { return array(); }
513
  $found_keys = array();
514
 
515
  // find each selector
516
+ for ($c = 0; $c < $count; ++$c) {
517
+ // The change on the below line was documented on the sourceforge
518
+ // code tracker id 2788009
519
  // used to be: if (($levle=count($selectors[0]))===0) return array();
520
+ if (($levle = count($selectors[$c])) === 0) { return array(); }
521
+ if (!isset($this->_[HDOM_INFO_BEGIN])) { return array(); }
522
 
523
+ $head = array($this->_[HDOM_INFO_BEGIN] => 1);
524
+ $cmd = ' '; // Combinator
525
 
526
  // handle descendant selectors, no recursive!
527
+ for ($l = 0; $l < $levle; ++$l) {
 
528
  $ret = array();
529
+
530
+ foreach ($head as $k => $v) {
531
+ $n = ($k === -1) ? $this->dom->root : $this->dom->nodes[$k];
532
  //PaperG - Pass this optional parameter on to the seek function.
533
+ $n->seek($selectors[$c][$l], $ret, $cmd, $lowercase);
534
  }
535
+
536
  $head = $ret;
537
+ $cmd = $selectors[$c][$l][4]; // Next Combinator
538
  }
539
 
540
+ foreach ($head as $k => $v) {
541
+ if (!isset($found_keys[$k])) {
 
 
542
  $found_keys[$k] = 1;
543
  }
544
  }
548
  ksort($found_keys);
549
 
550
  $found = array();
551
+ foreach ($found_keys as $k => $v) {
552
  $found[] = $this->dom->nodes[$k];
553
+ }
554
 
555
  // return nth-element or array
556
+ if (is_null($idx)) { return $found; }
557
+ elseif ($idx < 0) { $idx = count($found) + $idx; }
558
  return (isset($found[$idx])) ? $found[$idx] : null;
559
  }
560
 
561
+ protected function seek($selector, &$ret, $parent_cmd, $lowercase = false)
 
 
562
  {
563
  global $debug_object;
564
  if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
565
 
566
+ list($tag, $id, $class, $attributes, $cmb) = $selector;
567
+ $nodes = array();
568
+
569
+ if ($parent_cmd === ' ') { // Descendant Combinator
570
+ // Find parent closing tag if the current element doesn't have a closing
571
+ // tag (i.e. void element)
572
+ $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0;
573
+ if ($end == 0) {
574
+ $parent = $this->parent;
575
+ while (!isset($parent->_[HDOM_INFO_END]) && $parent !== null) {
576
+ $end -= 1;
577
+ $parent = $parent->parent;
 
578
  }
579
+ $end += $parent->_[HDOM_INFO_END];
580
  }
 
 
581
 
582
+ // Get list of target nodes
583
+ $nodes_start = $this->_[HDOM_INFO_BEGIN] + 1;
584
+ $nodes_count = $end - $nodes_start;
585
+ $nodes = array_slice($this->dom->nodes, $nodes_start, $nodes_count, true);
586
+ } elseif ($parent_cmd === '>') { // Child Combinator
587
+ $nodes = $this->children;
588
+ } elseif ($parent_cmd === '+'
589
+ && $this->parent
590
+ && in_array($this, $this->parent->children)) { // Next-Sibling Combinator
591
+ $index = array_search($this, $this->parent->children, true) + 1;
592
+ if ($index < count($this->parent->children))
593
+ $nodes[] = $this->parent->children[$index];
594
+ } elseif ($parent_cmd === '~'
595
+ && $this->parent
596
+ && in_array($this, $this->parent->children)) { // Subsequent Sibling Combinator
597
+ $index = array_search($this, $this->parent->children, true);
598
+ $nodes = array_slice($this->parent->children, $index);
599
+ }
600
+
601
+ // Go throgh each element starting at this element until the end tag
602
+ // Note: If this element is a void tag, any previous void element is
603
+ // skipped.
604
+ foreach($nodes as $node) {
605
+ $pass = true;
606
+
607
+ // Skip root nodes
608
+ if(!$node->parent) {
609
+ $pass = false;
610
  }
 
 
611
 
612
+ // Skip if node isn't a child node (i.e. text nodes)
613
+ if($pass && !in_array($node, $node->parent->children, true)) {
614
+ $pass = false;
615
+ }
616
 
617
+ // Skip if tag doesn't match
618
+ if ($pass && $tag !== '' && $tag !== $node->tag && $tag !== '*') {
619
+ $pass = false;
620
+ }
621
 
622
+ // Skip if ID doesn't exist
623
+ if ($pass && $id !== '' && !isset($node->attr['id'])) {
624
+ $pass = false;
 
625
  }
626
 
627
+ // Check if ID matches
628
+ if ($pass && $id !== '' && isset($node->attr['id'])) {
629
+ // Note: Only consider the first ID (as browsers do)
630
+ $node_id = explode(' ', trim($node->attr['id']))[0];
631
+
632
+ if($id !== $node_id) { $pass = false; }
 
 
 
633
  }
 
 
 
 
 
 
 
 
 
 
 
634
 
635
+ // Check if all class(es) exist
636
+ if ($pass && $class !== '' && is_array($class) && !empty($class)) {
637
+ if (isset($node->attr['class'])) {
638
+ $node_classes = explode(' ', $node->attr['class']);
639
+
640
+ if ($lowercase) {
641
+ $node_classes = array_map('strtolower', $node_classes);
642
+ }
643
+
644
+ foreach($class as $c) {
645
+ if(!in_array($c, $node_classes)) {
646
+ $pass = false;
647
+ break;
648
+ }
649
+ }
650
  } else {
651
+ $pass = false;
652
  }
653
+ }
654
+
655
+ // Check attributes
656
+ if ($pass
657
+ && $attributes !== ''
658
+ && is_array($attributes)
659
+ && !empty($attributes)) {
660
+ foreach($attributes as $a) {
661
+ list (
662
+ $att_name,
663
+ $att_expr,
664
+ $att_val,
665
+ $att_inv,
666
+ $att_case_sensitivity
667
+ ) = $a;
668
+
669
+ // Handle indexing attributes (i.e. "[2]")
670
+ /**
671
+ * Note: This is not supported by the CSS Standard but adds
672
+ * the ability to select items compatible to XPath (i.e.
673
+ * the 3rd element within it's parent).
674
+ *
675
+ * Note: This doesn't conflict with the CSS Standard which
676
+ * doesn't work on numeric attributes anyway.
677
+ */
678
+ if (is_numeric($att_name)
679
+ && $att_expr === ''
680
+ && $att_val === '') {
681
+ $count = 0;
682
+
683
+ // Find index of current element in parent
684
+ foreach ($node->parent->children as $c) {
685
+ if ($c->tag === $node->tag) ++$count;
686
+ if ($c === $node) break;
687
+ }
688
+
689
+ // If this is the correct node, continue with next
690
+ // attribute
691
+ if ($count === (int)$att_name) continue;
692
+ }
693
+
694
+ // Check attribute availability
695
+ if ($att_inv) { // Attribute should NOT be set
696
+ if (isset($node->attr[$att_name])) {
697
+ $pass = false;
698
+ break;
699
+ }
700
+ } else { // Attribute should be set
701
+ // todo: "plaintext" is not a valid CSS selector!
702
+ if ($att_name !== 'plaintext'
703
+ && !isset($node->attr[$att_name])) {
704
+ $pass = false;
705
+ break;
706
  }
707
+ }
708
+
709
+ // Continue with next attribute if expression isn't defined
710
+ if ($att_expr === '') continue;
711
+
712
+ // If they have told us that this is a "plaintext"
713
+ // search then we want the plaintext of the node - right?
714
+ // todo "plaintext" is not a valid CSS selector!
715
+ if ($att_name === 'plaintext') {
716
+ $nodeKeyValue = $node->text();
717
+ } else {
718
+ $nodeKeyValue = $node->attr[$att_name];
719
+ }
720
+
721
+ if (is_object($debug_object)) {
722
+ $debug_object->debug_log(2,
723
+ 'testing node: '
724
+ . $node->tag
725
+ . ' for attribute: '
726
+ . $att_name
727
+ . $att_expr
728
+ . $att_val
729
+ . ' where nodes value is: '
730
+ . $nodeKeyValue
731
+ );
732
+ }
733
+
734
+ // If lowercase is set, do a case insensitive test of
735
+ // the value of the selector.
736
+ if ($lowercase) {
737
+ $check = $this->match(
738
+ $att_expr,
739
+ strtolower($att_val),
740
+ strtolower($nodeKeyValue),
741
+ $att_case_sensitivity
742
+ );
743
+ } else {
744
+ $check = $this->match(
745
+ $att_expr,
746
+ $att_val,
747
+ $nodeKeyValue,
748
+ $att_case_sensitivity
749
+ );
750
+ }
751
+
752
+ if (is_object($debug_object)) {
753
+ $debug_object->debug_log(2,
754
+ 'after match: '
755
+ . ($check ? 'true' : 'false')
756
+ );
757
+ }
758
+
759
+ if (!$check) {
760
+ $pass = false;
761
+ break;
762
  }
763
  }
 
 
764
  }
765
+
766
+ // Found a match. Add to list and clear node
767
+ if ($pass) $ret[$node->_[HDOM_INFO_BEGIN]] = 1;
768
  unset($node);
769
  }
770
  // It's passed by reference so this is actually what this function returns.
771
+ if (is_object($debug_object)) {
772
+ $debug_object->debug_log(1, 'EXIT - ret: ', $ret);
773
+ }
774
  }
775
 
776
+ protected function match($exp, $pattern, $value, $case_sensitivity)
777
+ {
778
  global $debug_object;
779
  if (is_object($debug_object)) {$debug_object->debug_log_entry(1);}
780
 
781
+ if ($case_sensitivity === 'i') {
782
+ $pattern = strtolower($pattern);
783
+ $value = strtolower($value);
784
+ }
785
+
786
  switch ($exp) {
787
  case '=':
788
+ return ($value === $pattern);
789
  case '!=':
790
+ return ($value !== $pattern);
791
  case '^=':
792
+ return preg_match('/^' . preg_quote($pattern, '/') . '/', $value);
793
  case '$=':
794
+ return preg_match('/' . preg_quote($pattern, '/') . '$/', $value);
795
  case '*=':
796
+ return preg_match('/' . preg_quote($pattern, '/') . '/', $value);
797
+ case '|=':
798
+ /**
799
+ * [att|=val]
800
+ *
801
+ * Represents an element with the att attribute, its value
802
+ * either being exactly "val" or beginning with "val"
803
+ * immediately followed by "-" (U+002D).
804
+ */
805
+ return strpos($value, $pattern) === 0;
806
+ case '~=':
807
+ /**
808
+ * [att~=val]
809
+ *
810
+ * Represents an element with the att attribute whose value is a
811
+ * whitespace-separated list of words, one of which is exactly
812
+ * "val". If "val" contains whitespace, it will never represent
813
+ * anything (since the words are separated by spaces). Also if
814
+ * "val" is the empty string, it will never represent anything.
815
+ */
816
+ return in_array($pattern, explode(' ', trim($value)), true);
817
  }
818
  return false;
819
  }
820
 
821
+ protected function parse_selector($selector_string)
822
+ {
823
  global $debug_object;
824
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
825
 
826
+ /**
827
+ * Pattern of CSS selectors, modified from mootools (https://mootools.net/)
828
+ *
829
+ * Paperg: Add the colon to the attribute, so that it properly finds
830
+ * <tag attr:ibute="something" > like google does.
831
+ *
832
+ * Note: if you try to look at this attribute, you MUST use getAttribute
833
+ * since $dom->x:y will fail the php syntax check.
834
+ *
835
+ * Notice the \[ starting the attribute? and the @? following? This
836
+ * implies that an attribute can begin with an @ sign that is not
837
+ * captured. This implies that an html attribute specifier may start
838
+ * with an @ sign that is NOT captured by the expression. Farther study
839
+ * is required to determine of this should be documented or removed.
840
+ *
841
+ * Matches selectors in this order:
842
+ *
843
+ * [0] - full match
844
+ *
845
+ * [1] - tag name
846
+ * ([\w:\*-]*)
847
+ * Matches the tag name consisting of zero or more words, colons,
848
+ * asterisks and hyphens.
849
+ *
850
+ * [2] - id name
851
+ * (?:\#([\w-]+))
852
+ * Optionally matches a id name, consisting of an "#" followed by
853
+ * the id name (one or more words and hyphens).
854
+ *
855
+ * [3] - class names (including dots)
856
+ * (?:\.([\w\.-]+))?
857
+ * Optionally matches a list of classs, consisting of an "."
858
+ * followed by the class name (one or more words and hyphens)
859
+ * where multiple classes can be chained (i.e. ".foo.bar.baz")
860
+ *
861
+ * [4] - attributes
862
+ * ((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)?
863
+ * Optionally matches the attributes list
864
+ *
865
+ * [5] - separator
866
+ * ([\/, >+~]+)
867
+ * Matches the selector list separator
868
+ */
869
+ // phpcs:ignore Generic.Files.LineLength
870
+ $pattern = "/([\w:\*-]*)(?:\#([\w-]+))?(?:|\.([\w\.-]+))?((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)?([\/, >+~]+)/is";
871
+
872
+ preg_match_all(
873
+ $pattern,
874
+ trim($selector_string) . ' ', // Add final ' ' as pseudo separator
875
+ $matches,
876
+ PREG_SET_ORDER
877
+ );
878
+
879
+ if (is_object($debug_object)) {
880
+ $debug_object->debug_log(2, 'Matches Array: ', $matches);
881
+ }
882
 
883
  $selectors = array();
884
  $result = array();
 
885
 
886
  foreach ($matches as $m) {
887
  $m[0] = trim($m[0]);
888
+
889
+ // Skip NoOps
890
+ if ($m[0] === '' || $m[0] === '/' || $m[0] === '//') { continue; }
891
+
892
+ // Convert to lowercase
893
+ if ($this->dom->lowercase) {
894
+ $m[1] = strtolower($m[1]);
895
+ }
896
+
897
+ // Extract classes
898
+ if ($m[3] !== '') { $m[3] = explode('.', $m[3]); }
899
+
900
+ /* Extract attributes (pattern based on the pattern above!)
901
+
902
+ * [0] - full match
903
+ * [1] - attribute name
904
+ * [2] - attribute expression
905
+ * [3] - attribute value
906
+ * [4] - case sensitivity
907
+ *
908
+ * Note: Attributes can be negated with a "!" prefix to their name
909
+ */
910
+ if($m[4] !== '') {
911
+ preg_match_all(
912
+ "/\[@?(!?[\w:-]+)(?:([!*^$|~]?=)[\"']?(.*?)[\"']?)?(?:\s+?([iIsS])?)?\]/is",
913
+ trim($m[4]),
914
+ $attributes,
915
+ PREG_SET_ORDER
916
+ );
917
+
918
+ // Replace element by array
919
+ $m[4] = array();
920
+
921
+ foreach($attributes as $att) {
922
+ // Skip empty matches
923
+ if(trim($att[0]) === '') { continue; }
924
+
925
+ $inverted = (isset($att[1][0]) && $att[1][0] === '!');
926
+ $m[4][] = array(
927
+ $inverted ? substr($att[1], 1) : $att[1], // Name
928
+ (isset($att[2])) ? $att[2] : '', // Expression
929
+ (isset($att[3])) ? $att[3] : '', // Value
930
+ $inverted, // Inverted Flag
931
+ (isset($att[4])) ? strtolower($att[4]) : '', // Case-Sensitivity
932
+ );
933
+ }
934
+ }
935
+
936
+ // Sanitize Separator
937
+ if ($m[5] !== '' && trim($m[5]) === '') { // Descendant Separator
938
+ $m[5] = ' ';
939
+ } else { // Other Separator
940
+ $m[5] = trim($m[5]);
941
+ }
942
+
943
+ // Clear Separator if it's a Selector List
944
+ if ($is_list = ($m[5] === ',')) { $m[5] = ''; }
945
+
946
+ // Remove full match before adding to results
947
+ array_shift($m);
948
+ $result[] = $m;
949
+
950
+ if ($is_list) { // Selector List
951
  $selectors[] = $result;
952
  $result = array();
953
  }
954
  }
955
+
956
+ if (count($result) > 0) { $selectors[] = $result; }
957
  return $selectors;
958
  }
959
 
960
  function __get($name)
961
  {
962
+ if (isset($this->attr[$name])) {
 
963
  return $this->convert_text($this->attr[$name]);
964
  }
965
+ switch ($name) {
 
966
  case 'outertext': return $this->outertext();
967
  case 'innertext': return $this->innertext();
968
  case 'plaintext': return $this->text();
974
  function __set($name, $value)
975
  {
976
  global $debug_object;
977
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
978
 
979
+ switch ($name) {
 
980
  case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value;
981
  case 'innertext':
982
+ if (isset($this->_[HDOM_INFO_TEXT])) {
983
+ return $this->_[HDOM_INFO_TEXT] = $value;
984
+ }
985
  return $this->_[HDOM_INFO_INNER] = $value;
986
  }
987
+
988
+ if (!isset($this->attr[$name])) {
989
  $this->_[HDOM_INFO_SPACE][] = array(' ', '', '');
990
  $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
991
  }
992
+
993
  $this->attr[$name] = $value;
994
  }
995
 
996
  function __isset($name)
997
  {
998
+ switch ($name) {
 
999
  case 'outertext': return true;
1000
  case 'innertext': return true;
1001
  case 'plaintext': return true;
1004
  return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]);
1005
  }
1006
 
1007
+ function __unset($name)
1008
+ {
1009
+ if (isset($this->attr[$name])) { unset($this->attr[$name]); }
1010
  }
1011
 
 
1012
  function convert_text($text)
1013
  {
1014
  global $debug_object;
1015
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
1016
 
1017
  $converted_text = $text;
1018
 
1019
+ $sourceCharset = '';
1020
+ $targetCharset = '';
1021
 
1022
+ if ($this->dom) {
 
1023
  $sourceCharset = strtoupper($this->dom->_charset);
1024
  $targetCharset = strtoupper($this->dom->_target_charset);
1025
  }
 
1026
 
1027
+ if (is_object($debug_object)) {
1028
+ $debug_object->debug_log(3,
1029
+ 'source charset: '
1030
+ . $sourceCharset
1031
+ . ' target charaset: '
1032
+ . $targetCharset
1033
+ );
1034
+ }
1035
+
1036
+ if (!empty($sourceCharset)
1037
+ && !empty($targetCharset)
1038
+ && (strcasecmp($sourceCharset, $targetCharset) != 0)) {
1039
  // Check if the reported encoding could have been incorrect and the text is actually already UTF-8
1040
+ if ((strcasecmp($targetCharset, 'UTF-8') == 0)
1041
+ && ($this->is_utf8($text))) {
1042
  $converted_text = $text;
1043
+ } else {
 
 
1044
  $converted_text = iconv($sourceCharset, $targetCharset, $text);
1045
  }
1046
  }
1047
 
1048
  // Lets make sure that we don't have that silly BOM issue with any of the utf-8 text we output.
1049
+ if ($targetCharset === 'UTF-8') {
1050
+ if (substr($converted_text, 0, 3) === "\xef\xbb\xbf") {
 
 
1051
  $converted_text = substr($converted_text, 3);
1052
  }
1053
+
1054
+ if (substr($converted_text, -3) === "\xef\xbb\xbf") {
1055
  $converted_text = substr($converted_text, 0, -3);
1056
  }
1057
  }
1059
  return $converted_text;
1060
  }
1061
 
 
 
 
 
 
 
1062
  static function is_utf8($str)
1063
  {
1064
+ $c = 0; $b = 0;
1065
+ $bits = 0;
1066
+ $len = strlen($str);
1067
+ for($i = 0; $i < $len; $i++) {
1068
+ $c = ord($str[$i]);
1069
+ if($c > 128) {
1070
+ if(($c >= 254)) { return false; }
1071
+ elseif($c >= 252) { $bits = 6; }
1072
+ elseif($c >= 248) { $bits = 5; }
1073
+ elseif($c >= 240) { $bits = 4; }
1074
+ elseif($c >= 224) { $bits = 3; }
1075
+ elseif($c >= 192) { $bits = 2; }
1076
+ else { return false; }
1077
+ if(($i + $bits) > $len) { return false; }
1078
+ while($bits > 1) {
 
 
 
1079
  $i++;
1080
+ $b = ord($str[$i]);
1081
+ if($b < 128 || $b > 191) { return false; }
1082
  $bits--;
1083
  }
1084
  }
1085
  }
1086
  return true;
1087
  }
 
 
 
 
 
 
 
1088
 
 
 
 
 
 
 
 
 
1089
  function get_display_size()
1090
  {
1091
  global $debug_object;
1093
  $width = -1;
1094
  $height = -1;
1095
 
1096
+ if ($this->tag !== 'img') {
 
1097
  return false;
1098
  }
1099
 
1100
  // See if there is aheight or width attribute in the tag itself.
1101
+ if (isset($this->attr['width'])) {
 
1102
  $width = $this->attr['width'];
1103
  }
1104
 
1105
+ if (isset($this->attr['height'])) {
 
1106
  $height = $this->attr['height'];
1107
  }
1108
 
1109
  // Now look for an inline style.
1110
+ if (isset($this->attr['style'])) {
 
1111
  // Thanks to user gnarf from stackoverflow for this regular expression.
1112
  $attributes = array();
1113
+
1114
+ preg_match_all(
1115
+ '/([\w-]+)\s*:\s*([^;]+)\s*;?/',
1116
+ $this->attr['style'],
1117
+ $matches,
1118
+ PREG_SET_ORDER
1119
+ );
1120
+
1121
  foreach ($matches as $match) {
1122
+ $attributes[$match[1]] = $match[2];
1123
  }
1124
 
1125
  // If there is a width in the style attributes:
1126
+ if (isset($attributes['width']) && $width == -1) {
 
1127
  // check that the last two characters are px (pixels)
1128
+ if (strtolower(substr($attributes['width'], -2)) === 'px') {
 
1129
  $proposed_width = substr($attributes['width'], 0, -2);
1130
  // Now make sure that it's an integer and not something stupid.
1131
+ if (filter_var($proposed_width, FILTER_VALIDATE_INT)) {
 
1132
  $width = $proposed_width;
1133
  }
1134
  }
1135
  }
1136
 
1137
  // If there is a width in the style attributes:
1138
+ if (isset($attributes['height']) && $height == -1) {
 
1139
  // check that the last two characters are px (pixels)
1140
+ if (strtolower(substr($attributes['height'], -2)) == 'px') {
 
1141
  $proposed_height = substr($attributes['height'], 0, -2);
1142
  // Now make sure that it's an integer and not something stupid.
1143
+ if (filter_var($proposed_height, FILTER_VALIDATE_INT)) {
 
1144
  $height = $proposed_height;
1145
  }
1146
  }
1149
  }
1150
 
1151
  // Future enhancement:
1152
+ // Look in the tag to see if there is a class or id specified that has
1153
+ // a height or width attribute to it.
1154
 
1155
  // Far future enhancement
1156
+ // Look at all the parent tags of this image to see if they specify a
1157
+ // class or id that has an img selector that specifies a height or width
1158
+ // Note that in this case, the class or id will have the img subselector
1159
+ // for it to apply to the image.
1160
 
1161
  // ridiculously far future development
1162
+ // If the class or id is specified in a SEPARATE css file thats not on
1163
+ // the page, go get it and do what we were just doing for the ones on
1164
+ // the page.
1165
+
1166
+ $result = array(
1167
+ 'height' => $height,
1168
+ 'width' => $width
1169
+ );
1170
 
 
 
1171
  return $result;
1172
  }
1173
 
1174
+ function save($filepath = '')
1175
+ {
1176
+ $ret = $this->outertext();
1177
+
1178
+ if ($filepath !== '') {
1179
+ file_put_contents($filepath, $ret, LOCK_EX);
1180
+ }
1181
+
1182
+ return $ret;
1183
+ }
1184
+
1185
+ function addClass($class)
1186
+ {
1187
+ if (is_string($class)) {
1188
+ $class = explode(' ', $class);
1189
+ }
1190
+
1191
+ if (is_array($class)) {
1192
+ foreach($class as $c) {
1193
+ if (isset($this->class)) {
1194
+ if ($this->hasClass($c)) {
1195
+ continue;
1196
+ } else {
1197
+ $this->class .= ' ' . $c;
1198
+ }
1199
+ } else {
1200
+ $this->class = $c;
1201
+ }
1202
+ }
1203
+ } else {
1204
+ if (is_object($debug_object)) {
1205
+ $debug_object->debug_log(2, 'Invalid type: ', gettype($class));
1206
+ }
1207
+ }
1208
+ }
1209
+
1210
+ function hasClass($class)
1211
+ {
1212
+ if (is_string($class)) {
1213
+ if (isset($this->class)) {
1214
+ return in_array($class, explode(' ', $this->class), true);
1215
+ }
1216
+ } else {
1217
+ if (is_object($debug_object)) {
1218
+ $debug_object->debug_log(2, 'Invalid type: ', gettype($class));
1219
+ }
1220
+ }
1221
+
1222
+ return false;
1223
+ }
1224
+
1225
+ function removeClass($class = null)
1226
+ {
1227
+ if (!isset($this->class)) {
1228
+ return;
1229
+ }
1230
+
1231
+ if (is_null($class)) {
1232
+ $this->removeAttribute('class');
1233
+ return;
1234
+ }
1235
+
1236
+ if (is_string($class)) {
1237
+ $class = explode(' ', $class);
1238
+ }
1239
+
1240
+ if (is_array($class)) {
1241
+ $class = array_diff(explode(' ', $this->class), $class);
1242
+ if (empty($class)) {
1243
+ $this->removeAttribute('class');
1244
+ } else {
1245
+ $this->class = implode(' ', $class);
1246
+ }
1247
+ }
1248
+ }
1249
+
1250
+ function getAllAttributes()
1251
+ {
1252
+ return $this->attr;
1253
+ }
1254
+
1255
+ function getAttribute($name)
1256
+ {
1257
+ return $this->__get($name);
1258
+ }
1259
+
1260
+ function setAttribute($name, $value)
1261
+ {
1262
+ $this->__set($name, $value);
1263
+ }
1264
+
1265
+ function hasAttribute($name)
1266
+ {
1267
+ return $this->__isset($name);
1268
+ }
1269
+
1270
+ function removeAttribute($name)
1271
+ {
1272
+ $this->__set($name, null);
1273
+ }
1274
+
1275
+ function remove()
1276
+ {
1277
+ if ($this->parent) {
1278
+ $this->parent->removeChild($this);
1279
+ }
1280
+ }
1281
+
1282
+ function removeChild($node)
1283
+ {
1284
+ $nidx = array_search($node, $this->nodes, true);
1285
+ $cidx = array_search($node, $this->children, true);
1286
+ $didx = array_search($node, $this->dom->nodes, true);
1287
+
1288
+ if ($nidx !== false && $cidx !== false && $didx !== false) {
1289
+
1290
+ foreach($node->children as $child) {
1291
+ $node->removeChild($child);
1292
+ }
1293
+
1294
+ foreach($node->nodes as $entity) {
1295
+ $enidx = array_search($entity, $node->nodes, true);
1296
+ $edidx = array_search($entity, $node->dom->nodes, true);
1297
+
1298
+ if ($enidx !== false && $edidx !== false) {
1299
+ unset($node->nodes[$enidx]);
1300
+ unset($node->dom->nodes[$edidx]);
1301
+ }
1302
+ }
1303
+
1304
+ unset($this->nodes[$nidx]);
1305
+ unset($this->children[$cidx]);
1306
+ unset($this->dom->nodes[$didx]);
1307
+
1308
+ $node->clear();
1309
+
1310
+ }
1311
+ }
1312
+
1313
+ function getElementById($id)
1314
+ {
1315
+ return $this->find("#$id", 0);
1316
+ }
1317
+
1318
+ function getElementsById($id, $idx = null)
1319
+ {
1320
+ return $this->find("#$id", $idx);
1321
+ }
1322
+
1323
+ function getElementByTagName($name)
1324
+ {
1325
+ return $this->find($name, 0);
1326
+ }
1327
+
1328
+ function getElementsByTagName($name, $idx = null)
1329
+ {
1330
+ return $this->find($name, $idx);
1331
+ }
1332
+
1333
+ function parentNode()
1334
+ {
1335
+ return $this->parent();
1336
+ }
1337
+
1338
+ function childNodes($idx = -1)
1339
+ {
1340
+ return $this->children($idx);
1341
+ }
1342
+
1343
+ function firstChild()
1344
+ {
1345
+ return $this->first_child();
1346
+ }
1347
+
1348
+ function lastChild()
1349
+ {
1350
+ return $this->last_child();
1351
+ }
1352
+
1353
+ function nextSibling()
1354
+ {
1355
+ return $this->next_sibling();
1356
+ }
1357
+
1358
+ function previousSibling()
1359
+ {
1360
+ return $this->prev_sibling();
1361
+ }
1362
+
1363
+ function hasChildNodes()
1364
+ {
1365
+ return $this->has_child();
1366
+ }
1367
+
1368
+ function nodeName()
1369
+ {
1370
+ return $this->tag;
1371
+ }
1372
+
1373
+ function appendChild($node)
1374
+ {
1375
+ $node->parent($this);
1376
+ return $node;
1377
+ }
1378
 
1379
  }
1380
 
 
 
 
 
 
 
 
 
1381
  class simple_html_dom
1382
  {
1383
  public $root = null;
1384
  public $nodes = array();
1385
  public $callback = null;
1386
  public $lowercase = false;
 
1387
  public $original_size;
1388
  public $size;
1389
+
1390
  protected $pos;
1391
  protected $doc;
1392
  protected $char;
1393
+
1394
  protected $cursor;
1395
  protected $parent;
1396
  protected $noise = array();
1398
  protected $token_equal = ' =/>';
1399
  protected $token_slash = " />\r\n\t";
1400
  protected $token_attr = ' >';
1401
+
1402
  public $_charset = '';
1403
  public $_target_charset = '';
1404
+
1405
+ protected $default_br_text = '';
1406
+
1407
+ public $default_span_text = '';
1408
+
1409
+ protected $self_closing_tags = array(
1410
+ 'area' => 1,
1411
+ 'base' => 1,
1412
+ 'br' => 1,
1413
+ 'col' => 1,
1414
+ 'embed' => 1,
1415
+ 'hr' => 1,
1416
+ 'img' => 1,
1417
+ 'input' => 1,
1418
+ 'link' => 1,
1419
+ 'meta' => 1,
1420
+ 'param' => 1,
1421
+ 'source' => 1,
1422
+ 'track' => 1,
1423
+ 'wbr' => 1
1424
+ );
1425
+ protected $block_tags = array(
1426
+ 'body' => 1,
1427
+ 'div' => 1,
1428
+ 'form' => 1,
1429
+ 'root' => 1,
1430
+ 'span' => 1,
1431
+ 'table' => 1
1432
+ );
1433
  protected $optional_closing_tags = array(
1434
+ // Not optional, see
1435
+ // https://www.w3.org/TR/html/textlevel-semantics.html#the-b-element
1436
+ 'b' => array('b' => 1),
1437
+ 'dd' => array('dd' => 1, 'dt' => 1),
1438
+ // Not optional, see
1439
+ // https://www.w3.org/TR/html/grouping-content.html#the-dl-element
1440
+ 'dl' => array('dd' => 1, 'dt' => 1),
1441
+ 'dt' => array('dd' => 1, 'dt' => 1),
1442
+ 'li' => array('li' => 1),
1443
+ 'optgroup' => array('optgroup' => 1, 'option' => 1),
1444
+ 'option' => array('optgroup' => 1, 'option' => 1),
1445
+ 'p' => array('p' => 1),
1446
+ 'rp' => array('rp' => 1, 'rt' => 1),
1447
+ 'rt' => array('rp' => 1, 'rt' => 1),
1448
+ 'td' => array('td' => 1, 'th' => 1),
1449
+ 'th' => array('td' => 1, 'th' => 1),
1450
+ 'tr' => array('td' => 1, 'th' => 1, 'tr' => 1),
1451
  );
1452
 
1453
+ function __construct(
1454
+ $str = null,
1455
+ $lowercase = true,
1456
+ $forceTagsClosed = true,
1457
+ $target_charset = DEFAULT_TARGET_CHARSET,
1458
+ $stripRN = true,
1459
+ $defaultBRText = DEFAULT_BR_TEXT,
1460
+ $defaultSpanText = DEFAULT_SPAN_TEXT,
1461
+ $options = 0)
1462
  {
1463
+ if ($str) {
1464
+ if (preg_match('/^http:\/\//i', $str) || is_file($str)) {
 
 
1465
  $this->load_file($str);
1466
+ } else {
1467
+ $this->load(
1468
+ $str,
1469
+ $lowercase,
1470
+ $stripRN,
1471
+ $defaultBRText,
1472
+ $defaultSpanText,
1473
+ $options
1474
+ );
1475
  }
1476
  }
1477
+ // Forcing tags to be closed implies that we don't trust the html, but
1478
+ // it can lead to parsing errors if we SHOULD trust the html.
1479
  if (!$forceTagsClosed) {
1480
+ $this->optional_closing_array = array();
1481
  }
1482
+
1483
+ $this->_target_charset = $target_charset;
1484
  }
1485
 
1486
  function __destruct()
1488
  $this->clear();
1489
  }
1490
 
1491
+ function load(
1492
+ $str,
1493
+ $lowercase = true,
1494
+ $stripRN = true,
1495
+ $defaultBRText = DEFAULT_BR_TEXT,
1496
+ $defaultSpanText = DEFAULT_SPAN_TEXT,
1497
+ $options = 0)
1498
  {
1499
  global $debug_object;
1500
 
1501
  // prepare
1502
+ $this->prepare($str, $lowercase, $defaultBRText, $defaultSpanText);
1503
+
 
 
 
1504
  // Per sourceforge http://sourceforge.net/tracker/?func=detail&aid=2949097&group_id=218559&atid=1044037
1505
  // Script tags removal now preceeds style tag removal.
1506
  // strip out <script> tags
1507
  $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is");
1508
  $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is");
1509
+
1510
+ // strip out the \r \n's if we are told to.
1511
+ if ($stripRN) {
1512
+ $this->doc = str_replace("\r", ' ', $this->doc);
1513
+ $this->doc = str_replace("\n", ' ', $this->doc);
1514
+
1515
+ // set the length of content since we have changed it.
1516
+ $this->size = strlen($this->doc);
1517
+ }
1518
+
1519
+ // strip out cdata
1520
+ $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true);
1521
+ // strip out comments
1522
+ $this->remove_noise("'<!--(.*?)-->'is");
1523
  // strip out <style> tags
1524
  $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is");
1525
  $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is");
1527
  $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is");
1528
  // strip out server side scripts
1529
  $this->remove_noise("'(<\?)(.*?)(\?>)'s", true);
1530
+
1531
+ if($options & HDOM_SMARTY_AS_TEXT) { // Strip Smarty scripts
1532
+ $this->remove_noise("'(\{\w)(.*?)(\})'s", true);
1533
+ }
1534
 
1535
  // parsing
1536
+ $this->parse();
1537
  // end
1538
  $this->root->_[HDOM_INFO_END] = $this->cursor;
1539
  $this->parse_charset();
1540
 
1541
  // make load function chainable
1542
  return $this;
 
1543
  }
1544
 
 
1545
  function load_file()
1546
  {
1547
  $args = func_get_args();
1548
+
1549
+ if(($doc = call_user_func_array('file_get_contents', $args)) !== false) {
1550
+ $this->load($doc, true);
1551
+ } else {
1552
  return false;
1553
  }
1554
  }
1555
 
 
1556
  function set_callback($function_name)
1557
  {
1558
  $this->callback = $function_name;
1559
  }
1560
 
 
1561
  function remove_callback()
1562
  {
1563
  $this->callback = null;
1564
  }
1565
 
1566
+ function save($filepath = '')
 
1567
  {
1568
  $ret = $this->root->innertext();
1569
+ if ($filepath !== '') { file_put_contents($filepath, $ret, LOCK_EX); }
1570
  return $ret;
1571
  }
1572
 
1573
+ function find($selector, $idx = null, $lowercase = false)
 
 
1574
  {
1575
  return $this->root->find($selector, $idx, $lowercase);
1576
  }
1577
 
 
1578
  function clear()
1579
  {
1580
+ if (isset($this->nodes)) {
1581
+ foreach ($this->nodes as $n) {
1582
+ $n->clear();
1583
+ $n = null;
1584
+ }
1585
+ }
1586
+
1587
+ // This add next line is documented in the sourceforge repository.
1588
+ // 2977248 as a fix for ongoing memory leaks that occur even with the
1589
+ // use of clear.
1590
+ if (isset($this->children)) {
1591
+ foreach ($this->children as $n) {
1592
+ $n->clear();
1593
+ $n = null;
1594
+ }
1595
+ }
1596
+
1597
+ if (isset($this->parent)) {
1598
+ $this->parent->clear();
1599
+ unset($this->parent);
1600
+ }
1601
+
1602
+ if (isset($this->root)) {
1603
+ $this->root->clear();
1604
+ unset($this->root);
1605
+ }
1606
+
1607
  unset($this->doc);
1608
  unset($this->noise);
1609
  }
1610
 
1611
+ function dump($show_attr = true)
1612
  {
1613
  $this->root->dump($show_attr);
1614
  }
1615
 
1616
+ protected function prepare(
1617
+ $str, $lowercase = true,
1618
+ $defaultBRText = DEFAULT_BR_TEXT,
1619
+ $defaultSpanText = DEFAULT_SPAN_TEXT)
1620
  {
1621
  $this->clear();
1622
 
1623
+ $this->doc = trim($str);
1624
+ $this->size = strlen($this->doc);
1625
+ $this->original_size = $this->size; // original size of the html
 
 
 
 
 
 
1626
  $this->pos = 0;
1627
  $this->cursor = 1;
1628
  $this->noise = array();
1629
  $this->nodes = array();
1630
  $this->lowercase = $lowercase;
1631
+ $this->default_br_text = $defaultBRText;
1632
+ $this->default_span_text = $defaultSpanText;
1633
  $this->root = new simple_html_dom_node($this);
1634
  $this->root->tag = 'root';
1635
  $this->root->_[HDOM_INFO_BEGIN] = -1;
1636
  $this->root->nodetype = HDOM_TYPE_ROOT;
1637
  $this->parent = $this->root;
1638
+ if ($this->size > 0) { $this->char = $this->doc[0]; }
1639
  }
1640
 
 
1641
  protected function parse()
1642
  {
1643
+ while (true) {
1644
+ // Read next tag if there is no text between current position and the
1645
+ // next opening tag.
1646
+ if (($s = $this->copy_until_char('<')) === '') {
1647
+ if($this->read_tag()) {
1648
+ continue;
1649
+ } else {
1650
+ return true;
1651
+ }
1652
+ }
1653
 
1654
+ // Add a text node for text between tags
1655
+ $node = new simple_html_dom_node($this);
1656
+ ++$this->cursor;
1657
+ $node->_[HDOM_INFO_TEXT] = $s;
1658
+ $this->link_nodes($node, false);
1659
+ }
1660
  }
1661
 
 
 
 
1662
  protected function parse_charset()
1663
  {
1664
  global $debug_object;
1665
 
1666
  $charset = null;
1667
 
1668
+ if (function_exists('get_last_retrieve_url_contents_content_type')) {
 
1669
  $contentTypeHeader = get_last_retrieve_url_contents_content_type();
1670
  $success = preg_match('/charset=(.+)/', $contentTypeHeader, $matches);
1671
+ if ($success) {
 
1672
  $charset = $matches[1];
1673
+ if (is_object($debug_object)) {
1674
+ $debug_object->debug_log(2,
1675
+ 'header content-type found charset of: '
1676
+ . $charset
1677
+ );
1678
+ }
1679
  }
 
1680
  }
1681
 
1682
+ if (empty($charset)) {
1683
+ // https://www.w3.org/TR/html/document-metadata.html#statedef-http-equiv-content-type
1684
+ $el = $this->root->find('meta[http-equiv=Content-Type]', 0, true);
1685
+
1686
+ if (!empty($el)) {
1687
  $fullvalue = $el->content;
1688
+ if (is_object($debug_object)) {
1689
+ $debug_object->debug_log(2,
1690
+ 'meta content-type tag found'
1691
+ . $fullvalue
1692
+ );
1693
+ }
1694
 
1695
+ if (!empty($fullvalue)) {
1696
+ $success = preg_match(
1697
+ '/charset=(.+)/i',
1698
+ $fullvalue,
1699
+ $matches
1700
+ );
1701
+
1702
+ if ($success) {
1703
  $charset = $matches[1];
1704
+ } else {
1705
+ // If there is a meta tag, and they don't specify the
1706
+ // character set, research says that it's typically
1707
+ // ISO-8859-1
1708
+ if (is_object($debug_object)) {
1709
+ $debug_object->debug_log(2,
1710
+ 'meta content-type tag couldn\'t be parsed. using iso-8859 default.'
1711
+ );
1712
+ }
1713
+
1714
  $charset = 'ISO-8859-1';
1715
  }
1716
  }
1717
  }
1718
  }
1719
 
1720
+ if (empty($charset)) {
1721
+ // https://www.w3.org/TR/html/document-metadata.html#character-encoding-declaration
1722
+ if ($meta = $this->root->find('meta[charset]', 0)) {
1723
+ $charset = $meta->charset;
1724
+ if (is_object($debug_object)) {
1725
+ $debug_object->debug_log(2, 'meta charset: ' . $charset);
1726
+ }
 
 
 
1727
  }
1728
+ }
1729
+
1730
+ if (empty($charset)) {
1731
+ // Try to guess the charset based on the content
1732
+ // Requires Multibyte String (mbstring) support (optional)
1733
+ if (function_exists('mb_detect_encoding')) {
1734
+ /**
1735
+ * mb_detect_encoding() is not intended to distinguish between
1736
+ * charsets, especially single-byte charsets. Its primary
1737
+ * purpose is to detect which multibyte encoding is in use,
1738
+ * i.e. UTF-8, UTF-16, shift-JIS, etc.
1739
+ *
1740
+ * -- https://bugs.php.net/bug.php?id=38138
1741
+ *
1742
+ * Adding both CP1251/ISO-8859-5 and CP1252/ISO-8859-1 will
1743
+ * always result in CP1251/ISO-8859-5 and vice versa.
1744
+ *
1745
+ * Thus, only detect if it's either UTF-8 or CP1252/ISO-8859-1
1746
+ * to stay compatible.
1747
+ */
1748
+ $encoding = mb_detect_encoding(
1749
+ $this->doc,
1750
+ array( 'UTF-8', 'CP1252', 'ISO-8859-1' )
1751
+ );
1752
+
1753
+ if ($encoding === 'CP1252' || $encoding === 'ISO-8859-1') {
1754
+ // Due to a limitation of mb_detect_encoding
1755
+ // 'CP1251'/'ISO-8859-5' will be detected as
1756
+ // 'CP1252'/'ISO-8859-1'. This will cause iconv to fail, in
1757
+ // which case we can simply assume it is the other charset.
1758
+ if (!@iconv('CP1252', 'UTF-8', $this->doc)) {
1759
+ $encoding = 'CP1251';
1760
+ }
1761
+ }
1762
 
1763
+ if ($encoding !== false) {
1764
+ $charset = $encoding;
1765
+ if (is_object($debug_object)) {
1766
+ $debug_object->debug_log(2, 'mb_detect: ' . $charset);
1767
+ }
1768
+ }
1769
  }
1770
  }
1771
 
1772
+ if (empty($charset)) {
1773
+ // Assume it's UTF-8 as it is the most likely charset to be used
1774
+ $charset = 'UTF-8';
1775
+ if (is_object($debug_object)) {
1776
+ $debug_object->debug_log(2, 'No match found, assume ' . $charset);
1777
+ }
1778
+ }
1779
+
1780
+ // Since CP1252 is a superset, if we get one of it's subsets, we want
1781
+ // it instead.
1782
+ if ((strtolower($charset) == 'iso-8859-1')
1783
+ || (strtolower($charset) == 'latin1')
1784
+ || (strtolower($charset) == 'latin-1')) {
1785
  $charset = 'CP1252';
1786
+ if (is_object($debug_object)) {
1787
+ $debug_object->debug_log(2,
1788
+ 'replacing ' . $charset . ' with CP1252 as its a superset'
1789
+ );
1790
+ }
1791
  }
1792
 
1793
+ if (is_object($debug_object)) {
1794
+ $debug_object->debug_log(1, 'EXIT - ' . $charset);
1795
+ }
1796
 
1797
  return $this->_charset = $charset;
1798
  }
1799
 
 
1800
  protected function read_tag()
1801
  {
1802
+ // Set end position if no further tags found
1803
+ if ($this->char !== '<') {
1804
  $this->root->_[HDOM_INFO_END] = $this->cursor;
1805
  return false;
1806
  }
1807
+
1808
  $begin_tag_pos = $this->pos;
1809
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1810
 
1811
  // end tag
1812
+ if ($this->char === '/') {
1813
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1814
+
1815
+ // Skip whitespace in end tags (i.e. in "</ html>")
 
1816
  $this->skip($this->token_blank);
1817
  $tag = $this->copy_until_char('>');
1818
 
1819
+ // Skip attributes in end tags
1820
+ if (($pos = strpos($tag, ' ')) !== false) {
1821
  $tag = substr($tag, 0, $pos);
1822
+ }
1823
 
1824
  $parent_lower = strtolower($this->parent->tag);
1825
  $tag_lower = strtolower($tag);
1826
 
1827
+ // The end tag is supposed to close the parent tag. Handle situations
1828
+ // when it doesn't
1829
+ if ($parent_lower !== $tag_lower) {
1830
+ // Parent tag does not have to be closed necessarily (optional closing tag)
1831
+ // Current tag is a block tag, so it may close an ancestor
1832
+ if (isset($this->optional_closing_tags[$parent_lower])
1833
+ && isset($this->block_tags[$tag_lower])) {
1834
+
1835
  $this->parent->_[HDOM_INFO_END] = 0;
1836
  $org_parent = $this->parent;
1837
 
1838
+ // Traverse ancestors to find a matching opening tag
1839
+ // Stop at root node
1840
+ while (($this->parent->parent)
1841
+ && strtolower($this->parent->tag) !== $tag_lower
1842
+ ){
1843
  $this->parent = $this->parent->parent;
1844
+ }
1845
 
1846
+ // If we don't have a match add current tag as text node
1847
+ if (strtolower($this->parent->tag) !== $tag_lower) {
1848
  $this->parent = $org_parent; // restore origonal parent
1849
+
1850
+ if ($this->parent->parent) {
1851
+ $this->parent = $this->parent->parent;
1852
+ }
1853
+
1854
  $this->parent->_[HDOM_INFO_END] = $this->cursor;
1855
  return $this->as_text_node($tag);
1856
  }
1857
+ } elseif (($this->parent->parent)
1858
+ && isset($this->block_tags[$tag_lower])
1859
+ ) {
1860
+ // Grandparent exists and current tag is a block tag, so our
1861
+ // parent doesn't have an end tag
1862
+ $this->parent->_[HDOM_INFO_END] = 0; // No end tag
1863
  $org_parent = $this->parent;
1864
 
1865
+ // Traverse ancestors to find a matching opening tag
1866
+ // Stop at root node
1867
+ while (($this->parent->parent)
1868
+ && strtolower($this->parent->tag) !== $tag_lower
1869
+ ) {
1870
  $this->parent = $this->parent->parent;
1871
+ }
1872
 
1873
+ // If we don't have a match add current tag as text node
1874
+ if (strtolower($this->parent->tag) !== $tag_lower) {
1875
  $this->parent = $org_parent; // restore origonal parent
1876
  $this->parent->_[HDOM_INFO_END] = $this->cursor;
1877
  return $this->as_text_node($tag);
1878
  }
1879
+ } elseif (($this->parent->parent)
1880
+ && strtolower($this->parent->parent->tag) === $tag_lower
1881
+ ) { // Grandparent exists and current tag closes it
1882
  $this->parent->_[HDOM_INFO_END] = 0;
1883
  $this->parent = $this->parent->parent;
1884
+ } else { // Random tag, add as text node
 
1885
  return $this->as_text_node($tag);
1886
+ }
1887
  }
1888
 
1889
+ // Set end position of parent tag to current cursor position
1890
  $this->parent->_[HDOM_INFO_END] = $this->cursor;
 
1891
 
1892
+ if ($this->parent->parent) {
1893
+ $this->parent = $this->parent->parent;
1894
+ }
1895
+
1896
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1897
  return true;
1898
  }
1899
 
1900
+ // start tag
1901
  $node = new simple_html_dom_node($this);
1902
  $node->_[HDOM_INFO_BEGIN] = $this->cursor;
1903
  ++$this->cursor;
1904
+ $tag = $this->copy_until($this->token_slash); // Get tag name
1905
  $node->tag_start = $begin_tag_pos;
1906
 
1907
  // doctype, cdata & comments...
1908
+ // <!DOCTYPE html>
1909
+ // <![CDATA[ ... ]]>
1910
+ // <!-- Comment -->
1911
+ if (isset($tag[0]) && $tag[0] === '!') {
1912
  $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>');
1913
 
1914
+ if (isset($tag[2]) && $tag[1] === '-' && $tag[2] === '-') { // Comment ("<!--")
1915
  $node->nodetype = HDOM_TYPE_COMMENT;
1916
  $node->tag = 'comment';
1917
+ } else { // Could be doctype or CDATA but we don't care
1918
  $node->nodetype = HDOM_TYPE_UNKNOWN;
1919
  $node->tag = 'unknown';
1920
  }
1921
+
1922
+ if ($this->char === '>') { $node->_[HDOM_INFO_TEXT] .= '>'; }
1923
+
1924
  $this->link_nodes($node, true);
1925
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1926
  return true;
1927
  }
1928
 
1929
+ // The start tag cannot contain another start tag, if so add as text
1930
+ // i.e. "<<html>"
1931
+ if ($pos = strpos($tag, '<') !== false) {
1932
  $tag = '<' . substr($tag, 0, -1);
1933
  $node->_[HDOM_INFO_TEXT] = $tag;
1934
  $this->link_nodes($node, false);
1936
  return true;
1937
  }
1938
 
1939
+ // Handle invalid tag names (i.e. "<html#doc>")
1940
+ if (!preg_match('/^\w[\w:-]*$/', $tag)) {
1941
  $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>');
1942
+
1943
+ // Next char is the beginning of a new tag, don't touch it.
1944
+ if ($this->char === '<') {
1945
  $this->link_nodes($node, false);
1946
  return true;
1947
  }
1948
 
1949
+ // Next char closes current tag, add and be done with it.
1950
+ if ($this->char === '>') { $node->_[HDOM_INFO_TEXT] .= '>'; }
1951
  $this->link_nodes($node, false);
1952
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
1953
  return true;
1954
  }
1955
 
1956
+ // begin tag, add new node
1957
  $node->nodetype = HDOM_TYPE_ELEMENT;
1958
  $tag_lower = strtolower($tag);
1959
  $node->tag = ($this->lowercase) ? $tag_lower : $tag;
1960
 
1961
  // handle optional closing tags
1962
+ if (isset($this->optional_closing_tags[$tag_lower])) {
1963
+ // Traverse ancestors to close all optional closing tags
1964
+ while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)])) {
 
1965
  $this->parent->_[HDOM_INFO_END] = 0;
1966
  $this->parent = $this->parent->parent;
1967
  }
1969
  }
1970
 
1971
  $guard = 0; // prevent infinity loop
1972
+
1973
+ // [0] Space between tag and first attribute
1974
  $space = array($this->copy_skip($this->token_blank), '', '');
1975
 
1976
  // attributes
1977
+ do {
1978
+ // Everything until the first equal sign should be the attribute name
1979
+ $name = $this->copy_until($this->token_equal);
1980
+
1981
+ if ($name === '' && $this->char !== null && $space[0] === '') {
1982
  break;
1983
  }
1984
+
1985
+ if ($guard === $this->pos) { // Escape infinite loop
1986
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
 
1987
  continue;
1988
  }
1989
+
1990
  $guard = $this->pos;
1991
 
1992
  // handle endless '<'
1993
+ // Out of bounds before the tag ended
1994
+ if ($this->pos >= $this->size - 1 && $this->char !== '>') {
1995
  $node->nodetype = HDOM_TYPE_TEXT;
1996
  $node->_[HDOM_INFO_END] = 0;
1997
+ $node->_[HDOM_INFO_TEXT] = '<' . $tag . $space[0] . $name;
1998
  $node->tag = 'text';
1999
  $this->link_nodes($node, false);
2000
  return true;
2001
  }
2002
 
2003
  // handle mismatch '<'
2004
+ // Attributes cannot start after opening tag
2005
+ if ($this->doc[$this->pos - 1] == '<') {
2006
  $node->nodetype = HDOM_TYPE_TEXT;
2007
  $node->tag = 'text';
2008
  $node->attr = array();
2009
  $node->_[HDOM_INFO_END] = 0;
2010
+ $node->_[HDOM_INFO_TEXT] = substr(
2011
+ $this->doc,
2012
+ $begin_tag_pos,
2013
+ $this->pos - $begin_tag_pos - 1
2014
+ );
2015
  $this->pos -= 2;
2016
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2017
  $this->link_nodes($node, false);
2018
  return true;
2019
  }
2020
 
2021
+ if ($name !== '/' && $name !== '') { // this is a attribute name
2022
+ // [1] Whitespace after attribute name
2023
  $space[1] = $this->copy_skip($this->token_blank);
2024
+
2025
+ $name = $this->restore_noise($name); // might be a noisy name
2026
+
2027
+ if ($this->lowercase) { $name = strtolower($name); }
2028
+
2029
+ if ($this->char === '=') { // attribute with value
2030
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2031
+ $this->parse_attr($node, $name, $space); // get attribute value
2032
+ } else {
2033
  //no value attr: nowrap, checked selected...
2034
  $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
2035
  $node->attr[$name] = true;
2036
+ if ($this->char != '>') { $this->char = $this->doc[--$this->pos]; } // prev
2037
  }
2038
+
2039
  $node->_[HDOM_INFO_SPACE][] = $space;
2040
+
2041
+ // prepare for next attribute
2042
+ $space = array(
2043
+ $this->copy_skip($this->token_blank),
2044
+ '',
2045
+ ''
2046
+ );
2047
+ } else { // no more attributes
2048
  break;
2049
+ }
2050
+ } while ($this->char !== '>' && $this->char !== '/'); // go until the tag ended
2051
 
2052
  $this->link_nodes($node, true);
2053
  $node->_[HDOM_INFO_ENDSPACE] = $space[0];
2054
 
2055
+ // handle empty tags (i.e. "<div/>")
2056
+ if ($this->copy_until_char('>') === '/') {
 
2057
  $node->_[HDOM_INFO_ENDSPACE] .= '/';
2058
  $node->_[HDOM_INFO_END] = 0;
2059
+ } else {
 
 
2060
  // reset parent
2061
+ if (!isset($this->self_closing_tags[strtolower($node->tag)])) {
2062
+ $this->parent = $node;
2063
+ }
2064
  }
2065
+
2066
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2067
 
2068
  // If it's a BR tag, we need to set it's text to the default text.
2069
  // This way when we see it in plaintext, we can generate formatting that the user wants.
2070
  // since a br tag never has sub nodes, this works well.
2071
+ if ($node->tag === 'br') {
 
2072
  $node->_[HDOM_INFO_INNER] = $this->default_br_text;
2073
  }
2074
 
2075
  return true;
2076
  }
2077
 
 
2078
  protected function parse_attr($node, $name, &$space)
2079
  {
2080
+ $is_duplicate = isset($node->attr[$name]);
2081
+
2082
+ if (!$is_duplicate) // Copy whitespace between "=" and value
2083
+ $space[2] = $this->copy_skip($this->token_blank);
 
 
2084
 
 
2085
  switch ($this->char) {
2086
  case '"':
2087
+ $quote_type = HDOM_QUOTE_DOUBLE;
2088
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2089
+ $value = $this->copy_until_char('"');
2090
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2091
  break;
2092
  case '\'':
2093
+ $quote_type = HDOM_QUOTE_SINGLE;
2094
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2095
+ $value = $this->copy_until_char('\'');
2096
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2097
  break;
2098
  default:
2099
+ $quote_type = HDOM_QUOTE_NO;
2100
+ $value = $this->copy_until($this->token_attr);
2101
+ }
2102
+
2103
+ $value = $this->restore_noise($value);
2104
+
2105
+ // PaperG: Attributes should not have \r or \n in them, that counts as
2106
+ // html whitespace.
2107
+ $value = str_replace("\r", '', $value);
2108
+ $value = str_replace("\n", '', $value);
2109
+
2110
+ // PaperG: If this is a "class" selector, lets get rid of the preceeding
2111
+ // and trailing space since some people leave it in the multi class case.
2112
+ if ($name === 'class') {
2113
+ $value = trim($value);
2114
  }
2115
+
2116
+ if (!$is_duplicate) {
2117
+ $node->_[HDOM_INFO_QUOTE][] = $quote_type;
2118
+ $node->attr[$name] = $value;
 
 
2119
  }
2120
  }
2121
 
 
2122
  protected function link_nodes(&$node, $is_child)
2123
  {
2124
  $node->parent = $this->parent;
2125
  $this->parent->nodes[] = $node;
2126
+ if ($is_child) {
 
2127
  $this->parent->children[] = $node;
2128
  }
2129
  }
2130
 
 
2131
  protected function as_text_node($tag)
2132
  {
2133
  $node = new simple_html_dom_node($this);
2134
  ++$this->cursor;
2135
  $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>';
2136
  $this->link_nodes($node, false);
2137
+ $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2138
  return true;
2139
  }
2140
 
2141
  protected function skip($chars)
2142
  {
2143
  $this->pos += strspn($this->doc, $chars, $this->pos);
2144
+ $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2145
  }
2146
 
2147
  protected function copy_skip($chars)
2149
  $pos = $this->pos;
2150
  $len = strspn($this->doc, $chars, $pos);
2151
  $this->pos += $len;
2152
+ $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2153
+ if ($len === 0) { return ''; }
2154
  return substr($this->doc, $pos, $len);
2155
  }
2156
 
2159
  $pos = $this->pos;
2160
  $len = strcspn($this->doc, $chars, $pos);
2161
  $this->pos += $len;
2162
+ $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
2163
  return substr($this->doc, $pos, $len);
2164
  }
2165
 
2166
  protected function copy_until_char($char)
2167
  {
2168
+ if ($this->char === null) { return ''; }
2169
 
2170
+ if (($pos = strpos($this->doc, $char, $this->pos)) === false) {
2171
+ $ret = substr($this->doc, $this->pos, $this->size - $this->pos);
2172
  $this->char = null;
2173
  $this->pos = $this->size;
2174
  return $ret;
2175
  }
2176
 
2177
+ if ($pos === $this->pos) { return ''; }
2178
+
2179
  $pos_old = $this->pos;
2180
  $this->char = $this->doc[$pos];
2181
  $this->pos = $pos;
2182
+ return substr($this->doc, $pos_old, $pos - $pos_old);
2183
  }
2184
 
2185
+ protected function remove_noise($pattern, $remove_tag = false)
2186
  {
2187
+ global $debug_object;
2188
+ if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
2189
 
2190
+ $count = preg_match_all(
2191
+ $pattern,
2192
+ $this->doc,
2193
+ $matches,
2194
+ PREG_SET_ORDER | PREG_OFFSET_CAPTURE
2195
+ );
 
 
 
 
2196
 
2197
+ for ($i = $count - 1; $i > -1; --$i) {
2198
+ $key = '___noise___' . sprintf('% 5d', count($this->noise) + 1000);
2199
 
2200
+ if (is_object($debug_object)) {
2201
+ $debug_object->debug_log(2, 'key is: ' . $key);
 
2202
  }
2203
 
2204
+ $idx = ($remove_tag) ? 0 : 1; // 0 = entire match, 1 = submatch
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2205
  $this->noise[$key] = $matches[$i][$idx][0];
2206
  $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0]));
2207
  }
2208
 
2209
  // reset the length of content
 
2210
  $this->size = strlen($this->doc);
2211
+
2212
+ if ($this->size > 0) {
2213
+ $this->char = $this->doc[0];
 
2214
  }
2215
  }
2216
 
 
2217
  function restore_noise($text)
2218
  {
2219
  global $debug_object;
2220
  if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
2221
 
2222
+ while (($pos = strpos($text, '___noise___')) !== false) {
2223
+ // Sometimes there is a broken piece of markup, and we don't GET the
2224
+ // pos+11 etc... token which indicates a problem outside of us...
2225
+
2226
+ // todo: "___noise___1000" (or any number with four or more digits)
2227
+ // in the DOM causes an infinite loop which could be utilized by
2228
+ // malicious software
2229
+ if (strlen($text) > $pos + 15) {
2230
+ $key = '___noise___'
2231
+ . $text[$pos + 11]
2232
+ . $text[$pos + 12]
2233
+ . $text[$pos + 13]
2234
+ . $text[$pos + 14]
2235
+ . $text[$pos + 15];
2236
+
2237
+ if (is_object($debug_object)) {
2238
+ $debug_object->debug_log(2, 'located key of: ' . $key);
2239
  }
2240
+
2241
+ if (isset($this->noise[$key])) {
2242
+ $text = substr($text, 0, $pos)
2243
+ . $this->noise[$key]
2244
+ . substr($text, $pos + 16);
2245
+ } else {
2246
  // do this to prevent an infinite loop.
2247
+ $text = substr($text, 0, $pos)
2248
+ . 'UNDEFINED NOISE FOR KEY: '
2249
+ . $key
2250
+ . substr($text, $pos + 16);
2251
  }
2252
+ } else {
2253
+ // There is no valid key being given back to us... We must get
2254
+ // rid of the ___noise___ or we will have a problem.
2255
+ $text = substr($text, 0, $pos)
2256
+ . 'NO NUMERIC NOISE KEY'
2257
+ . substr($text, $pos + 11);
2258
  }
2259
  }
2260
  return $text;
2261
  }
2262
 
 
2263
  function search_noise($text)
2264
  {
2265
  global $debug_object;
2266
  if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
2267
 
2268
+ foreach($this->noise as $noiseElement) {
2269
+ if (strpos($noiseElement, $text) !== false) {
 
 
2270
  return $noiseElement;
2271
  }
2272
  }
2273
  }
2274
+
2275
  function __toString()
2276
  {
2277
  return $this->root->innertext();
2279
 
2280
  function __get($name)
2281
  {
2282
+ switch ($name) {
2283
+ case 'outertext':
 
2284
  return $this->root->innertext();
2285
+ case 'innertext':
2286
  return $this->root->innertext();
2287
  case 'plaintext':
2288
  return $this->root->text();
2293
  }
2294
  }
2295
 
2296
+ function childNodes($idx = -1)
2297
+ {
2298
+ return $this->root->childNodes($idx);
2299
+ }
2300
+
2301
+ function firstChild()
2302
+ {
2303
+ return $this->root->first_child();
2304
+ }
2305
+
2306
+ function lastChild()
2307
+ {
2308
+ return $this->root->last_child();
2309
+ }
2310
+
2311
+ function createElement($name, $value = null)
2312
+ {
2313
+ return @str_get_html("<$name>$value</$name>")->firstChild();
2314
+ }
2315
+
2316
+ function createTextNode($value)
2317
+ {
2318
+ return @end(str_get_html($value)->nodes);
2319
+ }
2320
+
2321
+ function getElementById($id)
2322
+ {
2323
+ return $this->find("#$id", 0);
2324
+ }
2325
+
2326
+ function getElementsById($id, $idx = null)
2327
+ {
2328
+ return $this->find("#$id", $idx);
2329
+ }
2330
+
2331
+ function getElementByTagName($name)
2332
+ {
2333
+ return $this->find($name, 0);
2334
+ }
2335
+
2336
+ function getElementsByTagName($name, $idx = -1)
2337
+ {
2338
+ return $this->find($name, $idx);
2339
+ }
2340
+
2341
+ function loadFile()
2342
+ {
2343
+ $args = func_get_args();
2344
+ $this->load_file($args);
2345
+ }
2346
+ }
iubenda_cookie_solution.php CHANGED
@@ -1,915 +1,557 @@
1
- <?php
2
- /*
3
- Plugin Name: iubenda Cookie Solution for GDPR
4
- Plugin URI: https://www.iubenda.com
5
- Description: iubenda Cookie Solution allows you to make your website GDPR compliant and manage all aspects of cookie law on WP.
6
- Version: 1.15.8
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-cookie-law-solution
12
- Domain Path: /languages
13
-
14
- ibenda Cookie Solution
15
- Copyright (C) 2018-2019, 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
- // set plugin instance
32
- $iubenda_cookie_law_solution = new iubenda_Cookie_Law_Solution();
33
-
34
- /**
35
- * iubenda_Cookie_Law_Solution final class.
36
- *
37
- * @class iubenda_Cookie_Law_Solution
38
- * @version 1.15.7
39
- */
40
- class iubenda_Cookie_Law_Solution {
41
-
42
- public $options;
43
- public $defaults = array(
44
- 'parse' => false, // iubenda_parse
45
- 'skip_parsing' => true, // skip_parsing
46
- 'ctype' => true, // iubenda_ctype
47
- 'parse' => false, // iubenda_parse
48
- 'parser_engine' => 'new', // parser_engine
49
- 'output_feed' => true, // iubenda_output_feed
50
- 'code_default' => false, // iubenda-code-default,
51
- 'menu_position' => 'topmenu',
52
- 'custom_scripts' => array(),
53
- 'custom_iframes' => array(),
54
- 'deactivation' => false
55
- );
56
- public $version = '1.15.8';
57
- public $no_html = false;
58
- public $links = array();
59
- public $multilang = false;
60
- public $languages = array();
61
- public $lang_default = '';
62
-
63
- /**
64
- * Class constructor.
65
- */
66
- public function __construct() {
67
- register_activation_hook( __FILE__, array( $this, 'activation' ) );
68
- register_deactivation_hook( __FILE__, array( $this, 'deactivation' ) );
69
-
70
- // settings
71
- $this->options = array_merge( $this->defaults, (array) get_option( 'iubenda_cookie_law_solution', $this->defaults ) );
72
-
73
- // actions
74
- add_action( 'admin_init', array( $this, 'register_options' ) );
75
- add_action( 'admin_init', array( $this, 'update_plugin' ), 9 );
76
- add_action( 'admin_init', array( $this, 'admin_page_redirect' ), 20 );
77
- add_action( 'admin_menu', array( $this, 'admin_menu_options' ) );
78
- add_action( 'admin_notices', array( $this, 'settings_errors' ) );
79
- add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
80
- add_action( 'plugins_loaded', array( $this, 'init' ) );
81
- add_action( 'after_setup_theme', array( $this, 'register_shortcode' ) );
82
- add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
83
- add_action( 'admin_print_styles', array( $this, 'admin_print_styles' ) );
84
- add_action( 'wp_head', array( $this, 'wp_head' ), 99 );
85
- add_action( 'template_redirect', array( $this, 'output_start' ), 0 );
86
- add_action( 'shutdown', array( $this, 'output_end' ), 100 );
87
- }
88
-
89
- /**
90
- * Initialize plugin.
91
- *
92
- * @return void
93
- */
94
- public function init() {
95
- // check if WPML or Polylang is active
96
- include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
97
-
98
- // Polylang support
99
- if ( ( is_plugin_active( 'polylang/polylang.php' ) || is_plugin_active( 'polylang-pro/polylang.php' ) ) && function_exists( 'PLL' ) ) {
100
- $this->multilang = true;
101
-
102
- // get registered languages
103
- $registered_languages = PLL()->model->get_languages_list();
104
-
105
- if ( ! empty( $registered_languages ) ) {
106
- foreach ( $registered_languages as $language )
107
- $this->languages[$language->slug] = $language->name;
108
- }
109
-
110
- // get default language
111
- $this->lang_default = pll_default_language();
112
-
113
- // WPML support
114
- } elseif ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) && class_exists( 'SitePress' ) ) {
115
- $this->multilang = true;
116
-
117
- global $sitepress;
118
-
119
- // get registered languages
120
- $registered_languages = icl_get_languages();
121
-
122
- if ( ! empty( $registered_languages ) ) {
123
- foreach ( $registered_languages as $language )
124
- $this->languages[$language['code']] = $language['display_name'];
125
- }
126
-
127
- // get default language
128
- $this->lang_default = $sitepress->get_default_language();
129
- }
130
-
131
- // load iubenda parser
132
- require_once( dirname( __FILE__ ) . '/iubenda-cookie-class/iubenda.class.php' );
133
-
134
- $links = array(
135
- 'en' => array(
136
- 'guide' => 'https://www.iubenda.com/en/iubenda-cookie-law-solution',
137
- 'plugin_page' => 'https://www.iubenda.com/en/help/posts/1215',
138
- 'generating_code' => 'https://www.iubenda.com/en/help/posts/1177',
139
- 'support_forum' => 'https://support.iubenda.com/support/home',
140
- 'documentation' => 'https://www.iubenda.com/en/help/posts/1215'
141
- ),
142
- 'it' => array(
143
- 'guide' => 'https://www.iubenda.com/it/soluzione-cookie-law',
144
- 'plugin_page' => 'https://www.iubenda.com/it/help/posts/810',
145
- 'generating_code' => 'https://www.iubenda.com/it/help/posts/680',
146
- 'support_forum' => 'https://support.iubenda.com/support/home',
147
- 'documentation' => 'https://www.iubenda.com/it/help/posts/810',
148
- )
149
- );
150
-
151
- $locale = explode( '_', get_locale() );
152
- $locale_code = $locale[0];
153
-
154
- // assign links
155
- $this->links = in_array( $locale_code, array_keys( $links ) ) ? $links[$locale_code] : $links['en'];
156
- }
157
-
158
- /**
159
- * Plugin activation.
160
- *
161
- * @return void
162
- */
163
- public function activation() {
164
- add_option( 'iubenda_cookie_law_solution', $this->options, '', 'no' );
165
- add_option( 'iubenda_cookie_law_version', $this->version, '', 'no' );
166
- }
167
-
168
- /**
169
- * Plugin deactivation.
170
- *
171
- * @return void
172
- */
173
- public function deactivation() {
174
- // remove options from database?
175
- if ( $this->options['deactivation'] ) {
176
- delete_option( 'iubenda_cookie_law_solution' );
177
- delete_option( 'iubenda_cookie_law_version' );
178
- }
179
- }
180
-
181
- /**
182
- * Plugin options migration for versions < 1.14.0
183
- *
184
- * @return void
185
- */
186
- public function update_plugin() {
187
- if ( ! current_user_can( 'install_plugins' ) )
188
- return;
189
-
190
- $db_version = get_option( 'iubenda_cookie_law_version' );
191
- $db_version = ! $db_version ? '1.13.0' : $db_version;
192
-
193
- if ( $db_version != false ) {
194
- if ( version_compare( $db_version, '1.14.0', '<' ) ) {
195
- $options = array();
196
-
197
- $old_new = array(
198
- 'iubenda_parse' => 'parse',
199
- 'skip_parsing' => 'skip_parsing',
200
- 'iubenda_ctype' => 'ctype',
201
- 'iubenda_parse' => 'parse',
202
- 'parser_engine' => 'parser_engine',
203
- 'iubenda_output_feed' => 'output_feed',
204
- 'iubenda-code-default' => 'code_default',
205
- 'default_skip_parsing' => '',
206
- 'default_iubendactype' => '',
207
- 'default_iubendaparse' => '',
208
- 'default_parser_engine' => '',
209
- 'iub_code' => '',
210
- );
211
-
212
- foreach ( $old_new as $old => $new ) {
213
- if ( $new ) {
214
- $options[$new] = get_option( $old );
215
- }
216
- delete_option( $old );
217
- }
218
-
219
- // multilang support
220
- if ( ! empty( $this->languages ) ) {
221
- foreach ( $this->languages as $lang ) {
222
- $code = get_option( 'iubenda-code-' . $lang );
223
-
224
- if ( ! empty( $code ) ) {
225
- $options['code_' . $lang] = $code;
226
-
227
- delete_option( 'iubenda-code-' . $lang );
228
- }
229
- }
230
- }
231
-
232
- add_option( 'iubenda_cookie_law_solution', $options, '', 'no' );
233
- add_option( 'iubenda_cookie_law_version', $this->version, '', 'no' );
234
- }
235
- }
236
- }
237
-
238
- /**
239
- * Register shortcode function.
240
- *
241
- * @return void
242
- */
243
- public function register_shortcode() {
244
- add_shortcode( 'iub-cookie-policy', array( $this, 'block_shortcode' ) );
245
- add_shortcode( 'iub-cookie-block', array( $this, 'block_shortcode' ) );
246
- add_shortcode( 'iub-cookie-skip', array( $this, 'skip_shortcode' ) );
247
- }
248
-
249
- /**
250
- * Handle block shortcode function.
251
- *
252
- * @param array $atts
253
- * @param mixed $content
254
- * @return mixed
255
- */
256
- public function block_shortcode( $atts, $content = '' ) {
257
- return '<!--IUB-COOKIE-BLOCK-START-->' . do_shortcode( $content ) . '<!--IUB-COOKIE-BLOCK-END-->';
258
- }
259
-
260
- /**
261
- * Handle skip shortcode function.
262
- *
263
- * @param array $atts
264
- * @param mixed $content
265
- * @return mixed
266
- */
267
- public function skip_shortcode( $atts, $content = '' ) {
268
- return '<!--IUB-COOKIE-BLOCK-SKIP-START-->' . do_shortcode( $content ) . '<!--IUB-COOKIE-BLOCK-SKIP-END-->';
269
- }
270
-
271
- /**
272
- * Add submenu.
273
- *
274
- * @return void
275
- */
276
- public function admin_menu_options() {
277
- if ( $this->options['menu_position'] === 'submenu' ) {
278
- // sub menu
279
- add_submenu_page(
280
- 'options-general.php', 'iubenda', 'iubenda', apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ), 'iubenda-cookie-law-solution', array( $this, 'options_page' ), 'none'
281
- );
282
- } else {
283
- // top menu
284
- add_menu_page(
285
- 'iubenda', 'iubenda', apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ), 'iubenda-cookie-law-solution', array( $this, 'options_page' ), 'none'
286
- );
287
- }
288
- }
289
-
290
- /**
291
- * Load textdomain.
292
- *
293
- * @return void
294
- */
295
- public function load_textdomain() {
296
- load_plugin_textdomain( 'iubenda-cookie-law-solution', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
297
- }
298
-
299
- /**
300
- * Load admin scripts and styles.
301
- *
302
- * @param string $page
303
- * @return void
304
- */
305
- public function admin_enqueue_scripts( $page ) {
306
- if ( ! in_array( $page, array( 'toplevel_page_iubenda-cookie-law-solution', 'settings_page_iubenda-cookie-law-solution' ) ) )
307
- return;
308
-
309
- wp_enqueue_script(
310
- 'iubenda-admin', plugins_url( 'js/admin.js', __FILE__ ), array( 'jquery' )
311
- );
312
-
313
- wp_enqueue_style( 'iubenda-admin', plugins_url( 'css/admin.css', __FILE__ ) );
314
- }
315
-
316
- /**
317
- * Load admin style inline, for menu icon only.
318
- *
319
- * @return mixed
320
- */
321
- public function admin_print_styles() {
322
- echo '
323
- <style>
324
- a.toplevel_page_iubenda-cookie-law-solution .wp-menu-image {
325
- background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj48c3ZnIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAyMzIgNTAzIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zOnNlcmlmPSJodHRwOi8vd3d3LnNlcmlmLmNvbS8iIHN0eWxlPSJmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6MS40MTQyMTsiPiAgICA8ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDEzNi4yNDcsMjY4LjgzMSkiPiAgICAgICAgPHBhdGggZD0iTTAsLTM1LjgxTC0zNi4zLDAuNDg5TC0zNi4zLDE0MC45NzhMMCwxNDAuOTc4TDAsLTM1LjgxWk0tMjAuOTM4LC0xMjkuODAyQy02LjI4NywtMTI5LjgwMiA1LjU4NywtMTQxLjU2NSA1LjU4NywtMTU2LjA2QzUuNTg3LC0xNzAuNTU2IC02LjI4NywtMTgyLjMwOCAtMjAuOTM4LC0xODIuMzA4Qy0zNS42LC0xODIuMzA4IC00Ny40NzQsLTE3MC41NTYgLTQ3LjQ3NCwtMTU2LjA2Qy00Ny40NzQsLTE0MS41NjUgLTM1LjYsLTEyOS44MDIgLTIwLjkzOCwtMTI5LjgwMk04OS4zNiwtMTU0LjQxNkM4OS4zNiwtMTI3LjgyNSA3OS41NzUsLTEwMy40OTkgNjMuMjY5LC04NC42NzJMODYuNjk0LDIyNi42MjhMLTEyMi43MjgsMjI2LjYyOEwtMTAwLjAyNCwtNzkuMjI5Qy0xMTkuMzUxLC05OC42NjggLTEzMS4yNDcsLTEyNS4xNTkgLTEzMS4yNDcsLTE1NC40MTZDLTEzMS4yNDcsLTIxNC4wODYgLTgxLjg3NCwtMjYyLjQzOCAtMjAuOTM4LC0yNjIuNDM4QzM5Ljk5OSwtMjYyLjQzOCA4OS4zNiwtMjE0LjA4NiA4OS4zNiwtMTU0LjQxNiIgc3R5bGU9ImZpbGw6d2hpdGU7ZmlsbC1ydWxlOm5vbnplcm87Ii8+ICAgIDwvZz48L3N2Zz4=);
326
- background-position: center center;
327
- background-repeat: no-repeat;
328
- background-size: 7px auto;
329
- }
330
- </style>
331
- ';
332
- }
333
-
334
- /**
335
- * Redirect to the correct urle after switching menu position.
336
- *
337
- * @global string $pagenow
338
- * @return void
339
- */
340
- public function admin_page_redirect() {
341
- if ( ! empty( $_GET['settings-updated'] ) && ! empty( $_GET['page'] ) && in_array( $_GET['page'], array( 'iubenda-cookie-law-solution' ) ) ) {
342
- global $pagenow;
343
-
344
- // no redirect by default
345
- $redirect_to = false;
346
-
347
- if ( $this->options['menu_position'] === 'submenu' && $pagenow === 'admin.php' ) {
348
- // sub menu
349
- $redirect_to = admin_url( 'options-general.php?page=iubenda-cookie-law-solution' );
350
- } elseif ( $this->options['menu_position'] === 'topmenu' && $pagenow === 'options-general.php' ) {
351
- // top menu
352
- $redirect_to = admin_url( 'admin.php?page=iubenda-cookie-law-solution' );
353
- }
354
-
355
- if ( $redirect_to ) {
356
- // make sure it's current host location
357
- wp_safe_redirect( add_query_arg( 'settings-updated', true, $redirect_to ) );
358
- exit;
359
- }
360
- }
361
- }
362
-
363
- /**
364
- * Add wp_head content.
365
- *
366
- * @return void
367
- */
368
- public function wp_head() {
369
- // break on admin side
370
- if ( is_admin() )
371
- return;
372
-
373
- // check content type
374
- if ( (bool) $this->options['ctype'] == true ) {
375
- $iub_headers = headers_list();
376
- $destroy = true;
377
-
378
- foreach ( $iub_headers as $header ) {
379
- if ( strpos( $header, "Content-Type: text/html" ) !== false || strpos( $header, "Content-type: text/html" ) !== false ) {
380
- $destroy = false;
381
- break;
382
- }
383
- }
384
-
385
- if ( $destroy )
386
- $this->no_html = true;
387
- }
388
-
389
- // is post or not html content type?
390
- if ( $_POST || $this->no_html )
391
- return;
392
-
393
- // initial head output
394
- $iubenda_code = "";
395
-
396
- if ( $this->multilang === true && defined( 'ICL_LANGUAGE_CODE' ) && isset( $this->options['code_' . ICL_LANGUAGE_CODE] ) ) {
397
- $iubenda_code .= $this->options['code_' . ICL_LANGUAGE_CODE];
398
-
399
- // no code for current language, use default
400
- if ( ! $iubenda_code )
401
- $iubenda_code .= $this->options['code_default'];
402
- } else
403
- $iubenda_code .= $this->options['code_default'];
404
-
405
- $iubenda_code = $this->parse_code( $iubenda_code, true );
406
-
407
- if ( $iubenda_code !== '' ) {
408
- $iubenda_code .= "\n
409
- <script>
410
- var iCallback = function() {};
411
-
412
- if ( typeof _iub.csConfiguration != 'undefined' ) {
413
- if ( 'callback' in _iub.csConfiguration ) {
414
- if ( 'onConsentGiven' in _iub.csConfiguration.callback )
415
- iCallback = _iub.csConfiguration.callback.onConsentGiven;
416
-
417
- _iub.csConfiguration.callback.onConsentGiven = function() {
418
- iCallback();
419
-
420
- /* separator */
421
- jQuery('noscript._no_script_iub').each(function (a, b) { var el = jQuery(b); el.after(el.html()); });
422
- }
423
- }
424
- }
425
- </script>";
426
-
427
- echo '<!--IUB-COOKIE-SKIP-START-->' . $iubenda_code . '<!--IUB-COOKIE-SKIP-END-->';
428
- }
429
- }
430
-
431
- /**
432
- * Initialize html output.
433
- *
434
- * @return void
435
- */
436
- public function output_start() {
437
- if ( ! is_admin() )
438
- ob_start( array( $this, 'output_callback' ) );
439
- }
440
-
441
- /**
442
- * Finish html output.
443
- *
444
- * @return void
445
- */
446
- public function output_end() {
447
- if ( ! is_admin() && ob_get_level() )
448
- ob_end_flush();
449
- }
450
-
451
- /**
452
- * Handle final html output.
453
- *
454
- * @param mixed $output
455
- * @return mixed
456
- */
457
- public function output_callback( $output ) {
458
- // check whether to run parser or not
459
-
460
- // bail on ajax, xmlrpc or iub_no_parse request
461
- if (
462
- ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST )
463
- || ( defined( 'DOING_AJAX' ) && DOING_AJAX )
464
- || isset( $_SERVER["HTTP_X_REQUESTED_WITH"] )
465
- || isset( $_GET['iub_no_parse'] )
466
- )
467
- return $output;
468
-
469
- // bail on admin side
470
- if ( is_admin() )
471
- return $output;
472
-
473
- // bail on rss feed
474
- if ( is_feed() && $this->options['output_feed'] )
475
- return $output;
476
-
477
- if ( strpos( $output, "<html" ) === false )
478
- return $output;
479
- elseif ( strpos( $output, "<html" ) > 200 )
480
- return $output;
481
-
482
- // bail if skripts blocking disabled
483
- if ( ! $this->options['parse'] )
484
- return $output;
485
-
486
- // bail if consent given and skip parsing enabled
487
- if ( iubendaParser::consent_given() && $this->options['skip_parsing'] )
488
- return $output;
489
-
490
- // bail if bot detectd, no html in output or it's a post request
491
- if ( iubendaParser::bot_detected() || $_POST || $this->no_html )
492
- return $output;
493
-
494
- // google recaptcha v3 compatibility
495
- if ( class_exists( 'WPCF7' ) && (int) WPCF7::get_option( 'iqfix_recaptcha' ) === 0 && ! iubendaParser::consent_given() )
496
- $this->options['custom_scripts'][] = 'grecaptcha';
497
-
498
- $startime = microtime( true );
499
- $output = apply_filters( 'iubenda_initial_output', $output );
500
-
501
- // experimental class
502
- if ( $this->options['parser_engine'] == 'new' ) {
503
- $iubenda = new iubendaParser( mb_convert_encoding( $output, 'HTML-ENTITIES', 'UTF-8' ), array( 'type' => 'faster', 'scripts' => $this->options['custom_scripts'], 'iframes' => $this->options['custom_iframes'] ) );
504
-
505
- // render output
506
- $output = $iubenda->parse();
507
-
508
- // append signature
509
- $output .= '<!-- Parsed with iubenda experimental class in ' . round( microtime( true ) - $startime, 4 ) . ' sec. -->';
510
- // default class
511
- } else {
512
- $iubenda = new iubendaParser( $output, array( 'type' => 'page', 'scripts' => $this->options['custom_scripts'], 'iframes' => $this->options['custom_iframes'] ) );
513
-
514
- // render output
515
- $output = $iubenda->parse();
516
-
517
- // append signature
518
- $output .= '<!-- Parsed with iubenda default class in ' . round( microtime( true ) - $startime, 4 ) . ' sec. -->';
519
- }
520
-
521
- return apply_filters( 'iubenda_final_output', $output );
522
- }
523
-
524
- /**
525
- * Register plugin options.
526
- *
527
- * @return void
528
- */
529
- public function register_options() {
530
- register_setting( 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution', array( $this, 'save_options' ) );
531
-
532
- add_settings_section( 'iubenda_cookie_law_solution', '', '', 'iubenda_cookie_law_solution' );
533
- add_settings_field( 'iub_code', __( 'Code', 'iubenda-cookie-law-solution' ), array( $this, 'iub_code' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
534
- add_settings_field( 'iub_parse', __( 'Scripts blocking', 'iubenda-cookie-law-solution' ), array( $this, 'iub_parse' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
535
- add_settings_field( 'iub_custom_scripts', __( 'Custom scripts', 'iubenda-cookie-law-solution' ), array( $this, 'iub_custom_scripts' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
536
- add_settings_field( 'iub_ctype', __( 'Content type', 'iubenda-cookie-law-solution' ), array( $this, 'iub_ctype' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
537
- add_settings_field( 'iub_output_feed', __( 'RSS feed', 'iubenda-cookie-law-solution' ), array( $this, 'iub_output_feed' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
538
- add_settings_field( 'iub_menu_position', __( 'Menu position', 'iubenda-cookie-law-solution' ), array( $this, 'iub_menu_position' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
539
- add_settings_field( 'iub_deactivation', __( 'Deactivation', 'iubenda-cookie-law-solution' ), array( $this, 'iub_deactivation' ), 'iubenda_cookie_law_solution', 'iubenda_cookie_law_solution' );
540
- }
541
-
542
- /**
543
- * Display errors and notices.
544
- *
545
- * @global string $pagenow
546
- */
547
- public function settings_errors() {
548
- global $pagenow;
549
-
550
- // force display notices in top menu settings page
551
- if ( $pagenow != 'options-general.php' )
552
- settings_errors( 'iub_settings_errors' );
553
- }
554
-
555
- /**
556
- * Code option.
557
- *
558
- * @return mixed
559
- */
560
- public function iub_code() {
561
- // multilang support
562
- if ( $this->multilang && ! empty( $this->languages ) ) {
563
- echo '
564
- <div id="contextual-help-wrap" class="contextual-help-wrap hidden" tabindex="-1" style="display: block;">
565
- <div id="contextual-help-back" class="contextual-help-back"></div>
566
- <div id="contextual-help-columns" class="contextual-help-columns">
567
- <div class="contextual-help-tabs">
568
- <ul>';
569
- foreach ( $this->languages as $lang_id => $lang_name ) {
570
- echo '
571
- <li class="' . ( $this->lang_default == $lang_id ? 'active' : '' ) . '">
572
- <a href="#tab-panel-' . $lang_id . '" aria-controls="tab-panel-' . $lang_id . '">' . $lang_name . '</a>
573
- </li>';
574
- }
575
- echo '
576
- </ul>
577
- </div>
578
-
579
- <div id="contextual-help-tabs-wrap" class="contextual-help-tabs-wrap">';
580
- foreach ( $this->languages as $lang_id => $lang_name ) {
581
- // get code for the language
582
- $code = ! empty( $this->options['code_' . $lang_id] ) ? html_entity_decode( $this->parse_code( $this->options['code_' . $lang_id] ) ) : '';
583
- // handle default, if empty
584
- $code = empty( $code ) && $lang_id == $this->lang_default ? html_entity_decode( $this->parse_code( $this->options['code_default'] ) ) : $code;
585
-
586
- echo '
587
- <div id="tab-panel-' . $lang_id . '" class="help-tab-content' . ( $this->lang_default == $lang_id ? ' active' : '' ) . '">
588
- <textarea name="iubenda_cookie_law_solution[code_' . $lang_id . ']" class="large-text" cols="50" rows="10">' . $code . '</textarea>
589
- <p class="description">' . sprintf( __( 'Enter the iubenda code for %s.', 'iubenda-cookie-law-solution' ), $lang_name ) . '</p>
590
- </div>';
591
- }
592
- echo '
593
- </div>
594
- </div>
595
- </div>';
596
- } else {
597
- echo '
598
- <div id="iub_code_default">
599
- <textarea name="iubenda_cookie_law_solution[code_default]" class="large-text" cols="50" rows="10">' . html_entity_decode( $this->parse_code( $this->options['code_default'] ) ) . '</textarea>
600
- <p class="description">' . __( 'Enter the iubenda code.', 'iubenda-cookie-law-solution' ) . '</p>
601
- </div>';
602
- }
603
- }
604
-
605
- /**
606
- * Custom scripts option.
607
- *
608
- * @return void
609
- */
610
- public function iub_custom_scripts() {
611
- echo '
612
- <div id="contextual-help-wrap-2" class="contextual-help-wrap hidden" tabindex="-1" style="display: block;">
613
- <div id="contextual-help-back-2" class="contextual-help-back"></div>
614
- <div id="contextual-help-columns-2" class="contextual-help-columns">
615
- <div class="contextual-help-tabs">
616
- <ul>
617
- <li class="active">
618
- <a href="#tab-panel-scripts" aria-controls="tab-panel-scripts">' . esc_html__( 'Scripts', 'iubenda-cookie-law-solution' ) . '</a>
619
- </li>
620
- <li>
621
- <a href="#tab-panel-iframes" aria-controls="tab-panel-iframes">' . esc_html__( 'Iframes', 'iubenda-cookie-law-solution' ) . '</a>
622
- </li>
623
- </ul>
624
- </div>
625
- <div id="contextual-help-tabs-wrap-2" class="contextual-help-tabs-wrap">
626
- <div id="tab-panel-scripts" class="help-tab-content active">
627
- <textarea name="iubenda_cookie_law_solution[custom_scripts]" class="large-text" cols="50" rows="10">' . esc_textarea( implode( "\n", $this->options['custom_scripts'] ) ) . '</textarea>
628
- <p class="description">' . __( 'Enter a list of custom scripts (one per line).', 'iubenda-cookie-law-solution' ) . '</p>
629
- </div>
630
- <div id="tab-panel-iframes" class="help-tab-content">
631
- <textarea name="iubenda_cookie_law_solution[custom_iframes]" class="large-text" cols="50" rows="10">' . esc_textarea( implode( "\n", $this->options['custom_iframes'] ) ) . '</textarea>
632
- <p class="description">' . __( 'Enter a list of custom iframes (one per line).', 'iubenda-cookie-law-solution' ) . '</p>
633
- </div>
634
- </div>
635
- </div>
636
- </div>';
637
- }
638
-
639
- /**
640
- * Parsing option.
641
- *
642
- * @return mixed
643
- */
644
- public function iub_parse() {
645
- echo '
646
- <div id="iub_parse_container">
647
- <label><input id="iub_parse" type="checkbox" name="iubenda_cookie_law_solution[parse]" value="1" ' . checked( true, (bool) $this->options['parse'], false ) . '/>' . __( 'Automatically block scripts detected by the plugin.', 'iubenda-cookie-law-solution' ) . '</label>
648
- <p class="description">' . '(' . sprintf( __( "see <a href=\"%s\" target=\"_blank\">our documentation</a> for the list of detected scripts.", 'iubenda-cookie-law-solution' ), $this->links['documentation'] ) . ')' . '</p>
649
- <div id="iub_parser_engine_container"' . ( $this->options['parse'] === false ? ' style="display: none;"' : '' ) . '>
650
- <div>
651
- <label><input id="iub_parser_engine-new" type="radio" name="iubenda_cookie_law_solution[parser_engine]" value="new" ' . checked( 'new', $this->options['parser_engine'], false ) . ' />' . __( 'Primary', 'iubenda-cookie-law-solution' ) . '</label>
652
- <label><input id="iub_parser_engine-default" type="radio" name="iubenda_cookie_law_solution[parser_engine]" value="default" ' . checked( 'default', $this->options['parser_engine'], false ) . ' />' . __( 'Secondary', 'iubenda-cookie-law-solution' ) . '</label>
653
- <p class="description">' . __( 'Select parsing engine.', 'iubenda-cookie-law-solution' ) . '</p>
654
- </div>
655
- <div>
656
- <label><input id="iub_skip_parsing" type="checkbox" name="iubenda_cookie_law_solution[skip_parsing]" value="1" ' . checked( true, (bool) $this->options['skip_parsing'], false ) . '/>' . __( 'Leave scripts untouched on the page if the user has already given consent', 'iubenda-cookie-law-solution' ) . '</label>
657
- <p class="description">(' . __( "improves performance, highly recommended, to be deactivated only if your site uses a caching system", 'iubenda-cookie-law-solution' ) . ')</p>
658
- </div>
659
- </div>
660
- </div>';
661
- }
662
-
663
- /**
664
- * Ctype option.
665
- *
666
- * @return mixed
667
- */
668
- public function iub_ctype() {
669
- echo '
670
- <div id="iub_ctype_container">
671
- <label><input id="iub_ctype" type="checkbox" name="iubenda_cookie_law_solution[ctype]" value="1" ' . checked( true, (bool) $this->options['ctype'], false ) . '/>' . __( 'Restrict the plugin to run only for requests that have "Content-type: text / html" (recommended)', 'iubenda-cookie-law-solution' ) . '</label>
672
- </div>';
673
- }
674
-
675
- /**
676
- * RSS feed option.
677
- *
678
- * @return mixed
679
- */
680
- public function iub_output_feed() {
681
- echo '
682
- <div id="iub_output_feed_container">
683
- <label><input id="iub_ctype" type="checkbox" name="iubenda_cookie_law_solution[output_feed]" value="1" ' . checked( true, (bool) $this->options['output_feed'], false ) . '/>' . __( 'Do not run the plugin inside the RSS feed (recommended)', 'iubenda-cookie-law-solution' ) . '</label>
684
- </div>';
685
- }
686
-
687
- /**
688
- * Menu option.
689
- *
690
- * @return mixed
691
- */
692
- public function iub_menu_position() {
693
- echo '
694
- <div id="iub_menu_position_container">
695
- <label><input id="iub_menu_position-topmenu" type="radio" name="iubenda_cookie_law_solution[menu_position]" value="topmenu" ' . checked( 'topmenu', $this->options['menu_position'], false ) . ' />' . __( 'Top menu', 'iubenda-cookie-law-solution' ) . '</label>
696
- <label><input id="iub_menu_position-submenu" type="radio" name="iubenda_cookie_law_solution[menu_position]" value="submenu" ' . checked( 'submenu', $this->options['menu_position'], false ) . ' />' . __( 'Submenu', 'iubenda-cookie-law-solution' ) . '</label>
697
- <p class="description">' . __( 'Select whether to display iubenda in a top admin menu or the Settings submenu.', 'iubenda-cookie-law-solution' ) . '</p>
698
- </div>';
699
- }
700
-
701
- /**
702
- * Deactivation option.
703
- *
704
- * @return mixed
705
- */
706
- public function iub_deactivation() {
707
- echo '
708
- <div id="iub_deactivation_container">
709
- <label><input id="iub_deactivation" type="checkbox" name="iubenda_cookie_law_solution[deactivation]" value="1" ' . checked( true, (bool) $this->options['deactivation'], false ) . '/>' . __( 'Delete all plugin data upon deactivation?', 'iubenda-cookie-law-solution' ) . '</label>
710
- </div>';
711
- }
712
-
713
- /**
714
- * Save options.
715
- *
716
- * @return void
717
- */
718
- public function save_options( $input ) {
719
- if ( ! current_user_can( apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ) ) )
720
- return $input;
721
-
722
- // save options
723
- if ( isset( $_POST['save_iubenda_options'] ) ) {
724
- $input['parse'] = (bool) isset( $input['parse'] );
725
- $input['parser_engine'] = isset( $input['parser_engine'] ) && in_array( $input['parser_engine'], array( 'default', 'new' ) ) ? $input['parser_engine'] : $this->defaults['parser_engine'];
726
- $input['skip_parsing'] = (bool) isset( $input['skip_parsing'] );
727
- $input['ctype'] = (bool) isset( $input['ctype'] );
728
- $input['output_feed'] = (bool) isset( $input['output_feed'] );
729
- $input['menu_position'] = isset( $input['menu_position'] ) && in_array( $input['menu_position'], array( 'topmenu', 'submenu' ) ) ? $input['menu_position'] : $this->defaults['menu_position'];
730
- $input['deactivation'] = (bool) isset( $input['deactivation'] );
731
-
732
- // multilang support
733
- if ( $this->multilang && ! empty( $this->languages ) ) {
734
- foreach ( $this->languages as $lang_id => $lang_name ) {
735
- $input['code_' . $lang_id] = ! empty( $input['code_' . $lang_id] ) ? $this->parse_code( $input['code_' . $lang_id] ) : '';
736
-
737
- // handle default lang too
738
- if ( $lang_id == $this->lang_default ) {
739
- $input['code_default'] = ! empty( $input['code_' . $lang_id] ) ? $this->parse_code( $input['code_' . $lang_id] ) : $this->options['code_default'];
740
- }
741
- }
742
- } else
743
- $input['code_default'] = ! empty( $input['code_default'] ) ? $this->parse_code( $input['code_default'] ) : '';
744
-
745
- // scripts
746
- if ( isset( $input['custom_scripts'] ) ) {
747
- $input['custom_scripts'] = trim( $input['custom_scripts'] );
748
-
749
- if ( ! empty( $input['custom_scripts'] ) )
750
- $input['custom_scripts'] = array_map( 'trim', explode( "\n", str_replace( "\r", '', $input['custom_scripts'] ) ) );
751
- else
752
- $input['custom_scripts'] = array();
753
- } else
754
- $input['custom_scripts'] = array();
755
-
756
- // iframes
757
- if ( isset( $input['custom_iframes'] ) ) {
758
- $input['custom_iframes'] = trim( $input['custom_iframes'] );
759
-
760
- if ( ! empty( $input['custom_iframes'] ) )
761
- $input['custom_iframes'] = array_map( 'trim', explode( "\n", str_replace( "\r", '', $input['custom_iframes'] ) ) );
762
- else
763
- $input['custom_iframes'] = array();
764
- } else
765
- $input['custom_iframes'] = array();
766
-
767
- add_settings_error( 'iub_settings_errors', 'iub_settings_updated', __( 'Settings saved.', 'iubenda-cookie-law-solution' ), 'updated' );
768
- // reset options
769
- } elseif ( isset( $_POST['reset_iubenda_options'] ) ) {
770
- $input = $this->defaults;
771
-
772
- // multilang support
773
- if ( $this->multilang && ! empty( $this->languages ) ) {
774
- foreach ( $this->languages as $lang_id => $lang_name ) {
775
- $input['code_' . $lang_id] = '';
776
- }
777
- }
778
-
779
- add_settings_error( 'iub_settings_errors', 'iub_settings_restored', __( 'Settings restored to defaults.', 'iubenda-cookie-law-solution' ), 'updated' );
780
- }
781
-
782
- return $input;
783
- }
784
-
785
- /**
786
- * Parse iubenda code.
787
- *
788
- * @param string $source
789
- * @param bool $display
790
- * @return string
791
- */
792
- public function parse_code( $source, $display = false ) {
793
- // return $source;
794
- $source = trim( $source );
795
-
796
- preg_match_all( '/(\"(?:html|content)\"(?:\s+)?\:(?:\s+)?)\"((?:.*?)(?:[^\\\\]))\"/s', $source, $matches );
797
-
798
- // found subgroup?
799
- if ( ! empty( $matches[1] ) && ! empty( $matches[2] ) ) {
800
- foreach ( $matches[2] as $no => $match ) {
801
- $source = str_replace( $matches[0][$no], $matches[1][$no] . '[[IUBENDA_TAG_START]]' . $match . '[[IUBENDA_TAG_END]]', $source );
802
- }
803
-
804
- // kses it
805
- $source = wp_kses( $source, $this->get_allowed_html() );
806
-
807
- preg_match_all( '/\[\[IUBENDA_TAG_START\]\](.*?)\[\[IUBENDA_TAG_END\]\]/s', $source, $matches_tags );
808
-
809
- if ( ! empty( $matches_tags[1] ) ) {
810
- foreach ( $matches_tags[1] as $no => $match ) {
811
- $source = str_replace( $matches_tags[0][$no], '"' . ( $display ? str_replace( '</', '<\/', $matches[2][$no] ) : $matches[2][$no] ) . '"', $source );
812
- }
813
- }
814
- }
815
-
816
- return $source;
817
- }
818
-
819
- /**
820
- * Get allowed iubenda script HTML.
821
- *
822
- * @return array
823
- */
824
- public function get_allowed_html() {
825
- // Jetpack fix
826
- remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'filter' ), 11 );
827
-
828
- $html = array_merge(
829
- wp_kses_allowed_html( 'post' ),
830
- array(
831
- 'script' => array(
832
- 'type' => array(),
833
- 'src' => array(),
834
- 'charset' => array(),
835
- 'async' => array()
836
- ),
837
- 'noscript' => array(),
838
- 'style' => array(
839
- 'type' => array()
840
- ),
841
- 'iframe' => array(
842
- 'src' => array(),
843
- 'height' => array(),
844
- 'width' => array(),
845
- 'frameborder' => array(),
846
- 'allowfullscreen' => array()
847
- )
848
- )
849
- );
850
-
851
- return apply_filters( 'iub_code_allowed_html', $html );
852
- }
853
-
854
- /**
855
- * Load admin options page.
856
- *
857
- * @return void
858
- */
859
- public function options_page() {
860
- if ( ! current_user_can( apply_filters( 'iubenda_cookie_law_cap', 'manage_options' ) ) ) {
861
- wp_die( __( "You don't have permission to access this page.", 'iubenda-cookie-law-solution' ) );
862
- }
863
- ?>
864
- <div class="wrap">
865
- <div id="iubenda-view">
866
- <?php
867
- echo '
868
- <a class="iubenda-link" href="http://iubenda.com" title="iubenda" title="_blank">
869
- <img id="iubenda-logo" alt="iubenda logo" width="300" height="90" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNjM3LjggMjgzLjUiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDYzNy44IDI4My41OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHN0eWxlIHR5cGU9InRleHQvY3NzIj4uc3Qwe2ZpbGw6IzFDQzY5MTt9LnN0MXtmaWxsOiM1MTUyNTQ7fTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MCIgZD0iTTE3OC45LDk5LjljMCw4LjItMywxNS42LTgsMjEuNGw3LjIsOTUuNGgtNjQuMmw3LTkzLjhjLTUuOS02LTkuNi0xNC4xLTkuNi0yMy4xYzAtMTguMywxNS4xLTMzLjEsMzMuOC0zMy4xUzE3OC45LDgxLjYsMTc4LjksOTkuOSBNMTQ1LjEsMTA3LjRjNC41LDAsOC4xLTMuNiw4LjEtOC4xcy0zLjYtOC04LjEtOGMtNC41LDAtOC4xLDMuNi04LjEsOFMxNDAuNiwxMDcuNCwxNDUuMSwxMDcuNCBNMTUxLjUsMTM2LjJsLTExLjEsMTEuMXY0My4xaDExLjFWMTM2LjJ6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTI2NS40LDE3OC42Yy0yLjMsMS4yLTQuNywxLjgtNy4yLDEuOGMtMi44LDAtNS4zLTAuOC03LjQtMi40Yy0yLjEtMS42LTMuNS0zLjctNC4zLTYuMmMtMC44LTIuNS0xLjItNi4xLTEuMi0xMC44di0xOC4yYzAsMCwwLTAuOSwwLTIuOGMwLTAuNSwwLTIuOC0xLjUtMy41Yy0wLjItMC4xLTAuNi0wLjItMS4yLTAuM2MtMC40LDAtMC44LTAuNC0wLjgtMC44bDAtMi40YzAtMC41LDAuNC0wLjksMC44LTAuOWg5LjNjMS4zLDAsMi40LDEuMSwyLjQsMi40VjE0N2wwLDE1LjVjMCw0LjYsMC44LDcuNywyLjUsOS4xYzEuNiwxLjUsMy42LDIuMiw1LjksMi4yYzEuNiwwLDMuNC0wLjUsNS40LTEuNWMyLTEsNS4zLTIuOCw4LjEtNS42bDAtMi40bDAtMjIuMlYxNDBjMC0wLjUsMC0yLjgtMS40LTMuNWMtMC4yLTAuMS0wLjYtMC4yLTEuMS0wLjNjLTAuNC0wLjEtMC44LTAuNC0wLjgtMC44bDAtMi40YzAtMC41LDAuNC0wLjksMC45LTAuOWg5LjJjMS4zLDAsMi40LDEuMSwyLjQsMi40djhjMCwwLjEsMCwwLjEsMCwwLjJ2MTYuNmMwLDMuOCwwLDcuNCwwLDEwLjZjMCwwLjcsMCwxLjIsMCwxLjJjMCwwLjUtMC4xLDMuMSwxLjQsMy44YzAuMiwwLjEsMC42LDAuMiwxLjIsMC4zYzAuNCwwLDAuOCwwLjQsMC44LDAuOGwwLDIuNGMwLDAuNS0wLjQsMC44LTAuOSwwLjloLTkuMmMtMS4zLDAtMi40LTEuMS0yLjQtMi40bDAtNC41bDAtMi41QzI3MS45LDE3NC41LDI2Ny43LDE3Ny40LDI2NS40LDE3OC42Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTMwOS4yLDE3NmMxLjksMC45LDMuOSwxLjMsNiwxLjNjMy4yLDAsNi4zLTEuNyw5LTUuMmMyLjgtMy41LDQuMi04LjUsNC4yLTE1LjJjMC02LjEtMS40LTEwLjgtNC4yLTE0LjFjLTIuOC0zLjMtNi00LjktOS41LTQuOWMtMS45LDAtMy44LDAuNS01LjcsMS40Yy0xLjIsMC42LTIuOCwxLjgtNC43LDMuNGMtMC41LDAuNS0wLjgsMS4xLTAuOCwxLjhWMTcxYzAsMC43LDAuMywxLjQsMC44LDEuOEMzMDYsMTc0LjIsMzA3LjYsMTc1LjMsMzA5LjIsMTc2IE0yOTQuOCwxMThjMC0wLjUsMC0yLjctMS40LTMuNGMtMC4yLTAuMS0wLjMtMC4xLTAuNi0wLjJjLTAuNC0wLjEtMC42LTAuNC0wLjYtMC44bDAtMi4zYzAtMC41LDAuNC0wLjgsMC45LTAuOWgxLjhoNi41YzEuMywwLDIuMywxLDIuMywyLjNsMCwxMnYxNS40YzQuNy02LjQsOS44LTkuNiwxNS4zLTkuNmM1LDAsOS40LDIuMSwxMy4xLDYuM2MzLjcsNC4yLDUuNiw5LjksNS42LDE3LjJjMCw4LjUtMi45LDE1LjMtOC42LDIwLjVjLTQuOSw0LjQtMTAuNSw2LjctMTYuNSw2LjdjLTIuOCwwLTUuNy0wLjUtOC43LTEuNWMtMi41LTAuOS01LjEtMi4xLTcuNy0zLjdjLTAuOC0wLjUtMS4zLTEuNC0xLjMtMi40di00NmMwLTAuOSwwLTIsMC0zLjNMMjk0LjgsMTE4eiIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0zODkuMywxNzkuMWMtMC41LDAtMC45LTAuNC0wLjktMC45bDAtMi4zYzAtMC40LDAuMy0wLjgsMC43LTAuOGMwLjUtMC4xLDAuOC0wLjEsMS0wLjJjMS40LTAuNywxLjQtMi45LDEuNC0zLjR2LTIuN2MwLDAsMC01LjgsMC0xNy41YzAtMS45LDAtMy44LDAuMS01LjVsMC00LjZjMC0wLjUsMC0xLDAtMS41YzAtMC42LDAtMi44LTEuNC0zLjVjLTAuMS0wLjEtMC4zLTAuMS0wLjUtMC4yYy0wLjQtMC4xLTAuNi0wLjQtMC42LTAuOGwwLTIuM2MwLTAuNSwwLjQtMC44LDAuOS0wLjloOC4xYzEuMywwLDIuMywxLDIuMywyLjN2My40YzAsMCwwLDAuNiwwLDEuOGMwLDAuMywwLjIsMC42LDAuNiwwLjZjMC4yLDAsMC4zLTAuMSwwLjQtMC4yYzUuNC01LjksMTIuMy04LjgsMTcuMi04LjhjMi43LDAsNSwwLjYsNi45LDEuOWMxLjksMS4zLDMuNCwzLjQsNC42LDYuM2MwLjgsMi4xLDEuMiw1LjIsMS4yLDkuNHYxNi41bDAsNi4zYzAsMC41LDAsMi43LDEuNCwzLjRjMC4yLDAuMSwwLjQsMC4yLDAuOCwwLjJjMC40LDAuMSwwLjcsMC40LDAuNywwLjhsMCwyLjNjMCwwLjUtMC40LDAuOC0wLjgsMC45Yy0wLjgsMC0xLjUsMC0yLDBoLTYuNWMtMC4xLDAtMC4zLDAtMC40LDBoLTMuMWMtMS4xLDAtMi0wLjktMi0yYzAtMSwwLjctMS45LDEuNi0yLjJjMC4xLDAsMC4xLDAsMC4yLTAuMWMxLTAuNSwxLjMtMS44LDEuNC0yLjd2LTcuNGwwLTE1LjJjMC00LjMtMC42LTcuNC0xLjctOS4zYy0xLjItMS45LTMuMS0yLjktNS44LTIuOWMtNC4yLDAtMTAuMywyLjItMTQuNCw2Ljd2MjAuOHYwLjNsMCw2LjRjMCwwLjUsMCwyLjgsMS40LDMuNWMwLjEsMCwwLjEsMCwwLjIsMC4xYzEsMC4zLDEuNiwxLjIsMS42LDIuMmMwLDEuMS0wLjksMi0yLDJIMzk0QzM5NCwxNzkuMSwzOTIuNCwxNzkuMSwzODkuMywxNzkuMSIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik01MTUsMTUzLjRjLTYuNiwxLjMtMTAuNCwyLjItMTEuNCwyLjVjLTMuNywxLjItNi42LDIuNi02LjgsOC43Yy0wLjEsMi41LDAuOCw0LjcsMi4zLDYuM2MxLjUsMS43LDMuMywyLjUsNS4zLDIuNWMyLjUsMCw1LjctMS44LDkuNi00LjhjMC43LTAuNSwxLjEtMS4zLDEuMS0yLjJWMTUzLjR6IE01MjMuOCwxNzAuOGMwLDAuMSwwLDAuMiwwLDAuMmMwLDAuMiwwLDAuMywwLDAuNGMwLjEsMS40LDAuNiwyLjQsMS40LDIuOGMwLjIsMC4xLDAuNCwwLjIsMC42LDAuMmMwLjQsMC4xLDAuNywwLjQsMC43LDAuOGwwLDIuNGMwLDAuNS0wLjQsMC44LTAuOSwwLjloLTguM2MtMS4zLDAtMi4zLTEtMi4zLTIuM3YtNC41Yy01LDMuOS04LjIsNi4xLTkuNSw2LjdjLTEuOSwwLjktNCwxLjMtNi4xLDEuM2MtMy40LDAtNi4yLTEuMi04LjQtMy40Yy0yLjItMi4zLTMuMy01LjMtMy4zLTkuMWMwLTIuNCwwLjUtNC40LDEuNi02LjJjMS41LTIuNCwzLjctNS4yLDcuNi02LjhjNC0xLjYsNy4zLTIsMTgtNC40YzAtMC4zLDAtNCwwLTQuM2MwLTQuNS0wLjgtOS4yLTguNC04LjdjLTUuMywwLjMtMTAuMiwyLTE0LjcsNWMtMC40LDAuMy0wLjksMC4yLTEuMi0wLjJjLTAuMS0wLjEtMC4xLTAuMy0wLjEtMC41di0yLjhjMC0xLjUsMC4zLTIuNCwwLjktMi45YzMuMS0yLjUsMTAuOS01LjUsMTguNS01YzguNCwwLjYsMTEuNCw0LDEyLjksOS4zYzAuNSwxLjYsMSwyLjgsMSw3LjV2MTQuNWMwLDIsMCw0LDAsNS44VjE3MC44eiIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik00NjUuNCwxMzcuOGMtMS43LTEtMy40LTEuNS01LTEuNWMtMywwLTUuOCwxLjMtOC4zLDMuOGMtMi43LDIuOC00LjYsNi41LTQuNiwxMy41YzAsNywxLjUsMTIuNCw0LjYsMTYuMmMzLDMuNyw2LjQsNS42LDEwLjIsNS42YzIuNywwLDUuMy0xLjEsNy44LTMuNGMwLjktMC44LDEuNC0xLjksMS40LTN2LTIwLjhDNDcxLjQsMTQzLjksNDY5LjEsMTQwLDQ2NS40LDEzNy44IE00ODEuMywxNzQuNmMwLjEsMC4xLDAuMywwLjEsMC41LDAuMmMwLjQsMC4xLDAuNiwwLjQsMC42LDAuOGwwLDIuM2MwLDAuNS0wLjQsMC44LTAuOSwwLjloLThjLTEuMiwwLTIuMy0xLTIuMy0yLjJ2LTIuMmMtMi4zLDIuNC00LjYsNC4yLTYuOCw1LjNjLTIuMiwxLjEtNC42LDEuNi03LjEsMS42Yy01LjIsMC05LjctMi4yLTEzLjYtNi42Yy0zLjktNC40LTUuOC0xMC01LjgtMTYuOXMyLjEtMTMuMSw2LjQtMTguOGM0LjMtNS43LDkuOC04LjUsMTYuNS04LjVjNC4yLDAsNy42LDEuMywxMC40LDR2LTE2LjdjMC0wLjUsMC0yLjctMS40LTMuNGMtMC4xLTAuMS0wLjMtMC4xLTAuNS0wLjJjLTAuNC0wLjEtMC42LTAuNC0wLjYtMC44bDAtMi40YzAtMC41LDAuNC0wLjksMC45LTAuOWg3LjljMS4yLDAsMi4zLDEsMi4zLDIuMnY1OC45QzQ3OS45LDE3MS44LDQ3OS45LDE3My45LDQ4MS4zLDE3NC42Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTM1MCwxNTAuMmMwLDAuMSwwLDAuMywwLjEsMC4zYzAuMSwwLjEsMC4yLDAuMSwwLjQsMC4xaDIzLjljMC4zLDAsMC41LTAuMiwwLjUtMC40YzAuMy0yLjUsMC40LTctMy4zLTEwLjhjLTEuOC0xLjktNC4xLTIuOC04LjMtMi44QzM1NS43LDEzNi42LDM1MC44LDE0My45LDM1MCwxNTAuMiBNMzQ3LjUsMTc0LjljLTMuOS00LjMtNS45LTExLjMtNS45LTE4LjJjMC03LjMsMi4zLTEzLjksNi40LTE4LjdjNC4zLTUsMTAuMi03LjcsMTcuMS03LjdjNS44LDAsMTAuMiwyLDEzLjIsNS44YzIuNywzLjYsNC4xLDguOCw0LjEsMTUuNGMwLDAuOCwwLDEuOS0wLjEsMy4zYy0wLjEsMC45LTAuOCwxLjYtMS43LDEuNmgtMjkuOGMtMC4xLDAtMC4zLDAuMS0wLjQsMC4xYy0wLjEsMC4xLTAuMSwwLjItMC4xLDAuNGMwLjEsNS40LDEuOCwxMCw1LDEzLjJjMy4xLDMuMiw3LjQsNC45LDEyLjQsNC45YzMuNywwLDguNi0xLDEyLjQtMi4xYzAuNS0wLjIsMS4xLDAuMSwxLjMsMC43YzAuMSwwLjIsMC4xLDAuNCwwLDAuNWwtMC41LDEuOWMtMC4yLDAuNy0wLjcsMS4zLTEuMywxLjZjLTMuNywxLjgtOS4zLDMuNS0xNSwzLjVDMzU3LjYsMTgxLjIsMzUxLjYsMTc5LjUsMzQ3LjUsMTc0LjkiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNMjMxLjEsMTM1Ljl2MzYuOWMwLDEsMC42LDEuOSwxLjQsMi4zYzAuOSwwLjQsMS40LDEuMywxLjQsMi4zdjAuN2MwLDAuOC0wLjYsMS40LTEuNCwxLjRIMjIwYy0wLjgsMC0xLjQtMC42LTEuNC0xLjR2LTAuN2MwLTEsMC42LTEuOSwxLjQtMi4zYzAuOS0wLjQsMS40LTEuMywxLjQtMi4zdi0zNS43YzAtMC41LTAuNC0wLjktMC45LTAuOXMtMC45LTAuNC0wLjktMC45di0xLjJjMC0xLjIsMC45LTIuMSwyLjEtMi4xaDUuNkMyMjkuNCwxMzIsMjMxLjEsMTMzLjcsMjMxLjEsMTM1LjkiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNMjI2LjMsMTEwLjhjMy4zLDAsNiwyLjcsNiw1LjljMCwzLjMtMi43LDUuOS02LDUuOXMtNi0yLjctNi01LjlDMjIwLjMsMTEzLjUsMjIzLDExMC44LDIyNi4zLDExMC44Ii8+PC9zdmc+"/>
870
- </a>
871
- <p class="iubenda-text">
872
- ' . __( "This plugin is the easiest and most comprehensive way to adapt your WordPress site to the European cookie law. Upon your user's first visit, the plugin will take care of collecting their consent, of blocking the most popular among the scripts that install cookies and subsequently reactivate 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.", 'iubenda-cookie-law-solution' ) . '
873
- </p>
874
- <p class="iubenda-text">
875
- <span class="iubenda-title">' . __( "Would you like to know more about the cookie law?", 'iubenda-cookie-law-solution' ) . '</span><br />
876
- ' . sprintf( __( "Read our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">complete guide to the cookie law.</a>", 'iubenda-cookie-law-solution' ), $this->links['guide'] ) . '
877
- </p>
878
- <p class="iubenda-text">
879
- <span class="iubenda-title">' . __( "What is the full functionality of the plugin?", 'iubenda-cookie-law-solution' ) . '</span><br />
880
- ' . sprintf( __( "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">plugin page.</a>", 'iubenda-cookie-law-solution' ), $this->links['plugin_page'] ) . '
881
- </p>
882
- <p class="iubenda-text">
883
- <span class="iubenda-title">' . __( "Enter the iubenda code for the Cookie Solution below.", 'iubenda-cookie-law-solution' ) . '</span><br />
884
- ' . 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-cookie-law-solution' ), $this->links['generating_code'] ) . '
885
- </p>';
886
- ?>
887
- <form id="iubenda-tabs" action="options.php" method="post">
888
- <?php
889
- settings_fields( 'iubenda_cookie_law_solution' );
890
- do_settings_sections( 'iubenda_cookie_law_solution' );
891
-
892
- echo ' <p class="submit">';
893
- submit_button( '', 'primary', 'save_iubenda_options', false );
894
- echo ' ';
895
- submit_button( __( 'Reset to defaults', 'iubenda-cookie-law-solution' ), 'secondary', 'reset_iubenda_options', false );
896
- echo ' </p>';
897
- ?>
898
- </form>
899
- <?php echo '
900
- <p class="iubenda-text">
901
- <span class="iubenda-title">' . __( 'Need support for this plugin?', 'iubenda-cookie-law-solution' ) . '</span><br />
902
- ' . sprintf( __( "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">support forum.</a>", 'iubenda-cookie-law-solution' ), $this->links['support_forum'] ) . '
903
- </p>
904
- <p class="iubenda-text">
905
- <span class="iubenda-title">' . __( 'Want to try a beta version of this plugin with the latest features?', 'iubenda-cookie-law-solution' ) . '</span><br />
906
- ' . sprintf( __( "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">documentation pages</a> and follow the instructions to install a beta version.", 'iubenda-cookie-law-solution' ), $this->links['documentation'] ) . '
907
- </p>';
908
- ?>
909
- </div>
910
- <div class="clear"></div>
911
- </div>
912
- <?php
913
- }
914
-
915
- }
1
+ <?php
2
+ /*
3
+ Plugin Name: iubenda Cookie Solution for GDPR
4
+ Plugin URI: https://www.iubenda.com
5
+ Description: iubenda Cookie Solution allows you to make your website GDPR compliant and manage all aspects of cookie law on WP.
6
+ Version: 2.0-beta
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
+ ibenda Cookie Solution
15
+ Copyright (C) 2018-2019, 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.0
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
+ 'code_default' => false, // iubenda-code-default,
50
+ 'menu_position' => 'topmenu',
51
+ 'custom_scripts' => array(),
52
+ 'custom_iframes' => array(),
53
+ 'deactivation' => false
54
+ ),
55
+ 'cons' => array(
56
+ 'public_api_key' => '',
57
+ )
58
+ );
59
+ public $base_url;
60
+ public $version = '2.0';
61
+ public $no_html = false;
62
+ public $multilang = false;
63
+ public $languages = array();
64
+ public $lang_default = '';
65
+
66
+ /**
67
+ * Disable object clone.
68
+ */
69
+ private function __clone() {}
70
+
71
+ /**
72
+ * Disable unserializing of the class.
73
+ */
74
+ private function __wakeup() {}
75
+
76
+ /**
77
+ * Main plugin instance,
78
+ * Insures that only one instance of the plugin exists in memory at one time.
79
+ *
80
+ * @return object
81
+ */
82
+ public static function instance() {
83
+ if ( ! isset( self::$instance ) && ! ( self::$instance instanceof iubenda ) ) {
84
+
85
+ self::$instance = new iubenda;
86
+ self::$instance->define_constants();
87
+
88
+ add_action( 'plugins_loaded', array( self::$instance, 'load_textdomain' ) );
89
+ add_action( 'plugins_loaded', array( self::$instance, 'init' ) );
90
+
91
+ self::$instance->includes();
92
+
93
+ self::$instance->forms = new iubenda_Forms();
94
+ self::$instance->settings = new iubenda_Settings();
95
+ }
96
+
97
+ return self::$instance;
98
+ }
99
+
100
+ /**
101
+ * Class constructor.
102
+ */
103
+ public function __construct() {
104
+ register_activation_hook( __FILE__, array( $this, 'activation' ) );
105
+ register_deactivation_hook( __FILE__, array( $this, 'deactivation' ) );
106
+
107
+ // settings
108
+ $this->options['cs'] = array_merge( $this->defaults['cs'], (array) get_option( 'iubenda_cookie_law_solution', $this->defaults['cs'] ) );
109
+ $this->options['cons'] = array_merge( $this->defaults['cons'], (array) get_option( 'iubenda_consent_solution', $this->defaults['cons'] ) );
110
+
111
+ $this->base_url = esc_url_raw( add_query_arg( 'page', 'iubenda', admin_url( $this->options['cs']['menu_position'] === 'submenu' ? 'options-general.php' : 'admin.php' ) ) );
112
+
113
+ // actions
114
+ add_action( 'after_setup_theme', array( $this, 'register_shortcode' ) );
115
+ add_action( 'wp_head', array( $this, 'wp_head_cs' ), 0 );
116
+ add_action( 'wp_head', array( $this, 'wp_head_cons' ), 1 );
117
+ // add_action( 'wp_footer', array( $this, 'wp_footer_cons' ), 1 );
118
+ add_action( 'template_redirect', array( $this, 'output_start' ), 0 );
119
+ add_action( 'shutdown', array( $this, 'output_end' ), 100 );
120
+ }
121
+
122
+ /**
123
+ * Setup plugin constants.
124
+ *
125
+ * @return void
126
+ */
127
+ private function define_constants() {
128
+ define( 'IUBENDA_PLUGIN_URL', plugins_url( '', __FILE__ ) );
129
+ define( 'IUBENDA_PLUGIN_REL_PATH', dirname( plugin_basename( __FILE__ ) ) . '/' );
130
+ define( 'IUBENDA_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
131
+ }
132
+
133
+ /**
134
+ * Include required files.
135
+ *
136
+ * @return void
137
+ */
138
+ private function includes() {
139
+ include_once( IUBENDA_PLUGIN_PATH . 'includes/settings.php' );
140
+ include_once( IUBENDA_PLUGIN_PATH . 'includes/forms.php' );
141
+ }
142
+
143
+ /**
144
+ * Initialize plugin.
145
+ *
146
+ * @return void
147
+ */
148
+ public function init() {
149
+ // check if WPML or Polylang is active
150
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
151
+
152
+ // Polylang support
153
+ if ( ( is_plugin_active( 'polylang/polylang.php' ) || is_plugin_active( 'polylang-pro/polylang.php' ) ) && function_exists( 'PLL' ) ) {
154
+ $this->multilang = true;
155
+
156
+ // get registered languages
157
+ $registered_languages = PLL()->model->get_languages_list();
158
+
159
+ if ( ! empty( $registered_languages ) ) {
160
+ foreach ( $registered_languages as $language )
161
+ $this->languages[$language->slug] = $language->name;
162
+ }
163
+
164
+ // get default language
165
+ $this->lang_default = pll_default_language();
166
+
167
+ // WPML support
168
+ } elseif ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) && class_exists( 'SitePress' ) ) {
169
+ $this->multilang = true;
170
+
171
+ global $sitepress;
172
+
173
+ // get registered languages
174
+ $registered_languages = icl_get_languages();
175
+
176
+ if ( ! empty( $registered_languages ) ) {
177
+ foreach ( $registered_languages as $language )
178
+ $this->languages[$language['code']] = $language['display_name'];
179
+ }
180
+
181
+ // get default language
182
+ $this->lang_default = $sitepress->get_default_language();
183
+ }
184
+
185
+ // load iubenda parser
186
+ include_once( dirname( __FILE__ ) . '/iubenda-cookie-class/iubenda.class.php' );
187
+ }
188
+
189
+ /**
190
+ * Plugin activation.
191
+ *
192
+ * @return void
193
+ */
194
+ public function activation() {
195
+ add_option( 'iubenda_cookie_law_solution', $this->options['cs'], '', 'no' );
196
+ add_option( 'iubenda_cookie_law_solution', $this->options['cons'], '', 'no' );
197
+ add_option( 'iubenda_cookie_law_version', $this->version, '', 'no' );
198
+ }
199
+
200
+ /**
201
+ * Plugin deactivation.
202
+ *
203
+ * @return void
204
+ */
205
+ public function deactivation() {
206
+ // remove options from database?
207
+ if ( $this->options['cs']['deactivation'] ) {
208
+ delete_option( 'iubenda_cookie_law_solution' );
209
+ delete_option( 'iubenda_consent_solution' );
210
+ delete_option( 'iubenda_cookie_law_version' );
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Load textdomain.
216
+ *
217
+ * @return void
218
+ */
219
+ public function load_textdomain() {
220
+ load_plugin_textdomain( 'iubenda', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
221
+ }
222
+
223
+ /**
224
+ * Register shortcode function.
225
+ *
226
+ * @return void
227
+ */
228
+ public function register_shortcode() {
229
+ add_shortcode( 'iub-cookie-policy', array( $this, 'block_shortcode' ) );
230
+ add_shortcode( 'iub-cookie-block', array( $this, 'block_shortcode' ) );
231
+ add_shortcode( 'iub-cookie-skip', array( $this, 'skip_shortcode' ) );
232
+ }
233
+
234
+ /**
235
+ * Handle block shortcode function.
236
+ *
237
+ * @param array $atts
238
+ * @param mixed $content
239
+ * @return mixed
240
+ */
241
+ public function block_shortcode( $atts, $content = '' ) {
242
+ return '<!--IUB-COOKIE-BLOCK-START-->' . do_shortcode( $content ) . '<!--IUB-COOKIE-BLOCK-END-->';
243
+ }
244
+
245
+ /**
246
+ * Handle skip shortcode function.
247
+ *
248
+ * @param array $atts
249
+ * @param mixed $content
250
+ * @return mixed
251
+ */
252
+ public function skip_shortcode( $atts, $content = '' ) {
253
+ return '<!--IUB-COOKIE-BLOCK-SKIP-START-->' . do_shortcode( $content ) . '<!--IUB-COOKIE-BLOCK-SKIP-END-->';
254
+ }
255
+
256
+ /**
257
+ * Add wp_head cookie soution content.
258
+ *
259
+ * @return mixed
260
+ */
261
+ public function wp_head_cs() {
262
+ // check content type
263
+ if ( (bool) $this->options['cs']['ctype'] == true ) {
264
+ $iub_headers = headers_list();
265
+ $destroy = true;
266
+
267
+ foreach ( $iub_headers as $header ) {
268
+ if ( strpos( $header, "Content-Type: text/html" ) !== false || strpos( $header, "Content-type: text/html" ) !== false ) {
269
+ $destroy = false;
270
+ break;
271
+ }
272
+ }
273
+
274
+ if ( $destroy )
275
+ $this->no_html = true;
276
+ }
277
+
278
+ // is post or not html content type?
279
+ if ( $_POST || $this->no_html )
280
+ return;
281
+
282
+ // initial head output
283
+ $iubenda_code = "";
284
+
285
+ if ( $this->multilang === true && defined( 'ICL_LANGUAGE_CODE' ) && isset( $this->options['cs']['code_' . ICL_LANGUAGE_CODE] ) ) {
286
+ $iubenda_code .= $this->options['cs']['code_' . ICL_LANGUAGE_CODE];
287
+
288
+ // no code for current language, use default
289
+ if ( ! $iubenda_code )
290
+ $iubenda_code .= $this->options['cs']['code_default'];
291
+ } else
292
+ $iubenda_code .= $this->options['cs']['code_default'];
293
+
294
+ $iubenda_code = $this->parse_code( $iubenda_code, true );
295
+
296
+ if ( $iubenda_code !== '' ) {
297
+ $iubenda_code .= "\n
298
+ <script>
299
+ var iCallback = function() {};
300
+ var _iub = _iub || {};
301
+
302
+ if ( typeof _iub.csConfiguration != 'undefined' ) {
303
+ if ( 'callback' in _iub.csConfiguration ) {
304
+ if ( 'onConsentGiven' in _iub.csConfiguration.callback )
305
+ iCallback = _iub.csConfiguration.callback.onConsentGiven;
306
+
307
+ _iub.csConfiguration.callback.onConsentGiven = function() {
308
+ iCallback();
309
+
310
+ /* separator */
311
+ jQuery('noscript._no_script_iub').each(function (a, b) { var el = jQuery(b); el.after(el.html()); });
312
+ }
313
+ }
314
+ }
315
+ </script>";
316
+
317
+ echo '<!--IUB-COOKIE-SKIP-START-->' . $iubenda_code . '<!--IUB-COOKIE-SKIP-END-->';
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Add wp_head consent solution content.
323
+ *
324
+ * @return mixed
325
+ */
326
+ public function wp_head_cons() {
327
+ if ( ! empty( $this->options['cons']['public_api_key'] ) ) {
328
+ echo '<!-- Library initialization -->
329
+ <script type="text/javascript">
330
+ var _iub = _iub || { };
331
+
332
+ _iub.cons_instructions = _iub.cons_instructions || [ ];
333
+ _iub.cons_instructions.push(
334
+ [ "init", {
335
+ api_key: "' . $this->options['cons']['public_api_key'] . '"
336
+ }, function ( ) {
337
+ // console.log( "init callBack" );
338
+ }
339
+ ]
340
+ );
341
+ </script>
342
+ <script type="text/javascript" src="//cdn.iubenda.com/cons/iubenda_cons.js" async></script>';
343
+ }
344
+ }
345
+
346
+ /**
347
+ * Add wp_head consent solution content.
348
+ *
349
+ * @return mixed
350
+ */
351
+ public function wp_footer_cons() {
352
+ if ( ! empty( $this->options['cons']['public_api_key'] ) ) {
353
+ echo '<script type="text/javascript">
354
+ console.log( document.getElementById( "wpcf7-f136-p87-o1" ).getElementsByClassName( "wpcf7-form" )[0] );
355
+ console.log( document.getElementById( "wpcf7-f136-p87-o1" ).getElementsByClassName( "wpcf7-submit" )[0] );
356
+
357
+ _iub.cons_instructions.push( [ "load", {
358
+ submitElement: document.getElementById( "wpcf7-f136-p87-o1" ).getElementsByClassName( "wpcf7-submit" )[0],
359
+ form: {
360
+ selector: document.getElementById( "wpcf7-f136-p87-o1" ).getElementsByClassName( "wpcf7-form" )[0],
361
+ map: {
362
+ subject: {
363
+ first_name: "your-name",
364
+ last_name: "your-name",
365
+ email: "your-email"
366
+ },
367
+ preferences: {
368
+ acceptance: "acceptance"
369
+ }
370
+ }
371
+ }
372
+ } ]
373
+ );
374
+ </script>';
375
+ }
376
+ }
377
+
378
+ /**
379
+ * Initialize html output.
380
+ *
381
+ * @return void
382
+ */
383
+ public function output_start() {
384
+ if ( ! is_admin() )
385
+ ob_start( array( $this, 'output_callback' ) );
386
+ }
387
+
388
+ /**
389
+ * Finish html output.
390
+ *
391
+ * @return void
392
+ */
393
+ public function output_end() {
394
+ if ( ! is_admin() && ob_get_level() )
395
+ ob_end_flush();
396
+ }
397
+
398
+ /**
399
+ * Handle final html output.
400
+ *
401
+ * @param mixed $output
402
+ * @return mixed
403
+ */
404
+ public function output_callback( $output ) {
405
+ // check whether to run parser or not
406
+
407
+ // bail on ajax, xmlrpc or iub_no_parse request
408
+ if (
409
+ ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST )
410
+ || ( defined( 'DOING_AJAX' ) && DOING_AJAX )
411
+ || isset( $_SERVER["HTTP_X_REQUESTED_WITH"] )
412
+ || isset( $_GET['iub_no_parse'] )
413
+ )
414
+ return $output;
415
+
416
+ // bail on admin side
417
+ if ( is_admin() )
418
+ return $output;
419
+
420
+ // bail on rss feed
421
+ if ( is_feed() && $this->options['cs']['output_feed'] )
422
+ return $output;
423
+
424
+ if ( strpos( $output, "<html" ) === false )
425
+ return $output;
426
+ elseif ( strpos( $output, "<html" ) > 200 )
427
+ return $output;
428
+
429
+ // bail if skripts blocking disabled
430
+ if ( ! $this->options['cs']['parse'] )
431
+ return $output;
432
+
433
+ // bail if consent given and skip parsing enabled
434
+ if ( iubendaParser::consent_given() && $this->options['cs']['skip_parsing'] )
435
+ return $output;
436
+
437
+ // bail if bot detectd, no html in output or it's a post request
438
+ if ( iubendaParser::bot_detected() || $_POST || $this->no_html )
439
+ return $output;
440
+
441
+ // google recaptcha v3 compatibility
442
+ if ( class_exists( 'WPCF7' ) && (int) WPCF7::get_option( 'iqfix_recaptcha' ) === 0 && ! iubendaParser::consent_given() )
443
+ $this->options['cs']['custom_scripts'][] = 'grecaptcha';
444
+
445
+ $startime = microtime( true );
446
+ $output = apply_filters( 'iubenda_initial_output', $output );
447
+
448
+ // experimental class
449
+ if ( $this->options['cs']['parser_engine'] == 'new' ) {
450
+ $iubenda = new iubendaParser( mb_convert_encoding( $output, 'HTML-ENTITIES', 'UTF-8' ), array( 'type' => 'faster', 'scripts' => $this->options['cs']['custom_scripts'], 'iframes' => $this->options['cs']['custom_iframes'] ) );
451
+
452
+ // render output
453
+ $output = $iubenda->parse();
454
+
455
+ // append signature
456
+ $output .= '<!-- Parsed with iubenda experimental class in ' . round( microtime( true ) - $startime, 4 ) . ' sec. -->';
457
+ // default class
458
+ } else {
459
+ $iubenda = new iubendaParser( $output, array( 'type' => 'page', 'scripts' => $this->options['cs']['custom_scripts'], 'iframes' => $this->options['cs']['custom_iframes'] ) );
460
+
461
+ // render output
462
+ $output = $iubenda->parse();
463
+
464
+ // append signature
465
+ $output .= '<!-- Parsed with iubenda default class in ' . round( microtime( true ) - $startime, 4 ) . ' sec. -->';
466
+ }
467
+
468
+ return apply_filters( 'iubenda_final_output', $output );
469
+ }
470
+
471
+ /**
472
+ * Parse iubenda code.
473
+ *
474
+ * @param string $source
475
+ * @param bool $display
476
+ * @return string
477
+ */
478
+ public function parse_code( $source, $display = false ) {
479
+ // return $source;
480
+ $source = trim( $source );
481
+
482
+ preg_match_all( '/(\"(?:html|content)\"(?:\s+)?\:(?:\s+)?)\"((?:.*?)(?:[^\\\\]))\"/s', $source, $matches );
483
+
484
+ // found subgroup?
485
+ if ( ! empty( $matches[1] ) && ! empty( $matches[2] ) ) {
486
+ foreach ( $matches[2] as $no => $match ) {
487
+ $source = str_replace( $matches[0][$no], $matches[1][$no] . '[[IUBENDA_TAG_START]]' . $match . '[[IUBENDA_TAG_END]]', $source );
488
+ }
489
+
490
+ // kses it
491
+ $source = wp_kses( $source, $this->get_allowed_html() );
492
+
493
+ preg_match_all( '/\[\[IUBENDA_TAG_START\]\](.*?)\[\[IUBENDA_TAG_END\]\]/s', $source, $matches_tags );
494
+
495
+ if ( ! empty( $matches_tags[1] ) ) {
496
+ foreach ( $matches_tags[1] as $no => $match ) {
497
+ $source = str_replace( $matches_tags[0][$no], '"' . ( $display ? str_replace( '</', '<\/', $matches[2][$no] ) : $matches[2][$no] ) . '"', $source );
498
+ }
499
+ }
500
+ }
501
+
502
+ return $source;
503
+ }
504
+
505
+ /**
506
+ * Get allowed iubenda script HTML.
507
+ *
508
+ * @return array
509
+ */
510
+ public function get_allowed_html() {
511
+ // Jetpack fix
512
+ remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'filter' ), 11 );
513
+
514
+ $html = array_merge(
515
+ wp_kses_allowed_html( 'post' ),
516
+ array(
517
+ 'script' => array(
518
+ 'type' => array(),
519
+ 'src' => array(),
520
+ 'charset' => array(),
521
+ 'async' => array()
522
+ ),
523
+ 'noscript' => array(),
524
+ 'style' => array(
525
+ 'type' => array()
526
+ ),
527
+ 'iframe' => array(
528
+ 'src' => array(),
529
+ 'height' => array(),
530
+ 'width' => array(),
531
+ 'frameborder' => array(),
532
+ 'allowfullscreen' => array()
533
+ )
534
+ )
535
+ );
536
+
537
+ return apply_filters( 'iub_code_allowed_html', $html );
538
+ }
539
+
540
+ }
541
+
542
+ /**
543
+ * Initialise Post Views Counter.
544
+ *
545
+ * @return object
546
+ */
547
+ function iubenda() {
548
+ static $instance;
549
+
550
+ // first call to instance() initializes the plugin
551
+ if ( $instance === null || ! ( $instance instanceof iubenda ) )
552
+ $instance = iubenda::instance();
553
+
554
+ return $instance;
555
+ }
556
+
557
+ $iubenda = iubenda();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/admin.js CHANGED
@@ -1,6 +1,11 @@
1
  ( function ( $ ) {
2
 
3
  $( document ).ready( function () {
 
 
 
 
 
4
 
5
  // read more option
6
  $( '#iub_parse' ).change( function () {
@@ -16,9 +21,7 @@
16
 
17
  $( '.iubenda-link' ).after( errors );
18
 
19
- /**
20
- * Help tabs.
21
- */
22
  $( '.contextual-help-tabs a' ).off( 'click' ).click( function ( e ) {
23
  var link = $( this ),
24
  panel,
@@ -42,7 +45,183 @@
42
  $( panelParent ).find( '.help-tab-content' ).not( panel ).removeClass( 'active' ).hide();
43
  panel.addClass( 'active' ).show();
44
  } );
 
 
 
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  } );
47
 
48
  } )( jQuery );
1
  ( function ( $ ) {
2
 
3
  $( document ).ready( function () {
4
+
5
+ // parse args
6
+ var args = $.parseJSON( iubAdminArgs );
7
+
8
+ // console.log( args );
9
 
10
  // read more option
11
  $( '#iub_parse' ).change( function () {
21
 
22
  $( '.iubenda-link' ).after( errors );
23
 
24
+ // Help tabs
 
 
25
  $( '.contextual-help-tabs a' ).off( 'click' ).click( function ( e ) {
26
  var link = $( this ),
27
  panel,
45
  $( panelParent ).find( '.help-tab-content' ).not( panel ).removeClass( 'active' ).hide();
46
  panel.addClass( 'active' ).show();
47
  } );
48
+
49
+ // Preferences fields
50
+ var preferencesID = $( '.preferences-field' ).length;
51
 
52
+ // Add new preferences field
53
+ $( document ).on( 'click', '.add-preferences-field', function ( e ) {
54
+ e.preventDefault();
55
+
56
+ $( '#postbox-container-2' ).change();
57
+
58
+ html = $( '#preferences-field-template' ).html();
59
+ html = html.replace( /__PREFERENCE_ID__/g, preferencesID++ );
60
+
61
+ $( '.preferences-table .add-preferences-field' ).closest( 'tr' ).before( '<tr class="preferences-field options-field" style="display: none;">' + html + '</tr>' );
62
+
63
+ var last = $( '.preferences-field' ).last();
64
+
65
+ last.fadeIn( 300 );
66
+ } );
67
+
68
+ // Remove preferences field
69
+ $( document ).on( 'click', '.remove-preferences-field', function ( e ) {
70
+ e.preventDefault();
71
+
72
+ $( '#postbox-container-2' ).change();
73
+
74
+ $( this ).closest( '.preferences-field' ).fadeOut( 300, function () {
75
+ $( this ).remove();
76
+ } );
77
+ } );
78
+
79
+ // Exclude fields
80
+ var excludeID = $( '.exclude-field' ).length;
81
+
82
+ // Add new preferences field
83
+ $( document ).on( 'click', '.add-exclude-field', function ( e ) {
84
+ e.preventDefault();
85
+
86
+ console.log( this );
87
+
88
+ $( '#postbox-container-2' ).change();
89
+
90
+ html = $( '#exclude-field-template' ).html();
91
+ html = html.replace( /__EXCLUDE_ID__/g, excludeID++ );
92
+
93
+ $( '.exclude-table .add-exclude-field' ).closest( 'tr' ).before( '<tr class="exclude-field options-field" style="display: none;">' + html + '</tr>' );
94
+
95
+ var last = $( '.exclude-field' ).last();
96
+
97
+ last.fadeIn( 300 );
98
+ } );
99
+
100
+ // Remove exclude field
101
+ $( document ).on( 'click', '.remove-exclude-field', function ( e ) {
102
+ e.preventDefault();
103
+
104
+ $( '#postbox-container-2' ).change();
105
+
106
+ $( this ).closest( '.exclude-field' ).fadeOut( 300, function () {
107
+ $( this ).remove();
108
+ } );
109
+ } );
110
+
111
+ // Legal notices fields
112
+ var legalNoticesID = $( '.legal_notices-field' ).length;
113
+
114
+ // Add new preferences field
115
+ $( document ).on( 'click', '.add-legal_notices-field', function ( e ) {
116
+ e.preventDefault();
117
+
118
+ $( '#postbox-container-2' ).change();
119
+
120
+ html = $( '#legal_notices-field-template' ).html();
121
+ html = html.replace( /__LEGAL_NOTICE_ID__/g, legalNoticesID++ );
122
+
123
+ console.log( html );
124
+
125
+ $( '.legal_notices-table .add-legal_notices-field' ).closest( 'tr' ).before( '<tr class="legal_notices-field options-field" style="display: none;">' + html + '</tr>' );
126
+
127
+ var last = $( '.legal_notices-field' ).last();
128
+
129
+ last.fadeIn( 300 );
130
+ } );
131
+
132
+ // Remove legal notices field
133
+ $( document ).on( 'click', '.remove-legal_notices-field', function ( e ) {
134
+ e.preventDefault();
135
+
136
+ $( '#postbox-container-2' ).change();
137
+
138
+ $( this ).closest( '.legal_notices-field' ).fadeOut( 300, function () {
139
+ $( this ).remove();
140
+ } );
141
+ } );
142
+
143
+ // Remove template fields on save
144
+ $( document ).on( 'click', '#publish', function () {
145
+ $( '#preferences-field-template' ).remove();
146
+ $( '#exclude-field-template' ).remove();
147
+ $( '#legal_notices-field-template' ).remove();
148
+ } );
149
+
150
+ // Confirm form delete
151
+ $( document ).on( 'click', '#iubenda-consent-forms .delete-form', function () {
152
+ return confirm( args.deleteForm );
153
+ } );
154
+
155
+ // Handle form fields data
156
+ $( document ).on( 'change', '#postbox-container-2', function() {
157
+ var fields = {},
158
+ fieldsTypes = [ 'subject', 'preferences', 'exclude' ];
159
+
160
+ if ( args.formId > 0 ) {
161
+ // get all fields
162
+ fields.all = $( '.subject-fields-select.select-id option:not([value=""])' ).map( function() { return $( this ).val(); } ).get();
163
+
164
+ // get specific fields
165
+ $.each( fieldsTypes, function( index, fieldType ) {
166
+ fields[fieldType] = [];
167
+
168
+ var fieldItems = $( '.' + fieldType + '-field select' );
169
+
170
+ // get selected values
171
+ $.each( fieldItems, function( index, item ) {
172
+ if ( $( item ).val() != '' )
173
+ fields[fieldType].push( $( item ).val() );
174
+ } );
175
+
176
+ fields.fieldType = $.unique( fields[fieldType] );
177
+
178
+ // remove available fields if needed
179
+ if ( fields[fieldType].length > 0 ) {
180
+
181
+ // get options count
182
+ var templateItemsCount = $( '.template-field .' + fieldType + '-fields-select option:disabled' ).length;
183
+
184
+ // update if options count changed
185
+ if ( templateItemsCount !== 0 && fields[fieldType].length != templateItemsCount ) {
186
+ // console.log( fields[fieldType] );
187
+ }
188
+
189
+ // disable add button if needed
190
+ if ( fields.all.length == fields[fieldType].length ) {
191
+ $( '.add-' + fieldType + '-field' ).attr( 'disabled', 'disabled' );
192
+ } else {
193
+ $( '.add-' + fieldType + '-field' ).attr( 'disabled', false );
194
+ }
195
+
196
+ // adjust disabled options
197
+ $.each( fields.all, function( index, fieldName ) {
198
+ if ( $.inArray( fieldName, fields[fieldType] ) < 0 ) {
199
+ // options field
200
+ $( '.' + fieldType + '-fields-select option:not(:checked)[value="' + fieldName + '"]' ).attr( 'disabled', false );
201
+ // template field
202
+ $( '.template-field .' + fieldType + '-fields-select option[value="' + fieldName + '"]' ).attr( 'disabled', false );
203
+ } else {
204
+ $( '.' + fieldType + '-fields-select option:not(:checked)[value="' + fieldName + '"]' ).attr( 'disabled', 'disabled' );
205
+ $( '.template-field .' + fieldType + '-fields-select option[value="' + fieldName + '"]' ).attr( 'disabled', 'disabled' );
206
+ }
207
+ } );
208
+ }
209
+ } );
210
+
211
+ // console.log( fields );
212
+ }
213
+
214
+ } );
215
+
216
+ // Force trigger change on document ready
217
+ $( document ).on( 'ready', function() {
218
+ $( '#postbox-container-2' ).change();
219
+ } );
220
+
221
+ $( document ).on( 'mouseenter mouseleave', '#postbox-container-2 .options-field, #postbox-container-2 .submit-field', function() {
222
+ $( '#postbox-container-2' ).change();
223
+ } );
224
+
225
  } );
226
 
227
  } )( jQuery );
js/frontend.js ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ( function ( $ ) {
2
+
3
+ $( document ).ready( function () {
4
+ // parse args
5
+ var args = $.parseJSON( iubForms );
6
+
7
+ // console.log( args );
8
+
9
+ // loop though plugins
10
+ if ( $( args ).length > 0 ) {
11
+ $.each( args, function( source, forms ) {
12
+ // loop through forms
13
+ if ( $( forms ).length > 0 ) {
14
+ $.each( forms, function( id, form ) {
15
+ // console.log( form );
16
+
17
+ var formArgs = {};
18
+
19
+ // get corresponding html form id
20
+ switch ( source ) {
21
+
22
+ // WordPress Comment Form
23
+ case 'wp_comment_form' :
24
+ var htmlFormContainer = $( '#commentform' );
25
+
26
+ // form exists, let's use it
27
+ if ( htmlFormContainer.length > 0 ) {
28
+ // adjust submit element id
29
+ var submitElement = document.getElementById( htmlFormContainer.attr( 'id' ) ).querySelectorAll('input[type=submit]')[0];
30
+
31
+ if ( typeof submitElement !== 'undefined' && submitElement.name == 'submit' ) {
32
+ submitElement.id = 'wp-comment-submit';
33
+ submitElement.name = 'wp-comment-submit';
34
+ }
35
+
36
+ // setup vars
37
+ formArgs = {
38
+ submitElement: submitElement,
39
+ form: {
40
+ selector: document.getElementById( htmlFormContainer.attr( 'id' ) ),
41
+ map: form.form.map
42
+ }
43
+ };
44
+ }
45
+
46
+ break;
47
+
48
+ // Contact Form 7
49
+ case 'wpcf7' :
50
+ // var regex = new RegExp( '^wpcf7-f([0-9]*)-' );
51
+ var htmlFormContainer = $( 'div[id^="wpcf7-f' + id + '-' );
52
+
53
+ // form exists, let's use it
54
+ if ( htmlFormContainer.length > 0 ) {
55
+ // setup vars
56
+ formArgs = {
57
+ // submitElement: document.getElementById( htmlFormContainer.attr( 'id' ) ).getElementsByClassName( 'wpcf7-submit' )[0],
58
+ submitElement: null,
59
+ form: {
60
+ selector: document.getElementById( htmlFormContainer.attr( 'id' ) ).getElementsByClassName( 'wpcf7-form' )[0],
61
+ map: form.form.map
62
+ }
63
+ };
64
+
65
+ // handle ajax submit
66
+ $( document ).on( 'wpcf7mailsent', formArgs.form.selector, function( e ) {
67
+ _iub.cons.sendData();
68
+ } );
69
+
70
+ };
71
+
72
+ break;
73
+ }
74
+
75
+ // make sure corresponding form exists push form
76
+ if ( ! $.isEmptyObject( formArgs ) ) {
77
+ // push consent vars
78
+ if ( typeof form.consent !== 'undefined' && form.consent.legal_notices.length > 0 ) {
79
+ formArgs.consent = {};
80
+ formArgs.consent.legal_notices = form.consent.legal_notices;
81
+ }
82
+
83
+ console.log( formArgs );
84
+
85
+ // build form consent data
86
+ _iub.cons_instructions.push( [ 'load', formArgs ] );
87
+ }
88
+ } );
89
+ }
90
+ } );
91
+ }
92
+ } );
93
+
94
+ } )( jQuery );
languages/iubenda-cookie-law-solution-it_IT.mo CHANGED
Binary file
languages/iubenda-cookie-law-solution-it_IT.po CHANGED
@@ -1,71 +1,241 @@
1
  msgid ""
2
  msgstr ""
3
  "Project-Id-Version: Iubenda Cookie Solution\n"
4
- "POT-Creation-Date: 2018-12-05 13:47+0100\n"
5
- "PO-Revision-Date: 2019-01-08 10:45+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.2\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
- #: iubenda_cookie_solution.php:503
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  msgid "Code"
21
  msgstr "Codice"
22
 
23
- #: iubenda_cookie_solution.php:504
24
  msgid "Scripts blocking"
25
  msgstr "Blocco preventivo dei codici"
26
 
27
- #: iubenda_cookie_solution.php:505
28
  msgid "Custom scripts"
29
  msgstr "Scripts personalizzati"
30
 
31
- #: iubenda_cookie_solution.php:506
32
  msgid "Content type"
33
  msgstr "Tipo di contenuto"
34
 
35
- #: iubenda_cookie_solution.php:507
36
  msgid "RSS feed"
37
  msgstr "Feed RSS"
38
 
39
- #: iubenda_cookie_solution.php:508
40
  msgid "Menu position"
41
  msgstr "Posizione menu"
42
 
43
- #: iubenda_cookie_solution.php:509
44
  msgid "Deactivation"
45
  msgstr "Disattivazione"
46
 
47
- #: iubenda_cookie_solution.php:559
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  #, php-format
49
  msgid "Enter the iubenda code for %s."
50
  msgstr "Inserire il codice di iubenda per %s."
51
 
52
- #: iubenda_cookie_solution.php:570
53
  msgid "Enter the iubenda code."
54
  msgstr "Inserire il codice di iubenda."
55
 
56
- #: iubenda_cookie_solution.php:598
57
  msgid "Enter a list of custom scripts (one per line)."
58
  msgstr "Inserire una lista di script personalizzati (uno per riga)."
59
 
60
- #: iubenda_cookie_solution.php:602
61
  msgid "Enter a list of custom iframes (one per line)."
62
  msgstr "Inserire un elenco di iframe personalizzati (uno per riga)."
63
 
64
- #: iubenda_cookie_solution.php:617
65
  msgid "Automatically block scripts detected by the plugin."
66
  msgstr "Blocca automaticamente gli script rilevati dal plugin."
67
 
68
- #: iubenda_cookie_solution.php:618
69
  #, php-format
70
  msgid ""
71
  "see <a href=\"%s\" target=\"_blank\">our documentation</a> for the list of "
@@ -74,26 +244,26 @@ msgstr ""
74
  "visita <a href=\"%s\" target=\"_blank\">la nostra documentazione</a> per la "
75
  "lista degli script rilevati automaticamente dal plugin."
76
 
77
- #: iubenda_cookie_solution.php:621
78
  msgid "Primary"
79
  msgstr "Prima"
80
 
81
- #: iubenda_cookie_solution.php:622
82
  msgid "Secondary"
83
  msgstr "Seconda"
84
 
85
- #: iubenda_cookie_solution.php:623
86
  msgid "Select parsing engine."
87
  msgstr "Seleziona il motore di parsing."
88
 
89
- #: iubenda_cookie_solution.php:626
90
  msgid ""
91
  "Leave scripts untouched on the page if the user has already given consent"
92
  msgstr ""
93
  "Lascia gli script intatti sulla pagina se l'utente ha già prestato il "
94
  "consenso"
95
 
96
- #: iubenda_cookie_solution.php:627
97
  msgid ""
98
  "improves performance, highly recommended, to be deactivated only if your "
99
  "site uses a caching system"
@@ -101,7 +271,7 @@ msgstr ""
101
  "migliora le prestazioni, altamente consigliato, da disattivare solo qualora "
102
  "il tuo sito utilizzi un sistema di cache"
103
 
104
- #: iubenda_cookie_solution.php:641
105
  msgid ""
106
  "Restrict the plugin to run only for requests that have \"Content-type: "
107
  "text / html\" (recommended)"
@@ -109,19 +279,19 @@ msgstr ""
109
  "Restringi l'esecuzione del plugin alle sole richieste che presentano "
110
  "\"Content-type: text/html\" (consigliato)"
111
 
112
- #: iubenda_cookie_solution.php:653
113
  msgid "Do not run the plugin inside the RSS feed (recommended)"
114
  msgstr "Non eseguire il plugin all'interno dei Feed RSS (consigliato)"
115
 
116
- #: iubenda_cookie_solution.php:665
117
  msgid "Top menu"
118
  msgstr "Menu principale"
119
 
120
- #: iubenda_cookie_solution.php:666
121
  msgid "Submenu"
122
  msgstr "Sottomenu"
123
 
124
- #: iubenda_cookie_solution.php:667
125
  msgid ""
126
  "Select whether to display iubenda in a top admin menu or the Settings "
127
  "submenu."
@@ -129,116 +299,235 @@ msgstr ""
129
  "Scegli se visualizzare iubenda in una voce di menu principale del pannello "
130
  "admin o in un sottomenu della scheda Impostazioni."
131
 
132
- #: iubenda_cookie_solution.php:679
133
  msgid "Delete all plugin data upon deactivation?"
134
  msgstr ""
135
  "Vuoi eliminare tutti i dati del plugin al momento della disattivazione?"
136
 
137
- #: iubenda_cookie_solution.php:738
138
- msgid "Settings saved."
139
- msgstr "Impostazioni salvate."
140
 
141
- #: iubenda_cookie_solution.php:749
142
- msgid "Settings restored to defaults."
143
- msgstr "Impostazioni di default ripristinate."
 
144
 
145
- #: iubenda_cookie_solution.php:795
146
- msgid "You don't have permission to access this page."
147
- msgstr "Non disponi dell'autorizzazione per accedere a questa pagina."
 
148
 
149
- #: iubenda_cookie_solution.php:804
150
- msgid ""
151
- "This plugin is the easiest and most comprehensive way to adapt your "
152
- "WordPress site to the European cookie law. Upon your user's first visit, the "
153
- "plugin will take care of collecting their consent, of blocking the most "
154
- "popular among the scripts that install cookies and subsequently reactivate "
155
- "these scripts as soon as consent is provided. The basic settings include "
156
- "obtaining consent by a simple scroll action (the most effective method) and "
157
- "script reactivation without refreshing the page."
158
  msgstr ""
159
- "Questo plugin è il modo più semplice e completo per adeguare il tuo sito "
160
- "WordPress alla cookie law. Alla prima visita dell'utente il plugin si "
161
- "occuperà di raccoglierne il consenso, di bloccare i più popolari fra gli "
162
- "script che installano cookie e di riattivarli non appena il consenso viene "
163
- "fornito. Le impostazioni di base includono la raccolta del consenso tramite "
164
- "il semplice scroll (il metodo più efficace) e la riattivazione senza il "
165
- "refresh della pagina."
166
 
167
- #: iubenda_cookie_solution.php:807
168
- msgid "Would you like to know more about the cookie law?"
169
- msgstr "Vuoi capire di più sulla cookie law?"
170
 
171
- #: iubenda_cookie_solution.php:808
172
- #, php-format
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  msgid ""
174
- "Read our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">complete "
175
- "guide to the cookie law.</a>"
 
176
  msgstr ""
177
- "Consulta la nostra <a href=\"%s\" class=\"iubenda-url\" target=\"_blank"
178
- "\">guida completa alla cookie law</a>"
179
 
180
- #: iubenda_cookie_solution.php:811
181
- msgid "What is the full functionality of the plugin?"
182
- msgstr "Qual è la completa funzionalità del plugin?"
183
 
184
- #: iubenda_cookie_solution.php:812
185
- #, php-format
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  msgid ""
187
- "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">plugin page."
188
- "</a>"
 
189
  msgstr ""
190
- "Visita la <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">nostra "
191
- "pagina dedicata</a> al plugin"
192
 
193
- #: iubenda_cookie_solution.php:815
194
- msgid "Enter the iubenda code for the Cookie Solution below."
195
- msgstr "Inserisci qui sotto il codice di iubenda per la Cookie Solution."
196
 
197
- #: iubenda_cookie_solution.php:816
198
- #, php-format
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  msgid ""
200
- "In order to run the plugin, you need to enter the iubenda code that "
201
- "activates the cookie law banner and the cookie policy in the form below. "
202
- "This code can be generated on www.iubenda.com, following <a href=\"%s\" "
203
- "class=\"iubenda-url\" target=\"_blank\">this guide.</a>"
204
  msgstr ""
205
- "Per far funzionare il plugin, è necessario inserire nel form sottostante il "
206
- "codice di iubenda che attiva il banner cookie law e la cookie policy. Questo "
207
- "codice può essere generato su www.iubenda.com, <a href=\"%s\" class="
208
- "\"iubenda-url\" target=\"_blank\">seguendo questa guida.</a>"
209
 
210
- #: iubenda_cookie_solution.php:827
211
- msgid "Reset to defaults"
212
- msgstr "Ripristina le impostazioni di default"
213
 
214
- #: iubenda_cookie_solution.php:833
215
- msgid "Need support for this plugin?"
216
- msgstr "Hai bisogno di supporto su questo plugin?"
217
 
218
- #: iubenda_cookie_solution.php:834
219
- #, php-format
 
 
 
 
 
 
 
220
  msgid ""
221
- "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">support "
222
- "forum.</a>"
223
  msgstr ""
224
- "Visita il nostro <a href=\"%s\" class=\"iubenda-url\" target=\"_blank"
225
- "\">forum di supporto</a>"
226
 
227
- #: iubenda_cookie_solution.php:837
228
- msgid "Want to try a beta version of this plugin with the latest features?"
229
  msgstr ""
230
- "Vuoi provare una versione Beta di questo plugin, con le funzionalità più "
231
- "recenti?"
232
 
233
- #: iubenda_cookie_solution.php:838
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  #, php-format
235
  msgid ""
236
- "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank"
237
- "\">documentation pages</a> and follow the instructions to install a beta "
238
- "version."
239
  msgstr ""
240
- "Visita la <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">nostra "
241
- "documentazione</a> e segui le istruzioni per installare una versione Beta."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
  #~ msgid "Default"
244
  #~ msgstr "Default"
@@ -249,9 +538,6 @@ msgstr ""
249
  #~ msgid "What’s the full functionality of the plugin?"
250
  #~ msgstr "Quali sono le funzionalità complete del plugin?"
251
 
252
- #~ msgid "Settings applied successfully"
253
- #~ msgstr "Impostazioni salvate con successo"
254
-
255
  #~ msgid "Select a language to correctly pair it with your script"
256
  #~ msgstr "Seleziona una lingua a cui associare il tuo codice"
257
 
@@ -286,9 +572,6 @@ msgstr ""
286
  #~ "attiva questa opzione solo qualora avessi problemi di performance o "
287
  #~ "notassi che il blocco dei codici viene applicato più volte"
288
 
289
- #~ msgid "Save"
290
- #~ msgstr "Salva"
291
-
292
  #~ msgid "Parsed with iubenda experimental class in %s sec."
293
  #~ msgstr "Parsed with iubenda experimental class in %s sec."
294
 
1
  msgid ""
2
  msgstr ""
3
  "Project-Id-Version: Iubenda Cookie Solution\n"
4
+ "POT-Creation-Date: 2019-07-31 10:35+0200\n"
5
+ "PO-Revision-Date: 2019-07-31 10:35+0200\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.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/forms-list-table.php:92
20
+ msgid "Form Title"
21
+ msgstr ""
22
+
23
+ #: includes/forms-list-table.php:93
24
+ msgid "Form ID"
25
+ msgstr ""
26
+
27
+ #: includes/forms-list-table.php:94
28
+ msgid "Form Source"
29
+ msgstr ""
30
+
31
+ #: includes/forms-list-table.php:95
32
+ msgid "Fields"
33
+ msgstr ""
34
+
35
+ #: includes/forms-list-table.php:96
36
+ msgid "Date"
37
+ msgstr ""
38
+
39
+ #: includes/forms-list-table.php:165
40
+ msgid "Edit"
41
+ msgstr ""
42
+
43
+ #: includes/forms-list-table.php:166
44
+ msgid "Delete"
45
+ msgstr ""
46
+
47
+ #: includes/forms-list-table.php:277
48
+ msgid "Filter"
49
+ msgstr ""
50
+
51
+ #: includes/forms-list-table.php:294
52
+ msgid "Filter by source"
53
+ msgstr ""
54
+
55
+ #: includes/forms-list-table.php:296
56
+ msgid "All form sources"
57
+ msgstr ""
58
+
59
+ #: includes/forms-list-table.php:364
60
+ msgid "No forms found."
61
+ msgstr ""
62
+
63
+ #: includes/forms.php:123 includes/settings.php:123
64
+ msgid "Forms"
65
+ msgstr ""
66
+
67
+ #: includes/forms.php:124
68
+ msgid "Form"
69
+ msgstr ""
70
+
71
+ #: includes/settings.php:41 includes/settings.php:42 includes/settings.php:43
72
+ #: includes/settings.php:44 includes/settings.php:45
73
+ msgid "string"
74
+ msgstr ""
75
+
76
+ #: includes/settings.php:57 includes/settings.php:168
77
+ msgid "Cookie Solution"
78
+ msgstr ""
79
+
80
+ #: includes/settings.php:63 includes/settings.php:169
81
+ msgid "Consent Solution"
82
+ msgstr ""
83
+
84
+ #: includes/settings.php:112
85
  msgid "Code"
86
  msgstr "Codice"
87
 
88
+ #: includes/settings.php:113
89
  msgid "Scripts blocking"
90
  msgstr "Blocco preventivo dei codici"
91
 
92
+ #: includes/settings.php:114
93
  msgid "Custom scripts"
94
  msgstr "Scripts personalizzati"
95
 
96
+ #: includes/settings.php:115
97
  msgid "Content type"
98
  msgstr "Tipo di contenuto"
99
 
100
+ #: includes/settings.php:116
101
  msgid "RSS feed"
102
  msgstr "Feed RSS"
103
 
104
+ #: includes/settings.php:117
105
  msgid "Menu position"
106
  msgstr "Posizione menu"
107
 
108
+ #: includes/settings.php:118
109
  msgid "Deactivation"
110
  msgstr "Disattivazione"
111
 
112
+ #: includes/settings.php:124
113
+ msgid "Public Api Key"
114
+ msgstr ""
115
+
116
+ #: includes/settings.php:127 includes/settings.php:131
117
+ msgid "Fields Mapping"
118
+ msgstr ""
119
+
120
+ #: includes/settings.php:189
121
+ msgid "Are you sure you want to delete this form?"
122
+ msgstr ""
123
+
124
+ #: includes/settings.php:337
125
+ msgid "You don't have permission to access this page."
126
+ msgstr "Non disponi dell'autorizzazione per accedere a questa pagina."
127
+
128
+ #: includes/settings.php:354
129
+ msgid ""
130
+ "This plugin is the easiest and most comprehensive way to adapt your "
131
+ "WordPress site to the European cookie law. Upon your user's first visit, the "
132
+ "plugin will take care of collecting their consent, of blocking the most "
133
+ "popular among the scripts that install cookies and subsequently reactivate "
134
+ "these scripts as soon as consent is provided. The basic settings include "
135
+ "obtaining consent by a simple scroll action (the most effective method) and "
136
+ "script reactivation without refreshing the page."
137
+ msgstr ""
138
+ "Questo plugin è il modo più semplice e completo per adeguare il tuo sito "
139
+ "WordPress alla cookie law. Alla prima visita dell'utente il plugin si "
140
+ "occuperà di raccoglierne il consenso, di bloccare i più popolari fra gli "
141
+ "script che installano cookie e di riattivarli non appena il consenso viene "
142
+ "fornito. Le impostazioni di base includono la raccolta del consenso tramite "
143
+ "il semplice scroll (il metodo più efficace) e la riattivazione senza il "
144
+ "refresh della pagina."
145
+
146
+ #: includes/settings.php:357
147
+ msgid "Would you like to know more about the cookie law?"
148
+ msgstr "Vuoi capire di più sulla cookie law?"
149
+
150
+ #: includes/settings.php:358
151
+ #, php-format
152
+ msgid ""
153
+ "Read our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">complete "
154
+ "guide to the cookie law.</a>"
155
+ msgstr ""
156
+ "Consulta la nostra <a href=\"%s\" class=\"iubenda-url\" target=\"_blank"
157
+ "\">guida completa alla cookie law</a>"
158
+
159
+ #: includes/settings.php:361
160
+ msgid "What is the full functionality of the plugin?"
161
+ msgstr "Qual è la completa funzionalità del plugin?"
162
+
163
+ #: includes/settings.php:362
164
+ #, php-format
165
+ msgid ""
166
+ "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">plugin page."
167
+ "</a>"
168
+ msgstr ""
169
+ "Visita la <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">nostra "
170
+ "pagina dedicata</a> al plugin"
171
+
172
+ #: includes/settings.php:365
173
+ msgid "Enter the iubenda code for the Cookie Solution below."
174
+ msgstr "Inserisci qui sotto il codice di iubenda per la Cookie Solution."
175
+
176
+ #: includes/settings.php:366
177
+ #, php-format
178
+ msgid ""
179
+ "In order to run the plugin, you need to enter the iubenda code that "
180
+ "activates the cookie law banner and the cookie policy in the form below. "
181
+ "This code can be generated on www.iubenda.com, following <a href=\"%s\" "
182
+ "class=\"iubenda-url\" target=\"_blank\">this guide.</a>"
183
+ msgstr ""
184
+ "Per far funzionare il plugin, è necessario inserire nel form sottostante il "
185
+ "codice di iubenda che attiva il banner cookie law e la cookie policy. Questo "
186
+ "codice può essere generato su www.iubenda.com, <a href=\"%s\" class="
187
+ "\"iubenda-url\" target=\"_blank\">seguendo questa guida.</a>"
188
+
189
+ #: includes/settings.php:371
190
+ msgid ""
191
+ "Maintaining comprehensive records of consent are a vital part of privacy "
192
+ "compliance in general but are specifically required under the GDPR. These "
193
+ "records should include a way of identifying the user, proof of consent, "
194
+ "record of the consenting action and the legal documents available to the "
195
+ "user at the time of consent, among other things. You can read about the <a "
196
+ "href=\"https://www.iubenda.com/en/help/5428-gdpr-guide#records-of-consent\" "
197
+ "target=\"_blank\">full requirements here</a>."
198
+ msgstr ""
199
+
200
+ #: includes/settings.php:404
201
+ msgid "Reset to defaults"
202
+ msgstr "Ripristina le impostazioni di default"
203
+
204
+ #: includes/settings.php:414
205
+ msgid "Need support for this plugin?"
206
+ msgstr "Hai bisogno di supporto su questo plugin?"
207
+
208
+ #: includes/settings.php:415
209
+ #, php-format
210
+ msgid ""
211
+ "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">support "
212
+ "forum.</a>"
213
+ msgstr ""
214
+ "Visita il nostro <a href=\"%s\" class=\"iubenda-url\" target=\"_blank"
215
+ "\">forum di supporto</a>"
216
+
217
+ #: includes/settings.php:459
218
  #, php-format
219
  msgid "Enter the iubenda code for %s."
220
  msgstr "Inserire il codice di iubenda per %s."
221
 
222
+ #: includes/settings.php:470
223
  msgid "Enter the iubenda code."
224
  msgstr "Inserire il codice di iubenda."
225
 
226
+ #: includes/settings.php:498
227
  msgid "Enter a list of custom scripts (one per line)."
228
  msgstr "Inserire una lista di script personalizzati (uno per riga)."
229
 
230
+ #: includes/settings.php:502
231
  msgid "Enter a list of custom iframes (one per line)."
232
  msgstr "Inserire un elenco di iframe personalizzati (uno per riga)."
233
 
234
+ #: includes/settings.php:517
235
  msgid "Automatically block scripts detected by the plugin."
236
  msgstr "Blocca automaticamente gli script rilevati dal plugin."
237
 
238
+ #: includes/settings.php:518
239
  #, php-format
240
  msgid ""
241
  "see <a href=\"%s\" target=\"_blank\">our documentation</a> for the list of "
244
  "visita <a href=\"%s\" target=\"_blank\">la nostra documentazione</a> per la "
245
  "lista degli script rilevati automaticamente dal plugin."
246
 
247
+ #: includes/settings.php:521
248
  msgid "Primary"
249
  msgstr "Prima"
250
 
251
+ #: includes/settings.php:522
252
  msgid "Secondary"
253
  msgstr "Seconda"
254
 
255
+ #: includes/settings.php:523
256
  msgid "Select parsing engine."
257
  msgstr "Seleziona il motore di parsing."
258
 
259
+ #: includes/settings.php:526
260
  msgid ""
261
  "Leave scripts untouched on the page if the user has already given consent"
262
  msgstr ""
263
  "Lascia gli script intatti sulla pagina se l'utente ha già prestato il "
264
  "consenso"
265
 
266
+ #: includes/settings.php:527
267
  msgid ""
268
  "improves performance, highly recommended, to be deactivated only if your "
269
  "site uses a caching system"
271
  "migliora le prestazioni, altamente consigliato, da disattivare solo qualora "
272
  "il tuo sito utilizzi un sistema di cache"
273
 
274
+ #: includes/settings.php:541
275
  msgid ""
276
  "Restrict the plugin to run only for requests that have \"Content-type: "
277
  "text / html\" (recommended)"
279
  "Restringi l'esecuzione del plugin alle sole richieste che presentano "
280
  "\"Content-type: text/html\" (consigliato)"
281
 
282
+ #: includes/settings.php:553
283
  msgid "Do not run the plugin inside the RSS feed (recommended)"
284
  msgstr "Non eseguire il plugin all'interno dei Feed RSS (consigliato)"
285
 
286
+ #: includes/settings.php:565
287
  msgid "Top menu"
288
  msgstr "Menu principale"
289
 
290
+ #: includes/settings.php:566
291
  msgid "Submenu"
292
  msgstr "Sottomenu"
293
 
294
+ #: includes/settings.php:567
295
  msgid ""
296
  "Select whether to display iubenda in a top admin menu or the Settings "
297
  "submenu."
299
  "Scegli se visualizzare iubenda in una voce di menu principale del pannello "
300
  "admin o in un sottomenu della scheda Impostazioni."
301
 
302
+ #: includes/settings.php:579
303
  msgid "Delete all plugin data upon deactivation?"
304
  msgstr ""
305
  "Vuoi eliminare tutti i dati del plugin al momento della disattivazione?"
306
 
307
+ #: includes/settings.php:592
308
+ msgid "Enter your iubenda Javascript library public API key."
309
+ msgstr ""
310
 
311
+ #: includes/settings.php:608
312
+ #, php-format
313
+ msgid "A list forms of available for field mapping. Currently supports: %s"
314
+ msgstr ""
315
 
316
+ #: includes/settings.php:656
317
+ #, php-format
318
+ msgid "%s form title."
319
+ msgstr ""
320
 
321
+ #: includes/settings.php:656
322
+ msgid "Unknown"
 
 
 
 
 
 
 
323
  msgstr ""
 
 
 
 
 
 
 
324
 
325
+ #: includes/settings.php:658
326
+ msgid "Available form fields:"
327
+ msgstr ""
328
 
329
+ #: includes/settings.php:664
330
+ msgid "Publish"
331
+ msgstr ""
332
+
333
+ #: includes/settings.php:669
334
+ msgid "Status"
335
+ msgstr ""
336
+
337
+ #: includes/settings.php:682
338
+ msgid "Cancel"
339
+ msgstr ""
340
+
341
+ #: includes/settings.php:687
342
+ msgid "Save"
343
+ msgstr "Salva"
344
+
345
+ #: includes/settings.php:700
346
+ msgid "Map fields"
347
+ msgstr ""
348
+
349
+ #: includes/settings.php:706
350
+ msgid "Subject fields"
351
+ msgstr ""
352
+
353
+ #: includes/settings.php:707
354
  msgid ""
355
+ "Subject fields allows you to store a series of values saved about your "
356
+ "subjects/users. Please map the subject/user data with the corresponding form "
357
+ "fields."
358
  msgstr ""
 
 
359
 
360
+ #: includes/settings.php:712
361
+ msgid "Subject field"
362
+ msgstr ""
363
 
364
+ #: includes/settings.php:713 includes/settings.php:752
365
+ msgid "Form field"
366
+ msgstr ""
367
+
368
+ #: includes/settings.php:719
369
+ msgid "Autogenerated"
370
+ msgstr ""
371
+
372
+ #: includes/settings.php:719
373
+ msgid "None"
374
+ msgstr ""
375
+
376
+ #: includes/settings.php:745
377
+ msgid "Preferences fields"
378
+ msgstr ""
379
+
380
+ #: includes/settings.php:746
381
  msgid ""
382
+ "Preferences fields allows you to save the various opt-ins the user has "
383
+ "agreed to, such as terms and conditions, newsletter, profiling, etc. Please "
384
+ "create at least one preferences field."
385
  msgstr ""
 
 
386
 
387
+ #: includes/settings.php:751
388
+ msgid "Preferences field"
389
+ msgstr ""
390
 
391
+ #: includes/settings.php:757 includes/settings.php:779
392
+ #: includes/settings.php:890 includes/settings.php:900
393
+ #: includes/settings.php:916
394
+ msgid "Enter field name"
395
+ msgstr ""
396
+
397
+ #: includes/settings.php:767 includes/settings.php:789
398
+ #: includes/settings.php:826 includes/settings.php:849
399
+ #: includes/settings.php:900 includes/settings.php:916
400
+ msgid "Remove"
401
+ msgstr ""
402
+
403
+ #: includes/settings.php:798
404
+ msgid "Add New Preference"
405
+ msgstr ""
406
+
407
+ #: includes/settings.php:805
408
+ msgid "Exclude fields"
409
+ msgstr ""
410
+
411
+ #: includes/settings.php:806
412
  msgid ""
413
+ "Exclude fields allows you to create a list of field names that you would "
414
+ "like to exclude from proofs (for e.g. password or other fields not related "
415
+ "to the consent)."
 
416
  msgstr ""
 
 
 
 
417
 
418
+ #: includes/settings.php:811
419
+ msgid "Exclude field"
420
+ msgstr ""
421
 
422
+ #: includes/settings.php:859
423
+ msgid "Add New Exclude"
424
+ msgstr ""
425
 
426
+ #: includes/settings.php:869
427
+ msgid "Legal Notices"
428
+ msgstr ""
429
+
430
+ #: includes/settings.php:875
431
+ msgid "Legal documents"
432
+ msgstr ""
433
+
434
+ #: includes/settings.php:876
435
  msgid ""
436
+ "If you use iubenda for your legal documents it is required for you to "
437
+ "declare which of them are being agreed upon on each consent creation."
438
  msgstr ""
 
 
439
 
440
+ #: includes/settings.php:881
441
+ msgid "Identifier"
442
  msgstr ""
 
 
443
 
444
+ #: includes/settings.php:890
445
+ msgid "Please check the legal notices you are using."
446
+ msgstr ""
447
+
448
+ #: includes/settings.php:906
449
+ msgid "Optionally add your custom document identifiers."
450
+ msgstr ""
451
+
452
+ #: includes/settings.php:925
453
+ msgid "Add New Document"
454
+ msgstr ""
455
+
456
+ #: includes/settings.php:998 includes/settings.php:1030
457
+ msgid "Settings saved."
458
+ msgstr "Impostazioni salvate."
459
+
460
+ #: includes/settings.php:1010 includes/settings.php:1035
461
+ msgid "Settings restored to defaults."
462
+ msgstr "Impostazioni di default ripristinate."
463
+
464
+ #: includes/settings.php:1059
465
  #, php-format
466
  msgid ""
467
+ "Please enable comments cookies opt-in checkbox in the <a href=\"%s\" target="
468
+ "\"_blank\">Discussion settings</a>."
 
469
  msgstr ""
470
+
471
+ #: includes/settings.php:1079
472
+ msgid "No forms or form changes detected."
473
+ msgstr ""
474
+
475
+ #: includes/settings.php:1147
476
+ msgid "Form saving failed. Please fill the Subject and Preferences fields."
477
+ msgstr ""
478
+
479
+ #: includes/settings.php:1171
480
+ #, fuzzy
481
+ #| msgid "Settings applied successfully"
482
+ msgid "Form saved successfully - form status changed to Mapped."
483
+ msgstr "Impostazioni salvate con successo"
484
+
485
+ #: includes/settings.php:1174
486
+ #, fuzzy
487
+ #| msgid "Settings applied successfully"
488
+ msgid "Form updated successfully."
489
+ msgstr "Impostazioni salvate con successo"
490
+
491
+ #: includes/settings.php:1177
492
+ msgid "Form saving failed."
493
+ msgstr ""
494
+
495
+ #: includes/settings.php:1194
496
+ #, fuzzy
497
+ #| msgid "Settings applied successfully"
498
+ msgid "Form deleted successfully."
499
+ msgstr "Impostazioni salvate con successo"
500
+
501
+ #: includes/settings.php:1196
502
+ msgid "Form delete failed."
503
+ msgstr ""
504
+
505
+ #: includes/settings.php:1256
506
+ msgid "Dismiss this notice."
507
+ msgstr ""
508
+
509
+ #, fuzzy
510
+ #~| msgid "Settings applied successfully"
511
+ #~ msgid "Forms detected successfully."
512
+ #~ msgstr "Impostazioni salvate con successo"
513
+
514
+ #, fuzzy
515
+ #~| msgid "Content type"
516
+ #~ msgid "Contents"
517
+ #~ msgstr "Tipo di contenuto"
518
+
519
+ #~ msgid "Want to try a beta version of this plugin with the latest features?"
520
+ #~ msgstr ""
521
+ #~ "Vuoi provare una versione Beta di questo plugin, con le funzionalità più "
522
+ #~ "recenti?"
523
+
524
+ #~ msgid ""
525
+ #~ "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank"
526
+ #~ "\">documentation pages</a> and follow the instructions to install a beta "
527
+ #~ "version."
528
+ #~ msgstr ""
529
+ #~ "Visita la <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">nostra "
530
+ #~ "documentazione</a> e segui le istruzioni per installare una versione Beta."
531
 
532
  #~ msgid "Default"
533
  #~ msgstr "Default"
538
  #~ msgid "What’s the full functionality of the plugin?"
539
  #~ msgstr "Quali sono le funzionalità complete del plugin?"
540
 
 
 
 
541
  #~ msgid "Select a language to correctly pair it with your script"
542
  #~ msgstr "Seleziona una lingua a cui associare il tuo codice"
543
 
572
  #~ "attiva questa opzione solo qualora avessi problemi di performance o "
573
  #~ "notassi che il blocco dei codici viene applicato più volte"
574
 
 
 
 
575
  #~ msgid "Parsed with iubenda experimental class in %s sec."
576
  #~ msgstr "Parsed with iubenda experimental class in %s sec."
577
 
languages/iubenda-cookie-law-solution.pot CHANGED
@@ -2,208 +2,472 @@
2
  msgid ""
3
  msgstr ""
4
  "Project-Id-Version: Iubenda Cookie Solution\n"
5
- "POT-Creation-Date: 2018-12-05 13:47+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.2\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
- #: iubenda_cookie_solution.php:503
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  msgid "Code"
21
  msgstr ""
22
 
23
- #: iubenda_cookie_solution.php:504
24
  msgid "Scripts blocking"
25
  msgstr ""
26
 
27
- #: iubenda_cookie_solution.php:505
28
  msgid "Custom scripts"
29
  msgstr ""
30
 
31
- #: iubenda_cookie_solution.php:506
32
  msgid "Content type"
33
  msgstr ""
34
 
35
- #: iubenda_cookie_solution.php:507
36
  msgid "RSS feed"
37
  msgstr ""
38
 
39
- #: iubenda_cookie_solution.php:508
40
  msgid "Menu position"
41
  msgstr ""
42
 
43
- #: iubenda_cookie_solution.php:509
44
  msgid "Deactivation"
45
  msgstr ""
46
 
47
- #: iubenda_cookie_solution.php:559
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  #, php-format
49
  msgid "Enter the iubenda code for %s."
50
  msgstr ""
51
 
52
- #: iubenda_cookie_solution.php:570
53
  msgid "Enter the iubenda code."
54
  msgstr ""
55
 
56
- #: iubenda_cookie_solution.php:598
57
  msgid "Enter a list of custom scripts (one per line)."
58
  msgstr ""
59
 
60
- #: iubenda_cookie_solution.php:602
61
  msgid "Enter a list of custom iframes (one per line)."
62
  msgstr ""
63
 
64
- #: iubenda_cookie_solution.php:617
65
  msgid "Automatically block scripts detected by the plugin."
66
  msgstr ""
67
 
68
- #: iubenda_cookie_solution.php:618
69
  #, php-format
70
  msgid ""
71
  "see <a href=\"%s\" target=\"_blank\">our documentation</a> for the list of "
72
  "detected scripts."
73
  msgstr ""
74
 
75
- #: iubenda_cookie_solution.php:621
76
  msgid "Primary"
77
  msgstr ""
78
 
79
- #: iubenda_cookie_solution.php:622
80
  msgid "Secondary"
81
  msgstr ""
82
 
83
- #: iubenda_cookie_solution.php:623
84
  msgid "Select parsing engine."
85
  msgstr ""
86
 
87
- #: iubenda_cookie_solution.php:626
88
  msgid ""
89
  "Leave scripts untouched on the page if the user has already given consent"
90
  msgstr ""
91
 
92
- #: iubenda_cookie_solution.php:627
93
  msgid ""
94
  "improves performance, highly recommended, to be deactivated only if your "
95
  "site uses a caching system"
96
  msgstr ""
97
 
98
- #: iubenda_cookie_solution.php:641
99
  msgid ""
100
  "Restrict the plugin to run only for requests that have \"Content-type: "
101
  "text / html\" (recommended)"
102
  msgstr ""
103
 
104
- #: iubenda_cookie_solution.php:653
105
  msgid "Do not run the plugin inside the RSS feed (recommended)"
106
  msgstr ""
107
 
108
- #: iubenda_cookie_solution.php:665
109
  msgid "Top menu"
110
  msgstr ""
111
 
112
- #: iubenda_cookie_solution.php:666
113
  msgid "Submenu"
114
  msgstr ""
115
 
116
- #: iubenda_cookie_solution.php:667
117
  msgid ""
118
  "Select whether to display iubenda in a top admin menu or the Settings "
119
  "submenu."
120
  msgstr ""
121
 
122
- #: iubenda_cookie_solution.php:679
123
  msgid "Delete all plugin data upon deactivation?"
124
  msgstr ""
125
 
126
- #: iubenda_cookie_solution.php:738
127
- msgid "Settings saved."
128
  msgstr ""
129
 
130
- #: iubenda_cookie_solution.php:749
131
- msgid "Settings restored to defaults."
 
132
  msgstr ""
133
 
134
- #: iubenda_cookie_solution.php:795
135
- msgid "You don't have permission to access this page."
 
136
  msgstr ""
137
 
138
- #: iubenda_cookie_solution.php:804
139
- msgid ""
140
- "This plugin is the easiest and most comprehensive way to adapt your "
141
- "WordPress site to the European cookie law. Upon your user's first visit, "
142
- "the plugin will take care of collecting their consent, of blocking the most "
143
- "popular among the scripts that install cookies and subsequently reactivate "
144
- "these scripts as soon as consent is provided. The basic settings include "
145
- "obtaining consent by a simple scroll action (the most effective method) and "
146
- "script reactivation without refreshing the page."
147
  msgstr ""
148
 
149
- #: iubenda_cookie_solution.php:807
150
- msgid "Would you like to know more about the cookie law?"
151
  msgstr ""
152
 
153
- #: iubenda_cookie_solution.php:808
154
- #, php-format
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  msgid ""
156
- "Read our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">complete "
157
- "guide to the cookie law.</a>"
 
158
  msgstr ""
159
 
160
- #: iubenda_cookie_solution.php:811
161
- msgid "What is the full functionality of the plugin?"
162
  msgstr ""
163
 
164
- #: iubenda_cookie_solution.php:812
165
- #, php-format
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  msgid ""
167
- "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">plugin "
168
- "page.</a>"
 
169
  msgstr ""
170
 
171
- #: iubenda_cookie_solution.php:815
172
- msgid "Enter the iubenda code for the Cookie Solution below."
173
  msgstr ""
174
 
175
- #: iubenda_cookie_solution.php:816
176
- #, php-format
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  msgid ""
178
- "In order to run the plugin, you need to enter the iubenda code that "
179
- "activates the cookie law banner and the cookie policy in the form below. "
180
- "This code can be generated on www.iubenda.com, following <a href=\"%s\" "
181
- "class=\"iubenda-url\" target=\"_blank\">this guide.</a>"
182
  msgstr ""
183
 
184
- #: iubenda_cookie_solution.php:827
185
- msgid "Reset to defaults"
186
  msgstr ""
187
 
188
- #: iubenda_cookie_solution.php:833
189
- msgid "Need support for this plugin?"
190
  msgstr ""
191
 
192
- #: iubenda_cookie_solution.php:834
193
- #, php-format
 
 
 
 
 
 
 
194
  msgid ""
195
- "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">support "
196
- "forum.</a>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  msgstr ""
198
 
199
- #: iubenda_cookie_solution.php:837
200
- msgid "Want to try a beta version of this plugin with the latest features?"
201
  msgstr ""
202
 
203
- #: iubenda_cookie_solution.php:838
204
  #, php-format
205
  msgid ""
206
- "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank"
207
- "\">documentation pages</a> and follow the instructions to install a beta "
208
- "version."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  msgstr ""
2
  msgid ""
3
  msgstr ""
4
  "Project-Id-Version: Iubenda Cookie Solution\n"
5
+ "POT-Creation-Date: 2019-07-31 10:35+0200\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.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/forms-list-table.php:92
20
+ msgid "Form Title"
21
+ msgstr ""
22
+
23
+ #: includes/forms-list-table.php:93
24
+ msgid "Form ID"
25
+ msgstr ""
26
+
27
+ #: includes/forms-list-table.php:94
28
+ msgid "Form Source"
29
+ msgstr ""
30
+
31
+ #: includes/forms-list-table.php:95
32
+ msgid "Fields"
33
+ msgstr ""
34
+
35
+ #: includes/forms-list-table.php:96
36
+ msgid "Date"
37
+ msgstr ""
38
+
39
+ #: includes/forms-list-table.php:165
40
+ msgid "Edit"
41
+ msgstr ""
42
+
43
+ #: includes/forms-list-table.php:166
44
+ msgid "Delete"
45
+ msgstr ""
46
+
47
+ #: includes/forms-list-table.php:277
48
+ msgid "Filter"
49
+ msgstr ""
50
+
51
+ #: includes/forms-list-table.php:294
52
+ msgid "Filter by source"
53
+ msgstr ""
54
+
55
+ #: includes/forms-list-table.php:296
56
+ msgid "All form sources"
57
+ msgstr ""
58
+
59
+ #: includes/forms-list-table.php:364
60
+ msgid "No forms found."
61
+ msgstr ""
62
+
63
+ #: includes/forms.php:123 includes/settings.php:123
64
+ msgid "Forms"
65
+ msgstr ""
66
+
67
+ #: includes/forms.php:124
68
+ msgid "Form"
69
+ msgstr ""
70
+
71
+ #: includes/settings.php:41 includes/settings.php:42 includes/settings.php:43
72
+ #: includes/settings.php:44 includes/settings.php:45
73
+ msgid "string"
74
+ msgstr ""
75
+
76
+ #: includes/settings.php:57 includes/settings.php:168
77
+ msgid "Cookie Solution"
78
+ msgstr ""
79
+
80
+ #: includes/settings.php:63 includes/settings.php:169
81
+ msgid "Consent Solution"
82
+ msgstr ""
83
+
84
+ #: includes/settings.php:112
85
  msgid "Code"
86
  msgstr ""
87
 
88
+ #: includes/settings.php:113
89
  msgid "Scripts blocking"
90
  msgstr ""
91
 
92
+ #: includes/settings.php:114
93
  msgid "Custom scripts"
94
  msgstr ""
95
 
96
+ #: includes/settings.php:115
97
  msgid "Content type"
98
  msgstr ""
99
 
100
+ #: includes/settings.php:116
101
  msgid "RSS feed"
102
  msgstr ""
103
 
104
+ #: includes/settings.php:117
105
  msgid "Menu position"
106
  msgstr ""
107
 
108
+ #: includes/settings.php:118
109
  msgid "Deactivation"
110
  msgstr ""
111
 
112
+ #: includes/settings.php:124
113
+ msgid "Public Api Key"
114
+ msgstr ""
115
+
116
+ #: includes/settings.php:127 includes/settings.php:131
117
+ msgid "Fields Mapping"
118
+ msgstr ""
119
+
120
+ #: includes/settings.php:189
121
+ msgid "Are you sure you want to delete this form?"
122
+ msgstr ""
123
+
124
+ #: includes/settings.php:337
125
+ msgid "You don't have permission to access this page."
126
+ msgstr ""
127
+
128
+ #: includes/settings.php:354
129
+ msgid ""
130
+ "This plugin is the easiest and most comprehensive way to adapt your "
131
+ "WordPress site to the European cookie law. Upon your user's first visit, "
132
+ "the plugin will take care of collecting their consent, of blocking the most "
133
+ "popular among the scripts that install cookies and subsequently reactivate "
134
+ "these scripts as soon as consent is provided. The basic settings include "
135
+ "obtaining consent by a simple scroll action (the most effective method) and "
136
+ "script reactivation without refreshing the page."
137
+ msgstr ""
138
+
139
+ #: includes/settings.php:357
140
+ msgid "Would you like to know more about the cookie law?"
141
+ msgstr ""
142
+
143
+ #: includes/settings.php:358
144
+ #, php-format
145
+ msgid ""
146
+ "Read our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">complete "
147
+ "guide to the cookie law.</a>"
148
+ msgstr ""
149
+
150
+ #: includes/settings.php:361
151
+ msgid "What is the full functionality of the plugin?"
152
+ msgstr ""
153
+
154
+ #: includes/settings.php:362
155
+ #, php-format
156
+ msgid ""
157
+ "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">plugin "
158
+ "page.</a>"
159
+ msgstr ""
160
+
161
+ #: includes/settings.php:365
162
+ msgid "Enter the iubenda code for the Cookie Solution below."
163
+ msgstr ""
164
+
165
+ #: includes/settings.php:366
166
+ #, php-format
167
+ msgid ""
168
+ "In order to run the plugin, you need to enter the iubenda code that "
169
+ "activates the cookie law banner and the cookie policy in the form below. "
170
+ "This code can be generated on www.iubenda.com, following <a href=\"%s\" "
171
+ "class=\"iubenda-url\" target=\"_blank\">this guide.</a>"
172
+ msgstr ""
173
+
174
+ #: includes/settings.php:371
175
+ msgid ""
176
+ "Maintaining comprehensive records of consent are a vital part of privacy "
177
+ "compliance in general but are specifically required under the GDPR. These "
178
+ "records should include a way of identifying the user, proof of consent, "
179
+ "record of the consenting action and the legal documents available to the "
180
+ "user at the time of consent, among other things. You can read about the <a "
181
+ "href=\"https://www.iubenda.com/en/help/5428-gdpr-guide#records-of-consent\" "
182
+ "target=\"_blank\">full requirements here</a>."
183
+ msgstr ""
184
+
185
+ #: includes/settings.php:404
186
+ msgid "Reset to defaults"
187
+ msgstr ""
188
+
189
+ #: includes/settings.php:414
190
+ msgid "Need support for this plugin?"
191
+ msgstr ""
192
+
193
+ #: includes/settings.php:415
194
+ #, php-format
195
+ msgid ""
196
+ "Visit our <a href=\"%s\" class=\"iubenda-url\" target=\"_blank\">support "
197
+ "forum.</a>"
198
+ msgstr ""
199
+
200
+ #: includes/settings.php:459
201
  #, php-format
202
  msgid "Enter the iubenda code for %s."
203
  msgstr ""
204
 
205
+ #: includes/settings.php:470
206
  msgid "Enter the iubenda code."
207
  msgstr ""
208
 
209
+ #: includes/settings.php:498
210
  msgid "Enter a list of custom scripts (one per line)."
211
  msgstr ""
212
 
213
+ #: includes/settings.php:502
214
  msgid "Enter a list of custom iframes (one per line)."
215
  msgstr ""
216
 
217
+ #: includes/settings.php:517
218
  msgid "Automatically block scripts detected by the plugin."
219
  msgstr ""
220
 
221
+ #: includes/settings.php:518
222
  #, php-format
223
  msgid ""
224
  "see <a href=\"%s\" target=\"_blank\">our documentation</a> for the list of "
225
  "detected scripts."
226
  msgstr ""
227
 
228
+ #: includes/settings.php:521
229
  msgid "Primary"
230
  msgstr ""
231
 
232
+ #: includes/settings.php:522
233
  msgid "Secondary"
234
  msgstr ""
235
 
236
+ #: includes/settings.php:523
237
  msgid "Select parsing engine."
238
  msgstr ""
239
 
240
+ #: includes/settings.php:526
241
  msgid ""
242
  "Leave scripts untouched on the page if the user has already given consent"
243
  msgstr ""
244
 
245
+ #: includes/settings.php:527
246
  msgid ""
247
  "improves performance, highly recommended, to be deactivated only if your "
248
  "site uses a caching system"
249
  msgstr ""
250
 
251
+ #: includes/settings.php:541
252
  msgid ""
253
  "Restrict the plugin to run only for requests that have \"Content-type: "
254
  "text / html\" (recommended)"
255
  msgstr ""
256
 
257
+ #: includes/settings.php:553
258
  msgid "Do not run the plugin inside the RSS feed (recommended)"
259
  msgstr ""
260
 
261
+ #: includes/settings.php:565
262
  msgid "Top menu"
263
  msgstr ""
264
 
265
+ #: includes/settings.php:566
266
  msgid "Submenu"
267
  msgstr ""
268
 
269
+ #: includes/settings.php:567
270
  msgid ""
271
  "Select whether to display iubenda in a top admin menu or the Settings "
272
  "submenu."
273
  msgstr ""
274
 
275
+ #: includes/settings.php:579
276
  msgid "Delete all plugin data upon deactivation?"
277
  msgstr ""
278
 
279
+ #: includes/settings.php:592
280
+ msgid "Enter your iubenda Javascript library public API key."
281
  msgstr ""
282
 
283
+ #: includes/settings.php:608
284
+ #, php-format
285
+ msgid "A list forms of available for field mapping. Currently supports: %s"
286
  msgstr ""
287
 
288
+ #: includes/settings.php:656
289
+ #, php-format
290
+ msgid "%s form title."
291
  msgstr ""
292
 
293
+ #: includes/settings.php:656
294
+ msgid "Unknown"
 
 
 
 
 
 
 
295
  msgstr ""
296
 
297
+ #: includes/settings.php:658
298
+ msgid "Available form fields:"
299
  msgstr ""
300
 
301
+ #: includes/settings.php:664
302
+ msgid "Publish"
303
+ msgstr ""
304
+
305
+ #: includes/settings.php:669
306
+ msgid "Status"
307
+ msgstr ""
308
+
309
+ #: includes/settings.php:682
310
+ msgid "Cancel"
311
+ msgstr ""
312
+
313
+ #: includes/settings.php:687
314
+ msgid "Save"
315
+ msgstr ""
316
+
317
+ #: includes/settings.php:700
318
+ msgid "Map fields"
319
+ msgstr ""
320
+
321
+ #: includes/settings.php:706
322
+ msgid "Subject fields"
323
+ msgstr ""
324
+
325
+ #: includes/settings.php:707
326
  msgid ""
327
+ "Subject fields allows you to store a series of values saved about your "
328
+ "subjects/users. Please map the subject/user data with the corresponding "
329
+ "form fields."
330
  msgstr ""
331
 
332
+ #: includes/settings.php:712
333
+ msgid "Subject field"
334
  msgstr ""
335
 
336
+ #: includes/settings.php:713 includes/settings.php:752
337
+ msgid "Form field"
338
+ msgstr ""
339
+
340
+ #: includes/settings.php:719
341
+ msgid "Autogenerated"
342
+ msgstr ""
343
+
344
+ #: includes/settings.php:719
345
+ msgid "None"
346
+ msgstr ""
347
+
348
+ #: includes/settings.php:745
349
+ msgid "Preferences fields"
350
+ msgstr ""
351
+
352
+ #: includes/settings.php:746
353
  msgid ""
354
+ "Preferences fields allows you to save the various opt-ins the user has "
355
+ "agreed to, such as terms and conditions, newsletter, profiling, etc. Please "
356
+ "create at least one preferences field."
357
  msgstr ""
358
 
359
+ #: includes/settings.php:751
360
+ msgid "Preferences field"
361
  msgstr ""
362
 
363
+ #: includes/settings.php:757 includes/settings.php:779
364
+ #: includes/settings.php:890 includes/settings.php:900
365
+ #: includes/settings.php:916
366
+ msgid "Enter field name"
367
+ msgstr ""
368
+
369
+ #: includes/settings.php:767 includes/settings.php:789
370
+ #: includes/settings.php:826 includes/settings.php:849
371
+ #: includes/settings.php:900 includes/settings.php:916
372
+ msgid "Remove"
373
+ msgstr ""
374
+
375
+ #: includes/settings.php:798
376
+ msgid "Add New Preference"
377
+ msgstr ""
378
+
379
+ #: includes/settings.php:805
380
+ msgid "Exclude fields"
381
+ msgstr ""
382
+
383
+ #: includes/settings.php:806
384
  msgid ""
385
+ "Exclude fields allows you to create a list of field names that you would "
386
+ "like to exclude from proofs (for e.g. password or other fields not related "
387
+ "to the consent)."
 
388
  msgstr ""
389
 
390
+ #: includes/settings.php:811
391
+ msgid "Exclude field"
392
  msgstr ""
393
 
394
+ #: includes/settings.php:859
395
+ msgid "Add New Exclude"
396
  msgstr ""
397
 
398
+ #: includes/settings.php:869
399
+ msgid "Legal Notices"
400
+ msgstr ""
401
+
402
+ #: includes/settings.php:875
403
+ msgid "Legal documents"
404
+ msgstr ""
405
+
406
+ #: includes/settings.php:876
407
  msgid ""
408
+ "If you use iubenda for your legal documents it is required for you to "
409
+ "declare which of them are being agreed upon on each consent creation."
410
+ msgstr ""
411
+
412
+ #: includes/settings.php:881
413
+ msgid "Identifier"
414
+ msgstr ""
415
+
416
+ #: includes/settings.php:890
417
+ msgid "Please check the legal notices you are using."
418
+ msgstr ""
419
+
420
+ #: includes/settings.php:906
421
+ msgid "Optionally add your custom document identifiers."
422
+ msgstr ""
423
+
424
+ #: includes/settings.php:925
425
+ msgid "Add New Document"
426
+ msgstr ""
427
+
428
+ #: includes/settings.php:998 includes/settings.php:1030
429
+ msgid "Settings saved."
430
  msgstr ""
431
 
432
+ #: includes/settings.php:1010 includes/settings.php:1035
433
+ msgid "Settings restored to defaults."
434
  msgstr ""
435
 
436
+ #: includes/settings.php:1059
437
  #, php-format
438
  msgid ""
439
+ "Please enable comments cookies opt-in checkbox in the <a href=\"%s\" target="
440
+ "\"_blank\">Discussion settings</a>."
441
+ msgstr ""
442
+
443
+ #: includes/settings.php:1079
444
+ msgid "No forms or form changes detected."
445
+ msgstr ""
446
+
447
+ #: includes/settings.php:1147
448
+ msgid "Form saving failed. Please fill the Subject and Preferences fields."
449
+ msgstr ""
450
+
451
+ #: includes/settings.php:1171
452
+ msgid "Form saved successfully - form status changed to Mapped."
453
+ msgstr ""
454
+
455
+ #: includes/settings.php:1174
456
+ msgid "Form updated successfully."
457
+ msgstr ""
458
+
459
+ #: includes/settings.php:1177
460
+ msgid "Form saving failed."
461
+ msgstr ""
462
+
463
+ #: includes/settings.php:1194
464
+ msgid "Form deleted successfully."
465
+ msgstr ""
466
+
467
+ #: includes/settings.php:1196
468
+ msgid "Form delete failed."
469
+ msgstr ""
470
+
471
+ #: includes/settings.php:1256
472
+ msgid "Dismiss this notice."
473
  msgstr ""
readme.txt CHANGED
@@ -141,6 +141,10 @@ We will be very happy to receive feedback here: [Uservoice forum](http://support
141
 
142
  == Changelog ==
143
 
 
 
 
 
144
  = 1.15.8 =
145
  * New: Introducing a way to skip specific script parsing
146
  * Fix: Google ReCaptcha with Contact Form 7 initialization issue
@@ -358,7 +362,5 @@ We will be very happy to receive feedback here: [Uservoice forum](http://support
358
 
359
  == Upgrade Notice ==
360
 
361
- = 1.15.8 =
362
- * New: Introducing a way to skip specific script parsing
363
- * Fix: Google ReCaptcha with Contact Form 7 initialization issue
364
- * Fix: Improved handling of iubenda script HTML
141
 
142
  == Changelog ==
143
 
144
+ = 2.0-beta =
145
+ * New: Introducing iubenda Consent Solution integration
146
+ * Tweak: Simple HTML Dom update to 1.9
147
+
148
  = 1.15.8 =
149
  * New: Introducing a way to skip specific script parsing
150
  * Fix: Google ReCaptcha with Contact Form 7 initialization issue
362
 
363
  == Upgrade Notice ==
364
 
365
+ = 2.0 =
366
+ * New: Introducing iubenda Consent Solution integration