Skip to content

Privacy ​

Export and erase a person's data on request, as WordPress's Tools → Export and Erase Personal Data: confirmed by email, across every module.

kitloom/privacy · admins: kitloom/privacy-filament, kitloom/privacy-nova

Video lessons ​

Recorded in the Filament admin; the Nova admin works the same way.

Erase personal data
Export personal data

When someone asks what your site keeps about them, or asks you to forget them, this module answers as WordPress's Tools → Export Personal Data and Erase Personal Data do: you add the request, the person confirms it from an email, and the site gathers — or erases — what every module keeps about their email address. The admin is kitloom/privacy-filament or kitloom/privacy-nova, under Privacy.

How a request goes ​

  1. Add request. Enter the person's email address or user name. Keep "Send a confirmation email" on unless you know it was them — whoever writes to you in someone's name should not get their data.
  2. The person confirms. The email's link opens a page with one button; the link works for a day (confirm_hours). You get an email at the site's administration address (Settings → General) when they confirm. A request nobody confirmed in time is marked Failed by the daily cleanup.
  3. Export or erase.
    • Export Personal Data → Send export link: the archive is made and the person gets a download link that works for 3 days (exports.days); the request is completed once the email is out. Download personal data makes the same archive for you, to send another way; the request stays open until you mark it completed.
    • The archive is made on the queue, page by page, as WordPress's screen asks every module one page at a time: a shop with years of orders does not hold your click until it times out. Meanwhile the row says The archive is being prepared; the link is mailed when it is made, and Download the archive hands you the last one made. On the sync queue (no worker) it is all done before the page comes back. An archive whose making failed may be asked for again; one that never finished counts as lost after a day.
    • Erase Personal Data → Erase personal data: every module erases or makes anonymous what it keeps, and you see how many records went and what was kept, and why. The person is told by email. A request still waiting can be erased by force.
  4. Completed. "Mark as completed" closes a request handled otherwise; "Remove request" deletes it and its archive — the person's data stays as it is.

The archive is a zip with a page to read (index.html) and the same as data (export.json).

What is exported and erased ​

DataExportErase
The account (WordPress's user)user name, email, website, registration date, names, biography— not erased: if they asked to be forgotten, delete the user under Users, as in WordPress
Commentsauthor, email, website, IP address, browser, date, text, the postthe text stays under "Anonymous" — in the site's language (app.locale), whoever runs the erasure; email, website, browser and user go; the IP address keeps only its network
Other moduleswhat each module declares — orders, payments, form messages, bookings…what each module may drop; what the law requires it to keep (orders and payments for the accounts) stays, with its reason in the report

A module adds its own data by tagging a Kitloom\WpSchema\Contracts\PersonalDataExporter and a PersonalDataEraser (kitloom/wp-schema); nothing here names a module. An exporter answers page by page: each page is asked on the queue, so a page should be a few hundred records, not all of them.

The users' exporter is keyed kitloom-user, and the comments' exporter and eraser kitloom-comments, though they live here and not in kitloom/comments: comments are WordPress's own and are handled with or without that module. A key is a stable id, not a package name: two exporters of one key are refused, so a module that brings its own exporter of comments picks another key — or the application turns these off with core_data.register.

AI agents ​

With kitloom/ai installed, an agent whose user may export personal data lists the requests of the kinds the user handles (privacy_requests_list), adds one for an address or a user name (privacy_request_create) and marks one completed (privacy_request_complete). An agent's request always sends the confirmation email: it knows of the person only from what it read. Exporting and erasing stay with a person in the admin — one sends the data out, the other cannot be undone. kitloom-privacy.ai.register false — no request tools.

Where it lives ​

WhatWhere
Requestsrows of posts with post_type = 'user_request', as WordPress keeps them: the address in post_title, the action (export_personal_data, remove_personal_data) in post_name, the status request-pending, request-confirmed, request-failed, request-completed; confirmed and completed times in post meta. Requests made in WordPress before the move are the same rows.
Archivesthe private disk exports.disk (local), folder privacy-exports/; deleted after exports.days. While one is made, what the modules answered waits in the request's meta (_export_data_grouped, as WordPress names it) and goes with the archive
Pages of the emails' links/privacy/confirm/{id}/{key} and the signed /privacy/export/{id}
Cleanupphp artisan privacy:prune, daily through the scheduler
CapabilitiesWordPress's export_others_personal_data and erase_others_personal_data, administrators' by default
Configurationconfig/kitloom-privacy.php

One server or several ​

local keeps the archives in storage/app/private of the server: right for one server. Where the disk is reset on every deploy, or each instance has its own — Laravel Cloud, DigitalOcean App Platform, several servers behind a load balancer — the queue's worker makes the archive on its instance and the emailed link is opened on another, or after the next deploy, and the person reads "The file is no longer there". There, put the archives on a private bucket: a disk of its own in config/filesystems.php (S3, R2, Spaces — not public), named in PRIVACY_EXPORTS_DISK.

With kitloom/health installed, Site Health has a check of the module's own, Personal data archives (privacy_exports_disk): a warning when the archives are on a disk of the local driver. It is asked only where Site Health knows the host's disk does not last — Laravel Cloud, or HEALTH_EPHEMERAL_DISK=true — and not on one server. kitloom-privacy.health.register false — no check.

What the application overrides ​

  • The times, the disk and the address prefix: config/kitloom-privacy.php (php artisan vendor:publish --tag=kitloom-privacy-config), or PRIVACY_CONFIRM_HOURS, PRIVACY_EXPORT_DAYS, PRIVACY_EXPORTS_DISK.
  • Users and comments as WordPress handles them: core_data.register set to false leaves them to a module of the application's own.
  • The admin sections: kitloom-privacy.filament.register and kitloom-privacy.nova.register.

Tests ​

From the application that installs the package: php vendor/bin/phpunit --testsuite Privacy.

kitloom — modules and themes for Laravel.
Pricing · Services · License · Refunds · Privacy · Community · [email protected]