soderlind / super-admin-all-sites-menu
For the super admin, replace WP Admin Bar My Sites menu with an All Sites menu.
Package info
github.com/soderlind/super-admin-all-sites-menu
Language:JavaScript
Type:wordpress-plugin
pkg:composer/soderlind/super-admin-all-sites-menu
Fund package maintenance!
- dev-main
- 1.11.0
- 1.10.0
- 1.9.0
- 1.8.5
- 1.8.4
- 1.8.3
- 1.8.2
- 1.8.1
- 1.8.0
- 1.7.3
- 1.7.1
- 1.7.0
- 1.6.9
- 1.6.8
- 1.6.7
- 1.6.6
- 1.6.4
- 1.6.2
- 1.6.1
- 1.6.0
- 1.5.0
- 1.4.28
- 1.4.27
- 1.4.26
- 1.4.25
- 1.4.24
- 1.4.23
- 1.4.22
- 1.4.21
- 1.4.20
- 1.4.19
- 1.4.18
- 1.4.17
- 1.4.16
- 1.4.15
- 1.4.14
- 1.4.13
- 1.4.12
- 1.4.11
- 1.4.10
- 1.4.9
- 1.4.8
- 1.4.7
- 1.4.6
- 1.4.5
- 1.4.4
- 1.4.3
- 1.4.2
- 1.4.1
- 1.4.0
- 1.3.8
- 1.3.7
- 1.3.6
- 1.3.5
- 1.3.4
- 1.3.3
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.4
- 1.2.3
- 1.2.2
- 1.2.1
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.8
- 1.0.7
- 1.0.6
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- dev-dependabot/npm_and_yarn/multi-bf05dc1ecf
- dev-dependabot/npm_and_yarn/flatted-3.4.2
- dev-optimize
- dev-fix/dependencies
This package is auto-updated.
Last update: 2026-03-26 00:56:50 UTC
README
Replace the default My Sites menu in the WordPress Admin Bar with a fast, searchable All Sites menu — built for super admins managing large multisite networks.
Why?
The built-in My Sites menu has problems on large networks:
- It only lists sites where you are a local admin.
- It can't scroll past the viewport (open bug since 2010).
- It calls
switch_to_blog()for every site, which is slow.
This plugin fixes all three. Site data is fetched once via the REST API, cached in IndexedDB, and rendered client-side — so the menu loads instantly on subsequent visits.
Features
- Switch free, no
switch_to_blog()— reads site properties directly, avoiding the performance hit. - IndexedDB caching — menu data is stored locally and updated automatically when sites, blog names, or monitored plugins change.
- Incremental REST loading — fetches sites in batches (default 100) so the admin bar isn't blocked.
- Lists every subsite, not just sites you administer locally.
- Alphabetical sorting with a built-in search filter (appears when you have 20+ sites).
- Restricted Site Access indicator — sites running Restricted Site Access get a red icon.
- Extra quick-links per site: New Page, Users, Plugins, Settings; plus "Add New Site" under Network Admin.
Requirements
| Requirement | Minimum |
|---|---|
| WordPress | 5.6 (Multisite) |
| PHP | 8.0 |
| Browser | Any modern browser (no IE 11) |
Installation
WordPress.org
Install from wordpress.org/plugins/super-admin-all-sites-menu, then Network Activate.
Manual
- Download the latest release.
- Upload to
wp-content/plugins/and network activate.
Composer
composer require soderlind/super-admin-all-sites-menu
Filters
All filters are optional. Add them to a plugin or your theme's functions.php.
all_sites_menu_order_by
Sort order. Accepts name (default), id, or url.
add_filter( 'all_sites_menu_order_by', function( string $order_by ): string { return 'url'; } );
all_sites_menu_load_increments
Sites fetched per REST batch. Default 100.
add_filter( 'all_sites_menu_load_increments', function( int $increments ): int { return 300; } );
all_sites_menu_plugin_trigger
Plugins whose (de)activation triggers an IndexedDB refresh. Default: [ 'restricted-site-access/restricted_site_access.php' ].
add_filter( 'all_sites_menu_plugin_trigger', function( array $plugins ): array { return [ 'restricted-site-access/restricted_site_access.php', 'myplugin/myplugin.php', ]; } );
all_sites_menu_search_threshold
Minimum number of sites before the search field appears. Default 20.
add_filter( 'all_sites_menu_search_threshold', function( int $threshold ): int { return 40; } );
all_sites_menu_force_refresh_expiration
Seconds between forced cache refreshes. Default 3600 (1 hour). Set to 0 to disable.
add_filter( 'all_sites_menu_force_refresh_expiration', function( int $seconds ): int { return 7200; } );
all_sites_menu_submenu_items
Customise the per-site submenu items. Add, remove, or reorder entries. Each item is an associative array with id, title, and href keys.
Parameters:
| Param | Type | Description |
|---|---|---|
$items |
array |
Default submenu items (Dashboard, New Post, New Page, …, Visit). |
$blog_id |
int |
The numeric blog ID. |
$admin_url |
string |
The site admin URL, e.g. https://example.com/wp-admin. |
$site_url |
string |
The site frontend URL, e.g. https://example.com. |
Add an "Edit Site" link (network admin):
add_filter( 'all_sites_menu_submenu_items', function( array $items, int $blog_id, string $admin_url ): array { $items[] = [ 'id' => 'edit-site', 'title' => 'Edit Site', 'href' => network_admin_url( 'site-info.php?id=' . $blog_id ), ]; return $items; }, 10, 3 );
Remove "Manage Comments":
add_filter( 'all_sites_menu_submenu_items', function( array $items ): array { return array_filter( $items, fn( $item ) => $item['id'] !== 'c' ); } );
Demo
Try it in WordPress Playground (loads 50 subsites — may take a moment).
- Deactivate the plugin to see the default My Sites menu fail to scroll.
- Activate Restricted Site Access to see the red indicator icon.
How it works
PHP (server) JS (browser)
───────────── ────────────
get_timestamp() ──inline_script──▶ pluginAllSitesMenu.timestamp
│
Compare with IndexedDB timestamp
│
┌──────────┴──────────┐
│ mismatch │ match
▼ ▼
Clear DB Use cached data
│ │
▼ │
REST /sites?offset=0 │
REST /sites?offset=100 │
…(batched) │
│ │
▼ ▼
Store in IndexedDB ──▶ Render menu
The PHP timestamp acts as a cache version. It is bumped whenever a site is added/deleted, a blog name changes, or a monitored plugin is (de)activated. On the client side, a mismatch triggers a full re-fetch; a match means the cached data is used as-is.
Development
# Install dependencies npm install # Build npm run build # Run tests npm test # Format source npm run format
Changelog
See CHANGELOG.md.
Credits
- Dexie.js (Apache 2.0) — IndexedDB wrapper
- Submenu offset adjustment — zephyr7501
- Search field CSS — trepmal/my-sites-search
License
Copyright 2021 Per Soderlind. Licensed under the GNU General Public License v2 or later.
You should have received a copy of the GNU Lesser General Public License along with the Extension. If not, see http://www.gnu.org/licenses/.

