Make WordPress Core

Opened 14 years ago

Last modified 4 weeks ago

#20578 reviewing enhancement

Allow users to delete a plugin without uninstalling

Reported by: scribu Owned by:
Priority: normal Milestone: Future Release
Component: Plugins Version:
Severity: normal Keywords: ux-feedback ui-feedback has-screenshots needs-patch
Cc: Focuses: ui

Description

Sometimes, a user may need to delete plugin files without deleting all the plugin data.

Attachments (6)

20578-delete-files-or-both.patch​ (4.5 KB ) - added by kurtpayne 14 years ago.
Separate buttons for delete files and delete files + data
Screen Shot 2014-01-26 at 10.18.28 PM.png​ (51.1 KB ) - added by helen 13 years ago.
After 20578-delete-files-or-both.patch - Jetpack apparently includes another plugin, hence the multiple plugins.
20578.diff​ (7.1 KB ) - added by swissspidy 11 years ago.
20578.2.diff​ (8.3 KB ) - added by swissspidy 11 years ago.
20578.3.diff​ (8.6 KB ) - added by swissspidy 10 years ago.
Delete-plugin-along-with-data.jpg​ (25.0 KB ) - added by paaljoachim 5 years ago.
Example mockup for including a checkbox for deleting plugin data.

Download all attachments as: .zip

Change History (60)

#1 follow-up: @scribu
14 years ago

​Nacin say:

I think it would be good for the uninstall confirmation page to be a choice between "Delete Files and Data" vs "Delete Files". The plugin's uninstall routine would only be fired if the "and Data" was chosen.

#2 @scribu
14 years ago

One scenario: Alice wants to install the development version of a plugin, to test a certain bug fix.

She downloads the zip file. To install it, she first has to remove the existing version.

But, since she has valuable data stored by that plugin, she will have to use FTP to delete the current plugin version, instead of just using wp-admin.

#3 in reply to: ↑ 1 ; follow-up: @helenyhou
14 years ago

Replying to scribu:

​Nacin say:

I think it would be good for the uninstall confirmation page to be a choice between "Delete Files and Data" vs "Delete Files". The plugin's uninstall routine would only be fired if the "and Data" was chosen.

Yes, please!

#4 @wpsmith
14 years ago

  • Cc travis@… added

Also in light of the previous ticket, it would be good to have a confirmation screen confirming deletion of plugin v. deletion + data deletion.

#5 @lightningspirit
14 years ago

+1 I suggest to use the current UI and add a new button labeled "Yes, delete both files and data" but perhaps a new design for this confirmation page may improve what we have now.

#6 @knutsp
14 years ago

  • Cc knut@… added

+1 Sometimes a plugin gets partly (un)installed during automatic update due to failing to delete the plugin folder (in use error) or a request timeout. To be able to reinstall a plugin you then must delete it, either trough FTP or the proposed delete without uninstalling action.

Plugins page should als list folders without a valid plugin inside (empty or not) and offer to delete that folder and contents. Separate ticket for this?

#7 @scribu
14 years ago

Plugins page should als list folders without a valid plugin inside (empty or not) and offer to delete that folder and contents. Separate ticket for this?

Yes, please.

#8 @ryanduff
14 years ago

  • Cc ryan@… added

#9 @kurtpayne
14 years ago

  • Cc kpayne@… added

#10 @kirasong
14 years ago

  • Cc mike.schroder@… added

@kurtpayne
14 years ago

Separate buttons for delete files and delete files + data

#11 in reply to: ↑ 3 @kurtpayne
14 years ago

  • Keywords has-patch dev-feedback added

Replying to helenyhou:

Replying to scribu:

​Nacin say:

I think it would be good for the uninstall confirmation page to be a choice between "Delete Files and Data" vs "Delete Files". The plugin's uninstall routine would only be fired if the "and Data" was chosen.

Yes, please!

20578-delete-files-or-both.patch​ is a first attempt at this. It needs some language rework, and maybe a UX update (someone will be confused by 3 buttons). And having duplicate forms for the presentation logic feels clunky.

#12 @helen
13 years ago

  • Focuses ui added
  • Keywords needs-ui removed

