flarum/gdpr
A Flarum extension for GDPR compliance, giving users tools to export their personal data and request account deletion or anonymization, with admin controls to manage privacy, consent, and data-handling requests.
composer require flarum/gdpr
php flarum migrate
php flarum cache:clear
Then enable GDPR in Admin → Extensions and reload the admin UI. The extension registers its settings under the admin Privacy/GDPR section and adds permissions (flarum-gdpr.deleteOwnAccount, flarum-gdpr.downloadOwnData — check the exact keys in src/), so a freshly enabled install does nothing user-facing until you grant those to the Members group.
Where to look first, in order:
vendor/flarum/gdpr/extend.php — the whole public surface (routes, permissions, settings, frontend, locales) is registered here. Read it before anything else.vendor/flarum/gdpr/src/Data/ (or src/Data/Type/) — the export/anonymization "type" classes. Each one knows how to extract a slice of a user's data and how to scrub it. This is the directory you will most often need to extend.vendor/flarum/gdpr/src/Api/ and src/Controller/ — the export and account-deletion endpoints, including auth/confirmation flow.vendor/flarum/gdpr/js/src/forum/ — the user-facing "Download my data" / "Delete my account" UI in Settings.vendor/flarum/gdpr/locale/en.yml — every string, useful for understanding the intended workflow before reading PHP.Note this repository is a read-only subtree split; the code you install is a mirror of a directory inside the main Flarum extensions monorepo. Do not file issues or PRs here.
First use case: log in as a regular member, open Settings → Privacy, click Download my data, and watch the queue/logs. If nothing happens, you have found the single most common setup failure (see Gotchas) — fix that before configuring anything else.
Configure via the admin panel, not code. All behaviour is DB-backed settings (allow export, allow self-deletion, anonymize posts vs. delete them, confirmation requirements). For reproducible environments, set them in a seeder/migration using Flarum\Settings\SettingsRepositoryInterface::set() rather than clicking through admin, and document the keys you rely on.
Add your own export data type. If your extension stores user-linked data (custom profile fields, orders, uploaded files), GDPR export is incomplete until you register a type. The extension ships an extender for this — in current versions it is consumed in extend.php alongside the built-in types:
use Flarum\Gdpr\Extend\UserData;
return [
(new UserData)->addType(MyPlugin\UserData\Orders::class),
];
Your class typically extends the package's abstract data type and implements an export method (returning an array/iterable serialized into the archive) and, where applicable, an anonymization method. Match the signatures of the built-in classes in src/Data/ rather than guessing.
Hook account deletion for side effects. Subscribe to Flarum core's user lifecycle events (Flarum\User\Event\Deleting, Deleted) in your own extend.php to purge rows the extension doesn't know about. Do the cleanup in Deleting if you want it to run inside the same transaction, Deleted if best-effort is acceptable.
Anonymization means "keep the content, drop the identity." If you must preserve discussion continuity (SEO, moderation history), enable anonymization instead of hard deletion, and make sure your custom tables follow the same rule: null or hash the user id, keep the row. Decide this per-table deliberately — a half-anonymized user is a compliance problem.
Queue everything heavy. Exports and bulk anonymization should run on a worker: run php flarum queue:work under supervisor/systemd, and schedule php flarum schedule:run via cron so any cleanup commands the extension registers actually fire. Verify with php flarum queue:work --once after a test export.
Frontend overrides. If you need to change the privacy settings UI, use a JS override on the extension's settings component in your own extend.php rather than editing vendor files; the subtree split means your edits vanish on the next composer update.
Test in the integration harness. Flarum's Flarum\Testing\integration\TestCase with an in-memory SQLite DB works fine here; enable the extension in $this->extension('flarum-gdpr'), seed a user with posts, hit the export endpoint, and assert the archive contains each registered type. Also assert that a non-permitted user gets a 403 — permission regressions are the easiest thing to ship broken.
vcs composer entry."flarum/gdpr": "^1.0") and confirm the tag exists with composer show flarum/gdpr --all; don't let a floating constraint pull something odd into production.php flarum queue:work --once and the jobs/failed_jobs tables first, always.log mailer, and remember the archive may have expired by the time you click it.local disk that isn't writable by the PHP/queue user produces failures only at generation time, not at request time. Check storage/ permissions and disk config before debugging the extension.deleteOwnAccount/downloadOwnData to Members makes the feature look broken. Grant, then clear cache; permission changes are cached.php flarum cache:clear after every settings, locale, or permission change — and after composer update, since the extension's frontend assets are compiled into the core bundle.locale/. If you need jurisdiction-specific wording (e.g. a different retention statement), override the keys from your own extension's locale files rather than editing vendor YAML.vendor/ do not.How can I help you explore Laravel packages today?