wppaste
WordPress

check_ajax_referer( int|string $action = -1, false|string $query_arg = false, bool $stop = true ): int|false

Since
2.0.3
Source
wp-includes/pluggable.php:1317

Validates the nonce submitted with an AJAX request, checking $_REQUEST for a custom key or falling back to '_ajax_nonce' then '_wpnonce'. Returns 1 or 2 for a valid nonce depending on its age, or false only when $stop is set to false, since by default a failed check calls wp_die() or die() and ends the request immediately. Pair it with wp_create_nonce() on the side that generates the nonce, since check_ajax_referer() only verifies what wp_verify_nonce() tells it.

Verifies the Ajax request to prevent processing requests external of the blog.

Compatibility

WordPress
since 2.0.3
PHP
7.4–8.6-dev
  • 6.7.7
  • 6.8.8
  • 6.9.7
  • 7.0.4
  • 7.1.0

Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.

Parameters

$actionint|stringoptional
Action nonce.Default: -1
$query_argfalse|stringoptional
Key to check for the nonce in $_REQUEST (since 2.5). If false, $_REQUEST values will be evaluated for '_ajax_nonce', and '_wpnonce' (in that order). Default false.Default: false
$stopbooloptional
Whether to stop early when the nonce cannot be verified.
Default true.Default: true

Return value

int|false
1 if the nonce is valid and generated between 0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
False if the nonce is invalid.

Code examples

Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.

Verify a nonce before trashing a post in an AJAX-style handler

Simulate an incoming AJAX request that asks to trash post 2, using the default _wpnonce field and letting the function stop execution on failure.

$action = 'delete_post_2';
$_REQUEST['_wpnonce'] = wp_create_nonce( $action );

check_ajax_referer( $action );

$trashed = wp_trash_post( 2 );

if ( $trashed ) {
	printf( 'Post 2 moved to trash: %s', esc_html( $trashed->post_title ) );
} else {
	echo 'Could not trash the post.';
}

Because $stop defaults to true, an invalid nonce here would call wp_die() and nothing after check_ajax_referer() would run.

Check a custom nonce field name without killing the script on failure

Look up post meta only if a nonce sent under a custom field name verifies, but keep the script running either way by passing $stop as false.

$_REQUEST['price_nonce'] = wp_create_nonce( 'wrong_action' );

$result = check_ajax_referer( 'bookstore_price_nonce', 'price_nonce', false );

if ( false === $result ) {
	echo 'Nonce mismatch, price lookup blocked.' . "\n";
} else {
	printf( 'Nonce is valid (result: %d). Price for post 2: %s', $result, esc_html( get_post_meta( 2, 'price', true ) ) );
}

echo 'Script kept running because $stop was false.';

The nonce is deliberately created for a different action, so this prints the mismatch branch and proves execution continued past the check.

Common problems and fixes · 4

Why does my AJAX request just die with -1 instead of showing my own error?

By default $stop is true, so a failed nonce check calls wp_die( -1, 403 ) when wp_doing_ajax() is true, or plain die( '-1' ) otherwise, before your code ever runs.

Why do I see a _doing_it_wrong notice mentioning check_ajax_referer?

The $action parameter defaults to the sentinel value -1, and the function explicitly calls _doing_it_wrong() whenever that default is left in place, since 4.7.0.

Why does check_ajax_referer() still pass even though I never set $query_arg?

When $query_arg is false, the function falls back to checking $_REQUEST['_ajax_nonce'] first, then $_REQUEST['_wpnonce'], so a nonce sent under either default name is accepted silently.

Why does an if ( check_ajax_referer( ... ) === true ) check always fail?

A successful check never returns boolean true; it returns 1 (nonce 0-12 hours old) or 2 (12-24 hours old), matching what wp_verify_nonce() returns. Only a failed check with $stop set to false returns false.

Alternatives and related functions

wp_verify_nonce
When you already have the raw nonce value in hand and want to verify it directly without touching $_REQUEST or risking a wp_die() call.
check_admin_referer
When verifying a nonce on a regular admin form submission rather than an AJAX request.
wp_create_nonce
When you need to generate the nonce value that check_ajax_referer() will later verify.

Performance profile

How much work a call to check_ajax_referer() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.

Cost class
Trivial

Touches nothing outside its own arguments.

