diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 44728a2e41..835fa7190e 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -6039,6 +6039,52 @@ function _doing_it_wrong( $function_name, $message, $version ) { } } +/** + * Generates a user-level error/warning/notice/deprecation message. + * + * Generates the message when `WP_DEBUG` is true. + * + * @since 6.4.0 + * + * @param string $function_name The function that triggered the error. + * @param string $message The message explaining the error. + * @param int $error_level Optional. The designated error type for this error. + * Only works with E_USER family of constants. Default E_USER_NOTICE. + */ +function wp_trigger_error( $function_name, $message, $error_level = E_USER_NOTICE ) { + + // Bail out if WP_DEBUG is not turned on. + if ( ! WP_DEBUG ) { + return; + } + + /** + * Fires when the given function triggers a user-level error/warning/notice/deprecation message. + * + * Can be used for debug backtracking. + * + * @since 6.4.0 + * + * @param string $function_name The function that was called. + * @param string $message A message explaining what has been done incorrectly. + * @param int $error_level The designated error type for this error. + */ + do_action( 'wp_trigger_error_run', $function_name, $message, $error_level ); + + if ( ! empty( $function_name ) ) { + $message = sprintf( '%s(): %s', $function_name, $message ); + } + + /* + * If the message appears in the browser, then it needs to be escaped. + * Note the warning in the `trigger_error()` PHP manual. + * @link https://www.php.net/manual/en/function.trigger-error.php + */ + $message = esc_html( $message ); + + trigger_error( $message, $error_level ); +} + /** * Determines whether the server is running an earlier than 1.5.0 version of lighttpd. * diff --git a/tests/phpunit/tests/functions/wpTriggerError.php b/tests/phpunit/tests/functions/wpTriggerError.php new file mode 100644 index 0000000000..40582bc24a --- /dev/null +++ b/tests/phpunit/tests/functions/wpTriggerError.php @@ -0,0 +1,101 @@ +expectError(); + $this->expectErrorMessage( $expected_message ); + + wp_trigger_error( $function_name, $message, E_USER_ERROR ); + } + + /** + * @ticket 57686 + * + * @dataProvider data_should_trigger_error + * + * @param string $function_name The function name to test. + * @param string $message The message to test. + * @param string $expected_message The expected error message. + */ + public function test_should_trigger_warning( $function_name, $message, $expected_message ) { + $this->expectWarning(); + $this->expectWarningMessage( $expected_message ); + + wp_trigger_error( $function_name, $message, E_USER_WARNING ); + } + + /** + * @ticket 57686 + * + * @dataProvider data_should_trigger_error + * + * @param string $function_name The function name to test. + * @param string $message The message to test. + * @param string $expected_message The expected error message. + */ + public function test_should_trigger_notice( $function_name, $message, $expected_message ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected_message ); + + wp_trigger_error( $function_name, $message ); + } + + /** + * @ticket 57686 + * + * @dataProvider data_should_trigger_error + * + * @param string $function_name The function name to test. + * @param string $message The message to test. + * @param string $expected_message The expected error message. + */ + public function test_should_trigger_deprecation( $function_name, $message, $expected_message ) { + $this->expectDeprecation(); + $this->expectDeprecationMessage( $expected_message ); + + wp_trigger_error( $function_name, $message, E_USER_DEPRECATED ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_should_trigger_error() { + return array( + 'function name and message are given' => array( + 'function_name' => 'some_function', + 'message' => 'expected the function name and message', + 'expected_message' => 'some_function(): expected the function name and message', + ), + 'message is given' => array( + 'function_name' => '', + 'message' => 'expect only the message', + 'expected_message' => 'expect only the message', + ), + 'function name is given' => array( + 'function_name' => 'some_function', + 'message' => '', + 'expected_message' => 'some_function(): ', + ), + ); + } +}