Cool, patch still applies. Thoughts on the UI/UX front:

  • The return to plugin list button really should be a link, and should be now, too.
  • You are correct, some language needs reworking.

Will upload a screenshot momentarily for convenient discussion without having to apply the patch.

@helen
13 years ago

After 20578-delete-files-or-both.patch - Jetpack apparently includes another plugin, hence the multiple plugins.

#13 @celloexpressions
13 years ago

Could we make one of the buttons primary? Three flat options is tough, even if we tweak the wording.

#14 @grapplerulrich
13 years ago

Related: 8783

The second answer does not fully match the question.

Are you sure you wish to delete these files and data?
Yes, Delete only the files.

A better question would be "Are you sure you want to uninstall these plugins?"

#15 @Ipstenu
13 years ago

Or a better answer of "No, delete only the files."

Also why are we capitalizing 'Delete' here, following a comma?

#16 @helen
13 years ago

Ahem, you guys. kurtpayne said that he knows the language needs reworking/actual attention.

#18 @jorbin
11 years ago

  • Keywords ux-feedback ui-feedback added

This seems like a nice enhancement. I agree with the concerns about having three buttons. Would love to see a mockup or wireframe of a better confirmation page that incorporates the three options.

#19 @DrewAPicture
11 years ago

  • Keywords needs-patch added; has-patch dev-feedback removed

To move forward, this will need a new patch incorporating feedback in comment:12 from @helen.

@swissspidy
11 years ago

#20 @swissspidy
11 years ago

  • Keywords has-patch has-screenshots added; needs-patch removed
  • Milestone Awaiting Review → Future Release

20578.diff​ is a new patch incorporating some feedback.

After (hopefully) removing the list of files which will be deleted (see #34439), I thought I should give it a shot. Why not even consider this for 4.5?

Some highlights:

Makes the 'Return to Plugins page' button a link

  • Moves the link below the buttons. Works great because of #34439.
  • I slightly changed the wording because that string is already used elsewhere

Adds primary and secondary buttons

Two buttons for an uninstallable plugin, only a single button for one without an uninstall handler.

Note: Since you can choose if data should be deleted or not, the (will also delete its data) text can be removed.

Docs

Adds the $uninstall_plugin flag to the delete_plugin and deleted_plugin hooks. Updates DocBlocks properly.

Screenshots

  1. Delete single plugin (no uninstall handler)

https://cldup.com/M0zjGHSeQd.png

  1. Delete single plugin (uninstall handler)

https://cldup.com/RPgo2aXM2x.png

  1. Delete multiple plugins (no uninstall handler)

https://cldup.com/-lZM8J3ggz.png

#21 @swissspidy
11 years ago

  • Milestone Future Release → 4.5

Changing milestone for 4.5 consideration.

With the current patch the string changes are minimal, but the UI is greatly improved.

This ticket was mentioned in ​Slack in #design by swissspidy. ​View the logs.


11 years ago

#23 follow-up: @obenland
11 years ago

How many of our users will know the difference between only deleting files and deleting files and data? How many of them will be even more confused by that option?

I find the case where you would want to hang on to data but delete plugin files to be an extreme edge case from a user's POV. Even the example provided here as to why this would be a worthwhile change cites a dev scenario.

#24 @grapplerulrich
11 years ago

How many of our users will know the difference between only deleting files and deleting files and data? How many of them will be even more confused by that option?

Possible ways of finding out are: surveys or user testing. Do we have any possibility of doing this?

Even the example provided here as to why this would be a worthwhile change cites a dev scenario.

I don't think it is a dev scenario but a site management scenario. A developer can easily use FTP to replace the files. It is the site manager who does not understand FTP and prefers to use the admin area.

Another similar scenario is testing beta plugins on a staging site.

#25 in reply to: ↑ 23 @swissspidy
11 years ago

Replying to obenland:

I find the case where you would want to hang on to data but delete plugin files to be an extreme edge case from a user's POV. Even the example provided here as to why this would be a worthwhile change cites a dev scenario.

Thanks for chiming in! I thought the consensus was that this is welcome enhancement and just the details need to be set, but I'm happy to share my opinion on it.

I first stumbled upon this after a ​blog post (in German) by @grapplerulrich back in 2014. He noted that many people tried to delete a plugin before uploading a newer version via the browser uploader. However, while doing so they completely removed all plugin data by accident. Being able to remove a plugin without deleting its data would prevent this. Related: #9757

In the past few years I've seen many plugins (including WooCommerce and other big ones) creating custom uninstall routines just because users frequently uninstalled plugins unintentionally. There's a reason they did this, and it's clear to me that it's because WordPress doesn't prevent this, which this ticket aims to solve.

How many of our users will know the difference between only deleting files and deleting files and data? How many of them will be even more confused by that option?

With some clear wording this is a non-issue. IMHO the difference between "just delete files" and "completely uninstall the plugin" is clear and people are used to such scenarios from other software.

#26 @Ipstenu
11 years ago

I find the case where you would want to hang on to data but delete plugin files to be an extreme edge case from a user's POV.

It's less extreme than one might think. Users get plugins from non-org sources all the time. And when, in debugging, we tell them to disable a plugin, you might be surprised to see how many people delete.

Users will be less confused by 'Delete the plugin and all of it's settings and configurations' and 'Delete the plugin files' than you might think. Users actually do kinda know that the 'code-y stuff' lives in files and the 'content stuff' is in the DB :)

#27 @afercia
11 years ago

Any unintentional data loss should be avoided, maybe just better explain what "data" is? :)

