This blog has been quiet since 2022, and the last post about WordPress here is from 2019. I thought about publishing this on Webdados or Naked Cat Plugins instead. But this is my opinion as a developer about a bug in WordPress core and a decision about my own products, so it belongs here.
I sell extensions for WooCommerce at Naked Cat Plugins. Most of them add features to one of my free plugins on WordPress.org: Shop as Client for WooCommerce is free, and the Shop as Client PRO add-on builds on it. Since WordPress 6.5, the PRO add-ons declare the free plugin in the Requires Plugins header, so WordPress won’t activate one without the other. That works on the plugins list. But a customer who uploads the PRO zip sees an Activate button that leads to an error page. This is how I found that, what I weighed before deciding what to do about it, and why I’m keeping the header for now.
How I got here
On 23 September 2026, Rodolfo Melogli asked on X: “WP plugin devs: is it not bad UX when a PRO plugin requires a free .org companion plugin to be installed first?”
Steve Jones answered with what several developers in the thread said they do: make the free plugin a dependency and, if Pro is installed without it, auto-install and activate it. Rodolfo replied with the screen he didn’t want customers to see:

My first reaction was that this can’t happen. Since WordPress 6.5, a plugin with the Requires Plugins header can’t be activated while its dependencies are missing: the Activate link on the plugins list is disabled. So auto-installing shouldn’t be needed. I asked how he got there, with this screenshot:

His answer: the customer buys Pro, installs and activates it on their site, and gets the wp_die() error because the free plugin isn’t there. So I tried it with the Shop as Client PRO add-on, uploading the zip on a site without the free plugin. The upload screen offers “Activate Plugin”, while the plugins list, for the same plugin, doesn’t:


