_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.
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?
- How do I stop _doing_it_wrong() from flooding the log for one specific function?
- Why is the version note missing from my doing_it_wrong message?
Why does _doing_it_wrong() sometimes show no visible warning at all?
How do I stop _doing_it_wrong() from flooding the log for one specific function?
Why is the version note missing from my doing_it_wrong message?
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
- Scaling
- Constant
- Instructions
- 12–60
- Plugin surface
- 2 hooks
- 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 73.
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.
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 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.
| When | Instructions | Calls it makes |
|---|---|---|
| always | 12 | do_action() |
!apply_filters() | 20 | do_action(), apply_filters() |
apply_filters() && !function_exists() | 37–41 | do_action(), apply_filters(), function_exists(), sprintf(), wp_trigger_error() |
apply_filters() && function_exists() | 52 | do_action(), apply_filters(), function_exists(), __(), __(), sprintf(), __(), sprintf(), wp_trigger_error() |
apply_filters() && function_exists() | 60 | do_action(), apply_filters(), function_exists(), __(), sprintf(), __(), __(), sprintf(), __(), sprintf(), wp_trigger_error() |
Across PHP versions
| PHP | Compiled | Executed | Branches | Notes |
|---|---|---|---|---|
| 8.6-dev | 73 | 12–60 | 5 | |
| 8.5 | 73 | 12–60 | 5 | |
| 8.4 | 73 | 12–60 | 5 | 5 fewer instructions than PHP 8.3 |
| 8.3 | 78 | 12–60 | 5 | |
| 8.2 | 78 | 12–60 | 5 | |
| 8.1 | 78 | 12–60 | 5 | |
| 7.4 | 78 | 12–60 | 5 |
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:
- do_action( doing_it_wrong_run )actionline 6123 (+11 into the body)
Fires when the given function is being used incorrectly.
- 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
- WP_AI_Client_Prompt_Builder::__construct()Constructor.
- WP_AI_Client_Prompt_Builder::using_abilities()Registers WordPress abilities as function declarations for the AI model.
- WP_Abilities_Registry::get_instance()Utility method to retrieve the main instance of the registry class.
- WP_Abilities_Registry::get_registered()Retrieves a registered ability.
- WP_Abilities_Registry::register()Registers a new ability.
- WP_Abilities_Registry::unregister()Unregisters an ability.
- WP_Ability::__construct()Constructor.
- WP_Ability::execute()Executes the ability after input validation and running a permission check.
- WP_Ability_Categories_Registry::get_instance()Utility method to retrieve the main instance of the registry class.
- WP_Ability_Categories_Registry::get_registered()Retrieves a registered ability category.
- WP_Ability_Categories_Registry::register()Registers a new ability category.
- WP_Ability_Categories_Registry::unregister()Unregisters an ability category.
Show all 50
- WP_Ability_Category::__construct()Constructor.
- WP_Admin_Bar::add_node()Adds a node to the menu.
- WP_Automatic_Updater::is_allowed_dir()Checks whether access to a given directory is allowed.
- WP_Block_Bindings_Registry::register()Registers a new block bindings source.
- WP_Block_Bindings_Registry::unregister()Unregisters a block bindings source.
- WP_Block_Metadata_Registry::get_collection_block_metadata_files()Gets the list of absolute paths to all block metadata files that are part of the given collection.
- WP_Block_Metadata_Registry::register_collection()Registers a block metadata collection.
- WP_Block_Pattern_Categories_Registry::register()Registers a pattern category.
- WP_Block_Pattern_Categories_Registry::unregister()Unregisters a pattern category.
- WP_Block_Patterns_Registry::register()Registers a block pattern.
- WP_Block_Patterns_Registry::unregister()Unregisters a block pattern.
- WP_Block_Styles_Registry::register()Registers a block style for the given block type.
- WP_Block_Styles_Registry::unregister()Unregisters a block style of the given block type.
- WP_Block_Templates_Registry::register()Registers a template.
- WP_Block_Templates_Registry::unregister()Unregisters a template.
- WP_Block_Type::__set()Proxies setting values for deprecated properties for script and style handles for backward compatibility.
- WP_Block_Type_Registry::register()Registers a block type.
- WP_Block_Type_Registry::unregister()Unregisters a block type.
- WP_Connector_Registry::get_registered()Retrieves a registered connector.
- WP_Connector_Registry::register()Registers a new connector.
- WP_Connector_Registry::set_instance()Sets the main instance of the registry class.
- WP_Connector_Registry::unregister()Unregisters a connector.
- WP_Customize_Manager::remove_panel()Removes a customize panel.
- WP_Customize_Partial::render()Renders the template partial involving the associated settings.
- WP_Date_Query::validate_date_values()Validates the given date_query values and triggers errors if something is not valid.
- WP_Dependencies::all_deps()Determines dependencies.
- WP_Duotone::enqueue_global_styles_preset()Enqueue preset assets for the page.
- WP_Duotone::get_filter_svg()Gets the SVG for the duotone filter definition.
- WP_Font_Collection::__construct()WP_Font_Collection constructor.
- WP_Font_Collection::load_from_json()Loads font collection data from a JSON file or URL.
- WP_Font_Collection::sanitize_and_validate_data()Sanitizes and validates the font collection data.
- WP_Font_Face::validate_font_face_declarations()Validates each font-face declaration (property and value pairing).
- WP_Font_Library::register_font_collection()Register a new font collection.
- WP_Font_Library::unregister_font_collection()Unregisters a previously registered font collection.
- WP_HTML_Processor::__construct()Constructor.
- WP_HTML_Processor::create_fragment()Creates an HTML processor in the fragment parsing mode.
- WP_HTML_Processor::create_fragment_at_current_node()Creates a fragment processor at the current node.
- WP_HTML_Processor::create_full_parser()Creates an HTML processor in the full parsing mode.
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.
Signature, return type and hooks compared across 5 parsed releases.
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.