#28 follow-ups: @grapplerulrich
11 years ago

@afercia - The data could be custom post types, settings, metadata or even custom tables. Anything that the plugin adds to the database during usage "should" be deleted on uninstall.

@swissspidy
11 years ago

#29 @swissspidy
11 years ago

Patch didn't apply cleanly anymore, so I created a new one (see 20578.2.diff​) with some refined wording. It also now clearly distinguishes between 1 and many plugin, to get rid of the "these files and data" wording. The list of files is not displayed any longer, so this doesn't make sense anymore.

  1. Delete single plugin (no uninstall handler)

https://cldup.com/PV1AlTkY4c.png

  1. Delete single plugin (uninstall handler)

https://cldup.com/2aiG68AeXX.png

  1. Delete multiple plugins (no uninstall handler)

https://cldup.com/Qt1ODkFd2k.png

  1. Delete multiple plugins (uninstall handler)

https://cldup.com/rKKB2W_zbK.png

IMHO that's the best wording so far. It makes it clear that completely uninstalling a plugin means deleting it and all of its data.

#30 in reply to: ↑ 28 ; follow-up: @swissspidy
11 years ago

Replying to grapplerulrich:

Any unintentional data loss should be avoided, maybe just better explain what "data" is? :)

The data could be custom post types, settings, metadata or even custom tables. Anything that the plugin adds to the database during usage "should" be deleted on uninstall.

Perhaps we could add a hook where plugins can describe what exactly they would delete? Would look weird with many plugins displaying such info though.

#31 in reply to: ↑ 30 @jdgrimes
11 years ago

Replying to swissspidy:

Replying to grapplerulrich:

Any unintentional data loss should be avoided, maybe just better explain what "data" is? :)

The data could be custom post types, settings, metadata or even custom tables. Anything that the plugin adds to the database during usage "should" be deleted on uninstall.

Perhaps we could add a hook where plugins can describe what exactly they would delete? Would look weird with many plugins displaying such info though.

The plugins are deactivated at that point. :-) This couldn't be a hook, it would have to be a file header or something. See #31136.

#32 in reply to: ↑ 28 @afercia
11 years ago

Replying to grapplerulrich:

@afercia - The data could be custom post types, settings, metadata or even custom tables. Anything that the plugin adds to the database during usage "should" be deleted on uninstall.

@grapplerulrich sure, and unfortunately many, many, plugins don't remove their settings, tables, etc. But the point is: unintentional data loss.

#33 follow-up: @grapplerulrich
11 years ago

@grapplerulrich sure, and unfortunately many, many, plugins don't remove their settings, tables, etc. But the point is: unintentional data loss.

What do you mean by unintentional data loss? I agree many plugins don't remove their settings but why support a bad habit. This step should start to educate users and get them to question the theme and plugin authors.

#34 in reply to: ↑ 33 ; follow-up: @Ipstenu
11 years ago

Replying to grapplerulrich:

