From f10f37c1c2d3c63d797016773f924b4c454ccbe3 Mon Sep 17 00:00:00 2001 From: Andreas Panagiotopoulos Date: Thu, 7 May 2026 18:44:51 +0300 Subject: [PATCH 1/2] Administration: maintain custom plugins_list group counts in deletePluginSuccess. Decrement counts for groups registered via the plugins_list filter when a plugin is deleted via AJAX, so tabs whose label is supplied through plugins_list_status_text (introduced in #60495) stay in sync without a page reload. See #65191. --- src/js/_enqueues/wp/updates.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/js/_enqueues/wp/updates.js b/src/js/_enqueues/wp/updates.js index ef4b47e66093e..20395e055d156 100644 --- a/src/js/_enqueues/wp/updates.js +++ b/src/js/_enqueues/wp/updates.js @@ -1377,6 +1377,11 @@ * @type {Object} */ plugins = settings.plugins, + knownKeys = [ + 'all', 'search', 'upgrade', 'active', 'inactive', + 'recently_activated', 'mustuse', 'dropins', 'paused', + 'auto-update-enabled', 'auto-update-disabled' + ], remainingCount; // Add a success message after deleting a plugin. @@ -1445,6 +1450,29 @@ } } + // Decrement counts for any custom group added through the + // `plugins_list` filter (e.g. a tab whose label is supplied + // via `plugins_list_status_text`, introduced in #60495). + _.each( _.keys( plugins ), function( key ) { + if ( -1 !== _.indexOf( knownKeys, key ) ) { + return; + } + if ( ! _.isArray( plugins[ key ] ) ) { + return; + } + if ( -1 === _.indexOf( plugins[ key ], response.plugin ) ) { + return; + } + + plugins[ key ] = _.without( plugins[ key ], response.plugin ); + + if ( plugins[ key ].length ) { + $views.find( '.' + key + ' .count' ).text( '(' + plugins[ key ].length + ')' ); + } else { + $views.find( '.' + key ).remove(); + } + } ); + plugins.all = _.without( plugins.all, response.plugin ); if ( plugins.all.length ) { From 98c5eb0df2f93de0a0b12a46fab70a10cb176edf Mon Sep 17 00:00:00 2001 From: Alessio Arzenton Date: Fri, 8 May 2026 15:59:54 +0200 Subject: [PATCH 2/2] style: move subsubsub list separator from PHP implementation to CSS pseudo-elements --- src/wp-admin/css/common.css | 4 ++++ src/wp-admin/includes/class-wp-list-table.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/wp-admin/css/common.css b/src/wp-admin/css/common.css index fa7180874250f..cdae914850160 100644 --- a/src/wp-admin/css/common.css +++ b/src/wp-admin/css/common.css @@ -464,6 +464,10 @@ code { white-space: nowrap; } +.subsubsub li:not(:last-child)::after { + content: "|"; +} + /* .widefat - main style for tables */ .widefat { border-spacing: 0; diff --git a/src/wp-admin/includes/class-wp-list-table.php b/src/wp-admin/includes/class-wp-list-table.php index 0795da27535c6..ca99984c9a1fd 100644 --- a/src/wp-admin/includes/class-wp-list-table.php +++ b/src/wp-admin/includes/class-wp-list-table.php @@ -525,7 +525,7 @@ public function views() { foreach ( $views as $class => $view ) { $views[ $class ] = "\t
  • $view"; } - echo implode( " |
  • \n", $views ) . "\n"; + echo implode( " \n", $views ) . "\n"; echo ''; }