wppaste
WordPress

wp_die( string|WP_Error $message = '', string|int $title = '', string|array|int $args = array() ): never|void

Since
2.0.4, 4.1.0, 5.1.0, 5.3.0, 5.5.0
Source
wp-includes/functions.php:3781

Halts WordPress execution and shows a themed error page, choosing HTML, JSON, JSONP, XML, or XML-RPC output based on the current request type. Accepts a plain string or a WP_Error object as $message, and lets an integer stand in for $title or $args as shorthand for the HTTP response code. It is meant for genuine dead ends, not routine validation, since the process cannot continue past it unless $args['exit'] is explicitly set to false.

Kills WordPress execution and displays HTML page with an error message.

Description

This function complements the die() PHP function. The difference is that HTML will be displayed to the user. It is recommended to use this function only when the execution should not continue any further. It is not recommended to call this function very often, and try to handle as many errors as possible silently or more gracefully.

As a shorthand, the desired HTTP response code may be passed as an integer to the $title parameter (the default title would apply) or the $args parameter.

Compatibility

WordPress
since 5.5.0
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

$messagestring|WP_Erroroptional
Error message. If this is a WP_Error object, and not an Ajax or XML-RPC request, the error's messages are used.
Default empty string.Default: ''
$titlestring|intoptional
Error title. If $message is a WP_Error object, error data with the key 'title' may be used to specify the title.
If $title is an integer, then it is treated as the response code.
Default empty string.Default: ''
$argsstring|array|intoptional
Arguments to control behavior. If $args is an integer, then it is treated as the response code. Default empty array.Default: array()
  • $responseintdefault: 200 for Ajax requests, 500 otherwise

    The HTTP response code.
  • $link_urlstringdefault: empty string

    A URL to include a link to. Only works in combination with $link_text.
  • $link_textstringdefault: empty string

    A label for the link to include. Only works in combination with $link_url.
  • $back_linkbooldefault: false

    Whether to include a link to go back.
  • $text_directionstringdefault: is the value of is_rtl()

    The text direction. This is only useful internally, when WordPress is still loading and the site's locale is not set up yet. Accepts 'rtl' and 'ltr'.
  • $charsetstringdefault: 'utf-8'

    Character set of the HTML output.
  • $codestringdefault: is 'wp_die', or the main error code if $message is a WP_Error

    Error code to use.
  • $exitbooldefault: true

    Whether to exit the process after completion.

Return value

never|void
Returns void if $args['exit'] is false, otherwise exits.

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.

Stop execution with a 404 error page when a post ID doesn't exist

A template or admin script looks up a post and needs to bail out cleanly if it's missing.

$post_id = 999;
$post    = get_post( $post_id );

if ( ! $post ) {
	echo 'Post ' . absint( $post_id ) . ' not found, calling wp_die().';
	wp_die(
		esc_html__( 'Sorry, that post could not be found.' ),
		esc_html__( 'Post Not Found' ),
		array(
			'response'  => 404,
			'back_link' => true,
		)
	);
}

echo esc_html( $post->post_title );

Post 999 does not exist in the baseline fixtures (only IDs 1 to 6), so this always reaches wp_die().

Kill the request with a WP_Error object so its message and title are reused

Validating submitted form data before letting a save routine continue.

$submitted_price = 'twenty dollars';

if ( ! is_numeric( $submitted_price ) ) {
	$error = new WP_Error(
		'invalid_price',
		esc_html__( 'The submitted price is not a valid number.' ),
		array( 'title' => esc_html__( 'Invalid Price Submitted' ) )
	);

	echo 'Validation failed, handing off to wp_die().';
	wp_die( $error, '', array( 'response' => 400 ) );
}

echo 'Price accepted: ' . esc_html( $submitted_price );

The WP_Error's 'title' data key only supplies the page title because $title itself is left empty here.

Common problems and fixes · 4

Why does calling wp_die() sometimes not stop my code from running?

By default wp_die() exits the process, but the source only exits when $args['exit'] evaluates to true. If a filter or an explicit call sets exit to false, wp_die() prints the error markup and returns void instead of halting.

Why does my Ajax handler get a plain 0 or -1 instead of the HTML error page?

wp_doing_ajax() is checked first in wp_die(), and when true it routes through the wp_die_ajax_handler filter to _ajax_wp_die_handler rather than the default HTML handler used for regular page loads.

Why did my custom title disappear and get replaced with a response code?

wp_die() checks is_int($title) before anything else and, if true, converts it into array('response' => $title) while resetting $title to an empty string, so a numeric second argument is never displayed as text.

Why is my WP_Error's custom title being ignored?

The 'title' key in a WP_Error's error data is only used when the $title parameter passed to wp_die() is an empty string; a non-empty $title always wins over the WP_Error's own title data.

