Skip to content

fix(item-restoration): send the REST nonce from the shop page - #208

Merged
Helias merged 1 commit into
masterfrom
fix/item-restoration-rest-nonce
Aug 7, 2026
Merged

fix(item-restoration): send the REST nonce from the shop page#208
Helias merged 1 commit into
masterfrom
fix/item-restoration-rest-nonce

Conversation

@Helias

@Helias Helias commented Aug 7, 2026

Copy link
Copy Markdown
Member

Item restoration is broken on the shop page: no matter how many deleted items a character has, it always says "There are no items to recover for the selected character".

The list endpoint answers 401 for everyone:

$ curl -i 'https://<site>/wp-json/acore/v1/item-restore/list/651402'
HTTP/2 401
{"code":"rest_forbidden","message":"Sorry, you are not allowed to do that.","data":{"status":401}}

#202 added permission_callback => is_user_logged_in() to both item-restore routes, which is the right thing to do, but the shop page still calls them with a bare fetch(). Being logged in isn't enough for the REST API: rest_cookie_check_errors() calls wp_set_current_user(0) when there's no _wpnonce param and no X-WP-Nonce header, so the request is anonymous and the permission callback rejects it.

The user panel page already got the nonce when it was reworked, so the shop page was the last caller left.

Second half of the fix: the fetch had no .catch and didn't look at the status, so an error body has no .length and lands in the same branch as an empty list. That's why a 401 was reported to players as "you have nothing to recover". Now a failed request shows an error instead.

How to test

Buy or open the item-restoration product with a character that has rows in recovery_item, they should be listed again. To check the failure path, drop the X-WP-Nonce header in devtools and confirm you get the error message rather than the empty state.

Follow-up, not in here

item-restore/list still takes any character guid from any logged-in user, so you can enumerate someone else's deleted items. The POST already checks ownership via currentAccountOwnsCharacterName(), the GET could use the same treatment.

Summary by CodeRabbit

  • Bug Fixes
    • Added a clear error message when item restoration fails to load.
    • Improved request validation to handle unsuccessful responses safely.
    • Preserved loading-state cleanup after both successful and failed requests.
    • Prevented incomplete item content from being displayed when restoration requests fail.

The item-restore routes got a permission_callback in #202, but the shop page
still calls them without X-WP-Nonce, so WordPress drops the cookie identity
and answers 401. The fetch has no error handling either, so that 401 ends up
in the same branch as an empty list and the page claims there is nothing to
recover.
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The item restoration UI now displays a load-error alert. REST requests include a WordPress REST nonce, validate HTTP status, and parse JSON only after successful responses. Failures hide the item container and stop the loader.

Changes

Item restoration loading flow

Layer / File(s) Summary
REST request and failure display
src/acore-wp-plugin/src/Hooks/WooCommerce/ItemRestoration.php
The UI adds a hidden load-error alert and references the server-generated REST nonce. The request sends the nonce, rejects unsuccessful HTTP responses, and parses JSON only after success. Failed requests hide the item container and display the alert.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the primary change: sending the REST nonce for item restoration requests from the shop page.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/item-restoration-rest-nonce

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/acore-wp-plugin/src/Hooks/WooCommerce/ItemRestoration.php`:
- Around line 229-246: Update selectCharacter() to track the latest item-list
request with a request identifier or equivalent token, and have every associated
then(), catch(), and finally() callback return without changing shared DOM when
it is no longer current. Apply the same stale-response guard to the request
handling around the fetch call and the additional callbacks near the later
referenced block, while preserving updates for the latest selected character.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 12321fc9-a2ff-4b80-b99d-62743a33d17c

📥 Commits

Reviewing files that changed from the base of the PR and between 5881c00 and eafc9c0.

📒 Files selected for processing (1)
  • src/acore-wp-plugin/src/Hooks/WooCommerce/ItemRestoration.php

Comment on lines +229 to +246
loadError.style.display = 'none';
loaderIcon.style.display = 'block';

itemListLoaders.forEach(element => element.classList.remove('hidden'));
itemContainer.classList.remove('hidden');
const character = charGuid;
const characterName = charList.options[charList.selectedIndex].innerText;

fetch('<?= get_rest_url(null, 'acore/v1/item-restore/list/'); ?>' + character)
.then((response) => response.json())
fetch('<?= get_rest_url(null, 'acore/v1/item-restore/list/'); ?>' + character, {
headers: { 'Accept': 'application/json', 'X-WP-Nonce': restNonce }
})
.then((response) => {
if (!response.ok) {
throw new Error('Request failed with status ' + response.status);
}

return response.json();
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Ignore stale responses when the character changes.

When selectCharacter() runs again before the previous request finishes, the older request can still update the shared DOM. A late response can replace the current character’s items. A late failure can hide a successful result and display the error alert. Track the latest request and ignore stale .then(), .catch(), and .finally() callbacks.

Proposed fix
+let latestRequestId = 0;
+
 function selectCharacter(charGuid) {
+  const requestId = ++latestRequestId;
+
   ...
   .then((response) => {
+      if (requestId !== latestRequestId) return;
       if (!response.ok) {
           throw new Error('Request failed with status ' + response.status);
       }
       return response.json();
   })
   .then(function(items) {
+      if (requestId !== latestRequestId) return;
       ...
   })
   .catch(() => {
+      if (requestId !== latestRequestId) return;
       ...
   })
   .finally(() => {
+      if (requestId !== latestRequestId) return;
       ...
   });
 }

Also applies to: 292-296

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/acore-wp-plugin/src/Hooks/WooCommerce/ItemRestoration.php` around lines
229 - 246, Update selectCharacter() to track the latest item-list request with a
request identifier or equivalent token, and have every associated then(),
catch(), and finally() callback return without changing shared DOM when it is no
longer current. Apply the same stale-response guard to the request handling
around the fetch call and the additional callbacks near the later referenced
block, while preserving updates for the latest selected character.

@Helias
Helias merged commit f1ff152 into master Aug 7, 2026
2 checks passed
@Helias
Helias deleted the fix/item-restoration-rest-nonce branch August 7, 2026 21:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant