Super Admin All Sites Menu

外掛說明

  • 不使用 switch_to_blog() 函式。也就是說,Super Admin All Sites Menu 會比 WordPress 工具列的 [我的網站] 選單更快且使用更少資源。
  • 子網站選單會儲存在伺服器本機的 IndexedDB (我說過它很快) 中,伺服器本機儲存區會因為以下狀況而更新:
    • 啟用外掛。
    • 新增或刪除網站。
    • 變更網站名稱。
    • IndexedDB 與網站變更不同步。
    • 啟用或停用 Restricted Site Access 外掛。
  • 更新子網站選單資料後,使用 AJAX 並以增量方式處理 (每次增量處理 100 個網站)。
  • 列出全部子網站。WordPress 工具列上的 [我的網站] 僅會列出具備子網站網站管理員權限的網站。
  • 使用 Restricted Site Access 外掛限制存取的網站會以紅色圖示標示。
  • 依據字母順序排列網站選單。
  • 搜尋篩選條件。
  • 新增更多選單項目
    • 在 [多站網路管理中心]…
      • 新增網站
    • 在每個網站…
      • 新增頁面
      • 使用者
      • 外掛
      • 設定

必要條件

  • WordPress 多站網路
  • 新式瀏覽器 (不支援 IE11)

功能示範

這個外掛已在 WordPress Playground 上提供功能示範。由於會載入 50 個子網站,所以載入速度稍慢。

  • 如果在主要網站的 [外掛] 選單中停用 Super Admin All Sites Menu,便會發現 WordPress 工具列的 [我的網站] 選單無法捲動且無法查看全部網站,這是已經存在長達 14 年的 WordPress 核心程式的程式碼錯誤

  • 如果啟用 Restricted Site Access 外掛,便會看到網站名稱旁顯示紅色圖示。目前由於 WordPress Playground 的問題,Restricted Site Access 的紅色圖示僅能在主要網站上顯示。

篩選器

網站管理員可以使用以下篩選器覆寫預設值:

  • all_sites_menu_order_by

    • 選單排序方式預設值為 name,接受 idurlname

      add_filter( 'all_sites_menu_order_by', function( string $order_by ) : string {
          return 'url';
      } );
      
  • all_sites_menu_load_increments

    • AJAX 載入增量。預設值為 100。

      add_filter( 'all_sites_menu_load_increments', function( int $increments ) : int {
          return 300;
      } );
      
  • all_sites_menu_plugin_trigger

    • 外掛啟用或停用後,觸發伺服器本機儲存區 (IndexedDB) 更新。預設值為 [ 'restricted-site-access/restricted_site_access.php' ]

      注意事項:值必須為陣列,且在陣列中的每個元素都必須指向外掛主要檔案。語法為 '外掛資料夾/外掛主要檔案.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

    • 如果值小於 N (代表子網站數量) ,則不顯示搜尋欄位。預設值為 20。

      add_filter( 'all_sites_menu_search_threshold', function( int $increments ) : int {
          return 40;
      } );
      
  • all_sites_menu_search_threshold

    • 如果值小於 N (代表子網站數量) ,則不顯示搜尋欄位。預設值為 20。

      add_filter( 'all_sites_menu_search_threshold', function( int $increments ) : int {
          return 40;
      } );
      
  • all_sites_menu_force_refresh_expiration

    • 設定強制重新整理時間間隔,單位為秒。預設值為 3600,設定為 0 代表停用強制重新整理。

      add_filter( 'all_sites_menu_force_refresh_expiration', function( int $seconds ) : int {
          return 3600;
      } );
      
  • all_sites_menu_submenu_items

    • 自訂個別網站子選單項目 (新增、移除或重新排序)。項目自訂方式:['id' => string, 'title' => string, 'href' => string]。接收 $items$blog_id$admin_url$site_url

      // Add an "Edit Site" link pointing to the network admin site-info page.
      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 );
      

外掛的開發工作位置

螢幕擷圖

  • 功能示範
  • 選單資料儲存於伺服器本機的 IndexedDB

使用者評論

這個外掛目前沒有任何使用者評論。

參與者及開發者

以下人員參與了開源軟體〈Super Admin All Sites Menu〉的開發相關工作。

參與者

