=== Nonce Failure Explainer ===
Contributors: shahzaibhassan
Tags: nonce, debugging, security, developer, ajax
Requires at least: 5.6
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Explains why a WordPress security check failed, instead of just telling you that it did.

== Description ==

"Security check failed" is an outcome, not a diagnosis. It does not tell you whether the nonce
field was missing, the action string differed, the session ended, a cached page served a stale
value, or the nonce simply expired.

Nonce Failure Explainer records every failed nonce check and states the most likely cause, along
with the specific thing to check next.

= What it records =

For each failure:

* The most likely cause, with an explicit confidence level
* A concrete next check to run
* The nonce action string
* The request type (ajax, rest, admin, admin-post, cron, cli, frontend), method, and path
* A best-effort guess at which plugin or theme ran the check
* Whether the user was logged in

= What it never records =

* The nonce value itself
* Authentication cookies or session tokens
* Passwords, API keys, or any request body
* Query strings, which routinely carry one-time tokens

Function arguments are excluded from the stack trace capture, so sensitive values are never
even loaded into memory during attribution.

= Causes it distinguishes =

* **No nonce was submitted** — the field or query argument never reached the server. Confirmed,
  not inferred.
* **The session ended** — an auth cookie arrived but no longer resolves to a user.
* **A cached page served a stale nonce** — detected when an anonymous request fails while a known
  caching layer is active.
* **No session token** — the user is logged in but has no session for the nonce to key against.
* **Expired or mismatched action** — everything needed was present, so the value itself did not
  match.

= Design =

Read-only. The plugin observes and explains; it never alters a request, extends a nonce lifetime,
or changes site behaviour in any way. Storage is a single non-autoloaded option capped at 200
events with a seven-day expiry, so it cannot grow unbounded on a busy site.

Nothing is sent anywhere. There is no external service, no telemetry, and no phone-home.

== Installation ==

1. Upload the plugin to `/wp-content/plugins/nonce-failure-explainer`, or install it through the
   Plugins screen.
2. Activate it.
3. Reproduce the failing request.
4. Visit **Tools → Nonce Failures**.

== Frequently Asked Questions ==

= Does this fix nonce failures? =

No, and deliberately so. Version 1 is a diagnostic tool. Automatically extending nonce lifetimes
or bypassing checks would weaken the protection nonces exist to provide.

= Will it slow my site down? =

The recorder only does work when a check actually fails, which on a healthy site is never. There
is no cost on successful requests.

= Why does it say "possible cause" rather than telling me exactly what happened? =

Because WordPress does not distinguish an expired nonce from one generated for a different action
— both simply fail to match. Where the cause can be established as fact, the plugin says
"Confirmed". Where it is inference, it says so.

= Is it safe on a production site? =

Yes. It is read-only, stores no secrets, and caps its own storage. The clearing action is
capability-checked and nonce-protected.

= Does it work with multisite? =

Yes. The log is per-site, and uninstalling clears it across every site in the network.

== Screenshots ==

1. Tools → Nonce Failures. Each failure carries a confidence level, the specific thing to check
next, the request context it came from, and where possible the plugin that ran the check.

== Changelog ==

= 1.0.0 =
* Initial release.