That’s a WordPress bug. I reported it back in the thread, and Rodolfo said he would report it to WordPress core.
The bug
The plugins list and the upload screen disagree about the same plugin. Checked against WordPress 7.2-alpha:
- Plugins list (
class-wp-plugins-list-table.php): a plugin with unmet dependencies gets a disabled Activate link, a disabled checkbox so bulk actions can’t reach it either, and the notice “This plugin cannot be activated because required plugins are missing or inactive.” Each name on its Requires line opens the plugin install modal, where a WordPress.org plugin can be installed and activated. - Upload screen (
Plugin_Installer_Skin::after()): builds the “Activate Plugin” button checking only the user’s permissions and whether the plugin is already active. It never looks at dependencies. - Activation (
validate_plugin_requirements()inwp-admin/includes/plugin.php): does check dependencies, and returns an error thatplugins.phpshows withwp_die(). That’s the page in Rodolfo’s screenshot.
Nothing breaks: the plugin is never activated with its dependency missing. But the button the customer is given leads to a dead end: a bare error page with a “Manage plugins” link. That’s the scenario Rodolfo described: a new customer’s first step after paying is to install what they bought, and this is the screen they get. It’s a functional bug, not a cosmetic one. The fix belongs in core: the upload screen should apply the same check the plugins list already does.
A plugin author can’t work around it from the Pro plugin: WordPress doesn’t load an inactive plugin’s code, so nothing in Pro runs during its own upload. A filter on the upload screen’s buttons (install_plugin_complete_actions) would have to live in a plugin that is already active.
Keep the header, or auto-install?
Until core fixes the upload screen, the header can’t give a customer who uploads Pro a good first screen. The only way around it is to remove the free plugin from Requires Plugins so Pro can activate, and have Pro install the free plugin itself. So I looked at what that costs.
Shop as Client Pro already had most of the safety net, because its minimum WordPress version is 6.4 and 6.4 ignores the header. On plugins_loaded it checks that the free plugin is loaded and recent enough, and that WooCommerce is loaded and recent enough. If either fails, Pro loads nothing and shows an admin notice. Without the header, that check does all the work.
What auto-installing gains
- Upload, Activate, working plugin. The customer never sees an error page.
- It can also update the free plugin when it’s older than Pro needs. The header only checks that the plugin exists, not its version.
- Customers who already have the free plugin see no difference.
What it costs
- Core no longer protects the free plugin. With the header, WordPress won’t let anyone deactivate or delete it while Pro is active. Without it, Pro has to cope: go quiet, show a notice with a Reactivate button.
- The Requires and Required by lines disappear from the plugins list, unless you add them back yourself.
- The install will sometimes fail, and each case needs a fallback:
DISALLOW_FILE_MODSis set.- The host needs FTP credentials instead of writing files directly.
- The user can’t install plugins (for example, a site admin on multisite who isn’t a super admin).
- The server can’t reach WordPress.org.
- Timing. The activation hook is the wrong place: any output there triggers WordPress’s “unexpected output” warning, and there’s no way to ask for FTP credentials. It has to run on the next admin page load, before the redirect to the settings page (which belongs to the free plugin, so the order matters).
- Edge cases. Bulk activation and WP-CLI skip that redirect, so the install happens on the next admin page. On multisite, a network-activated Pro needs the free plugin network-activated too.
- Consent. The customer clicked Activate on a plugin that can’t work without the free one, so installing it is defensible. Pro should still say what it did: “Shop as Client was installed and activated because the PRO add-on needs it.”
- Code to maintain. The header is one line. Doing this properly is a small class with its own notices and tests.
When the install can’t run, the fallback is a notice whose button points at core’s own install screen (update.php?action=install-plugin&plugin=shop-as-client, with the nonce). That screen knows how to ask for FTP credentials, so the worst case is one extra click through a normal WordPress screen, never an error page.
Side by side
The header wins on everything except the customer’s first minute after uploading, which is exactly where the bug is. “Auto-install” here means doing it properly, with the checks and fallbacks from the previous section.
| Situation | Requires Plugins header | Auto-install from Pro |
|---|---|---|
| Customer uploads the Pro zip and clicks Activate; free plugin missing | Fails. Error page from wp_die() (the core bug) | Works. Pro activates, installs, and activates the free plugin |
| Customer installs Pro, then activates it from the plugins list | Works. Activate is disabled; the row explains why and links to the install modal | Works. Pro activates and installs the free plugin |
| Someone later deactivates or deletes the free plugin | Blocked by core. Deactivate and Delete are disabled while Pro is active | Allowed. Pro has to go quiet and show a notice |
| Free plugin installed but older than Pro needs | Not checked. Pro’s own check has to catch it | Can update it, if the code does it |
| WordPress 6.4 or older | Ignored. Pro’s own check has to catch it | Works |
| Host needs FTP credentials | Works. Core’s install screens ask for them | Silent install impossible. Falls back to a notice linking to core’s install screen |
DISALLOW_FILE_MODS, or a user who can’t install plugins | Clear message. Nothing can be installed anyway | Can’t install. The notice has to say so, or Pro just looks broken |
| WordPress.org unreachable | Install modal fails with core’s own error | Download fails. Needs a notice |
| Requires and Required by lines on the plugins list | Yes, from core | No, unless added by hand |
| Code to maintain | One header line | A class with notices, fallbacks and tests |
So auto-install trades one broken screen for about half a dozen situations you now handle yourself. Whether that’s worth it depends on how many customers actually reach that screen.
An existing library: WP Dependency Installer
WP Dependency Installer by Andy Fragen is a drop-in class for exactly this: you list dependencies in a JSON file, and it installs and activates the required ones. Andy is also one of the authors of core’s Plugin Dependencies feature. I read the current version (last commit April 2025) to see which of the problems above it solves.
| Problem | What the library does |
|---|---|
| Silent install | Solved. A custom installer skin that prints nothing |
| Free plugin being deactivated or deleted | Partly. Removes the Deactivate and Delete links and adds a “Required Plugin” label and a “Required by” line. Bulk actions can still deactivate it |
| Host needs FTP credentials | Not handled. No check for direct file access, so core’s credentials form would print in the middle of admin_init |
DISALLOW_FILE_MODS, or a user who can’t install plugins | Silent. Both the install and the notice need update_plugins, so the customer sees nothing and no reason |
| Minimum version of the dependency | Not checked. Installed and active is enough |
| When the install runs | On any admin page load, for anyone who can update plugins. The nonce it checks is one it creates in the same request, so it doesn’t protect anything |
| Multisite | Network-activates only when the current page is in network admin |
It also pulls in a second package (afragen/wp-dismiss-notice) and supports GitHub, Bitbucket, and GitLab sources that a WordPress.org dependency doesn’t need. The parts worth borrowing are the empty installer skin and the row-link filtering, about 40 lines. The gaps are in the failure cases, and those are the ones between a customer and a broken screen.
And WooCommerce?
Shop as Client Pro requires two plugins: the free Shop as Client and WooCommerce. If auto-installing the free one is fine, would you auto-install WooCommerce too? I wouldn’t.
The customer was told both things before buying: that this is a WooCommerce extension, and that it’s an add-on for the free plugin on WordPress.org. The difference is what each one is:
- The free plugin is part of the product. Same author, same feature set, split in two because WordPress.org hosts the free half. Installing it completes what the customer bought. It changes nothing else about their site.
- WooCommerce is the platform. Installing it turns a site into a shop: new database tables, pages, a setup wizard, emails, settings. Nobody should get that as a side effect of activating an add-on.
- A missing WooCommerce usually means something else. The customer uploaded the plugin to the wrong site, or WooCommerce is deactivated on purpose (for example, to troubleshoot a conflict). Reactivating it would undo what they just did.
The same caution applies, on a smaller scale, to the free plugin itself. Installing it when it’s missing is safe. Activating it when it’s installed but inactive is a judgment call: most of the time it just hasn’t been activated yet, but someone may have turned it off deliberately. If Pro auto-installed, I’d activate it since the customer just activated Pro, and note that in the notice.
So WooCommerce stays in Requires Plugins. That means the upload bug can still reach a customer with no WooCommerce, but that’s rare for a WooCommerce extension, and the error message names the missing plugin. It also shows why the fix belongs in core: any plugin with a Requires Plugins header can hit it, whatever the author does about companion plugins.
Options, and where I landed
- Keep the header and set expectations. Say “install and activate the free plugin from WordPress.org first” on the product page, in the purchase email, and in the documentation. No code, but the customers who don’t read it still get the error page.
- Drop the free plugin from the header and auto-install it, with the checks and fallbacks above. WooCommerce stays in the header.
- Make Pro standalone, shipping the free plugin’s code inside it. No dependency at all. I won’t go that route. Most of my customers find the free plugin on WordPress.org, use it, and buy PRO when they need more. I also build PRO as an add-on on purpose: it doesn’t create its own settings or feature screens; it adds to the free plugin’s. Other developers can and will disagree with this. It’s a preference, not a rule.
- Wait for core to fix the upload screen. The right fix, but existing sites run older WordPress versions for years.
For Shop as Client PRO (and all my other paid add-ons), I’m keeping the Requires Plugins header, for now. Most of my customers come from the free plugin, so they already have it installed when they upload PRO, and the bug never shows. I have never had a support ticket about it. Auto-install would fix a problem I don’t know exists and take away core’s protection from every customer. I may revisit this if that changes.
The core bug should still be fixed. Until it is, every plugin using the header can put an error page in front of a customer who uploads it.
What I changed
After the thread on X and writing this post, I made the install order harder to miss for every Naked Cat Plugins PRO add-on that requires one of my free plugins on WordPress.org.
- Documentation: where the add-on has a documentation page, the setup instructions now say to install and activate the free plugin first. A new question, “I uploaded the PRO add-on and got an error when activating it. What’s wrong?”, explains the error page, says nothing on the site was broken or changed, and gives the two steps to get past it.
- Purchase note: every PRO add-on product, yearly and lifetime, now opens its purchase note with “Before installing: install and activate the free plugin from WordPress.org first”, linking to it. WooCommerce includes the purchase note in the order email, the same one that carries the license key and the download link, so it reaches the customer before they upload anything.
This is a real Shop as Client Pro order email, edited to show the new purchase note above “Getting started”:

I know people don’t read documentation, and many will still miss the purchase note in the email. But again, I’ve had zero support tickets about this so far. These are small text changes, not code: I’m not building a fix for a problem I haven’t seen.
Sources
- The X thread: Rodolfo’s question, Steve Jones, the error page, “that’s a dependency issue”, “how did you reach that screen?”, the steps, “WordPress should have blocked the activation”, “I expect that to work upon installation”, the bug, who reports it.
- WordPress core 7.2-alpha:
wp-admin/includes/class-plugin-installer-skin.php(after()),wp-admin/includes/plugin.php(validate_plugin_requirements()),wp-admin/includes/class-wp-plugins-list-table.php. - afragen/wp-dependency-installer, last commit 29 April 2025.
- Core ticket: After uploading a plugin that “requires” other plugins, the “Activate Plugin” button leads to a wp_die() WSOD
Disclaimer: I wrote this post with Claude, working from the X thread, my own tests, and my decisions. I reviewed and edited everything.