〈Super Admin All Sites Menu〉外掛目前已有 3 個本地化語言版本。 感謝全部譯者為這個外掛做出的貢獻。

將〈Super Admin All Sites Menu〉外掛本地化為台灣繁體中文版

對開發相關資訊感興趣?

任何人均可瀏覽程式碼、查看 SVN 存放庫,或透過 RSS 訂閱開發記錄

變更記錄

1.12.1

  • Fixed: Menu sometimes not loading after a REST API error — partial data is cleared and the next page load retries automatically
  • Fixed: Nonce middleware stacking on every REST batch request, causing slowdowns on large networks
  • Fixed: Infinite REST requests when API returns empty data — loading now terminates correctly
  • Fixed: Infinite loop when loadincrements is falsy/0 — defaults to 100
  • Fixed: refreshAdminbar() duplicating event listeners on repeated calls, causing erratic hover/toggle
  • Changed: Converted recursive REST loader to iterative loop to prevent stack overflow on large networks
  • Added: Test coverage for REST loading edge cases and refresh idempotency

1.12.0

  • Added: Menu colors now follow the user’s Administration Color Scheme
  • Added: Hover/focus on menu items uses the scheme’s highlight background, matching the admin sidebar

1.11.1

  • Fixed search box styling inconsistency between admin and front-end pages
  • Fixed action_enqueue_scripts parameter type error on front-end
  • Updated dependencies: @wordpress/api-fetch, @wordpress/i18n (56), @wordpress/scripts, dexie
  • Security: Resolved all npm audit vulnerabilities

1.11.0

  • Performance: Replaced per-site WP_Site::get_details() calls with a single batch SQL query, eliminating hidden switch_to_blog() overhead in the REST endpoint

1.10.1

  • Updated: @wordpress/scripts 30.7.0 31.6.0
  • Updated: dexie 4.0.11 4.2.0
  • Security: Resolved Dependabot alerts #102, #104, #108, #109 (minimatch ReDoS, serialize-javascript RCE, @tootallnate/once)
  • Changed: Added npm overrides for transitive dependency vulnerabilities (0 audit findings)

