Skip to content

Commit 22e274a

Browse files
authored
Merge pull request #76 from soderlind/refresh
fix: resolve menu load/refresh reliability issues
2 parents f9ca05f + 5950970 commit 22e274a

12 files changed

Lines changed: 266 additions & 42 deletions

File tree

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,25 @@
11
# Changelog
22

33
All notable changes to this project will be documented in this file.
4+
5+
### 1.12.1
6+
7+
#### Fixed
8+
9+
- Fixed menu sometimes not loading after a REST API error — `populateDB` now re-throws so the "Loading.." indicator stays visible and the next page load retries automatically
10+
- Fixed nonce middleware being stacked on every REST batch request, causing slowdowns on large networks
11+
- Fixed `loadSites` running forever when the API returns an empty data array — now terminates correctly
12+
- Fixed `loadSites` infinite recursion when `loadincrements` is falsy/0 — defaults to 100
13+
- Fixed `refreshAdminbar()` duplicating event listeners on repeated calls, causing erratic hover/toggle behaviour
14+
- Converted recursive `loadSites` to an iterative loop to prevent stack overflow on large networks
15+
- Removed unused `elements.timestamp` reference in init
16+
17+
18+
#### Added
19+
20+
- Added `rest.test.js` covering nonce idempotency, empty-data termination, maxSites limit, error propagation, and loadincrements fallback
21+
- Added refresh idempotency test to `refresh.test.js`
22+
423
### 1.12.0
524

625
#### Added

build/index.asset.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?php return array('dependencies' => array('wp-api-fetch', 'wp-i18n'), 'version' => 'a82fb6a8035da86fa674');
1+
<?php return array('dependencies' => array('wp-api-fetch', 'wp-i18n'), 'version' => '1e33e31af10a9a12d92d');

build/index.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "soderlind/super-admin-all-sites-menu",
33
"description": "For the super admin, replace WP Admin Bar My Sites menu with an All Sites menu.",
4-
"version": "1.12.0",
4+
"version": "1.12.1",
55
"keywords": [
66
"wordpress",
77
"multisite",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "super-admin-all-sites-menu",
3-
"version": "1.12.0",
3+
"version": "1.12.1",
44
"description": "For the super admin, replace WP Admin Bar My Sites menu with an All Sites menu.",
55
"main": "index.js",
66
"scripts": {

readme.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
=== Super Admin All Sites Menu ===
2-
Stable tag: 1.12.0
2+
Stable tag: 1.12.1
33
Requires at least: 5.6
44
Tested up to: 7.0
55
Requires PHP: 8.0
@@ -121,6 +121,16 @@ You can use the following filters to override the defaults:
121121

122122
== Changelog ==
123123

124+
= 1.12.1 =
125+
* Fixed: Menu sometimes not loading after a REST API error — partial data is cleared and the next page load retries automatically
126+
* Fixed: Nonce middleware stacking on every REST batch request, causing slowdowns on large networks
127+
* Fixed: Infinite REST requests when API returns empty data — loading now terminates correctly
128+
* Fixed: Infinite loop when `loadincrements` is falsy/0 — defaults to 100
129+
* Fixed: `refreshAdminbar()` duplicating event listeners on repeated calls, causing erratic hover/toggle
130+
* Changed: Converted recursive REST loader to iterative loop to prevent stack overflow on large networks
131+
* Fixed: Fatal error in `wp-portable-text` plugin — broken `stringNAMESPACE` constant and `self::NAMESPACE` (reserved keyword) references renamed to `REST_NAMESPACE`
132+
* Added: Test coverage for REST loading edge cases and refresh idempotency
133+
124134
= 1.12.0 =
125135
* Added: Menu colors now follow the user's Administration Color Scheme
126136
* Added: Hover/focus on menu items uses the scheme's highlight background, matching the admin sidebar

src/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ async function init() {
4141
const elements = {
4242
load: document.querySelector( '#wp-admin-bar-load-more' ),
4343
menu: document.querySelector( '#wp-admin-bar-my-sites-list' ),
44-
timestamp: document.querySelector( '#load-more-timestamp' ),
4544
};
4645

4746
if ( ! elements.load || ! elements.menu ) return;
@@ -98,9 +97,10 @@ async function populateDB( db ) {
9897
offset: 0,
9998
delayMs: 200,
10099
} );
101-
} catch {
100+
} catch ( err ) {
102101
// Clear partial data so next page load retries from scratch.
103102
await db.delete();
103+
throw err;
104104
}
105105
}
106106
}