@grapplerulrich sure, and unfortunately many, many, plugins don't remove their settings, tables, etc. But the point is: unintentional data loss.

What do you mean by unintentional data loss? I agree many plugins don't remove their settings but why support a bad habit. This step should start to educate users and get them to question the theme and plugin authors.

The unintentional data loss is actually the devs who do have an uninstall.php and thus remove the data without users understanding what we meant by 'files and data' (which is what it says now). I don't necessarily want to run uninstall.php when I'm deleting to upgrade :)

This ticket was mentioned in ​Slack in #core by chriscct7. ​View the logs.


11 years ago

#36 in reply to: ↑ 34 @chriscct7
11 years ago

  • Milestone 4.5 → Future Release

There appears to continue to be a lack of clear consensus on the handling on specifically this topic, and the enhancement window for 4.5 closes in just over 1 week. Punting out of the milestone so a consensus and a patch which solves that problem can be developed.

Replying to Ipstenu:

The unintentional data loss is actually the devs who do have an uninstall.php and thus remove the data without users understanding what we meant by 'files and data' (which is what it says now). I don't necessarily want to run uninstall.php when I'm deleting to upgrade :)

#37 @swissspidy
11 years ago

  • Owner set to swissspidy
  • Status new → reviewing

#38 follow-up: @Milmor
11 years ago

+1 for this feature.
I would leave "delete files only" as button-primary to prevent unintentional data loss.

Hope to see this feature soon. Having this supported by the core is clearer for the user and better for developers than use custom options to get uninstall intent.

@swissspidy
10 years ago

#39 in reply to: ↑ 38 @swissspidy
10 years ago

Replying to Milmor:

+1 for this feature.
I would leave "delete files only" as button-primary to prevent unintentional data loss.

Hope to see this feature soon. Having this supported by the core is clearer for the user and better for developers than use custom options to get uninstall intent.

There shouldn't be two primary buttons. A complete uninstall is the most likely action, the other is secondary.


20578.3.diff​ is a refresh of the previous patch against trunk.

#40 @swissspidy
10 years ago

  • Keywords needs-patch added; has-patch removed

Now with Shiny Updates V2 being part of core, we need to look into displaying this screen inside a modal (or something else) as well.

This ticket was mentioned in ​Slack in #feature-shinyupdates by paaljoachim. ​View the logs.


10 years ago

#42 follow-up: @paaljoachim
10 years ago

The most logical place is to inside the plugin delete modal have a message saying:

"Uninstall Plugin Data" - checkbox-

Last edited 10 years ago by paaljoachim (previous) (diff)

#43 in reply to: ↑ 42 @FolioVision
10 years ago

Replying to paaljoachim:

The most logical place is to inside the plugin delete modal have a message saying:

"Uninstall Plugin Data" - checkbox-

Absolutely. A modal message with a checkbox is quick and it's safe. That checkbox should NOT be checked by default (data deletion should be a deliberate choice).

#44 @swissspidy
10 years ago

  • Keywords shiny-updates added

#45 @mordauk
10 years ago

I'd love to see this too.

#46 @swissspidy
10 years ago

#37898 was marked as a duplicate.

This ticket was mentioned in ​Slack in #feature-shinyupdates by swissspidy. ​View the logs.


10 years ago

#48 @SergeyBiryukov
9 years ago

#41767 was marked as a duplicate.

#49 @alexsanford1
9 years ago

Given the upcoming enforceability of the GDPR, it is very important for plugins to give site owners the ability to delete all of the plugin's data in a safe way that is not prone to accidental deletion.

