Feature: Cleanup plugin data on uninstall via user opt in#692
Feature: Cleanup plugin data on uninstall via user opt in#692hbhalodia wants to merge 3 commits into
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
| ) | ||
| ); | ||
|
|
||
| register_setting( |
There was a problem hiding this comment.
So I know this was mentioned in the attached Issue but not sure I agree with having a setting for this. This seems like a lot to ask the average user to have to decide if they want this checked or not (most won't fully understand what it means). I'm open to differing opinions here but I'd suggest we remove the setting and just have the data deletion happen by default. cc / @jeffpaul
There was a problem hiding this comment.
Also fine to avoid an additional setting here as well and default to data deletion.
There was a problem hiding this comment.
Hi @dkotter @jeffpaul, In my opinion, we should go with what other plugins do mostly. As I have from 10 plugins, almost 8-9 plugins provide the an user option to cleanup the data in either way.
Either they provide the settings or when deactivate/uninstall they provide a modal popup to ask user choice to retain/remove the data.
In any how, we should respect the user's choice if they want to cleanup or not.
If we are not adding this, we can update this choice when user try to uninstall the plugin?
What?
Closes #690
Why?
How?
Use of AI Tools
Testing Instructions
wpai_*options or check for tablewp_wpai_request_logs. This should not exists.Screenshots or screencast
Screen.Recording.2026-06-10.at.12.26.58.PM.mov
Changelog Entry
AI Summary
Summary
Implements full data cleanup when the plugin is deleted, addressing #690 (no
uninstall.php, custom table andwpai_*options left behind). Cleanup is opt-in and destructive, so it only runs when the site explicitly enables a new "Remove all plugin data on uninstall" setting. Deletion happens on uninstall only — never on deactivation.Behavior
{$wpdb->prefix}wpai_request_logs.wpai_*options._transient_wpai_*/_transient_timeout_wpai_*and their site-transient equivalents).wpai_request_logs_cleanupcron event.get_sites()+switch_to_blog()), and the opt-in is evaluated per site so each site controls its own data.uninstall.php(the WordPress-recommended approach) rather thanregister_uninstall_hook(), keeping the logic out of the normal runtime path.Changes
Backend (PHP)
uninstall.php(new) — plugin-root uninstall entry point. Guards onWP_UNINSTALL_PLUGIN, loads only the autoloader (deliberately notai.php, to avoid bootstrappingMain), and callsUninstall::uninstall().includes/Admin/Uninstall.php(new) — the cleanup service:uninstall()— multisite-aware orchestration (loops sites; single-site otherwise).maybe_clean_current_site()— no-ops unlesswpai_remove_data_on_uninstallistruefor the current site.wpai_*options (viaesc_like+LIKE), deletes plugin transients, and clears the request-log cleanup cron.OPTION_REMOVE_DATA('wpai_remove_data_on_uninstall') as the single source of truth for the option key.includes/Settings/Settings_Registration.php— registerswpai_remove_data_on_uninstall(boolean, defaultfalse,rest_sanitize_boolean,show_in_rest: true) under the existingai_experimentsoption group, so the React UI can read/write it via the coreroot/siteentity.Frontend (React / TypeScript)
routes/ai-home/hooks/use-data-removal-setting.ts(new) —useDataRemovalSetting()returning{ enabled, update, isSaving }, mirroring theuse-developer-feature-settingspattern. Reads the value from the editedroot/siterecord and persists via__experimentalSaveSpecifiedEntityEdits, with success/error snackbars:routes/ai-home/components/DataRemovalSetting.tsx(new) — presentational component consuming the hook: a@wordpress/uiwarningNoticedescribing the consequences, stacked above aToggleControl.routes/ai-home/stage.tsx— integrates the control as a DataForm collapsible card section (layout: { type: 'card', withHeader: true, isOpened: true, isCollapsible: true }, label "Data"), consistent with the existing experiment-group accordions. The field is a presentational pseudo-field (same approach as the existingsection-actions-*fields), rendered last.Tests
tests/Integration/Includes/Admin/UninstallTest.php(new):test_uninstall_removes_data_when_opted_in— seeds the table +wpai_*options + a scheduled event, opts in, asserts all are removed and a non-wpai_option is preserved.test_uninstall_preserves_data_when_not_opted_in— asserts data is untouched when the opt-in is off.uninstall()since the bulkDELETEruns via direct SQL (irrelevant during a real uninstall request, but the in-requestalloptionscache would otherwise return stale values).Implementation notes
uninstall.phpperforms deletion, so deactivating remains fully reversible.LIKE 'wpai\_%'(escaped viaesc_like) so dynamic per-feature options (wpai_feature_{id}_enabled,wpai_feature_{id}_field_developer, etc.) are covered without enumerating them.handleChange) so the success message reads cleanly; routing it throughbuildToggleMessagewould have shown the raw option key.Testing instructions
wp_wpai_request_logsandwpai_*options remain.wpai_*options, transients, and thewpai_request_logs_cleanupcron are all removed.