Skip to content

Clean up the user meta of deleted users daily - #225

Merged
cs1m0n merged 2 commits into
masterfrom
feature/cleanup-meta-of-deleted-users
Oct 13, 2026
Merged

cs1m0n merged 2 commits into
masterfrom
feature/cleanup-meta-of-deleted-users

Conversation

@cs1m0n

@cs1m0n cs1m0n commented Oct 13, 2026

Copy link
Copy Markdown
Member

Older versions of Delete subscribers removed only the users row and the role row (wp_capabilities) of each subscriber. Sites that used it still have the rest of those users' meta: names, nicknames, session tokens, preferences and plugin data.

Changes

  • The daily cleanup task (BCC_Login_Cleanup, from Clean up data left behind by the old OpenID Connect Generic plugin #224) now also deletes the meta of users that no longer exist, through a new delete_orphaned_user_meta().
  • Delete subscribers uses the same function, so there's one implementation.
  • The button's notice no longer says "All subscribers were successfully deleted." when that step failed. A partly failed meta cleanup now says "Not all user meta of deleted users could be deleted."

Why the task waits a day

A database import (restore, push between environments) loads wp_usermeta before wp_users, so while it runs, every user looks deleted. In tests, a version that deleted in a single run removed every user's meta, roles included, when it ran during an import without table locks.

So the task only deletes the meta of users that were already missing at its previous run, at least 12 hours earlier. An import lasts minutes, and WP-Cron running the task twice in a row happens within seconds. Leftovers are removed on the second daily run after the update. The button still deletes immediately.

Notes for review

  • The lookup is a non-locking read. Deletes run in batches of 500 users, so only those users' rows are locked, for one short statement each, instead of one DELETE … LEFT JOIN over the whole table.
  • user_id 0 rows are left alone, because WordPress never stores meta for user 0.
  • The ids found are kept in the option bcc_login_missing_users, which isn't autoloaded.
  • Deleted users are also removed from the object cache, so a persistent cache can't still serve them.
  • Known gap: the next day's run could land in the seconds between wp_usermeta and wp_users loading, during an import of an older database in which yesterday's leftovers are still real users. Those users then lose their meta. Closing this would need a role-row check, which became very slow right after an import (a full scan per user while InnoDB statistics are empty).

Testing

Throwaway WordPress 7.0.2 / PHP 7.4 / MariaDB 10.5 with 3,000 users and about 65,000 meta rows. The data included 500 users' leftovers, users without a role row, and users whose role row is stored last.

  • The task ran mid-import (first push and same-site restore), plus repeated runs seconds apart. These deleted nothing.
  • The next day's run removed all leftover rows. No real user lost a row and no role was lost.
  • 3 imports of a dump without table locks, each raced by about 45 runs: nothing lost.
  • The button deleted all subscribers and their meta in one click, with the right notice.
  • The lookup takes 10 ms at 65k rows and 20 ms at 131k, also with a forced full scan.
  • PHPStan with the CI config passes, and there are no PHP notices.

🤖 Generated with Claude Code

Older versions of "Delete subscribers" removed only the users row and the
role row of each subscriber, so sites that used it still have the rest of
those users' meta, including their names and session tokens.

The daily cleanup task now also deletes the meta of users that no longer
exist. It only deletes users that were already missing at its previous
run, at least 12 hours earlier: a database import loads wp_usermeta
before wp_users, so while one is running every user seems to be missing.
The "Delete subscribers" button uses the same function and still deletes
immediately. Its notice no longer reports success when deleting the
subscribers failed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cs1m0n
cs1m0n requested a balanced review from Copilot October 13, 2026 04:27
@cs1m0n cs1m0n self-assigned this Oct 13, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Snapshot write failures and incomplete cache invalidation can leave cleanup state or deleted users stale.

2 open findings
What changed in this PR

Adds delayed daily cleanup of orphaned user metadata and reuses it for subscriber deletion.

Changes:

  • Tracks missing users for at least 12 hours before cleanup.
  • Deletes orphaned metadata in batches and clears caches.
  • Improves maintenance-action failure notices.
File Description
class-bcc-login-settings.php Reuses cleanup logic and improves notices.
class-bcc-login-cleanup.php Adds delayed, batched orphan-meta cleanup.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread plugins/bcc-login/includes/class-bcc-login-cleanup.php Outdated
Comment thread plugins/bcc-login/includes/class-bcc-login-settings.php
- The daily cleanup only deletes once its list of missing users is
  saved, so the next run never compares against an older list.
- "Delete subscribers" removes the deleted subscribers from the object
  cache directly. The leftover cleanup only finds users that still have
  meta, which isn't the case if the role was their only meta row.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cs1m0n
cs1m0n merged commit 9f2cc29 into master Oct 13, 2026
4 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants