Plugins window: real updates, not just a phantom badge#185
Merged
Conversation
- Introduced `desktop_mode_plugins_window_refresh_updates` filter to control lazy refresh of plugin updates in REST API. - Updated REST fields to include `package` and `slug` in `desktop_mode_update_available` for better update handling. - Implemented `runUpdate` and `runBulk` functions for updating plugins, ensuring proper state management during updates. - Added `enqueueUpdateJob` to manage concurrent plugin updates, preventing transient corruption. - Enhanced session recovery mechanisms to handle stale nonces and improve user experience during session expiry. - Implemented cross-tab synchronization for plugin state changes between Installed and Browse tabs. - Added comprehensive unit tests to validate new functionality and ensure reliability.
✅ WordPress Plugin Check Report
📊 ReportAll checks passed! No errors or warnings found. 🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the "Update available" tab showing zero plugins while the dock badge reported pending updates, and adds the per-row + bulk "Update now" UX Core has on
wp-admin/plugins.php.Update.plugins.mov
Bugs fixed
1. Stale
update_pluginstransient on REST requestsCore only refreshes
update_pluginsonload-plugins.php/load-update-core.php/ cron. REST is not on that list, so a freshly loaded Plugins window saw an empty/stale snapshot while the dock badge (which is rebuilt off$menuduring the desktop-shell page load) reported real numbers.Fix:
desktop_mode_plugins_window_maybe_refresh_update_transient()— lazy refresh on the first row of every REST plugins collection, inheriting Core's own 12h throttle (_maybe_update_plugins()posture). Guarded by a static so it runs once per request, and by a newdesktop_mode_plugins_window_refresh_updatesfilter for hosts that orchestrate updates themselves.2.
.php-strip mismatch (the real culprit)Core's
WP_REST_Plugins_Controlleremits thepluginfield with the.phpstripped (elementor/elementor), but every internal WP data structure — theupdate_pluginstransient,Plugin_Upgrader::bulk_upgrade(),wp_ajax_update_plugin— keys by the full filename (elementor/elementor.php). The REST field callback was looking up the stripped key against a fully-keyed transient → miss on every row → all rows reportedavailable: false.Fix:
desktop_mode_plugins_window_row_plugin_file()re-appends.phpwhen missing. Routeddesktop_mode_update_availableanddesktop_mode_size_kbthrough it (the size callback had the same latent bug for single-file plugins like Hello Dolly). Mirrored on the JS side inupdateInstalledPlugin()sowp_ajax_update_pluginreceives the form it actually keys against (otherwise the upgrader fell through to "Plugin is at the latest version").Update-now UX (matches
wp-admin/plugins.php)Update to X.Y.Zbutton in the actions cell when the user hasupdate_pluginsAND the transient entry ships apackageURL. Whenavailable && ! package(premium / no-wp.org-zip plugins), surfaces the same "Auto-update unavailable" hint Core renders.Update Naction in the bulk bar; fans through the same single-flight queue.update-queue.ts) — mirrors Core'swp.updates.ajaxLocked+ FIFOwp.updates.queuesemantics. ConcurrentPlugin_Upgraderruns corrupt theupdate_pluginstransient (documented in Core's own AJAX handler); enforcing single-flight is non-optional, not a polish item.wp_ajax_update_pluginwith the existing'updates'nonce. No reimplementation ofPlugin_Upgrader, which keeps us out ofwp-admin/includes/and keeps Plugin Check green.<wpd-badge tone="warning">N</wpd-badge>that recounts on every row update; hidden when zero.desktop-mode.plugin.changedwithaction: 'update', refreshes the framework menu (dock badge), bumps the row version inline.Data shape changes
desktop_mode_update_availableREST field now{ available, new_version, package, slug }(was{ available, new_version }).packageis the gate the JS uses to decide Update-button vs Auto-update-unavailable hint — matches Core's own gating inwp_plugin_update_row().capsconfig blob gainsupdate(boolean, mirrorscurrent_user_can( 'update_plugins' )). Server still re-validates every mutation in the AJAX handler.New filter
desktop_mode_plugins_window_refresh_updates(bool, defaulttrue) — opt-out of the lazy transient refresh. For managed hosts that run their own update orchestration.Tests
tests/phpunit/tests/pluginsWindowRegistration.php: +6 tests covering hit case with REST-stripped row shape (regression test for the.phpstrip), missing-packagefallback, the 12h throttle, the opt-out filter, andcaps.updatefor admin + editor. 27/27 in the class green, 660/660 in the full plugin suite green.Files
includes/plugins-window/rest-fields.php— normalization helper + lazy refresh + extended field shape.includes/plugins-window/permissions.php—caps.update.src/plugins-window/rest.ts—updateInstalledPlugin()(re-appends.phpbefore hittingwp_ajax_update_plugin).src/plugins-window/update-queue.ts(new) — single-flight queue.src/plugins-window/installed-view.ts— Update button (row + bulk), count badge, optimistic row repaint, broadcast on success.src/plugins-window/types.ts— extendeddesktop_mode_update_available+caps.update.tests/phpunit/tests/pluginsWindowRegistration.php— new coverage.docs/hooks-reference.md— new filter + extended field shape.