1.10.0

  • Added: Filterable per-site submenu items via all_sites_menu_submenu_items filter (#46)
  • Added: Numeric blog_id field in REST response for use in filters and custom JS (#46)
  • Added: Search by URL — the search filter now matches site URLs in addition to site names (#45)
  • Added: Updated search placeholder to “Search by name or URL”
  • Fixed: Sort by ID now uses numeric blog_id index for correct order instead of lexicographic string sort (#47)
  • Fixed: Admin bar item IDs now use correct blog-N string instead of 0 (#46)
  • Fixed: Search URL indexing decoupled from submenu order via data-url attribute (#46)

1.9.0

  • Fixed: PHP copy-paste bug in set_properties() — cache expiration validation checked wrong variable
  • Fixed: Removed dead REST guard in init() that could never match
  • Fixed: Removed redundant header() in REST callback
  • Fixed: toggleClass ReferenceError in refresh.js — Tab key navigation into submenus was broken
  • Fixed: IntersectionObserver race condition that could duplicate menu HTML
  • Fixed: Added partial-load recovery — failed REST fetches now clear IndexedDB so next load retries
  • Security: Added URL sanitisation and attribute escaping in menu template to prevent XSS
  • Changed: Rewrote refresh.js — removed dead code, modernised to classList API
  • Changed: Moved build-only packages from dependencies to devDependencies
  • Changed: Updated all npm packages to latest compatible versions
  • Tested up to WordPress 7.0

1.8.4

  • Update dependencies

1.8.3

  • Housekeeping

1.8.2

  • Abort early if the user does not have the required permissions
  • Security: Added endpoint verification for REST API requests
  • Bug fix: Added rest endpoint permission check
  • Code improvement: Added strict types declaration
  • Code improvement: Added return type declarations

1.8.1

  • Remove duplicate code

1.8.0

REQUIRE PHP 8.0 OR HIGHER

  • Code modernization: Refactored to use PHP 8.0+ features
  • Enhancement: Improved type safety and error handling
  • Performance: Better code organization with Config class
  • Enhancement: Increased default search threshold to 20 sites

1.7.3

  • Fixed search functionality:
    • Improved search performance with better indexing
    • Added mutation observer to handle dynamically loaded sites
    • Fixed event handling for search input
    • Added improved error handling for search elements
    • Better handling of empty search inputs

1.7.2

  • Bump version to trigger a deploy to WordPress.org

1.7.1

  • Bump version to trigger a deploy to WordPress.org

1.7.0

  • Major code refactoring and improvements:
    • Added comprehensive JSDoc documentation
    • Improved error handling throughout the codebase
    • Enhanced IndexedDB implementation with private class fields
    • Added debouncing to search functionality
    • Improved intersection observer implementations
    • Better type checking and null safety
    • Modernized class structure and module organization

1.6.9

  • Update dependencies

1.6.8

  • Update dependencies

1.6.7

  • Update dependencies

1.6.6

  • Tested with WordPress 6.4

1.6.5

  • Tested with WordPress 6.3

1.6.4

  • Fix bug in handling the REST API.

1.6.2

  • Tested with WordPress 6.0

1.6.1

  • Await for the promise populateDB() to resolve before continuing.

1.6.0

  • Use @wordpress/api-fetch to fetch subsite data.

1.5.0

  • Use REST instead of AJAX.

1.4.28

  • Housekeeping

1.4.27

  • Add missing textdomain to translations.
  • Update uninstall.php

1.4.26

  • Bundle Dexie using wp-scripts

1.4.25

  • Housekeeping

1.4.24

  • Use @wordpress/i18n to translate JavaScript.

1.4.23

  • Fix typo in textdomain.

1.4.22

  • Housekeeping

1.4.21

  • Update translation file (.pot)

1.4.20

  • Don’t set dependencies for style.

1.4.19

  • Import @wordpress/i18n

1.4.18

  • Replace build script from webpack to wp-scripts (@wordpress/scripts)

1.4.17

  • Use correct AJAX URL

1.4.16

  • Upgrade Dexie.js to v 3.2.0

1.4.15

  • Only load the plugin code if the admin bar is available.

1.4.14

  • Force refresh using a site transient.

1.4.13

  • Don’t list sites that are tagged as archived, deleted, mature or spam.

1.4.12

  • Update plugin banner

1.4.11

  • Add plugin banner

1.4.10

  • Housekeeping

1.4.9

  • Deploy to https://wordpress.org/plugins/super-admin-all-sites-menu/

1.4.8

  • Remove external dependencies.

1.4.7

  • Remove type=module from script tag. Not needed anymore since the script and modules are packed.

1.4.6

  • Pack JavaScript using webpack.

1.4.5

  • Only run if multisite.
  • Improved Dexie versioning.

1.4.4

  • Pass only one parameter to plugin_update_local_storage()
  • Close db connection when getting version number.

1.4.3

  • IndexedDB maintenance, i.e. remove old databases.

1.4.2

  • Dexie schema change, bump Dexie version number.

1.4.1

  • Make sure the local storage (IndexedDB) is in sync with server changes.

1.4.0

  • Refactored JavaScript again, I’m using this plugin to experiment with and to learn JavaScript better.

1.3.8

  • Refactor and rename db module.

1.3.7

  • Don’t display search field if there’s less than 20 subsites. The threshold is adjustable using the all_sites_menu_search_threshold filter

1.3.6

  • Fix load increments bug.

1.3.5

  • Housekeeping.

1.3.4

  • Add filters to defaults.

1.3.3

  • Update IndexedDB when you change a blog name.

1.3.2

  • Only change text/javscriptto module when tag has src attribute

1.3.0

  • Refactor
    • Split JavaScript into modules
    • If empty, populate IndexedDB with sites menu data.

1.2.4

  • Adjust the sites menu wrapper height

1.2.3

  • Remove window.hoverintent, it’s slow when you have a lot of sites, use addEventListener in capturing mode instead.

1.2.2

  • Housekeeping.

1.2.1

  • Update IndexedDB when Restricted Site Access is (de)activated.

1.2.0

  • Store subsite menu data in IndexedDB (local storage).
    • IndexedDB is updated when a site is added / deleted.
  • Add search.

1.1.2

  • Fix translations.

1.1.1

  • Housekeeping.

1.1.0

  • Lazy load the subsite menu, using IntersectionObserver and AJAX, loading only 80 subsites at a time.
  • Make subsites menu scrollable.

1.0.x

  • Initial release.