With that in mind, I think the proposed solution here (adding a checkbox to the dialog) provides a great balance between data deletion requirements and safety (so users don't delete data accidentally when trying to fix an issue with their installation, for example).

There are workarounds that plugin authors can use currently, but this should really be functionality provided by core (see some discussion for one specific plugin here: ​https://github.com/Automattic/sensei/issues/2116).

Any chance this could get some attention soon?

#50 @pputzer
8 years ago

Some traction on this would be nice. As is, the chance for unintentional data loss is very high. @swissspidy, are you still working on this?

#51 @swissspidy
5 years ago

  • Owner swissspidy removed

#52 @swissspidy
5 years ago

  • Keywords shiny-updates removed

Now that plugins can finally be updated/replaced by uploading a ZIP file without having to delete it first, is this still a common enough issue users encounter?

If so, I'd still lean towards offering two buttons instead of a checkbox, and I could easily update my patch for that.

#53 @paaljoachim
5 years ago

Hey @swissspidy

An usage example.
I took over the care of the Norwegian Permaculture web site. Doing a cleanup with Advanced Database cleaner I noticed it has many database entries from CiviCRM. One way to remove the orphaned entries is get the premium version of Advanced Database, another might be to install and activate CiviCRM and figure ut if it also has a method to remove all data as part of the settings. Some plugins has a part of their settings an option to also remove data on uninstall. Having a default method for the user to click the checkbox in the delete plugin dialog box to remove all data would be even better.

Having two buttons (example) - Delete plugin and Delete plugin and data.
Vs
Checkbox - remove all data.
One button - Delete plugin.

It is easier to accidentally click the wrong button. When two buttons are offered.
Vs the user having to intentionally click a checkbox to remove plugin data and then click the delete button.

@paaljoachim
5 years ago

Example mockup for including a checkbox for deleting plugin data.

#54 @JosVelasco
4 weeks ago

What plugins actually delete on uninstall: a survey of the top 200

AI disclosure. This report was written by an AI assistant (Claude Code) working under the direction of a human contributor, who set the questions, verified every figure and corrected several misclassifications the automated passes produced. The AI downloaded the plugin packages, extracted the uninstall routines, read them, and drafted the text below, including the proposal. No plugin was installed, activated or uninstalled at any point: every statement about plugin behaviour is inferred from reading source code, with no runtime verification. The limitations section lists known error sources and should be read before relying on any single row.

Posted in answer to comment:52, which asked whether this is still a common enough problem to act on. The 200 most-installed plugins were examined and the 121 that have an uninstall routine were read individually.

79 of the 200 have no uninstall routine at all, so their data always survives. Of the 121 that do, 28 destroy data that nothing can reconstruct, and 19 of those 28 already let the site owner decline. 22 plugins in total offer such a switch, under 22 different option names, two of them inverted so the flag means preserve rather than delete. All 200 produce the same "(will also delete its data)" notice, including 36 that delete nothing at all.

Proposal

Make it easy and standard for plugin authors to offer this choice, for those who want to. Not a mandate, not a behaviour change for anyone who does nothing, and no resolution required of the two-buttons-versus-checkbox question that has held this ticket since 2016.

This is where the measurements point most strongly. 22 authors already decided the choice was worth offering, and each designed a settings field and wrote the deletion gate themselves. None of that work is reusable by the next author, discoverable by a user who has learned where one plugin keeps it, or readable by tooling.

A convention would settle the option name and shape, the semantics including which direction the flag points, and offer a small core helper to read it, so an author opts in with roughly one line instead of a design decision.

Where the declaration has to live. is_uninstallable_plugin() only reports whether a file exists or a hook was registered, and by the time the uninstaller runs the plugin is deactivated and cannot be asked anything. A declared plugin header is the only place this information can come from, which makes #31136 the enabling ticket for this one.

Everything below is measurement.

Current behaviour, as verified

delete_plugins() calls uninstall_plugin() for every uninstallable plugin before removing files, so the admin Delete button always runs the uninstaller. Deactivation never does. Removing the directory outside WordPress runs nothing; verified by moving an inactive plugin's folder aside on a local install, after which the front page and the plugins screen both loaded normally.

No filter exists anywhere in that path: is_uninstallable_plugin() applies none, pre_uninstall_plugin is an action and cannot abort, and delete_plugin fires after the uninstaller has already run.

WP-CLI ships both operations separately. wp plugin delete is documented as "Deletes plugin files without deactivating or uninstalling"; wp plugin uninstall --skip-delete is the inverse.

No plugin in the directory offers this. The adjacent category addresses the inverse case, cleaning orphaned data after the fact: Advanced Database Cleaner, Plugins Garbage Collector, WP-Sweep.

Survey results

Each of the 121 routines was assigned a category according to whether what it destroys can be reconstructed afterwards: by the machine (caches, indexes, generated files), by a person re-entering it (settings, keys, layouts), by nobody (records of past events), or nothing at all.

category plugins installs of which, no switch
irrecoverable 28 51.4 M 9
re-enterable configuration 47 45.1 M 37
machine-reproducible 10 13.9 M 8
nothing 36 47.6 M n/a

The 9 that destroy irrecoverable data with no way to decline are 4.5% of the sample and 16.2 million active installs, of which contact-form-7 is 62%:

plugin installs destroyed unconditionally
contact-form-7 10.0 M every wpcf7_contact_form post, force-deleted, plus its table
redirection 2.0 M the redirect map, its logs and 404 table
loginizer 1.0 M loginizer_logs plus the hand-built whitelist and blacklist
sg-security 1.0 M activity log, and every user's 2FA secret
header-footer-code-manager 0.6 M hfcm_scripts, whose snippet LONGTEXT column holds user-entered HTML/JS/CSS
siteguard 0.6 M login and history tables
wp-maintenance-mode 0.4 M wpmm_subscribers
eps-301-redirects 0.3 M the redirects table and the 404 log
simple-history 0.3 M both audit-log tables

Of the 37 plugins destroying re-enterable configuration without a switch, 15 ship settings export or import, so a user can save a file before deleting.

The same notice, different behaviour

is_uninstallable_plugin() is satisfied by all of the following, which therefore show identical warnings:

  • hostinger (3.0 M): uninstall.php is two lines, the guard and nothing else.
  • popup-maker (0.7 M): the registered callback reaches uninstall_site(), an empty method.
  • wordpress-seo (10.0 M): registers __return_false, commented "This is done so that the 'uninstall_{$file}' is triggered." The integration hooking that action sets one array key to empty inside its own option. Settings and the indexables table are untouched.
  • contact-form-7 (10.0 M): force-deletes every form on the site.

Two plugins in the survey demonstrate the distinction is one authors can already make. litespeed-cache drops its cache and crawler tables but leaves img_optming alone, commented "Deleting img_optming only can be done when destroy all optm images". all-in-one-wp-security-and-firewall reads two separate settings before deleting, aiowps_on_uninstall_delete_db_tables and aiowps_on_uninstall_delete_configs, separating log tables from configuration.

woocommerce places its deletion behind WC_REMOVE_ALL_DATA, commented: "This is to prevent data loss when deleting the plugin from the backend and to ensure only the site owner can perform this action."

Data left behind

114 of the plugins without a switch leave autoloaded options or their own tables; 83 create tables. Autoloaded options belonging to a plugin that no longer runs are read on every request indefinitely.

Measured on one fifteen-year-old production site: 46 autoloaded options from a plugin deactivated years ago are 177.6 KB of a 565.4 KB autoload payload, or 31.4%, and include the single largest autoloaded option on the site at 173 KB.

Random sample, for comparison

150 plugins drawn at random from the full directory of 72,180: 4 have a switch, 105 have no uninstall routine at all, and the median plugin has 10 active installs with 50 of the 150 reporting none. The head of the directory is not representative of its body, and uniform sampling estimates the share of plugins rather than the share of installs. For a proportion near 10%, 150 gives roughly ±4.8% at 95% confidence and 382 would give ±3%.

Limitations

Static code reading only. No plugin was installed or activated, and no uninstall routine was executed. Known error sources: conditional branches judged unreachable may execute under untested configurations; multisite paths differ and the single-site path was generally the one read; premium editions ship different uninstallers than the directory builds examined; deletion delegated through a custom action or a dynamically named method escapes a reader as easily as a script. Table and option names indicate what is deleted, not what it contains, so category assignment required judgement about each plugin's purpose and is not a measurement.

Errors the AI passes produced, corrected before publication: an automated pass reported 18 switches where reading found 22, missing those routed through a plugin's own settings class (code-snippets, wp-statistics, all-in-one-wp-security-and-firewall, wp-smushit); wps-hide-login was classified as destroying accumulated history because an option is named whl_redirect_admin and "redirect" matched a pattern; wordpress-seo, redirection and google-site-kit were misclassified in both directions. Others of the same kind presumably remain. The counts are a well-supported floor rather than a census.

Note: See TracTickets for help on using tickets.