Alternatives and related functions

wp_send_json_error
When handling an Ajax request and you want a structured JSON error payload for JavaScript rather than a themed HTML death screen.
WP_Error
When the calling code should be able to inspect or recover from the failure instead of having execution stopped outright.
trigger_error
When you want to log or surface a warning without ending the request, since wp_die() is meant for genuine dead ends.
wp_redirect
When the better response to an invalid state is sending the visitor somewhere else rather than showing an error page.

Performance profile

How much work a call to wp_die() 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
23–65

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

Plugin surface
6 hooks

Third-party callbacks on 'wp_die_ajax_handler', 'wp_die_json_handler', 'wp_die_jsonp_handler' 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 callbacksapply_filters()called directly

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

What one call costs · 28 distinct outcomes

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

WhenInstructionsCalls it makes
wp_doing_ajax()23–26wp_doing_ajax(), apply_filters(), call_user_func()
!wp_doing_ajax() && wp_is_json_request()26–29wp_doing_ajax(), wp_is_json_request(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request()32–39wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && defined('XMLRPC_REQUEST')33–36wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request()34–40wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request()37–43wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && !wp_is_xml_request() && isset($wp_query) && function_exists() && is_feed()43–48wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), function_exists(), is_feed(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request() && !wp_is_xml_request() && isset($wp_query) && function_exists() && is_feed()46–51wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), function_exists(), is_feed(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && !wp_is_xml_request() && isset($wp_query) && !function_exists()47–52wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), function_exists(), function_exists(), function_exists(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && !wp_is_xml_request() && isset($wp_query) && is_comment_feed()47–52wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), function_exists(), function_exists(), is_comment_feed(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && !wp_is_xml_request() && isset($wp_query)50–56wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), function_exists(), function_exists(), function_exists(), is_trackback(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && !wp_is_xml_request() && isset($wp_query) && !is_comment_feed()50–55wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), function_exists(), function_exists(), is_comment_feed(), function_exists(), apply_filters(), call_user_func()
16 further outcomes, up to 65 instructions
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && !wp_is_xml_request() && isset($wp_query) && !is_feed()50–55wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), function_exists(), is_feed(), function_exists(), function_exists(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && !wp_is_xml_request() && isset($wp_query) && function_exists() && !is_feed() && is_comment_feed()50–55wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), function_exists(), is_feed(), function_exists(), is_comment_feed(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request() && !wp_is_xml_request() && isset($wp_query) && !function_exists()50–55wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), function_exists(), function_exists(), function_exists(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request() && !wp_is_xml_request() && isset($wp_query) && is_comment_feed()50–55wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), function_exists(), function_exists(), is_comment_feed(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && !wp_is_xml_request() && isset($wp_query) && !is_comment_feed()53–59wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), function_exists(), function_exists(), is_comment_feed(), function_exists(), is_trackback(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && !wp_is_xml_request() && isset($wp_query) && !is_feed()53–59wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), function_exists(), is_feed(), function_exists(), function_exists(), is_trackback(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && !wp_is_xml_request() && isset($wp_query) && !is_feed() && !is_comment_feed()53–58wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), function_exists(), is_feed(), function_exists(), is_comment_feed(), function_exists(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request() && !wp_is_xml_request() && isset($wp_query)53–59wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), function_exists(), function_exists(), function_exists(), is_trackback(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request() && !wp_is_xml_request() && isset($wp_query) && !is_comment_feed()53–58wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), function_exists(), function_exists(), is_comment_feed(), function_exists(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request() && !wp_is_xml_request() && isset($wp_query) && !is_feed()53–58wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), function_exists(), is_feed(), function_exists(), function_exists(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request() && !wp_is_xml_request() && isset($wp_query) && function_exists() && !is_feed() && is_comment_feed()53–58wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), function_exists(), is_feed(), function_exists(), is_comment_feed(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && !wp_is_serving_rest_request() && !wp_is_xml_request() && isset($wp_query) && function_exists() && !is_feed() && !is_comment_feed()56–62wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_xml_request(), function_exists(), is_feed(), function_exists(), is_comment_feed(), function_exists(), is_trackback(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request() && !wp_is_xml_request() && isset($wp_query) && !is_comment_feed()56–62wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), function_exists(), function_exists(), is_comment_feed(), function_exists(), is_trackback(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request() && !wp_is_xml_request() && isset($wp_query) && !is_feed()56–62wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), function_exists(), is_feed(), function_exists(), function_exists(), is_trackback(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request() && !wp_is_xml_request() && isset($wp_query) && !is_feed() && !is_comment_feed()56–61wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), function_exists(), is_feed(), function_exists(), is_comment_feed(), function_exists(), apply_filters(), call_user_func()
!wp_doing_ajax() && !wp_is_json_request() && wp_is_serving_rest_request() && !wp_is_jsonp_request() && !wp_is_xml_request() && isset($wp_query) && function_exists() && !is_feed() && !is_comment_feed()59–65wp_doing_ajax(), wp_is_json_request(), wp_is_serving_rest_request(), wp_is_jsonp_request(), wp_is_xml_request(), function_exists(), is_feed(), function_exists(), is_comment_feed(), function_exists(), is_trackback(), apply_filters(), call_user_func()

Across PHP versions

PHPCompiledExecutedBranchesNotes
8.6-dev9723–6516
8.59723–6516
8.49723–6516
8.39723–6516
8.29723–6516
8.19723–65163 fewer instructions than PHP 7.4
7.410023–6816

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 · 6

6 hooks fire while wp_die() runs, in this order:

  1. apply_filters( wp_die_ajax_handler )filterline 3799 (+18 into the body)

    Filters the callback for killing WordPress execution for Ajax requests.

  2. apply_filters( wp_die_json_handler )filterline 3808 (+27 into the body)

    Filters the callback for killing WordPress execution for JSON requests.

  3. apply_filters( wp_die_jsonp_handler )filterline 3817 (+36 into the body)

    Filters the callback for killing WordPress execution for JSONP REST requests.

  4. apply_filters( wp_die_xmlrpc_handler )filterline 3826 (+45 into the body)

    Filters the callback for killing WordPress execution for XML-RPC requests.

  5. apply_filters( wp_die_xml_handler )filterline 3839 (+58 into the body)

    Filters the callback for killing WordPress execution for XML requests.

  6. apply_filters( wp_die_handler )filterline 3848 (+67 into the body)

    Filters the callback for killing WordPress execution for all non-Ajax, non-JSON, non-XML requests.

Uses · 9

Used by · 50

Show all 50

Source code

function wp_die( $message = '', $title = '', $args = array() ) {	global $wp_query; 	if ( is_int( $args ) ) {		$args = array( 'response' => $args );	} elseif ( is_int( $title ) ) {		$args  = array( 'response' => $title );		$title = '';	} 	if ( wp_doing_ajax() ) {		/**		 * Filters the callback for killing WordPress execution for Ajax requests.		 *		 * @since 3.4.0		 *		 * @param callable $callback Callback function name.		 */		$callback = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );	} elseif ( wp_is_json_request() ) {		/**		 * Filters the callback for killing WordPress execution for JSON requests.		 *		 * @since 5.1.0		 *		 * @param callable $callback Callback function name.		 */		$callback = apply_filters( 'wp_die_json_handler', '_json_wp_die_handler' );	} elseif ( wp_is_serving_rest_request() && wp_is_jsonp_request() ) {		/**		 * Filters the callback for killing WordPress execution for JSONP REST requests.		 *		 * @since 5.2.0		 *		 * @param callable $callback Callback function name.		 */		$callback = apply_filters( 'wp_die_jsonp_handler', '_jsonp_wp_die_handler' );	} elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {		/**		 * Filters the callback for killing WordPress execution for XML-RPC requests.		 *		 * @since 3.4.0		 *		 * @param callable $callback Callback function name.		 */		$callback = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );	} elseif ( wp_is_xml_request()		|| isset( $wp_query ) &&			( function_exists( 'is_feed' ) && is_feed()			|| function_exists( 'is_comment_feed' ) && is_comment_feed()			|| function_exists( 'is_trackback' ) && is_trackback() ) ) {		/**		 * Filters the callback for killing WordPress execution for XML requests.		 *		 * @since 5.2.0		 *		 * @param callable $callback Callback function name.		 */		$callback = apply_filters( 'wp_die_xml_handler', '_xml_wp_die_handler' );	} else {		/**		 * Filters the callback for killing WordPress execution for all non-Ajax, non-JSON, non-XML requests.		 *		 * @since 3.0.0		 *		 * @param callable $callback Callback function name.		 */		$callback = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );	} 	call_user_func( $callback, $message, $title, $args );}

Changelog

Introduced in 2.0.4. 3 changes between 6.7.7 and 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.

7.1.0
Parameter $message retyped from string|WP_Error to string|WP_Error|int.verified against source
7.1.0
Return type changed from never|void to void.verified against source
7.0.4
Return type changed from none to never|void.verified against source
5.5.0
The $text_direction argument has a priority over get_language_attributes() in the default handler.from the docblock
5.3.0
The $charset argument was added.from the docblock
5.1.0
The $link_url, $link_text, and $exit arguments were added.from the docblock
4.1.0
The $title and $args parameters were changed to optionally accept an integer to be used as the response code.from the docblock
2.0.4
Introduced.from the docblock

About this page

Parsed data
Generated from the wordpress-develop 7.0.4 tag, from src/wp-includes/functions.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.