=== 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.1.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. The log, with the headline figures above it and a ranking of what is failing most.
2. One failure opened: the diagnosis, the specific thing to check next, and the request it came from.
3. Causes and fixes. A failure links straight to its own entry, which arrives already open.
4. The state a healthy site stays in, with how to reproduce the failure you are chasing.
5. The settings on this installation that decide whether a nonce verifies at all.

== Changelog ==

= 1.1.0 =
* The screen is now its own top-level menu rather than an item under Tools, and is split into three tabs.
* New "Causes and fixes" tab explaining every diagnosis in full, with the concrete checks to run for each. The log links straight to the relevant entry.
* New "Environment" tab reporting the settings that decide whether a nonce verifies: nonce lifetime, any detected page cache, persistent object cache, and login session length. A nonce lifetime shortened by another plugin, or a session shorter than the nonce it carries, explains failures that otherwise look like bugs.
* Headline figures above the log: how many failures, the most common cause, how many distinct nonce actions are involved, and the time span they cover. More than one action string means the problem is not a single broken form.
* The empty state now says that an empty log is the expected result on a healthy site, and explains how to reproduce a failure so it gets captured.
* The screen has been rebuilt: the three sections are now real pages in the sidebar, each recorded failure folds down so a long log stays readable, and every cause is a section you can open rather than a wall of text.
* Assets are versioned by file rather than by plugin version, so a changed stylesheet can never be served from a stale browser cache.
* Tested up to WordPress 7.1.

= 1.0.0 =
* Initial release.
