@@ -965,50 +965,153 @@ function wp_finalize_template_enhancement_output_buffer( string $output, int $ph
965965
966966 $ filtered_output = $ output ;
967967
968- /**
969- * Filters the template enhancement output buffer prior to sending to the client.
970- *
971- * This filter only applies the HTML output of an included template. This filter is a progressive enhancement
972- * intended for applications such as optimizing markup to improve frontend page load performance. Sites must not
973- * depend on this filter applying since they may opt to stream the responses instead. Callbacks for this filter are
974- * highly discouraged from using regular expressions to do any kind of replacement on the output. Use the HTML API
975- * (either `WP_HTML_Tag_Processor` or `WP_HTML_Processor`), or else use {@see DOM\HtmlDocument} as of PHP 8.4 which
976- * fully supports HTML5.
977- *
978- * Important: Because this filter is applied inside an output buffer callback (i.e. display handler), any callbacks
979- * added to the filter must not attempt to start their own output buffers. Otherwise, PHP will raise a fatal error:
980- * "Cannot use output buffering in output buffering display handlers."
981- *
982- * @since 6.9.0
983- *
984- * @param string $filtered_output HTML template enhancement output buffer.
985- * @param string $output Original HTML template output buffer.
986- */
987- $ filtered_output = (string ) apply_filters ( 'wp_template_enhancement_output_buffer ' , $ filtered_output , $ output );
968+ $ did_just_catch = false ;
969+
970+ $ error_log = array ();
971+ set_error_handler (
972+ static function ( int $ level , string $ message , ?string $ file = null , ?int $ line = null ) use ( &$ error_log , &$ did_just_catch ) {
973+ // Switch a user error to an exception so that it can be caught and the buffer can be returned.
974+ if ( E_USER_ERROR === $ level ) {
975+ throw new Exception ( __ ( 'User error triggered: ' ) . ' ' . $ message );
976+ }
977+
978+ // Display a caught exception as an error since it prevents any of the output buffer filters from applying.
979+ if ( $ did_just_catch ) { // @phpstan-ignore if.alwaysFalse (The variable is set in the catch block below.)
980+ $ level = E_USER_ERROR ;
981+ }
982+
983+ // Capture a reported error to be displayed by appending to the processed output buffer if display_errors is enabled.
984+ if ( error_reporting () & $ level ) {
985+ $ error_log [] = compact ( 'level ' , 'message ' , 'file ' , 'line ' );
986+ }
987+ return false ;
988+ }
989+ );
990+ $ original_display_errors = ini_get ( 'display_errors ' );
991+ if ( $ original_display_errors ) {
992+ ini_set ( 'display_errors ' , 0 );
993+ }
988994
989- /**
990- * Fires after the template enhancement output buffer has been finalized.
991- *
992- * This happens immediately before the template enhancement output buffer is flushed. No output may be printed at
993- * this action. However, HTTP headers may be sent, which makes this action complimentary to the
994- * {@see 'send_headers'} action, in which headers may be sent before the template has started rendering. In
995- * contrast, this `wp_finalized_template_enhancement_output_buffer` action is the possible point at which HTTP
996- * headers can be sent. This action does not fire if the "template enhancement output buffer" was not started. This
997- * output buffer is automatically started if this action is added before
998- * {@see wp_start_template_enhancement_output_buffer()} runs at the {@see 'wp_before_include_template'} action with
999- * priority 1000. Before this point, the output buffer will also be started automatically if there was a
1000- * {@see 'wp_template_enhancement_output_buffer'} filter added, or if the
1001- * {@see 'wp_should_output_buffer_template_for_enhancement'} filter is made to return `true`.
1002- *
1003- * Important: Because this action fires inside an output buffer callback (i.e. display handler), any callbacks added
1004- * to the action must not attempt to start their own output buffers. Otherwise, PHP will raise a fatal error:
1005- * "Cannot use output buffering in output buffering display handlers."
1006- *
1007- * @since 6.9.0
1008- *
1009- * @param string $output Finalized output buffer.
1010- */
1011- do_action ( 'wp_finalized_template_enhancement_output_buffer ' , $ filtered_output );
995+ try {
996+ /**
997+ * Filters the template enhancement output buffer prior to sending to the client.
998+ *
999+ * This filter only applies the HTML output of an included template. This filter is a progressive enhancement
1000+ * intended for applications such as optimizing markup to improve frontend page load performance. Sites must not
1001+ * depend on this filter applying since they may opt to stream the responses instead. Callbacks for this filter
1002+ * are highly discouraged from using regular expressions to do any kind of replacement on the output. Use the
1003+ * HTML API (either `WP_HTML_Tag_Processor` or `WP_HTML_Processor`), or else use {@see DOM\HtmlDocument} as of
1004+ * PHP 8.4 which fully supports HTML5.
1005+ *
1006+ * Do not print any output during this filter. While filters normally don't print anything, this is especially
1007+ * important since this applies during an output buffer callback. Prior to PHP 8.5, the output will be silently
1008+ * omitted, whereas afterward a deprecation notice will be emitted.
1009+ *
1010+ * Important: Because this filter is applied inside an output buffer callback (i.e. display handler), any
1011+ * callbacks added to the filter must not attempt to start their own output buffers. Otherwise, PHP will raise a
1012+ * fatal error: "Cannot use output buffering in output buffering display handlers."
1013+ *
1014+ * @since 6.9.0
1015+ *
1016+ * @param string $filtered_output HTML template enhancement output buffer.
1017+ * @param string $output Original HTML template output buffer.
1018+ */
1019+ $ filtered_output = (string ) apply_filters ( 'wp_template_enhancement_output_buffer ' , $ filtered_output , $ output );
1020+ } catch ( Throwable $ throwable ) {
1021+ // Emit to the error log as a warning not as an error to prevent halting execution.
1022+ $ did_just_catch = true ;
1023+ trigger_error (
1024+ sprintf (
1025+ /* translators: %s is the throwable class name */
1026+ __ ( 'Uncaught "%s" thrown: ' ),
1027+ get_class ( $ throwable )
1028+ ) . ' ' . $ throwable ->getMessage (),
1029+ E_USER_WARNING
1030+ );
1031+ $ did_just_catch = false ;
1032+ }
1033+
1034+ try {
1035+ /**
1036+ * Fires after the template enhancement output buffer has been finalized.
1037+ *
1038+ * This happens immediately before the template enhancement output buffer is flushed. No output may be printed
1039+ * at this action; prior to PHP 8.5, the output will be silently omitted, whereas afterward a deprecation notice
1040+ * will be emitted. Nevertheless, HTTP headers may be sent, which makes this action complimentary to the
1041+ * {@see 'send_headers'} action, in which headers may be sent before the template has started rendering. In
1042+ * contrast, this `wp_finalized_template_enhancement_output_buffer` action is the possible point at which HTTP
1043+ * headers can be sent. This action does not fire if the "template enhancement output buffer" was not started.
1044+ * This output buffer is automatically started if this action is added before
1045+ * {@see wp_start_template_enhancement_output_buffer()} runs at the {@see 'wp_before_include_template'} action
1046+ * with priority 1000. Before this point, the output buffer will also be started automatically if there was a
1047+ * {@see 'wp_template_enhancement_output_buffer'} filter added, or if the
1048+ * {@see 'wp_should_output_buffer_template_for_enhancement'} filter is made to return `true`.
1049+ *
1050+ * Important: Because this action fires inside an output buffer callback (i.e. display handler), any callbacks
1051+ * added to the action must not attempt to start their own output buffers. Otherwise, PHP will raise a fatal
1052+ * error: "Cannot use output buffering in output buffering display handlers."
1053+ *
1054+ * @since 6.9.0
1055+ *
1056+ * @param string $output Finalized output buffer.
1057+ */
1058+ do_action ( 'wp_finalized_template_enhancement_output_buffer ' , $ filtered_output );
1059+ } catch ( Throwable $ throwable ) {
1060+ // Emit to the error log as a warning not as an error to prevent halting execution.
1061+ $ did_just_catch = true ;
1062+ trigger_error (
1063+ sprintf (
1064+ /* translators: %s is the class name */
1065+ __ ( 'Uncaught "%s" thrown: ' ),
1066+ get_class ( $ throwable )
1067+ ) . ' ' . $ throwable ->getMessage (),
1068+ E_USER_WARNING
1069+ );
1070+ $ did_just_catch = false ;
1071+ }
1072+
1073+ // Append any errors to be displayed before returning flushing the buffer.
1074+ if ( $ original_display_errors && 'stderr ' !== $ original_display_errors ) {
1075+ foreach ( $ error_log as $ error ) {
1076+ switch ( $ error ['level ' ] ) {
1077+ case E_USER_NOTICE :
1078+ $ type = 'Notice ' ;
1079+ break ;
1080+ case E_USER_DEPRECATED :
1081+ $ type = 'Deprecated ' ;
1082+ break ;
1083+ case E_USER_WARNING :
1084+ $ type = 'Warning ' ;
1085+ break ;
1086+ default :
1087+ $ type = 'Error ' ;
1088+ }
1089+
1090+ if ( ini_get ( 'html_errors ' ) ) {
1091+ /*
1092+ * Adapted from PHP internals: <https://github.com/php/php-src/blob/a979e9f897a90a580e883b1f39ce5673686ffc67/main/main.c#L1478>.
1093+ * The self-closing tags are a vestige of the XHTML past!
1094+ */
1095+ $ format = "%s<br /> \n<b>%s</b>: %s in <b>%s</b> on line <b>%s</b><br /> \n%s " ;
1096+ } else {
1097+ // Adapted from PHP internals: <https://github.com/php/php-src/blob/a979e9f897a90a580e883b1f39ce5673686ffc67/main/main.c#L1492>.
1098+ $ format = "%s \n%s: %s in %s on line %s \n%s " ;
1099+ }
1100+ $ filtered_output .= sprintf (
1101+ $ format ,
1102+ ini_get ( 'error_prepend_string ' ),
1103+ $ type ,
1104+ $ error ['message ' ],
1105+ $ error ['file ' ],
1106+ $ error ['line ' ],
1107+ ini_get ( 'error_append_string ' )
1108+ );
1109+ }
1110+
1111+ ini_set ( 'display_errors ' , $ original_display_errors );
1112+ }
1113+
1114+ restore_error_handler ();
10121115
10131116 return $ filtered_output ;
10141117}
0 commit comments