src/modules/refresh.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44
* Submenu offset adjustment based on:
55
* @see https://qiita.com/zephyr7501/items/dd0967fddabd888b28c4
66
*/
7+
8+
let listenersAttached = false;
9+
710
export function refreshAdminbar() {
811
const sitemenu = document.getElementById( 'wp-admin-bar-my-sites-list' );
9-
if ( ! sitemenu ) {
12+
if ( ! sitemenu || listenersAttached ) {
1013
return;
1114
}
15+
listenersAttached = true;
1216

1317
sitemenu.addEventListener(
1418
'mouseenter',

src/modules/rest.js

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,23 @@ import apiFetch from '@wordpress/api-fetch';
77
*/
88
const delay = ( ms ) => new Promise( ( resolve ) => setTimeout( resolve, ms ) );
99

10+
/** Track whether the nonce middleware has already been registered. */
11+
let nonceMiddlewareSet = false;
12+
1013
/**
11-
* Using REST, incremental load sites and add them to local storage.
14+
* Register the REST nonce middleware once.
15+
*/
16+
function ensureNonceMiddleware() {
17+
if ( ! nonceMiddlewareSet ) {
18+
apiFetch.use(
19+
apiFetch.createNonceMiddleware( pluginAllSitesMenu.nonce )
20+
);
21+
nonceMiddlewareSet = true;
22+
}
23+
}
24+
25+
/**
26+
* Using REST, incrementally load sites and add them to local storage.
1227
*
1328
* @author Per Søderlind
1429
* @param {IndexedDB} db - IndexedDB instance
@@ -22,49 +37,43 @@ export async function loadSites(
2237
db,
2338
{ offset = 0, maxSites = 1000, delayMs = 1000 } = {}
2439
) {
25-
try {
26-
// Check if we've reached the maximum sites limit
27-
if ( maxSites > 0 && offset >= maxSites ) {
28-
return;
29-
}
40+
ensureNonceMiddleware();
3041

31-
// Set the nonce for the request
32-
apiFetch.use(
33-
apiFetch.createNonceMiddleware( pluginAllSitesMenu.nonce )
34-
);
42+
const increments = Number( pluginAllSitesMenu.loadincrements ) || 100;
43+
let currentOffset = offset;
3544

45+
while ( ! ( maxSites > 0 && currentOffset >= maxSites ) ) {
3646
// Add delay between requests to prevent overwhelming the server
37-
if ( offset > 0 ) {
47+
if ( currentOffset > 0 ) {
3848
await delay( delayMs );
3949
}
4050

41-
const res = await apiFetch( {
42-
url: pluginAllSitesMenu.restURL,
43-
method: 'POST',
44-
data: { offset },
45-
} );
51+
let res;
52+
try {
53+
res = await apiFetch( {
54+
url: pluginAllSitesMenu.restURL,
55+
method: 'POST',
56+
data: { offset: currentOffset },
57+
} );
58+
} catch ( err ) {
59+
console.error( 'Error in loadSites:', err.message );
60+
throw err;
61+
}
4662

4763
if ( ! res || typeof res.response !== 'string' ) {
4864
throw new Error( 'Invalid response format' );
4965
}
5066

51-
if ( res.response === 'success' && Array.isArray( res.data ) ) {
52-
await db.save( res.data );
53-
54-
// Calculate next offset
55-
const nextOffset = offset + pluginAllSitesMenu.loadincrements;
67+
// Server signals no more data.
68+
if ( res.response !== 'success' ) {
69+
return;
70+
}
5671

57-
// Recursive call with updated offset
58-
return loadSites( db, {
59-
offset: nextOffset,
60-
maxSites,
61-
delayMs,
62-
} );
72+
if ( ! Array.isArray( res.data ) || res.data.length === 0 ) {
73+
return;
6374
}
6475

65-
// TODO, should I: throw new Error( 'Unexpected response format' + res.response );
66-
} catch ( err ) {
67-
console.error( 'Error in loadSites:', err.message );
68-
throw err;
76+
await db.save( res.data );
77+
currentOffset += increments;
6978
}
7079
}

super-admin-all-sites-menu.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* Plugin URI: https://github.com/soderlind/super-admin-all-sites-menu
1313
* GitHub Plugin URI: https://github.com/soderlind/super-admin-all-sites-menu
1414
* Description: For the super admin, replace WP Admin Bar My Sites menu with an All Sites menu.
15-
* Version: 1.12.0
15+
* Version: 1.12.1
1616
* Author: Per Soderlind
1717
* Network: true
1818
* Author URI: https://soderlind.no

0 commit comments

Comments
 (0)