PluginProbe
GDPR / trunk
GDPR vtrunk
trunk 1.4.7 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.2
gdpr / includes / class-gdpr.php

class-gdpr.php in GDPR trunk, at includes/class-gdpr.php

706 lines 25.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The file that defines the core plugin class
5 *
6 * A class definition that includes attributes and functions used across both the
7 * public-facing side of the site and the admin area.
8 *
9 * @link https://trewknowledge.com
10 * @since 1.0.0
11 *
12 * @package GDPR
13 * @subpackage includes
14 * @author Fernando Claussen <fernandoclaussen@gmail.com>
15 */
16
17 /**
18 * The core plugin class.
19 *
20 * This is used to define internationalization, admin-specific hooks, and
21 * public-facing site hooks.
22 *
23 * Also maintains the unique identifier of this plugin as well as the current
24 * version of the plugin.
25 *
26 * @since 1.0.0
27 * @package GDPR
28 * @subpackage includes
29 * @author Fernando Claussen <fernandoclaussen@gmail.com>
30 */
31 class GDPR {
32
33 /**
34 * The unique identifier of this plugin.
35 *
36 * @since 1.0.0
37 * @author Fernando Claussen <fernandoclaussen@gmail.com>
38 * @access protected
39 * @var string $plugin_name The string used to uniquely identify this plugin.
40 */
41 protected $plugin_name;
42
43 /**
44 * The current version of the plugin.
45 *
46 * @since 1.0.0
47 * @author Fernando Claussen <fernandoclaussen@gmail.com>
48 * @access protected
49 * @var string $version The current version of the plugin.
50 */
51 protected $version;
52
53 /**
54 * Define the core functionality of the plugin.
55 *
56 * Set the plugin name and the plugin version that can be used throughout the plugin.
57 * Load the dependencies, define the locale, and set the hooks for the admin area and
58 * the public-facing side of the site.
59 *
60 * @since 1.0.0
61 * @author Fernando Claussen <fernandoclaussen@gmail.com>
62 */
63 public function __construct() {
64 if ( defined( 'GDPR_VERSION' ) ) {
65 $this->version = GDPR_VERSION;
66 } else {
67 $this->version = '1.0.0';
68 }
69 $this->plugin_name = 'gdpr';
70
71 $this->load_dependencies();
72 $this->define_common_hooks();
73 $this->define_admin_hooks();
74 $this->define_public_hooks();
75
76 if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) or ( defined( 'DOING_CRON' ) && DOING_CRON ) or ( defined( 'DOING_AJAX' ) && DOING_AJAX ) or ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) ) {
77 return;
78 }
79 }
80
81 /**
82 * Load the required dependencies for this plugin.
83 *
84 * @since 1.0.0
85 * @author Fernando Claussen <fernandoclaussen@gmail.com>
86 * @access private
87 */
88 private function load_dependencies() {
89 /**
90 * The class responsible for adding help tabs.
91 */
92 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-gdpr-help.php';
93
94 /**
95 * The class responsible logging user actions.
96 */
97 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-gdpr-audit-log.php';
98
99 /**
100 * The class responsible for defining the requests section of the plugin.
101 */
102 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-gdpr-requests.php';
103
104 /**
105 * The class responsible for defining the admin facing requests section of the plugin.
106 */
107 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-gdpr-requests-admin.php';
108
109 /**
110 * The class responsible for defining the admin facing requests section of the plugin.
111 */
112 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-gdpr-requests-public.php';
113
114 /**
115 * The class responsible for locating the email templates and sending emails.
116 */
117 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-gdpr-email.php';
118
119 /**
120 * The class responsible for defining all actions that occur in the admin area.
121 */
122 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-gdpr-admin.php';
123
124 /**
125 * The class responsible for defining all actions that occur in the public-facing
126 * side of the site.
127 */
128 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-gdpr-public.php';
129 /**
130 * The class responsible for defining compatibility to olp php versions.
131 */
132 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/compatibility-functions.php';
133
134 }
135
136 /**
137 * Define the locale for this plugin for internationalization.
138 * @since 1.0.0
139 * @author Fernando Claussen <fernandoclaussen@gmail.com>
140 */
141 public function set_locale() {
142
143 load_plugin_textdomain(
144 'gdpr',
145 false,
146 plugin_dir_url( dirname( __FILE__ ) ) . 'languages/'
147 );
148
149 }
150
151 /**
152 * Register all of the common hooks.
153 * @since 1.0.0
154 * @author Fernando Claussen <fernandoclaussen@gmail.com>
155 * @access private
156 */
157 private function define_common_hooks() {
158 add_action( 'wp_ajax_gdpr_generate_data_export', array( $this, 'export_data' ) );
159 }
160
161 /**
162 * Register all of the hooks related to the admin area functionality
163 * of the plugin.
164 *
165 * @since 1.0.0
166 * @author Fernando Claussen <fernandoclaussen@gmail.com>
167 * @access private
168 */
169 private function define_admin_hooks() {
170
171 $plugin_admin = new GDPR_Admin( $this->get_plugin_name(), $this->get_version() );
172 $requests_admin = new GDPR_Requests_Admin( $this->get_plugin_name(), $this->get_version() );
173 $requests = new GDPR_Requests( $this->get_plugin_name(), $this->get_version() );
174 $plugin_emails = new GDPR_Email();
175 $woo_add_to_registration = get_option( 'gdpr_add_consent_checkboxes_registration', false );
176 $woo_add_to_checkout = get_option( 'gdpr_add_consent_checkboxes_checkout', false );
177
178 add_filter( 'nonce_user_logged_out', array( $this, 'woo_nonce_fix' ), 100, 2 );
179 add_action( 'plugins_loaded', array( $this, 'set_locale' ) );
180 add_action( 'bp_account_details_fields', array( __CLASS__, 'consent_checkboxes' ) );
181 if ( $woo_add_to_registration ) {
182 add_action( 'woocommerce_register_form', array( __CLASS__, 'consent_checkboxes' ) );
183 }
184 if ( $woo_add_to_checkout ) {
185 add_action( 'woocommerce_checkout_update_user_meta', array( $plugin_admin, 'woocommerce_checkout_save_consent' ), 10, 2 );
186 add_filter( 'woocommerce_checkout_fields', array( $plugin_admin, 'woocommerce_consent_checkboxes' ) );
187 }
188 add_filter( 'manage_users_custom_column', array( $plugin_admin, 'add_consents_to_consents_column' ), 10, 3 );
189 add_filter( 'manage_users_columns', array( $plugin_admin, 'add_consents_column_to_user_table' ) );
190 add_filter( 'manage_users_sortable_columns', array( $plugin_admin, 'sort_consents_column_from_user_table' ) );
191 add_action( 'pre_get_users', array( $plugin_admin, 'sort_logic_for_consents_from_user_table' ) );
192 add_action( 'show_user_profile', array( $plugin_admin, 'edit_user_profile' ) );
193 add_action( 'personal_options_update', array( $plugin_admin, 'user_profile_update' ) );
194 add_action( 'admin_notices', array( $plugin_admin, 'policy_updated_notice' ) );
195 add_action( 'admin_notices', array( $plugin_admin, 'version_check_notice' ) );
196 add_action( 'admin_notices', array( $plugin_admin, 'review_settings_after_v2_notice' ) );
197 add_action( 'upgrader_process_complete', array( $plugin_admin, 'upgrade_completed' ), 10, 2 );
198 add_action( 'wp_ajax_ignore_policy_update', array( $plugin_admin, 'ignore_policy_update' ) );
199 add_action( 'wp_ajax_seek_consent', array( $plugin_admin, 'seek_consent' ) );
200 add_action( 'publish_page', array( $plugin_admin, 'policy_updated' ), 10, 2 );
201 add_action( 'admin_enqueue_scripts', array( $plugin_admin, 'enqueue_styles' ) );
202 add_action( 'admin_enqueue_scripts', array( $plugin_admin, 'enqueue_scripts' ) );
203 add_action( 'admin_menu', array( $plugin_admin, 'add_menu' ) );
204 add_action( 'admin_init', array( $plugin_admin, 'register_settings' ) );
205 add_action( 'register_form', array( __CLASS__, 'consent_checkboxes' ) );
206 add_action( 'registration_errors', array( $plugin_admin, 'registration_errors' ), 10, 3 );
207 add_action( 'user_register', array( __CLASS__, 'save_user_consent_on_registration' ) );
208 add_action( 'wp_ajax_gdpr_access_data', array( $plugin_admin, 'access_data' ) );
209 add_action( 'wp_ajax_gdpr_audit_log', array( $plugin_admin, 'audit_log' ) );
210 add_action( 'admin_post_gdpr_data_breach', array( $plugin_admin, 'send_data_breach_confirmation_email' ) );
211 add_action( 'clean_gdpr_data_breach_request', array( $plugin_admin, 'clean_data_breach_request' ), 10, 2 ); // CRON JOB
212
213 add_action( 'admin_post_gdpr_delete_user', array( $requests_admin, 'delete_user' ) );
214 add_action( 'admin_post_gdpr_cancel_request', array( $requests_admin, 'cancel_request' ) );
215 add_action( 'admin_post_gdpr_add_to_deletion_requests', array( $requests_admin, 'add_to_deletion_requests' ) );
216 add_action( 'admin_post_gdpr_mark_resolved', array( $requests_admin, 'mark_resolved' ) );
217 add_action( 'wp_ajax_gdpr_anonymize_comments', array( $requests_admin, 'anonymize_comments' ) );
218 add_action( 'wp_ajax_gdpr_reassign_content', array( $requests_admin, 'reassign_content' ) );
219
220 // CRON JOBS
221 add_action( 'clean_gdpr_requests', array( $requests, 'clean_requests' ) );
222 add_action( 'clean_gdpr_user_request_key', array( $requests, 'clean_user_request_key' ), 10, 2 );
223
224 add_action( 'send_data_breach_emails', array( $plugin_emails, 'send_data_breach_emails' ), 10, 2 );
225 }
226
227 /**
228 * Fixes nonce manipulation made by Woocommerce.
229 * @param int $user_id The user id.
230 * @param string $action The nonce Action.
231 * @return int The user id.
232 */
233 function woo_nonce_fix( $user_id, $action ) {
234 if ( ( 0 !== $user_id ) && $action && ( false !== strpos( $action, 'gdpr-' ) ) ) {
235 $user_id = 0;
236 }
237
238 return $user_id;
239 }
240
241 /**
242 * Register all of the hooks related to the public-facing functionality
243 * of the plugin.
244 *
245 * @since 1.0.0
246 * @author Fernando Claussen <fernandoclaussen@gmail.com>
247 * @access private
248 */
249 private function define_public_hooks() {
250
251 $plugin_public = new GDPR_Public( $this->get_plugin_name(), $this->get_version() );
252 $requests_public = new GDPR_Requests_Public( $this->get_plugin_name(), $this->get_version() );
253
254 add_action( 'wp_enqueue_scripts', array( $plugin_public, 'enqueue_styles' ) );
255 add_action( 'wp_enqueue_scripts', array( $plugin_public, 'enqueue_scripts' ) );
256 add_action( 'init', array( $plugin_public, 'set_plugin_cookies' ) );
257 add_action( 'wp_footer', array( $plugin_public, 'overlay' ) );
258 add_action( 'wp_footer', array( $plugin_public, 'privacy_bar' ) );
259 add_action( 'wp_footer', array( $plugin_public, 'is_consent_needed' ) );
260 add_action( 'wp_footer', array( $plugin_public, 'privacy_preferences_modal' ) );
261 add_action( 'wp_footer', array( $plugin_public, 'confirmation_screens' ) );
262 add_action( 'wp_ajax_disagree_with_terms', array( $plugin_public, 'logout' ) );
263 add_action( 'wp_ajax_agree_with_terms', array( $plugin_public, 'agree_with_terms' ) );
264 add_action( 'wp_ajax_gdpr_update_privacy_preferences', array( $plugin_public, 'update_privacy_preferences' ) );
265 add_action( 'wp_ajax_nopriv_gdpr_update_privacy_preferences', array( $plugin_public, 'update_privacy_preferences' ) );
266 add_action( 'wp_ajax_agree_with_new_policies', array( $plugin_public, 'agree_with_new_policies' ) );
267 add_action( 'wp_ajax_nopriv_agree_with_new_policies', array( $plugin_public, 'agree_with_new_policies' ) );
268
269 add_action( 'wp', array( $requests_public, 'request_confirmed' ) );
270 add_action( 'wp_ajax_gdpr_send_request_email', array( $requests_public, 'send_request_email' ) );
271 add_action( 'wp_ajax_nopriv_gdpr_send_request_email', array( $requests_public, 'send_request_email' ) );
272 }
273
274 /**
275 * Checks in an array if a value is found using LIKE instead of =.
276 * @since 1.4.3
277 * @author Fernando Claussen <fernandoclaussen@gmail.com>
278 * @return Bool
279 */
280 public static function similar_in_array( $needle, $haystack ) {
281 foreach ( $haystack as $value ) {
282 if ( stripos( strtolower( $value ), strtolower( $needle ) ) !== false ) {
283 return true;
284 }
285 }
286
287 return false;
288 }
289
290 /**
291 * Save the extra fields on a successful registration.
292 * @since 1.0.0
293 * @author Fernando Claussen <fernandoclaussen@gmail.com>
294 * @param int $user_id The user ID.
295 */
296 public static function save_user_consent_on_registration( $user_id ) { // phpcs:ignore
297 GDPR_Audit_Log::log( $user_id, esc_html__( 'User registered to the site.', 'gdpr' ) );
298
299 if ( isset( $_POST['user_consents'] ) && is_array( $_POST['user_consents'] ) ) {
300
301 $consents = array_map( 'sanitize_text_field', array_keys( wp_unslash( $_POST['user_consents'] ) ) ); // phpcs:ignore
302 foreach ( $consents as $consent ) {
303 /* translators: Name of consent */
304 GDPR_Audit_Log::log( $user_id, sprintf( esc_html__( 'User gave explicit consent to %s', 'gdpr' ), $consent ) );
305 if ( defined( 'WPCOM_IS_VIP_ENV' ) && WPCOM_IS_VIP_ENV ) {
306 add_user_attribute( $user_id, 'gdpr_consents', $consent );
307 } else {
308 add_user_meta( $user_id, 'gdpr_consents', $consent );
309 }
310 }
311 setcookie( 'gdpr[consent_types]', wp_json_encode( $consents ), time() + YEAR_IN_SECONDS, '/' );
312 }
313 }
314
315 /**
316 * Returns the consent checkboxes to be used across the site.
317 * @since 1.2.0
318 * @author Fernando Claussen <fernandoclaussen@gmail.com>
319 */
320 public static function get_consent_checkboxes( $consent_key = false ) {
321 $consent_types = get_option( 'gdpr_consent_types', array() );
322 if ( empty( $consent_types ) ) {
323 return;
324 }
325 $sent_extras = ( isset( $_POST['user_consents'] ) ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['user_consents'] ) ) : array(); // phpcs:ignore
326
327 $allowed_html = array(
328 'a' => array(
329 'href' => true,
330 'title' => true,
331 'target' => true,
332 ),
333 );
334
335 if ( $consent_key ) {
336 $consent_types = array_filter(
337 $consent_types, function( $key ) use ( $consent_key ) {
338 return $key === $consent_key;
339 }, ARRAY_FILTER_USE_KEY
340 );
341 }
342
343 ob_start();
344 foreach ( $consent_types as $key => $consent ) {
345 $required = ( isset( $consent['policy-page'] ) && $consent['policy-page'] ) ? 'required' : '';
346 $checked = ( isset( $sent_extras[ $key ] ) ) ? checked( $sent_extras[ $key ], 1, false ) : '';
347 echo '<p>' .
348 '<label class="gdpr-label">' .
349 '<input type="checkbox" name="user_consents[' . esc_attr( $key ) . ']" id="' . esc_attr( $key ) . '-consent" value="1" ' . esc_html( $required ) . ' ' . esc_html( $checked ) . '>' .
350 wp_kses( $consent['registration'], $allowed_html ) . '</label>' .
351 '</p>';
352 }
353
354 return ob_get_clean();
355 }
356
357 /**
358 * Renders consent checkboxes to be used across the site.
359 * @since 1.1.4
360 * @author Fernando Claussen <fernandoclaussen@gmail.com>
361 */
362 public static function consent_checkboxes( $consent_key = false ) {
363 echo self::get_consent_checkboxes( $consent_key ); // phpcs:ignore
364 }
365
366 /**
367 * Get user meta for exporting.
368 * @since 1.0.0
369 * @author Fernando Claussen <fernandoclaussen@gmail.com>
370 * @static
371 * @param int $user_id The user ID.
372 * @return array The user meta minus not important metas.
373 */
374 static function get_user_meta( $user_id ) {
375 if ( defined( 'WPCOM_IS_VIP_ENV' ) && WPCOM_IS_VIP_ENV ) {
376 $usermeta = get_user_attribute( $user_id );
377 } else {
378 $usermeta = get_user_meta( $user_id );
379 }
380 $remove_metadata = array(
381 'nickname',
382 'first_name',
383 'last_name',
384 'description',
385 'rich_editing',
386 'syntax_highlighting',
387 'comment_shortcuts',
388 'admin_color',
389 'use_ssl',
390 'show_admin_bar_front',
391 'wp_capabilities',
392 'wp_user_level',
393 'gdpr_consents',
394 'gdpr_audit_log',
395 'dismissed_wp_pointers',
396 'gdpr_delete_key',
397 'gdpr_rectify_key',
398 'gdpr_complaint_key',
399 'gdpr_export-data_key',
400
401 );
402
403 return array_diff_key( $usermeta, array_flip( $remove_metadata ) );
404 }
405
406 /**
407 * Generates the export in JSON or XML formats.
408 * @since 1.0.0
409 * @author Fernando Claussen <fernandoclaussen@gmail.com>
410 * @static
411 * @param string $email The user email.
412 * @param string $format Either XML or JSON.
413 * @return string Returns the file as string.
414 */
415 static function generate_export( $email, $format ) {
416
417 $email = sanitize_email( $email );
418 $user = get_user_by( 'email', $email );
419
420 if ( ! $user instanceof WP_User ) {
421 return false;
422 }
423
424 $usermeta = self::get_user_meta( $user->ID );
425 $comments = get_comments(
426 array(
427 'author_email' => $user->user_email,
428 'include_unapproved' => true,
429 )
430 );
431 if ( defined( 'WPCOM_IS_VIP_ENV' ) && WPCOM_IS_VIP_ENV ) {
432 $user_consents = get_user_attribute( $user->ID, 'gdpr_consents' );
433 } else {
434 $user_consents = get_user_meta( $user->ID, 'gdpr_consents' );
435 }
436 $extra_content = apply_filters( 'gdpr_export_data_extra_tables', '', $email );
437
438 switch ( strtolower( $format ) ) {
439 case 'json':
440 $metadata = array();
441
442 foreach ( $usermeta as $k => $v ) {
443 $metadata[ $k ] = array();
444 foreach ( $v as $value ) {
445 if ( is_serialized( $value ) ) {
446 $metadata[ $k ][] = maybe_unserialize( $value );
447 } else {
448 $metadata[ $k ] = $value;
449 }
450 }
451 }
452
453 $comments_array = array();
454 if ( ! empty( $comments ) ) {
455 foreach ( $comments as $k => $v ) {
456 $comments_array[ $k ] = array(
457 'comment_author' => $v->comment_author,
458 'comment_author_email' => $v->comment_author_email,
459 'comment_author_url' => $v->comment_author_url,
460 'comment_author_IP' => $v->comment_author_IP,
461 'comment_date' => $v->comment_date,
462 'comment_agent' => $v->comment_agent,
463 'comment_content' => $v->comment_content,
464 );
465 }
466 }
467
468 $json = array(
469 'Personal Information' => array(
470 'Username' => $user->user_login,
471 'First name' => $user->first_name,
472 'Last name' => $user->last_name,
473 'Email' => $user->user_email,
474 'Nickname' => $user->nickname,
475 'Display name' => $user->display_name,
476 'Description' => $user->description,
477 'Website' => $user->user_url,
478 ),
479 'Consents' => $user_consents,
480 'Metadata' => $metadata,
481 'Comments' => $comments_array,
482 );
483
484 if ( $extra_content ) {
485 $json[ $extra_content['name'] ] = $extra_content['content'];
486 }
487 return wp_json_encode( $json );
488 break;
489 case 'md':
490 case 'markdown':
491 # code...
492 break;
493
494 default: // XML
495 $dom = new DomDocument( '1.0', 'ISO-8859-1' );
496 $data_wrapper = $dom->createElement( 'Data' );
497 $dom->appendChild( $data_wrapper );
498 $personal_info = $dom->createElement( 'Personal_Information' );
499 $data_wrapper->appendChild( $personal_info );
500 $personal_info->appendChild( $dom->createElement( 'Username', $user->user_login ) );
501 $personal_info->appendChild( $dom->createElement( 'First_Name', $user->first_name ) );
502 $personal_info->appendChild( $dom->createElement( 'Last_Name', $user->last_name ) );
503 $personal_info->appendChild( $dom->createElement( 'Email', $user->user_email ) );
504 $personal_info->appendChild( $dom->createElement( 'Nickname', $user->nickname ) );
505 $personal_info->appendChild( $dom->createElement( 'Display_Name', $user->display_name ) );
506 $personal_info->appendChild( $dom->createElement( 'Description', $user->description ) );
507 $personal_info->appendChild( $dom->createElement( 'Website', $user->user_url ) );
508
509 if ( ! empty( $user_consents ) ) {
510 $consents = $dom->createElement( 'Consents' );
511 $data_wrapper->appendChild( $consents );
512 foreach ( $user_consents as $consent_item ) {
513 $consents->appendChild( $dom->createElement( 'consent', $consent_item ) );
514 }
515 }
516
517 if ( ! empty( $comments ) ) {
518 $comments_node = $dom->createElement( 'Comments' );
519 $data_wrapper->appendChild( $comments_node );
520 foreach ( $comments as $k => $v ) {
521 $single_comment = $dom->createElement( 'Comment' );
522 $comments_node->appendChild( $single_comment );
523 $single_comment->appendChild( $dom->createElement( 'comment_author', htmlspecialchars( $v->comment_author ) ) );
524 $single_comment->appendChild( $dom->createElement( 'comment_author_email', htmlspecialchars( $v->comment_author_email ) ) );
525 $single_comment->appendChild( $dom->createElement( 'comment_author_url', htmlspecialchars( $v->comment_author_url ) ) );
526 $single_comment->appendChild( $dom->createElement( 'comment_author_IP', htmlspecialchars( $v->comment_author_IP ) ) );
527 $single_comment->appendChild( $dom->createElement( 'comment_date', htmlspecialchars( $v->comment_date ) ) );
528 $single_comment->appendChild( $dom->createElement( 'comment_agent', htmlspecialchars( $v->comment_agent ) ) );
529 $single_comment->appendChild( $dom->createElement( 'comment_content', htmlspecialchars( $v->comment_content ) ) );
530 }
531 }
532
533 $meta_data = $dom->createElement( 'Metadata' );
534 $data_wrapper->appendChild( $meta_data );
535
536 foreach ( $usermeta as $k => $v ) {
537 $k = is_numeric( substr( $k, 0, 1 ) ) ? '_' . $k : $k;
538 $key = $dom->createElement( htmlspecialchars( $k ) );
539 $meta_data->appendChild( $key );
540 foreach ( $v as $value ) {
541 $key->appendChild( $dom->createElement( 'item', htmlspecialchars( $value ) ) );
542 }
543 }
544
545 if ( $extra_content ) {
546 $extra = $dom->createElement( $extra_content['name'] );
547 $data_wrapper->appendChild( $extra );
548 foreach ( $extra_content['content'] as $key => $obj ) {
549 $item = $extra->appendChild( $dom->createElement( 'item' ) );
550 foreach ( $obj as $k => $value ) {
551 $item->appendChild( $dom->createElement( $k, ( is_object( $value ) || is_array( $value ) ) ? wp_json_encode( (array) $value ) : $value ) );
552 }
553 }
554 }
555
556 $dom->preserveWhiteSpace = false;
557 $dom->formatOutput = true;
558 return $dom->saveXML();
559 break;
560 }
561
562 return false;
563
564 }
565
566 /**
567 * Export the generated export file.
568 * @since 1.0.0
569 * @author Fernando Claussen <fernandoclaussen@gmail.com>
570 */
571 function export_data() {
572 if ( ! isset( $_POST['nonce'], $_POST['email'], $_POST['type'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'gdpr-export-data' ) ) { // phpcs:ignore
573 wp_send_json_error();
574 }
575
576 $type = sanitize_text_field( wp_unslash( $_POST['type'] ) ); // phpcs:ignore
577 $email = sanitize_email( wp_unslash( $_POST['email'] ) ); // phpcs:ignore
578 $user = get_user_by( 'email', $email );
579
580 if ( ! $user instanceof WP_User ) {
581 wp_send_json_error();
582 }
583
584 $export = self::generate_export( $email, $type );
585 if ( $export ) {
586 wp_send_json_success( $export );
587 }
588
589 wp_send_json_error();
590 }
591
592 /**
593 * Save a consent to the user meta.
594 * @since 1.1.4
595 * @author Fernando Claussen <fernandoclaussen@gmail.com>
596 * @param integer $user_id The user ID.
597 * @param string $consent The consent ID.
598 * @return void
599 */
600 public static function save_consent( $user_id, $consent ) {
601 $registered_consent = get_option( 'gdpr_consent_types', array() );
602 if ( empty( $registered_consent ) ) {
603 return false;
604 }
605 $consent_ids = array_keys( $registered_consent );
606 $user = get_user_by( 'ID', $user_id );
607 $consent = sanitize_text_field( wp_unslash( $consent ) );
608
609 if ( $user ) {
610 if ( defined( 'WPCOM_IS_VIP_ENV' ) && WPCOM_IS_VIP_ENV ) {
611 $user_consent = get_user_attribute( $user_id, 'gdpr_consents' );
612 } else {
613 $user_consent = get_user_meta( $user_id, 'gdpr_consents' );
614 }
615 if ( in_array( $consent, $consent_ids, true ) && ! in_array( $consent, $user_consent, true ) ) {
616 if ( defined( 'WPCOM_IS_VIP_ENV' ) && WPCOM_IS_VIP_ENV ) {
617 add_user_attribute( $user_id, 'gdpr_consents', $consent );
618 } else {
619 add_user_meta( $user_id, 'gdpr_consents', $consent );
620 }
621 $user_consent[] = $consent;
622 setcookie( 'gdpr[consent_types]', wp_json_encode( $user_consent ), time() + YEAR_IN_SECONDS, '/' );
623 return true;
624 }
625 }
626
627 return false;
628 }
629
630 /**
631 * Remove a user consent.
632 * @since 1.1.4
633 * @author Fernando Claussen <fernandoclaussen@gmail.com>
634 * @param integer $user_id The user ID.
635 * @param string $consent The consent ID.
636 * @return void
637 */
638 public static function remove_consent( $user_id, $consent ) {
639 $user = get_user_by( 'ID', $user_id );
640
641 if ( $user ) {
642 if ( defined( 'WPCOM_IS_VIP_ENV' ) && WPCOM_IS_VIP_ENV ) {
643 $user_consent = get_user_attribute( $user_id, 'gdpr_consents' );
644 } else {
645 $user_consent = get_user_meta( $user_id, 'gdpr_consents' );
646 }
647
648 $consent = sanitize_text_field( wp_unslash( $consent ) );
649 $key = array_search( $consent, $user_consent, true );
650 if ( false !== $key ) {
651 if ( defined( 'WPCOM_IS_VIP_ENV' ) && WPCOM_IS_VIP_ENV ) {
652 delete_user_attribute( $user_id, 'gdpr_consents', $consent );
653 } else {
654 delete_user_meta( $user_id, 'gdpr_consents', $consent );
655 }
656 unset( $user_consent[ $key ] );
657 setcookie( 'gdpr[consent_types]', wp_json_encode( $user_consent ), time() + YEAR_IN_SECONDS, '/' );
658 return true;
659 }
660 }
661
662 return false;
663 }
664
665
666 /**
667 * Generates a random 6 digit pin.
668 * This pin is necessary to use with the audit log files.
669 *
670 * @since 1.0.0
671 * @author Fernando Claussen <fernandoclaussen@gmail.com>
672 * @static
673 * @param integer $length Number of digits.
674 * @return string Returns the generated pin
675 */
676 public static function generate_pin( $length = 6 ) {
677 $bytes = openssl_random_pseudo_bytes( $length / 2 );
678 return strtoupper( bin2hex( $bytes ) );
679 }
680
681
682 /**
683 * The name of the plugin used to uniquely identify it within the context of
684 * WordPress and to define internationalization functionality.
685 *
686 * @since 1.0.0
687 * @author Fernando Claussen <fernandoclaussen@gmail.com>
688 * @return string The name of the plugin.
689 */
690 public function get_plugin_name() {
691 return $this->plugin_name;
692 }
693
694 /**
695 * Retrieve the version number of the plugin.
696 *
697 * @since 1.0.0
698 * @author Fernando Claussen <fernandoclaussen@gmail.com>
699 * @return string The version number of the plugin.
700 */
701 public function get_version() {
702 return $this->version;
703 }
704
705 }
706