Scaling
Constant

No loop in the body: the same number of instructions runs whatever you pass in.

Instructions
25–48

Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 60.

Plugin surface
1 hook

Third-party callbacks on 'check_ajax_referer' run inside this call, and their cost is not bounded by anything here.

Called by
50

50 places in core call this, so the cost is paid more often than your own code shows.

What it touches

  • hookthird-party callbacksdo_action()called directly

Further down the call graph this can also reach option, cache, serialize, transient and query. Those are the worst case, several calls deep and usually down an error path, not what a normal call pays.

What one call costs · 6 distinct outcomes

One number would be a lie: the work depends on which branch runs. These are every distinct cost check_ajax_referer() can have, taken from its control-flow graph on PHP 8.5.

WhenInstructionsCalls it makes
$action !== -125–33wp_verify_nonce(), do_action()
$action !== -1 && $result === false && !wp_doing_ajax()33–39wp_verify_nonce(), do_action(), wp_doing_ajax(), exit()
$action === -133–41__(), _doing_it_wrong(), wp_verify_nonce(), do_action()
$action !== -1 && $result === false && wp_doing_ajax()34–40wp_verify_nonce(), do_action(), wp_doing_ajax(), wp_die()
$action === -1 && $result === false && !wp_doing_ajax()41–47__(), _doing_it_wrong(), wp_verify_nonce(), do_action(), wp_doing_ajax(), exit()
$action === -1 && $result === false && wp_doing_ajax()42–48__(), _doing_it_wrong(), wp_verify_nonce(), do_action(), wp_doing_ajax(), wp_die()

Across PHP versions

PHPCompiledExecutedBranchesNotes
8.6-dev6025–488
8.56025–488
8.46025–4882 more instructions than PHP 8.3
8.35825–488
8.25825–488
8.15825–488
7.45825–488

An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.

Hooks and filters fired · 1

One hook fires while check_ajax_referer() runs, in this order:

  1. do_action( check_ajax_referer )actionline 1343 (+26 into the body)

    Fires once the Ajax request has been validated or not.

Uses · 6

  • _doing_it_wrong()Marks something as being incorrectly called.
  • __()Retrieves the translation of $text.
  • wp_verify_nonce()Verifies that a correct security nonce was used with time limit.
  • do_action()Calls the callback functions that have been added to an action hook.
  • wp_doing_ajax()Determines whether the current request is a WordPress Ajax request.
  • wp_die()Kills WordPress execution and displays HTML page with an error message.

Used by · 50

Show all 50

Source code

	function check_ajax_referer( $action = -1, $query_arg = false, $stop = true ) {		if ( -1 === $action ) {			_doing_it_wrong( __FUNCTION__, __( 'You should specify an action to be verified by using the first parameter.' ), '4.7.0' );		} 		$nonce = ''; 		if ( $query_arg && isset( $_REQUEST[ $query_arg ] ) ) {			$nonce = $_REQUEST[ $query_arg ];		} elseif ( isset( $_REQUEST['_ajax_nonce'] ) ) {			$nonce = $_REQUEST['_ajax_nonce'];		} elseif ( isset( $_REQUEST['_wpnonce'] ) ) {			$nonce = $_REQUEST['_wpnonce'];		} 		$result = wp_verify_nonce( $nonce, $action ); 		/**		 * Fires once the Ajax request has been validated or not.		 *		 * @since 2.1.0		 *		 * @param string    $action The Ajax nonce action.		 * @param false|int $result False if the nonce is invalid, 1 if the nonce is valid and generated between		 *                          0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.		 */		do_action( 'check_ajax_referer', $action, $result ); 		if ( $stop && false === $result ) {			if ( wp_doing_ajax() ) {				wp_die( -1, 403 );			} else {				die( '-1' );			}		} 		return $result;	}

Changelog

Introduced in 2.0.3. Unchanged from 6.7.7 through 7.1.0.

  1. 6.7.7
  2. 6.8.8
  3. 6.9.7
  4. 7.0.4
  5. 7.1.0

Signature, return type and hooks compared across 5 parsed releases.

About this page

Parsed data
Generated from the wordpress-develop 6.7.7 tag, from src/wp-includes/pluggable.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.
Corrections
Something wrong on this page? Report it and it gets fixed in the next regeneration.