wp_debug_backtrace_summary()WP 3.4.0

Gets a trace with function names — a list of all functions/methods that were called to reach the current place in the code (from where this function was called).

The list is output as function names separated by commas or as an array.

Works based on the PHP function debug_backtrace().

1 time — 0.000001 sec (speed of light) | 50000 times — 0.23 sec (very fast) | PHP 7.1.11, WP 4.9.8

No Hooks.

Returns

String|Array. Function names separated by commas or an array of names where the closest function will be in the 0 element of the array.

Usage

wp_debug_backtrace_summary( $ignore_class, $skip_frames, $pretty );
$ignore_class(string)
The name of the class to skip in the list. All methods of the specified class will not be shown in the result.
Default: null
$skip_frames(int)
The number of elements (function names, classes) to skip. The closest names (the last ones that are closer to the end of the stack) will be skipped.
Default: 0
$pretty(true/false)

What result is needed?

  • true — a string with the list of names.
  • false — an array with the list of names.

Default: true

Examples

0

#1 Demo of what the function outputs

For example, connect to the hook pre_get_posts and see what wp_debug_backtrace_summary() returns with different parameters:

add_filter( 'pre_get_posts', 'my_function' );

function my_function(){

	$backtrace = wp_debug_backtrace_summary();
	/*
	require('/sites/test.ru/wp-blog-header.php'), wp, WP->main, WP->query_posts, WP_Query->query,
	WP_Query->get_posts, do_action_ref_array, WP_Hook->do_action, WP_Hook->apply_filters, my_function
	*/

	// Remove methods of the 'WP_Hook' class
	$backtrace = wp_debug_backtrace_summary( 'WP_Hook' );
	/*
	require('/sites/test.ru/wp-blog-header.php'), wp, WP->main, WP->query_posts, WP_Query->query,
	WP_Query->get_posts, do_action_ref_array, my_function
	*/

	// Remove the last 5 elements
	// The parameter `$ignore_class` is not taken into account when counting items, 
	// i.e. items are counted as if `$ignore_class=null`.
	$backtrace = wp_debug_backtrace_summary( 'WP_Hook', 5 );
	//>  require('/sites/test.ru/wp-blog-header.php'), wp, WP->main, WP->query_posts, WP_Query->query

	// get an array
	$backtrace = wp_debug_backtrace_summary( 'WP_Hook', 5, false );
	/*
	Array(
		[0] => WP_Query->query
		[1] => WP->query_posts
		[2] => WP->main
		[3] => wp
		[4] => require('/sites/test.ru/wp-blog-header.php')
	)
	*/

}
0

#2 Changing the time format in the "Recent Posts" widget

Unfortunately, there are no special hooks in the Recent Posts widget to change the date and time display format, but we can use the following trick:

add_filter( 'pre_option_date_format', function ( $pre_option ) {

	$backtrace = wp_debug_backtrace_summary( null, 0, false );

	if ( in_array( 'WP_Widget_Recent_Posts->widget', $backtrace ) ) {
		return 'G:i';
	}

	return $pre_option;
} );
0

#3 Add a call chain to the log

Suppose we need to add an error message to our logger. In this case it would be convenient to have a stack of calls to functions/methods that caused the error along with the error message:

function some_function(){

	// some code where an error might appear

	if( is_wp_error() ){
		$logger->error( 'Error message.', [ 'backtrace' => wp_debug_backtrace_summary() ] );
		return;
	}

	// do staff

}

Notes

Changelog

Since 3.4.0 Introduced.

wp_debug_backtrace_summary() code WP 6.8.3

function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
	static $truncate_paths;

	$trace       = debug_backtrace( false );
	$caller      = array();
	$check_class = ! is_null( $ignore_class );
	++$skip_frames; // Skip this function.

	if ( ! isset( $truncate_paths ) ) {
		$truncate_paths = array(
			wp_normalize_path( WP_CONTENT_DIR ),
			wp_normalize_path( ABSPATH ),
		);
	}

	foreach ( $trace as $call ) {
		if ( $skip_frames > 0 ) {
			--$skip_frames;
		} elseif ( isset( $call['class'] ) ) {
			if ( $check_class && $ignore_class === $call['class'] ) {
				continue; // Filter out calls.
			}

			$caller[] = "{$call['class']}{$call['type']}{$call['function']}";
		} else {
			if ( in_array( $call['function'], array( 'do_action', 'apply_filters', 'do_action_ref_array', 'apply_filters_ref_array' ), true ) ) {
				$caller[] = "{$call['function']}('{$call['args'][0]}')";
			} elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ), true ) ) {
				$filename = isset( $call['args'][0] ) ? $call['args'][0] : '';
				$caller[] = $call['function'] . "('" . str_replace( $truncate_paths, '', wp_normalize_path( $filename ) ) . "')";
			} else {
				$caller[] = $call['function'];
			}
		}
	}
	if ( $pretty ) {
		return implode( ', ', array_reverse( $caller ) );
	} else {
		return $caller;
	}
}