wppaste
WordPress

_doing_it_wrong( string $function_name, string $message, string $version )

Since
3.1.0, 5.4.0
Source
wp-includes/functions.php:6112

Flags $function_name as misused by firing the doing_it_wrong_run action and, when WP_DEBUG is true, triggering a PHP notice built from $message and $version. The doing_it_wrong_run action always fires, even in production with WP_DEBUG off, so it doubles as a logging hook. Use it inside your own functions to warn about wrong argument combinations; use _deprecated_function() instead when the whole function, not just a particular call, should no longer be used.

Marks something as being incorrectly called.

Description

There is a 'doing_it_wrong_run' hook that will be called that can be used to get the backtrace up to what file and function called the deprecated function.

The current behavior is to trigger a user error if WP_DEBUG is true.

Compatibility

WordPress
since 5.4.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

$function_namestring
The function that was called.
$messagestring
A message explaining what has been done incorrectly.
$versionstring
The version of WordPress where the message was added.

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.

Warn when a plugin function is called with a removed parameter

A wrapper around get_post_meta() still accepts an old currency argument it no longer does anything with.

function bookstore_get_price( $post_id, $legacy_currency = null ) {
	if ( null !== $legacy_currency ) {
		_doing_it_wrong(
			__FUNCTION__,
			'The $legacy_currency parameter is no longer used, prices are always stored in the site currency.',
			'7.1.0'
		);
	}

	return get_post_meta( $post_id, 'price', true );
}

// Capture the notice with a temporary error handler so it prints regardless of the WP_DEBUG setting.
set_error_handler( function( $errno, $errstr ) {
	echo '<p><strong>Triggered notice:</strong> ' . esc_html( wp_strip_all_tags( $errstr ) ) . '</p>';
	return true;
} );

$price = bookstore_get_price( 2, 'USD' );

restore_error_handler();

echo '<p>Price returned: ' . esc_html( $price ) . '</p>';

The strong-tagged notice only appears when WP_DEBUG is true; otherwise only the price line prints.

Log every doing_it_wrong() call without relying on WP_DEBUG

The doing_it_wrong_run action fires on every call, so it can catch incorrect usage on production sites where WP_DEBUG is disabled.

add_action( 'doing_it_wrong_run', function( $function_name, $message, $version ) {
	printf(
		'<p>Logged: %s called incorrectly (%s) since %s</p>',
		esc_html( $function_name ),
		esc_html( $message ),
		esc_html( $version )
	);
}, 10, 3 );

_doing_it_wrong( 'Bookstore_Catalog::get_books', 'Use Bookstore_Catalog::get_items() instead.', '7.1.0' );

echo '<p>Finished processing catalog request.</p>';

Common problems and fixes · 3

Why does _doing_it_wrong() sometimes show no visible warning at all?

The user-facing notice only appears when WP_DEBUG is true and the doing_it_wrong_trigger_error filter also returns true; the doing_it_wrong_run action still fires either way, it just does so silently. - Turn on WP_DEBUG in wp-config.php while developing. - Check whether a plugin filters doing_it_wrong_trigger_error to false for that function name.

How do I stop _doing_it_wrong() from flooding the log for one specific function?

There is no built-in per-function suppression in the source; the only lever is the doing_it_wrong_trigger_error filter, which receives $function_name as its second argument.
add_filter( 'doing_it_wrong_trigger_error', function( $trigger, $function_name ) { if ( 'my_legacy_function' === $function_name ) { return false; } return $trigger; }, 10, 2 );

Why is the version note missing from my doing_it_wrong message?

The '(This message was added in version %s.)' text is only appended when $version is truthy; passing an empty string or null for $version leaves that part of the message blank. - Always pass an actual version string such as '7.1.0'. - Never omit $version by passing '' just to skip the note; the resulting message will simply drop that sentence rather than error.

Alternatives and related functions

_deprecated_function
When the entire function should no longer be called at all, not just called with a particular set of arguments.
_deprecated_argument
When only one specific argument value or combination is what's outdated, and the rest of the function call is still valid.
_deprecated_hook
When it is a hook, not a function, that should no longer be used.
wp_trigger_error
When you want to trigger a PHP user error directly with your own formatted message, without the automatic doing_it_wrong wording and version note.

