This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
1 | <?php |
||
2 | /** |
||
3 | * Data retention class. |
||
4 | * |
||
5 | * @package Invoicing |
||
6 | * @since 2.8.22 |
||
7 | */ |
||
8 | |||
9 | defined( 'ABSPATH' ) || exit; |
||
10 | |||
11 | /** |
||
12 | * WPInv_Data_Retention Class. |
||
13 | * |
||
14 | * Handles user data anonymization and deletion. |
||
15 | * |
||
16 | * @since 2.8.22 |
||
17 | */ |
||
18 | class WPInv_Data_Retention { |
||
19 | |||
20 | /** |
||
21 | * Error message. |
||
22 | * |
||
23 | * @var string |
||
24 | */ |
||
25 | private $error_message; |
||
26 | |||
27 | /** |
||
28 | * Flag to control whether user deletion should be handled. |
||
29 | * |
||
30 | * @var bool |
||
31 | */ |
||
32 | private $handle_user_deletion = true; |
||
33 | |||
34 | /** |
||
35 | * Class constructor. |
||
36 | */ |
||
37 | public function __construct() { |
||
38 | add_filter( 'wpinv_settings_misc', array( $this, 'add_data_retention_settings' ) ); |
||
39 | |||
40 | add_action( 'wpmu_delete_user', array( $this, 'maybe_handle_user_deletion' ), 1 ); |
||
41 | add_action( 'delete_user', array( $this, 'maybe_handle_user_deletion' ), 1 ); |
||
42 | add_filter( 'wp_privacy_personal_data_erasure_request', array( $this, 'handle_erasure_request' ), 10, 2 ); |
||
43 | |||
44 | add_action( 'getpaid_daily_maintenance', array( $this, 'perform_data_retention_cleanup' ) ); |
||
45 | } |
||
46 | |||
47 | /** |
||
48 | * Adds data retention settings to the misc settings page. |
||
49 | * |
||
50 | * @param array $misc_settings Existing misc settings. |
||
51 | * @return array Updated misc settings. |
||
52 | */ |
||
53 | public function add_data_retention_settings( $misc_settings ) { |
||
54 | $misc_settings['data_retention'] = array( |
||
55 | 'id' => 'data_retention', |
||
56 | 'name' => '<h3>' . __( 'Data Retention', 'invoicing' ) . '</h3>', |
||
57 | 'type' => 'header', |
||
58 | ); |
||
59 | |||
60 | $misc_settings['data_retention_method'] = array( |
||
61 | 'id' => 'data_retention_method', |
||
62 | 'name' => __( 'Data Handling', 'invoicing' ), |
||
63 | 'desc' => __( 'Choose how to handle user data when deletion is required.', 'invoicing' ), |
||
64 | 'type' => 'select', |
||
65 | 'options' => array( |
||
66 | 'anonymize' => __( 'Anonymize data', 'invoicing' ), |
||
67 | 'delete' => __( 'Delete data without anonymization', 'invoicing' ), |
||
68 | ), |
||
69 | 'std' => 'anonymize', |
||
70 | 'tooltip' => __( 'Anonymization replaces personal data with non-identifiable information. Direct deletion removes all data permanently.', 'invoicing' ), |
||
71 | ); |
||
72 | |||
73 | $misc_settings['data_retention_period'] = array( |
||
74 | 'id' => 'data_retention_period', |
||
75 | 'name' => __( 'Retention Period', 'invoicing' ), |
||
76 | 'desc' => __( 'Specify how long to retain customer data after processing.', 'invoicing' ), |
||
77 | 'type' => 'select', |
||
78 | 'options' => array( |
||
79 | 'never' => __( 'Never delete (retain indefinitely)', 'invoicing' ), |
||
80 | '30' => __( '30 days', 'invoicing' ), |
||
81 | '90' => __( '90 days', 'invoicing' ), |
||
82 | '180' => __( '6 months', 'invoicing' ), |
||
83 | '365' => __( '1 year', 'invoicing' ), |
||
84 | '730' => __( '2 years', 'invoicing' ), |
||
85 | '1825' => __( '5 years', 'invoicing' ), |
||
86 | '3650' => __( '10 years', 'invoicing' ), |
||
87 | ), |
||
88 | 'std' => '3650', |
||
89 | 'tooltip' => __( 'Choose how long to keep processed customer data before final action. This helps balance data minimization with business needs.', 'invoicing' ), |
||
90 | ); |
||
91 | |||
92 | return $misc_settings; |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * Conditionally handles user deletion based on the flag. |
||
97 | * |
||
98 | * @param int $user_id The ID of the user being deleted. |
||
99 | */ |
||
100 | public function maybe_handle_user_deletion( $user_id ) { |
||
101 | if ( ! $this->handle_user_deletion ) { |
||
102 | return; |
||
103 | } |
||
104 | |||
105 | if ( current_user_can( 'manage_options' ) ) { |
||
106 | $this->handle_admin_user_deletion( $user_id ); |
||
107 | } else { |
||
108 | $this->handle_self_account_deletion( $user_id ); |
||
109 | } |
||
110 | } |
||
111 | |||
112 | /** |
||
113 | * Handles admin-initiated user deletion process. |
||
114 | * |
||
115 | * @since 2.8.22 |
||
116 | * @param int $user_id The ID of the user being deleted. |
||
117 | */ |
||
118 | public function handle_admin_user_deletion( $user_id ) { |
||
119 | if ( $this->has_active_subscriptions( $user_id ) ) { |
||
120 | $this->prevent_user_deletion( $user_id, 'active_subscriptions' ); |
||
121 | return; |
||
122 | } |
||
123 | |||
124 | if ( $this->has_paid_invoices( $user_id ) ) { |
||
125 | $retention_method = wpinv_get_option( 'data_retention_method', 'anonymize' ); |
||
126 | if ( 'anonymize' === $retention_method ) { |
||
127 | $this->anonymize_user_data( $user_id ); |
||
128 | $this->prevent_user_deletion( $user_id, 'paid_invoices' ); |
||
129 | } else { |
||
130 | $this->delete_user_data( $user_id ); |
||
131 | } |
||
132 | } |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Handles user account self-deletion. |
||
137 | * |
||
138 | * @since 2.8.22 |
||
139 | * @param int $user_id The ID of the user being deleted. |
||
140 | */ |
||
141 | public function handle_self_account_deletion( $user_id ) { |
||
142 | $this->cancel_active_subscriptions( $user_id ); |
||
143 | |||
144 | if ( $this->has_paid_invoices( $user_id ) ) { |
||
145 | $retention_method = wpinv_get_option( 'data_retention_method', 'anonymize' ); |
||
146 | |||
147 | if ( 'anonymize' === $retention_method ) { |
||
148 | $user = get_userdata( $user_id ); |
||
149 | |||
150 | $this->anonymize_user_data( $user_id ); |
||
151 | |||
152 | $message = apply_filters( 'uwp_get_account_deletion_message', '', $user ); |
||
153 | do_action( 'uwp_send_account_deletion_emails', $user, $message ); |
||
154 | |||
155 | $this->end_user_session(); |
||
156 | } |
||
157 | } |
||
158 | } |
||
159 | |||
160 | /** |
||
161 | * Checks if user has active subscriptions. |
||
162 | * |
||
163 | * @since 2.8.22 |
||
164 | * @param int $user_id The ID of the user being checked. |
||
165 | * @return bool True if user has active subscriptions, false otherwise. |
||
166 | */ |
||
167 | private function has_active_subscriptions( $user_id ) { |
||
168 | $subscriptions = getpaid_get_subscriptions( |
||
169 | array( |
||
170 | 'customer_in' => array( (int) $user_id ), |
||
171 | 'status' => 'active', |
||
172 | ) |
||
173 | ); |
||
174 | |||
175 | return ! empty( $subscriptions ); |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * Cancels all active subscriptions for a user. |
||
180 | * |
||
181 | * @since 2.8.22 |
||
182 | * @param int $user_id The ID of the user. |
||
183 | */ |
||
184 | private function cancel_active_subscriptions( $user_id ) { |
||
185 | $subscriptions = getpaid_get_subscriptions( |
||
186 | array( |
||
187 | 'customer_in' => array( (int) $user_id ), |
||
188 | 'status' => 'active', |
||
189 | ) |
||
190 | ); |
||
191 | |||
192 | foreach ( $subscriptions as $subscription ) { |
||
193 | $subscription->cancel(); |
||
194 | } |
||
195 | } |
||
196 | |||
197 | /** |
||
198 | * Checks if user has paid invoices. |
||
199 | * |
||
200 | * @since 2.8.22 |
||
201 | * @param int $user_id The ID of the user being checked. |
||
202 | * @return bool True if user has paid invoices, false otherwise. |
||
203 | */ |
||
204 | private function has_paid_invoices( $user_id ) { |
||
205 | $invoices = wpinv_get_invoices( |
||
206 | array( |
||
207 | 'user' => (int) $user_id, |
||
208 | 'status' => 'publish', |
||
209 | ) |
||
210 | ); |
||
211 | |||
212 | return ! empty( $invoices->total ); |
||
213 | } |
||
214 | |||
215 | /** |
||
216 | * Prevents user deletion by setting an error message and stopping execution. |
||
217 | * |
||
218 | * @since 2.8.22 |
||
219 | * @param int $user_id The ID of the user being deleted. |
||
220 | * @param string $reason The reason for preventing deletion. |
||
221 | */ |
||
222 | private function prevent_user_deletion( $user_id, $reason ) { |
||
223 | $user = get_userdata( $user_id ); |
||
224 | |||
225 | if ( 'active_subscriptions' === $reason ) { |
||
226 | $this->error_message = sprintf( |
||
227 | /* translators: %s: user login */ |
||
228 | esc_html__( 'User deletion for %s has been halted. All active subscriptions should be cancelled first.', 'invoicing' ), |
||
229 | $user->user_login |
||
230 | ); |
||
231 | } else { |
||
232 | $this->error_message = sprintf( |
||
233 | /* translators: %s: user login */ |
||
234 | esc_html__( 'User deletion for %s has been halted due to paid invoices. Data will be anonymized instead.', 'invoicing' ), |
||
235 | $user->user_login |
||
236 | ); |
||
237 | } |
||
238 | |||
239 | wp_die( $this->error_message, esc_html__( 'User Deletion Halted', 'invoicing' ), array( 'response' => 403 ) ); |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * Anonymizes user data. |
||
244 | * |
||
245 | * @since 2.8.22 |
||
246 | * @param int $user_id The ID of the user to anonymize. |
||
247 | * @return bool True on success, false on failure. |
||
248 | */ |
||
249 | private function anonymize_user_data( $user_id ) { |
||
250 | global $wpdb; |
||
251 | |||
252 | $user = get_userdata( $user_id ); |
||
253 | if ( ! $user ) { |
||
254 | return false; |
||
255 | } |
||
256 | |||
257 | $table_name = $wpdb->prefix . 'getpaid_customers'; |
||
258 | $deletion_date = gmdate( 'Y-m-d', strtotime( '+10 years' ) ); |
||
259 | $hashed_email = $this->hash_email( $user->user_email ); |
||
260 | |||
261 | $updated = $wpdb->update( |
||
262 | $table_name, |
||
263 | array( |
||
264 | 'is_anonymized' => 1, |
||
265 | 'deletion_date' => $deletion_date, |
||
266 | 'email' => $hashed_email, |
||
267 | 'email_cc' => $hashed_email, |
||
268 | 'phone' => '', |
||
269 | ), |
||
270 | array( 'user_id' => (int) $user->ID ) |
||
271 | ); |
||
272 | |||
273 | if ( false === $updated ) { |
||
274 | return false; |
||
275 | } |
||
276 | |||
277 | wp_update_user( |
||
278 | array( |
||
279 | 'ID' => (int) $user->ID, |
||
280 | 'user_email' => $hashed_email, |
||
281 | ) |
||
282 | ); |
||
283 | |||
284 | /** |
||
285 | * Fires when anonymizing user meta fields. |
||
286 | * |
||
287 | * @since 2.8.22 |
||
288 | * @param int $user_id The ID of the user being anonymized. |
||
289 | */ |
||
290 | do_action( 'wpinv_anonymize_user_meta_data', $user->ID ); |
||
291 | |||
292 | $user_meta_data = array( |
||
293 | 'nickname', |
||
294 | 'description', |
||
295 | 'rich_editing', |
||
296 | 'syntax_highlighting', |
||
297 | 'comment_shortcuts', |
||
298 | 'admin_color', |
||
299 | 'use_ssl', |
||
300 | 'show_admin_bar_front', |
||
301 | 'locale', |
||
302 | 'wp_capabilities', |
||
303 | 'wp_user_level', |
||
304 | 'dismissed_wp_pointers', |
||
305 | 'show_welcome_panel', |
||
306 | ); |
||
307 | |||
308 | /** |
||
309 | * Filters the user meta fields to be anonymized. |
||
310 | * |
||
311 | * @since 2.8.22 |
||
312 | * @param array $user_meta_data The meta fields to be anonymized. |
||
313 | * @param int $user_id The ID of the user being anonymized. |
||
314 | */ |
||
315 | $user_meta_data = apply_filters( 'wpinv_user_meta_data_to_anonymize', $user_meta_data, $user->ID ); |
||
316 | |||
317 | foreach ( $user_meta_data as $meta_key ) { |
||
318 | delete_user_meta( $user->ID, $meta_key ); |
||
319 | } |
||
320 | |||
321 | return $this->ensure_invoice_anonymization( $user->ID, 'anonymize' ); |
||
322 | } |
||
323 | |||
324 | /** |
||
325 | * Deletes user data without anonymization. |
||
326 | * |
||
327 | * @param int $user_id The ID of the user to delete. |
||
328 | * @return bool True on success, false on failure. |
||
329 | */ |
||
330 | private function delete_user_data( $user_id ) { |
||
331 | // Delete associated invoices. |
||
332 | $this->ensure_invoice_anonymization( $user_id, 'delete' ); |
||
333 | |||
334 | // Delete the user. |
||
335 | if ( is_multisite() ) { |
||
336 | wpmu_delete_user( $user_id ); |
||
337 | } else { |
||
338 | wp_delete_user( $user_id ); |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Fires after deleting user data without anonymization. |
||
343 | * |
||
344 | * @since 2.8.22 |
||
345 | * @param int $user_id The ID of the user being deleted. |
||
346 | */ |
||
347 | do_action( 'wpinv_delete_user_data', $user_id ); |
||
348 | |||
349 | return true; |
||
350 | } |
||
351 | |||
352 | /** |
||
353 | * Ensures invoice data remains anonymized. |
||
354 | * |
||
355 | * @since 2.8.22 |
||
356 | * @param int $user_id The ID of the user whose invoices should be checked. |
||
357 | * @param string $action The action to perform (anonymize or delete). |
||
358 | * @return bool True on success, false on failure. |
||
359 | */ |
||
360 | public function ensure_invoice_anonymization( $user_id, $action = 'anonymize' ) { |
||
361 | $invoices = wpinv_get_invoices( array( 'user' => $user_id ) ); |
||
362 | |||
363 | /** |
||
364 | * Filters the invoice meta fields to be anonymized. |
||
365 | * |
||
366 | * @since 2.8.22 |
||
367 | * @param array $inv_meta_data The meta fields to be anonymized. |
||
368 | * @param int $user_id The ID of the user being processed. |
||
369 | */ |
||
370 | $inv_meta_data = apply_filters( 'wpinv_invoice_meta_data_to_anonymize', array(), $user_id ); |
||
371 | |||
372 | foreach ( $invoices->invoices as $invoice ) { |
||
373 | foreach ( $inv_meta_data as $meta_key ) { |
||
374 | delete_post_meta( $invoice->get_id(), $meta_key ); |
||
375 | } |
||
376 | |||
377 | if ( 'anonymize' === $action ) { |
||
378 | $hashed_inv_email = $this->hash_email( $invoice->get_email() ); |
||
379 | $hashed_inv_email_cc = $this->hash_email( $invoice->get_email_cc() ); |
||
380 | |||
381 | $invoice->set_email( $hashed_inv_email ); |
||
382 | $invoice->set_email_cc( $hashed_inv_email_cc ); |
||
383 | $invoice->set_phone( '' ); |
||
384 | $invoice->set_ip( $this->anonymize_data( $invoice->get_ip() ) ); |
||
385 | $invoice->set_is_anonymized( 1 ); |
||
386 | |||
387 | /** |
||
388 | * Fires when anonymizing additional invoice data. |
||
389 | * |
||
390 | * @since 2.8.22 |
||
391 | * @param WPInv_Invoice $invoice The invoice being anonymized. |
||
392 | * @param string $action The action being performed (anonymize or delete). |
||
393 | */ |
||
394 | do_action( 'wpinv_anonymize_invoice_data', $invoice, $action ); |
||
395 | |||
396 | $invoice->save(); |
||
397 | } else { |
||
398 | $invoice->delete(); |
||
399 | } |
||
400 | } |
||
401 | |||
402 | return $this->log_deletion_action( $user_id, $invoices->invoices, $action ); |
||
403 | } |
||
404 | |||
405 | /** |
||
406 | * Logs the deletion or anonymization action for a user and their invoices. |
||
407 | * |
||
408 | * @since 2.8.22 |
||
409 | * @param int $user_id The ID of the user being processed. |
||
410 | * @param array $invoices An array of invoice objects being processed. |
||
411 | * @param string $action The action being performed (anonymize or delete). |
||
412 | * @return bool True on success, false on failure. |
||
413 | */ |
||
414 | private function log_deletion_action( $user_id, $invoices, $action ) { |
||
415 | global $wpdb; |
||
416 | |||
417 | $table_name = $wpdb->prefix . 'getpaid_anonymization_logs'; |
||
418 | $user_data = get_userdata( $user_id ); |
||
419 | |||
420 | $additional_info = array( |
||
421 | 'Username' => $user_data ? $user_data->user_login : 'N/A', |
||
422 | 'User Roles' => $user_data ? implode(', ', $user_data->roles) : 'N/A', |
||
423 | 'Email' => $user_data ? $user_data->user_email : 'N/A', |
||
424 | 'First Name' => $user_data ? $user_data->first_name : 'N/A', |
||
425 | 'Last Name' => $user_data ? $user_data->last_name : 'N/A', |
||
426 | 'Registered' => $user_data ? $user_data->user_registered : 'N/A', |
||
427 | 'invoice_count' => count( $invoices ), |
||
428 | ); |
||
429 | |||
430 | |||
431 | /** |
||
432 | * Filters the additional info before logging. |
||
433 | * |
||
434 | * @since 2.8.22 |
||
435 | * @param array $additional_info The additional information to be logged. |
||
436 | * @param int $user_id The ID of the user being processed. |
||
437 | * @param array $invoices The invoices being processed. |
||
438 | * @param string $action The action being performed (anonymize or delete). |
||
439 | */ |
||
440 | $additional_info = apply_filters( 'wpinv_anonymization_log_additional_info', $additional_info, $user_id, $invoices, $action ); |
||
441 | |||
442 | $data = array( |
||
443 | 'user_id' => $user_id, |
||
444 | 'action' => sanitize_text_field( $action ), |
||
445 | 'data_type' => 'User Invoices', |
||
446 | 'timestamp' => current_time( 'mysql' ), |
||
447 | 'additional_info' => wp_json_encode( $additional_info ), |
||
448 | ); |
||
449 | |||
450 | $format = array( |
||
451 | '%d', // user_id |
||
452 | '%s', // action |
||
453 | '%s', // data_type |
||
454 | '%s', // timestamp |
||
455 | '%s', // additional_info |
||
456 | ); |
||
457 | |||
458 | if ( ! empty( $user_id ) && ! empty( $action ) ) { |
||
459 | $result = $wpdb->update( |
||
460 | $table_name, |
||
461 | $data, |
||
462 | array( |
||
463 | 'user_id' => (int) $user_id, |
||
464 | 'action' => sanitize_text_field( $action ), |
||
465 | ), |
||
466 | $format, |
||
467 | array( '%d', '%s' ) |
||
468 | ); |
||
469 | |||
470 | if ( false === $result ) { |
||
471 | // If update fails, try to insert. |
||
472 | $result = $wpdb->insert( $table_name, $data, $format ); |
||
473 | } |
||
474 | |||
475 | if ( false === $result ) { |
||
476 | wpinv_error_log( sprintf( 'Failed to log anonymization action for user ID: %d. Error: %s', $user_id, $wpdb->last_error ) ); |
||
477 | return false; |
||
478 | } |
||
479 | } |
||
480 | |||
481 | /** |
||
482 | * Fires after logging a deletion or anonymization action. |
||
483 | * |
||
484 | * @since 2.8.22 |
||
485 | * @param int $user_id The ID of the user being processed. |
||
486 | * @param array $invoices An array of invoice objects being processed. |
||
487 | * @param string $action The action being performed (anonymize or delete). |
||
488 | * @param array $data The data that was inserted into the log. |
||
489 | */ |
||
490 | do_action( 'wpinv_after_log_deletion_action', $user_id, $invoices, $action, $data ); |
||
491 | |||
492 | return true; |
||
493 | } |
||
494 | |||
495 | /** |
||
496 | * Handles GDPR personal data erasure request. |
||
497 | * |
||
498 | * @since 2.8.22 |
||
499 | * @param array $response The default response. |
||
500 | * @param int $user_id The ID of the user being erased. |
||
501 | * @return array The modified response. |
||
502 | */ |
||
503 | public function handle_erasure_request( $response, $user_id ) { |
||
504 | if ( $this->has_active_subscriptions( $user_id ) ) { |
||
505 | $response['messages'][] = esc_html__( 'User has active subscriptions. Data cannot be erased at this time.', 'invoicing' ); |
||
506 | $response['items_removed'] = false; |
||
507 | } elseif ( $this->has_paid_invoices( $user_id ) ) { |
||
508 | $retention_method = wpinv_get_option( 'data_retention_method', 'anonymize' ); |
||
509 | if ( 'anonymize' === $retention_method ) { |
||
510 | $this->anonymize_user_data( $user_id ); |
||
511 | $response['messages'][] = esc_html__( 'User data has been anonymized due to existing paid invoices.', 'invoicing' ); |
||
512 | $response['items_removed'] = false; |
||
513 | $response['items_retained'] = true; |
||
514 | } else { |
||
515 | $this->delete_user_data( $user_id ); |
||
516 | $response['messages'][] = esc_html__( 'User data has been deleted.', 'invoicing' ); |
||
517 | $response['items_removed'] = true; |
||
518 | $response['items_retained'] = false; |
||
519 | } |
||
520 | } |
||
521 | |||
522 | return $response; |
||
523 | } |
||
524 | |||
525 | /** |
||
526 | * Hashes email for anonymization. |
||
527 | * |
||
528 | * @since 2.8.22 |
||
529 | * @param string $email The email to hash. |
||
530 | * @return string The hashed email. |
||
531 | */ |
||
532 | private function hash_email( $email ) { |
||
533 | $site_url = get_site_url(); |
||
534 | $domain = wp_parse_url( $site_url, PHP_URL_HOST ); |
||
535 | |||
536 | if ( empty( $domain ) ) { |
||
537 | return $email; |
||
538 | } |
||
539 | |||
540 | $clean_email = sanitize_email( strtolower( trim( $email ) ) ); |
||
541 | $hash = wp_hash( $clean_email ); |
||
542 | $hash = substr( $hash, 0, 20 ); |
||
543 | $anonymized_email = sprintf( '%s@%s', $hash, $domain ); |
||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
544 | |||
545 | /** |
||
546 | * Filters the anonymized email before returning. |
||
547 | * |
||
548 | * @since 2.8.22 |
||
549 | * @param string $anonymized_email The anonymized email address. |
||
550 | * @param string $email The original email address. |
||
551 | */ |
||
552 | return apply_filters( 'wpinv_anonymized_email', $anonymized_email, $email ); |
||
553 | } |
||
554 | |||
555 | /** |
||
556 | * Anonymizes a given piece of data. |
||
557 | * |
||
558 | * @since 2.8.22 |
||
559 | * @param string $data The data to anonymize. |
||
560 | * @return string The anonymized data. |
||
561 | */ |
||
562 | private function anonymize_data( $data ) { |
||
563 | if ( empty( $data ) ) { |
||
564 | return ''; |
||
565 | } |
||
566 | |||
567 | return wp_privacy_anonymize_data( 'text', $data ); |
||
568 | } |
||
569 | |||
570 | /** |
||
571 | * Performs data retention cleanup. |
||
572 | * |
||
573 | * This method is responsible for cleaning up anonymized user data |
||
574 | * that has exceeded the retention period. |
||
575 | * |
||
576 | * @since 2.8.22 |
||
577 | */ |
||
578 | public function perform_data_retention_cleanup() { |
||
579 | global $wpdb; |
||
580 | |||
581 | $retention_period = wpinv_get_option( 'data_retention_period', '3650' ); |
||
582 | |||
583 | // If retention period is set to 'never', exit the function. |
||
584 | if ( 'never' === $retention_period ) { |
||
585 | return; |
||
586 | } |
||
587 | |||
588 | $customers_table = $wpdb->prefix . 'getpaid_customers'; |
||
589 | |||
590 | // Calculate the cutoff date for data retention. |
||
591 | $cutoff_date = gmdate( 'Y-m-d', strtotime( "-$retention_period days" ) ); |
||
592 | |||
593 | $expired_records = $wpdb->get_results( |
||
594 | $wpdb->prepare( |
||
595 | "SELECT * FROM $customers_table WHERE deletion_date < %s AND is_anonymized = 1", |
||
596 | $cutoff_date |
||
597 | ) |
||
598 | ); |
||
599 | |||
600 | /** |
||
601 | * Fires before the data retention cleanup process begins. |
||
602 | * |
||
603 | * @since 2.8.22 |
||
604 | * @param array $expired_records Array of customer records to be processed. |
||
605 | */ |
||
606 | do_action( 'getpaid_data_retention_before_cleanup', $expired_records ); |
||
607 | |||
608 | if ( ! empty( $expired_records ) ) { |
||
609 | // Disable our custom user deletion handling. |
||
610 | $this->handle_user_deletion = false; |
||
611 | |||
612 | foreach ( $expired_records as $record ) { |
||
613 | // Delete associated invoices. |
||
614 | $this->ensure_invoice_anonymization( (int) $record->user_id, 'delete' ); |
||
615 | |||
616 | // Delete the user. |
||
617 | wp_delete_user( (int) $record->user_id ); |
||
618 | |||
619 | /** |
||
620 | * Fires after processing each expired record during cleanup. |
||
621 | * |
||
622 | * @since 2.8.22 |
||
623 | * @param object $record The customer record being processed. |
||
624 | */ |
||
625 | do_action( 'getpaid_data_retention_process_record', $record ); |
||
626 | } |
||
627 | |||
628 | // Re-enable our custom user deletion handling. |
||
629 | $this->handle_user_deletion = true; |
||
630 | |||
631 | /** |
||
632 | * Fires after the data retention cleanup process is complete. |
||
633 | * |
||
634 | * @since 2.8.22 |
||
635 | * @param array $expired_records Array of customer records that were processed. |
||
636 | */ |
||
637 | do_action( 'getpaid_data_retention_after_cleanup', $expired_records ); |
||
638 | } |
||
639 | |||
640 | /** |
||
641 | * Fires after the data retention cleanup attempt, regardless of whether records were processed. |
||
642 | * |
||
643 | * @since 2.8.22 |
||
644 | * @param int $retention_period The current retention period in years. |
||
645 | * @param string $cutoff_date The cutoff date used for identifying expired records. |
||
646 | */ |
||
647 | do_action( 'getpaid_data_retention_cleanup_complete', $retention_period, $cutoff_date ); |
||
648 | } |
||
649 | |||
650 | /** |
||
651 | * Ends the user's current session. |
||
652 | * |
||
653 | * @since 2.8.22 |
||
654 | */ |
||
655 | private function end_user_session() { |
||
656 | wp_logout(); |
||
657 | |||
658 | // Redirect after deletion. |
||
659 | $redirect_page = home_url(); |
||
660 | wp_safe_redirect( $redirect_page ); |
||
661 | exit(); |
||
0 ignored issues
–
show
|
|||
662 | } |
||
663 | } |