Erase Personal Data, by the consent IDs in the user's meta, * and then the meta entries of the erased IDs, so that nothing links the user to a decision any more. */ final class Eraser { /** * Log storage. * * @var LogRepository */ private LogRepository $log; /** * Constructor. * * @param LogRepository $log Log storage. */ public function __construct( LogRepository $log ) { $this->log = $log; } /** * Hook the eraser. */ public function register(): void { add_filter( 'wp_privacy_personal_data_erasers', array( $this, 'add' ) ); } /** * Add the eraser to core's list. * * @param mixed $erasers Registered erasers. * @return array */ public function add( $erasers ): array { $erasers = is_array( $erasers ) ? $erasers : array(); $erasers[] = array( 'eraser_friendly_name' => __( 'Consent log', 'consentfold' ), 'callback' => array( $this, 'erase' ), ); return $erasers; } /** * Erase the records of the user with an email address. * * @param string $email Email address. * @return array{items_removed: bool, items_retained: bool, messages: list, done: bool} */ public function erase( string $email ): array { $removed = false; $retained = false; $messages = array(); $user = get_user_by( 'email', $email ); if ( $user instanceof \WP_User ) { $erased = array(); foreach ( UserConsentIds::get( $user->ID ) as $consent_id ) { $removed = $this->log->delete_by_consent_id( $consent_id ) > 0 || $removed; // A failed delete reports no rows, like an empty one: look at what is left before letting the link go. if ( array() === $this->log->history( $consent_id ) ) { $erased[] = $consent_id; } else { $retained = true; } } UserConsentIds::forget( $user->ID, $erased ); if ( $retained ) { $messages[] = __( 'Some consent log records could not be deleted.', 'consentfold' ); } } return array( 'items_removed' => $removed, 'items_retained' => $retained, 'messages' => $messages, 'done' => true, ); } }