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:1413
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.
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,$_REQUESTvalues 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?
- Why do I see a _doing_it_wrong notice mentioning check_ajax_referer?
- Why does check_ajax_referer() still pass even though I never set $query_arg?
- Why does an if ( check_ajax_referer( ... ) === true ) check always fail?
Why does my AJAX request just die with -1 instead of showing my own error?
Why do I see a _doing_it_wrong notice mentioning check_ajax_referer?
Why does check_ajax_referer() still pass even though I never set $query_arg?
Why does an if ( check_ajax_referer( ... ) === true ) check always fail?
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
- Scaling
- Constant
- Instructions
- 25–48
- Plugin surface
- 1 hook
- Called by
- 50
Touches nothing outside its own arguments.
No loop in the body: the same number of instructions runs whatever you pass in.
Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 60.
Third-party callbacks on 'check_ajax_referer' run inside this call, and their cost is not bounded by anything here.
50 places in core call this, so the cost is paid more often than your own code shows.
What it touches
- hookthird-party callbacks
do_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.
| When | Instructions | Calls it makes |
|---|---|---|
$action !== -1 | 25–33 | wp_verify_nonce(), do_action() |
$action !== -1 && $result === false && !wp_doing_ajax() | 33–39 | wp_verify_nonce(), do_action(), wp_doing_ajax(), exit() |
$action === -1 | 33–41 | __(), _doing_it_wrong(), wp_verify_nonce(), do_action() |
$action !== -1 && $result === false && wp_doing_ajax() | 34–40 | wp_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
| PHP | Compiled | Executed | Branches | Notes |
|---|---|---|---|---|
| 8.6-dev | 60 | 25–48 | 8 | |
| 8.5 | 60 | 25–48 | 8 | |
| 8.4 | 60 | 25–48 | 8 | 2 more instructions than PHP 8.3 |
| 8.3 | 58 | 25–48 | 8 | |
| 8.2 | 58 | 25–48 | 8 | |
| 8.1 | 58 | 25–48 | 8 | |
| 7.4 | 58 | 25–48 | 8 |
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:
- do_action( check_ajax_referer )actionline 1439 (+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
- Custom_Background::ajax_background_add()Handles Ajax request for adding custom background context to an attachment.
- Custom_Background::wp_set_background_image()
- Custom_Image_Header::ajax_header_add()Given an attachment ID for a header image, updates its "last used" timestamp to now.
- Custom_Image_Header::ajax_header_crop()Gets attachment uploaded by Media Manager, crops it, then saves it as a new object. Returns JSON-encoded object details.
- Custom_Image_Header::ajax_header_remove()Given an attachment ID for a header image, unsets it as a user-uploaded header image for the active theme.
- WP_Customize_Manager::handle_changeset_trash_request()Handles request to trash a changeset.
- WP_Customize_Manager::handle_dismiss_autosave_or_lock_request()Deletes a given auto-draft changeset or the autosave revision for a given changeset or delete changeset lock.
- WP_Customize_Manager::handle_load_themes_request()Loads themes into the theme browsing/installation UI.
- WP_Customize_Manager::handle_override_changeset_lock_request()Removes changeset lock when take over request is sent via Ajax.
- WP_Customize_Manager::save()Handles customize_save WP Ajax request to save/update a changeset.
- WP_Customize_Manager::setup_theme()Starts preview and customize theme.
- WP_Customize_Nav_Menus::ajax_insert_auto_draft_post()Ajax handler for adding a new auto-draft post.
Show all 50
- WP_Customize_Nav_Menus::ajax_load_available_items()Ajax handler for loading available menu items.
- WP_Customize_Nav_Menus::ajax_search_available_items()Ajax handler for searching available menu items.
- WP_Customize_Widgets::wp_ajax_update_widget()Updates widget settings asynchronously.
- WP_Plugin_Dependencies::check_plugin_dependencies_during_ajax()Checks plugin dependencies after a plugin is installed via AJAX.
- _wp_ajax_add_hierarchical_term()Handles adding a hierarchical term via AJAX.
- wp_ajax_activate_plugin()Handles activating a plugin via AJAX.
- wp_ajax_add_link_category()Handles adding a link category via AJAX.
- wp_ajax_add_menu_item()Handles adding a menu item via AJAX.
- wp_ajax_add_meta()Handles adding meta via AJAX.
- wp_ajax_add_tag()Handles adding a tag via AJAX.
- wp_ajax_add_user()Handles adding a user via AJAX.
- wp_ajax_closed_postboxes()Handles closed post boxes via AJAX.
- wp_ajax_crop_image()Handles cropping an image via AJAX.
- wp_ajax_delete_comment()Handles deleting a comment via AJAX.
- wp_ajax_delete_inactive_widgets()Handles removing inactive widgets via AJAX.
- wp_ajax_delete_link()Handles deleting a link via AJAX.
- wp_ajax_delete_meta()Handles deleting meta via AJAX.
- wp_ajax_delete_page()Handles deleting a page via AJAX.
- wp_ajax_delete_plugin()Handles deleting a plugin via AJAX.
- wp_ajax_delete_post()Handles deleting a post via AJAX.
- wp_ajax_delete_tag()Handles deleting a tag via AJAX.
- wp_ajax_delete_theme()Handles deleting a theme via AJAX.
- wp_ajax_dim_comment()Handles dimming a comment via AJAX.
- wp_ajax_edit_comment()Handles editing a comment via AJAX.
- wp_ajax_fetch_list()Handles fetching a list table via AJAX.
- wp_ajax_find_posts()Handles querying posts for the Find Posts modal via AJAX.
- wp_ajax_get_comments()Handles getting comments via AJAX.
- wp_ajax_get_community_events()Handles Ajax requests for community events
- wp_ajax_get_permalink()Handles retrieving a permalink via AJAX.
- wp_ajax_get_post_thumbnail_html()Handles retrieving HTML for the featured image via AJAX.
- wp_ajax_health_check_background_updates()Handles site health checks on background updates via AJAX.
- wp_ajax_health_check_dotorg_communication()Handles site health checks on server communication via AJAX.
- wp_ajax_health_check_get_sizes()Handles site health check to get directories and database sizes via AJAX.
- wp_ajax_health_check_loopback_requests()Handles site health checks on loopback requests via AJAX.
- wp_ajax_health_check_site_status_result()Handles site health check to update the result status via AJAX.
- wp_ajax_hidden_columns()Handles hidden columns via AJAX.
- wp_ajax_image_editor()Handles image editing via AJAX.
- wp_ajax_imgedit_preview()Handles image editor previews via AJAX.
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.
Signature, return type and hooks compared across 5 parsed releases.
About this page
- Parsed data
- Generated from the wordpress-develop 6.9.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.