Performance profile

How much work a call to _doing_it_wrong() 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
12–60

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

Plugin surface
2 hooks

Third-party callbacks on 'doing_it_wrong_run', 'doing_it_wrong_trigger_error' 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 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 · 5 distinct outcomes

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

WhenInstructionsCalls it makes
always12do_action()
!apply_filters()20do_action(), apply_filters()
apply_filters() && !function_exists()37–41do_action(), apply_filters(), function_exists(), sprintf(), wp_trigger_error()
apply_filters() && function_exists()52do_action(), apply_filters(), function_exists(), __(), __(), sprintf(), __(), sprintf(), wp_trigger_error()
apply_filters() && function_exists()60do_action(), apply_filters(), function_exists(), __(), sprintf(), __(), __(), sprintf(), __(), sprintf(), wp_trigger_error()

Across PHP versions

PHPCompiledExecutedBranchesNotes
8.6-dev7312–605
8.57312–605
8.47312–6055 fewer instructions than PHP 8.3
8.37812–605
8.27812–605
8.17812–605
7.47812–605

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

2 hooks fire while _doing_it_wrong() runs, in this order:

  1. do_action( doing_it_wrong_run )actionline 6123 (+11 into the body)

    Fires when the given function is being used incorrectly.

  2. apply_filters( doing_it_wrong_trigger_error )filterline 6136 (+24 into the body)

    Filters whether to trigger an error for _doing_it_wrong() calls.

Uses · 4

  • do_action()Calls the callback functions that have been added to an action hook.
  • apply_filters()Calls the callback functions that have been added to a filter hook.
  • __()Retrieves the translation of $text.
  • wp_trigger_error()Generates a user-level error/warning/notice/deprecation message.

Used by · 50

Show all 50

Source code

function _doing_it_wrong( $function_name, $message, $version ) { 	/**	 * Fires when the given function is being used incorrectly.	 *	 * @since 3.1.0	 *	 * @param string $function_name The function that was called.	 * @param string $message       A message explaining what has been done incorrectly.	 * @param string $version       The version of WordPress where the message was added.	 */	do_action( 'doing_it_wrong_run', $function_name, $message, $version ); 	/**	 * Filters whether to trigger an error for _doing_it_wrong() calls.	 *	 * @since 3.1.0	 * @since 5.1.0 Added the `$function_name`, `$message`, and `$version` parameters.	 *	 * @param bool   $trigger       Whether to trigger the error for _doing_it_wrong() calls. Default true.	 * @param string $function_name The function that was called.	 * @param string $message       A message explaining what has been done incorrectly.	 * @param string $version       The version of WordPress where the message was added.	 */	if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true, $function_name, $message, $version ) ) {		if ( function_exists( '__' ) ) {			if ( $version ) {				/* translators: %s: Version number. */				$version = sprintf( __( '(This message was added in version %s.)' ), $version );			} 			$message .= ' ' . sprintf(				/* translators: %s: Documentation URL. */				__( 'Please see <a href="%s">Debugging in WordPress</a> for more information.' ),				__( 'https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/' )			); 			$message = sprintf(				/* translators: Developer debugging message. 1: PHP function name, 2: Explanatory message, 3: WordPress version number. */				__( 'Function %1$s was called <strong>incorrectly</strong>. %2$s %3$s' ),				$function_name,				$message,				$version			);		} else {			if ( $version ) {				$version = sprintf( '(This message was added in version %s.)', $version );			} 			$message .= sprintf(				' Please see <a href="%s">Debugging in WordPress</a> for more information.',				'https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/'			); 			$message = sprintf(				'Function %1$s was called <strong>incorrectly</strong>. %2$s %3$s',				$function_name,				$message,				$version			);		} 		wp_trigger_error( '', $message );	}}

Changelog

Introduced in 3.1.0. 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.

5.4.0
This function is no longer marked as "private".from the docblock
3.1.0
Introduced.from the docblock

About this page

Parsed data
Generated from the wordpress-develop 7.1.0 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.