Summary
desktop_mode_recycle_bin_empty() fetches one page of 200 items, deletes them, and returns success, leaving everything beyond the 200th item in the bin. Users with a >200-item trash see a "success" message and a still-non-empty bin.
The code comment promises "Loop in chunks" but the loop is missing.
Evidence
includes/recycle-bin/store.php:803-838:
function desktop_mode_recycle_bin_empty() {
$purged = 0;
$skipped = 0;
// Loop in chunks. `wp_delete_post()` is cheap individually but
// hammering it on a 10k-item bin without yielding back to PHP can
// still time out. 200 is plenty for a single REST roundtrip.
$batch = desktop_mode_recycle_bin_get_items( array( 'per_page' => 200, 'page' => 1 ) );
foreach ( $batch['items'] as $item ) {
// purge…
}
return array(
'purged' => $purged,
'skipped' => $skipped,
'remaining' => max( 0, $batch['total'] - $purged ),
);
}
Client (src/recycle-bin/index.ts:606-644) calls emptyBin() once, ignores the remaining field, shows success, and re-renders. So a 500-item bin → 200 purged, 300 silently remain, UI claims success.
Repro
- Trash 250+ posts.
- Open Recycle Bin in the shell.
- Click "Empty bin".
- Observe: success toast, bin still contains 50+ items.
Independently reproduced by an automated gray-box run with 250 trashed items.
Suggested fix
Two-part:
- Server: loop until
$batch['total'] is exhausted, OR keep the 200-cap-per-call but have the response signal remaining > 0 so the client can keep going. (The cap exists to avoid PHP timeouts on huge bins, which is a legitimate concern, keeping it and letting the client iterate is the safer call.)
- Client (
src/recycle-bin/index.ts:606-644): if remaining > 0, auto-call the endpoint again until it hits 0 (or until skipped matches the remaining set, indicating capability-blocked items). Surface progress (e.g. "Emptying… 200 of 500").
Add a >200-item case to tests/phpunit/tests/recycleBinStore.php (and the equivalent vitest) to lock this down.
Severity
High. Silent data-state mismatch, user trusts a success message that isn't true.
Summary
desktop_mode_recycle_bin_empty()fetches one page of 200 items, deletes them, and returns success, leaving everything beyond the 200th item in the bin. Users with a >200-item trash see a "success" message and a still-non-empty bin.The code comment promises "Loop in chunks" but the loop is missing.
Evidence
includes/recycle-bin/store.php:803-838:Client (
src/recycle-bin/index.ts:606-644) callsemptyBin()once, ignores theremainingfield, shows success, and re-renders. So a 500-item bin → 200 purged, 300 silently remain, UI claims success.Repro
Independently reproduced by an automated gray-box run with 250 trashed items.
Suggested fix
Two-part:
$batch['total']is exhausted, OR keep the 200-cap-per-call but have the response signalremaining > 0so the client can keep going. (The cap exists to avoid PHP timeouts on huge bins, which is a legitimate concern, keeping it and letting the client iterate is the safer call.)src/recycle-bin/index.ts:606-644): ifremaining > 0, auto-call the endpoint again until it hits 0 (or untilskippedmatches the remaining set, indicating capability-blocked items). Surface progress (e.g. "Emptying… 200 of 500").Add a >200-item case to
tests/phpunit/tests/recycleBinStore.php(and the equivalent vitest) to lock this down.Severity
High. Silent data-state mismatch, user trusts a success message that isn't true.