|null */ private static $current_snippet = null; /** * Tracks whether the error handler has been initialized. * * @var bool */ private static $initialized = false; /** * Initialize error handler. * * @return void */ public static function init() { if ( self::$initialized ) { return; } add_filter( 'wp_php_error_message', [ __CLASS__, 'customize_error_message' ], 9, 1 ); self::$initialized = true; } /** * Set the current snippet context for error handling. * * @param int $snippet_id Snippet ID. * @param string $title Snippet title. * @param string $content Optional snippet content. Accepted for backward compatibility and ignored. * * @return void */ public static function set_current_snippet( $snippet_id, $title, $content = null ) { self::$current_snippet = [ 'id' => $snippet_id, 'title' => $title, 'content' => $content, ]; } /** * Clear the current snippet context after execution. * * @return void */ public static function clear_current_snippet() { self::$current_snippet = null; } /** * Customize the error message displayed. * * @param string $message Original error message. * @return string Modified error message. */ public static function customize_error_message( $message ) { $error = error_get_last(); if ( ! $error || ! self::$current_snippet ) { return $message; } if ( ! self::is_eval_error( $error['file'] ) ) { return $message; } $snippet_title = self::$current_snippet['title']; $error_message = self::strip_stack_trace( $error['message'] ); $error_line = (int) $error['line']; // Build the custom error display. $custom_message = self::build_error_display( $snippet_title, $error_message, $error_line ); return $message . $custom_message; } /** * Check if error file indicates eval'd code. * * @param string $file Error file path. * @return bool True if error is from eval'd code. */ private static function is_eval_error( $file ) { return strpos( $file, "eval()'d code" ) !== false || strpos( $file, 'eval()\'d code' ) !== false; } /** * Strip stack trace from error message. * * @param string $error_message Raw error message that may contain stack trace. * @return string Clean error message without stack trace. */ private static function strip_stack_trace( $error_message ) { // Remove file path and eval() references. $error_message = preg_replace( '/\s+in\s+(?:\/|[A-Z]:[\/\\\\]).*?eval\(\)\'d code:\d+/i', '', $error_message ); // Remove generic "in /path/to/file" references. if ( $error_message ) { $error_message = preg_replace( '/\s+in\s+(?:\/[^\s]+|[A-Z]:[\/\\\\][^\s]+)/i', '', $error_message ); } $patterns = [ '/\s*Stack trace:.*/is', '/\s*#\d+\s+.*/is', '/\s*thrown in .*/is', ]; foreach ( $patterns as $pattern ) { if ( $error_message ) { $error_message = preg_replace( $pattern, '', $error_message ); } } if ( $error_message ) { $error_message = trim( $error_message ); } return $error_message ? $error_message : ''; } /** * Build the custom error display HTML. * * @param string $snippet_title Snippet title. * @param string $error_message Error message. * @param int $error_line Line number where error occurred. * @return string|false HTML for error display. */ private static function build_error_display( $snippet_title, $error_message, $error_line ) { $title = $snippet_title ? sprintf( // translators: %s is snippet title. esc_html__( 'Snippet: %s', 'insert-php' ), $snippet_title ) : ''; $line_info = $error_line ? sprintf( // translators: %d is line number. esc_html__( 'Line %d', 'insert-php' ), $error_line ) : ''; $full_error_text = sprintf( "%s\n%s: %s", $title, $line_info, $error_message ); ob_start(); ?>