Changeset 61120
- Timestamp:
- 11/04/2025 05:26:40 AM (6 weeks ago)
- Location:
- trunk
- Files:
-
- 2 edited
-
src/wp-includes/template.php (modified) (1 diff)
-
tests/phpunit/tests/template.php (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/template.php
r61111 r61120 966 966 $filtered_output = $output; 967 967 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 ); 988 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 ); 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 } 994 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(); 1012 1115 1013 1116 return $filtered_output; -
trunk/tests/phpunit/tests/template.php
r61111 r61120 65 65 66 66 /** 67 * @var string68 */69 protected $original_default_mimetype;70 71 /**72 67 * @var WP_Scripts|null 73 68 */ … … 83 78 */ 84 79 protected $original_theme_features; 80 81 /** 82 * @var array 83 */ 84 const RESTORED_CONFIG_OPTIONS = array( 85 'display_errors', 86 'error_reporting', 87 'log_errors', 88 'error_log', 89 'default_mimetype', 90 'html_errors', 91 'error_prepend_string', 92 'error_append_string', 93 ); 94 95 /** 96 * @var array 97 */ 98 protected $original_ini_config; 85 99 86 100 public function set_up() { 87 101 parent::set_up(); 88 $this->original_default_mimetype = ini_get( 'default_mimetype' ); 102 89 103 register_post_type( 90 104 'cpt', … … 118 132 119 133 $this->original_theme_features = $GLOBALS['_wp_theme_features']; 134 foreach ( self::RESTORED_CONFIG_OPTIONS as $option ) { 135 $this->original_ini_config[ $option ] = ini_get( $option ); 136 } 120 137 } 121 138 … … 126 143 127 144 $GLOBALS['_wp_theme_features'] = $this->original_theme_features; 128 129 ini_set( 'default_mimetype', $this->original_default_mimetype ); 145 foreach ( $this->original_ini_config as $option => $value ) { 146 ini_set( $option, $value ); 147 } 148 130 149 unregister_post_type( 'cpt' ); 131 150 unregister_taxonomy( 'taxo' ); … … 979 998 980 999 /** 1000 * Data provider for data_provider_to_test_wp_finalize_template_enhancement_output_buffer_with_errors_while_processing. 1001 * 1002 * @return array 1003 */ 1004 public function data_provider_to_test_wp_finalize_template_enhancement_output_buffer_with_errors_while_processing(): array { 1005 $log_and_display_all = array( 1006 'error_reporting' => E_ALL, 1007 'display_errors' => true, 1008 'log_errors' => true, 1009 'html_errors' => true, 1010 ); 1011 1012 $tests = array( 1013 'deprecated' => array( 1014 'ini_config_options' => $log_and_display_all, 1015 'emit_filter_errors' => static function () { 1016 trigger_error( 'You are history during filter.', E_USER_DEPRECATED ); 1017 }, 1018 'emit_action_errors' => static function () { 1019 trigger_error( 'You are history during action.', E_USER_DEPRECATED ); 1020 }, 1021 'expected_processed' => true, 1022 'expected_error_log' => array( 1023 'PHP Deprecated: You are history during filter. in __FILE__ on line __LINE__', 1024 'PHP Deprecated: You are history during action. in __FILE__ on line __LINE__', 1025 ), 1026 'expected_displayed_errors' => array( 1027 '<b>Deprecated</b>: You are history during filter. in <b>__FILE__</b> on line <b>__LINE__</b>', 1028 '<b>Deprecated</b>: You are history during action. in <b>__FILE__</b> on line <b>__LINE__</b>', 1029 ), 1030 ), 1031 'notice' => array( 1032 'ini_config_options' => $log_and_display_all, 1033 'emit_filter_errors' => static function () { 1034 trigger_error( 'POSTED: No trespassing during filter.', E_USER_NOTICE ); 1035 }, 1036 'emit_action_errors' => static function () { 1037 trigger_error( 'POSTED: No trespassing during action.', E_USER_NOTICE ); 1038 }, 1039 'expected_processed' => true, 1040 'expected_error_log' => array( 1041 'PHP Notice: POSTED: No trespassing during filter. in __FILE__ on line __LINE__', 1042 'PHP Notice: POSTED: No trespassing during action. in __FILE__ on line __LINE__', 1043 ), 1044 'expected_displayed_errors' => array( 1045 '<b>Notice</b>: POSTED: No trespassing during filter. in <b>__FILE__</b> on line <b>__LINE__</b>', 1046 '<b>Notice</b>: POSTED: No trespassing during action. in <b>__FILE__</b> on line <b>__LINE__</b>', 1047 ), 1048 ), 1049 'warning' => array( 1050 'ini_config_options' => $log_and_display_all, 1051 'emit_filter_errors' => static function () { 1052 trigger_error( 'AVISO: Piso mojado durante filtro.', E_USER_WARNING ); 1053 }, 1054 'emit_action_errors' => static function () { 1055 trigger_error( 'AVISO: Piso mojado durante acción.', E_USER_WARNING ); 1056 }, 1057 'expected_processed' => true, 1058 'expected_error_log' => array( 1059 'PHP Warning: AVISO: Piso mojado durante filtro. in __FILE__ on line __LINE__', 1060 'PHP Warning: AVISO: Piso mojado durante acción. in __FILE__ on line __LINE__', 1061 ), 1062 'expected_displayed_errors' => array( 1063 '<b>Warning</b>: AVISO: Piso mojado durante filtro. in <b>__FILE__</b> on line <b>__LINE__</b>', 1064 '<b>Warning</b>: AVISO: Piso mojado durante acción. in <b>__FILE__</b> on line <b>__LINE__</b>', 1065 ), 1066 ), 1067 'error' => array( 1068 'ini_config_options' => $log_and_display_all, 1069 'emit_filter_errors' => static function () { 1070 @trigger_error( 'ERROR: Can this mistake be rectified during filter?', E_USER_ERROR ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged 1071 }, 1072 'emit_action_errors' => static function () { 1073 @trigger_error( 'ERROR: Can this mistake be rectified during action?', E_USER_ERROR ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged 1074 }, 1075 'expected_processed' => false, 1076 'expected_error_log' => array( 1077 'PHP Warning: Uncaught "Exception" thrown: User error triggered: ERROR: Can this mistake be rectified during filter? in __FILE__ on line __LINE__', 1078 'PHP Warning: Uncaught "Exception" thrown: User error triggered: ERROR: Can this mistake be rectified during action? in __FILE__ on line __LINE__', 1079 ), 1080 'expected_displayed_errors' => array( 1081 '<b>Error</b>: Uncaught "Exception" thrown: User error triggered: ERROR: Can this mistake be rectified during filter? in <b>__FILE__</b> on line <b>__LINE__</b>', 1082 '<b>Error</b>: Uncaught "Exception" thrown: User error triggered: ERROR: Can this mistake be rectified during action? in <b>__FILE__</b> on line <b>__LINE__</b>', 1083 ), 1084 ), 1085 'exception' => array( 1086 'ini_config_options' => $log_and_display_all, 1087 'emit_filter_errors' => static function () { 1088 throw new Exception( 'I take exception to this filter!' ); 1089 }, 1090 'emit_action_errors' => static function () { 1091 throw new Exception( 'I take exception to this action!' ); 1092 }, 1093 'expected_processed' => false, 1094 'expected_error_log' => array( 1095 'PHP Warning: Uncaught "Exception" thrown: I take exception to this filter! in __FILE__ on line __LINE__', 1096 'PHP Warning: Uncaught "Exception" thrown: I take exception to this action! in __FILE__ on line __LINE__', 1097 ), 1098 'expected_displayed_errors' => array( 1099 '<b>Error</b>: Uncaught "Exception" thrown: I take exception to this filter! in <b>__FILE__</b> on line <b>__LINE__</b>', 1100 '<b>Error</b>: Uncaught "Exception" thrown: I take exception to this action! in <b>__FILE__</b> on line <b>__LINE__</b>', 1101 ), 1102 ), 1103 'multiple_non_errors' => array( 1104 'ini_config_options' => $log_and_display_all, 1105 'emit_filter_errors' => static function () { 1106 trigger_error( 'You are history during filter.', E_USER_DEPRECATED ); 1107 trigger_error( 'POSTED: No trespassing during filter.', E_USER_NOTICE ); 1108 trigger_error( 'AVISO: Piso mojado durante filtro.', E_USER_WARNING ); 1109 }, 1110 'emit_action_errors' => static function () { 1111 trigger_error( 'You are history during action.', E_USER_DEPRECATED ); 1112 trigger_error( 'POSTED: No trespassing during action.', E_USER_NOTICE ); 1113 trigger_error( 'AVISO: Piso mojado durante acción.', E_USER_WARNING ); 1114 }, 1115 'expected_processed' => true, 1116 'expected_error_log' => array( 1117 'PHP Deprecated: You are history during filter. in __FILE__ on line __LINE__', 1118 'PHP Notice: POSTED: No trespassing during filter. in __FILE__ on line __LINE__', 1119 'PHP Warning: AVISO: Piso mojado durante filtro. in __FILE__ on line __LINE__', 1120 'PHP Deprecated: You are history during action. in __FILE__ on line __LINE__', 1121 'PHP Notice: POSTED: No trespassing during action. in __FILE__ on line __LINE__', 1122 'PHP Warning: AVISO: Piso mojado durante acción. in __FILE__ on line __LINE__', 1123 ), 1124 'expected_displayed_errors' => array( 1125 '<b>Deprecated</b>: You are history during filter. in <b>__FILE__</b> on line <b>__LINE__</b>', 1126 '<b>Notice</b>: POSTED: No trespassing during filter. in <b>__FILE__</b> on line <b>__LINE__</b>', 1127 '<b>Warning</b>: AVISO: Piso mojado durante filtro. in <b>__FILE__</b> on line <b>__LINE__</b>', 1128 '<b>Deprecated</b>: You are history during action. in <b>__FILE__</b> on line <b>__LINE__</b>', 1129 '<b>Notice</b>: POSTED: No trespassing during action. in <b>__FILE__</b> on line <b>__LINE__</b>', 1130 '<b>Warning</b>: AVISO: Piso mojado durante acción. in <b>__FILE__</b> on line <b>__LINE__</b>', 1131 ), 1132 ), 1133 'deprecated_without_html' => array( 1134 'ini_config_options' => array_merge( 1135 $log_and_display_all, 1136 array( 1137 'html_errors' => false, 1138 ) 1139 ), 1140 'emit_filter_errors' => static function () { 1141 trigger_error( 'You are history during filter.', E_USER_DEPRECATED ); 1142 }, 1143 'emit_action_errors' => null, 1144 'expected_processed' => true, 1145 'expected_error_log' => array( 1146 'PHP Deprecated: You are history during filter. in __FILE__ on line __LINE__', 1147 ), 1148 'expected_displayed_errors' => array( 1149 'Deprecated: You are history during filter. in __FILE__ on line __LINE__', 1150 ), 1151 ), 1152 'warning_in_eval_with_prepend_and_append' => array( 1153 'ini_config_options' => array_merge( 1154 $log_and_display_all, 1155 array( 1156 'error_prepend_string' => '<details><summary>PHP Problem!</summary>', 1157 'error_append_string' => '</details>', 1158 ) 1159 ), 1160 'emit_filter_errors' => static function () { 1161 eval( "trigger_error( 'AVISO: Piso mojado durante filtro.', E_USER_WARNING );" ); // phpcs:ignore Squiz.PHP.Eval.Discouraged -- We're in a test! 1162 }, 1163 'emit_action_errors' => static function () { 1164 eval( "trigger_error( 'AVISO: Piso mojado durante acción.', E_USER_WARNING );" ); // phpcs:ignore Squiz.PHP.Eval.Discouraged -- We're in a test! 1165 }, 1166 'expected_processed' => true, 1167 'expected_error_log' => array( 1168 'PHP Warning: AVISO: Piso mojado durante filtro. in __FILE__ : eval()\'d code on line __LINE__', 1169 'PHP Warning: AVISO: Piso mojado durante acción. in __FILE__ : eval()\'d code on line __LINE__', 1170 ), 1171 'expected_displayed_errors' => array( 1172 '<b>Warning</b>: AVISO: Piso mojado durante filtro. in <b>__FILE__ : eval()\'d code</b> on line <b>__LINE__</b>', 1173 '<b>Warning</b>: AVISO: Piso mojado durante acción. in <b>__FILE__ : eval()\'d code</b> on line <b>__LINE__</b>', 1174 ), 1175 ), 1176 'notice_with_display_errors_stderr' => array( 1177 'ini_config_options' => array_merge( 1178 $log_and_display_all, 1179 array( 1180 'display_errors' => 'stderr', 1181 ) 1182 ), 1183 'emit_filter_errors' => static function () { 1184 trigger_error( 'POSTED: No trespassing during filter.' ); 1185 }, 1186 'emit_action_errors' => static function () { 1187 trigger_error( 'POSTED: No trespassing during action.' ); 1188 }, 1189 'expected_processed' => true, 1190 'expected_error_log' => array( 1191 'PHP Notice: POSTED: No trespassing during filter. in __FILE__ on line __LINE__', 1192 'PHP Notice: POSTED: No trespassing during action. in __FILE__ on line __LINE__', 1193 ), 1194 'expected_displayed_errors' => array(), 1195 ), 1196 ); 1197 1198 $tests_error_reporting_warnings_and_above = array(); 1199 foreach ( $tests as $name => $test ) { 1200 $test['ini_config_options']['error_reporting'] = E_ALL ^ E_USER_NOTICE ^ E_USER_DEPRECATED; 1201 1202 $test['expected_error_log'] = array_values( 1203 array_filter( 1204 $test['expected_error_log'], 1205 static function ( $log_entry ) { 1206 return ! ( str_contains( $log_entry, 'Notice' ) || str_contains( $log_entry, 'Deprecated' ) ); 1207 } 1208 ) 1209 ); 1210 1211 $test['expected_displayed_errors'] = array_values( 1212 array_filter( 1213 $test['expected_displayed_errors'], 1214 static function ( $log_entry ) { 1215 return ! ( str_contains( $log_entry, 'Notice' ) || str_contains( $log_entry, 'Deprecated' ) ); 1216 } 1217 ) 1218 ); 1219 1220 $tests_error_reporting_warnings_and_above[ "{$name}_with_warnings_and_above_reported" ] = $test; 1221 } 1222 1223 $tests_without_display_errors = array(); 1224 foreach ( $tests as $name => $test ) { 1225 $test['ini_config_options']['display_errors'] = false; 1226 $test['expected_displayed_errors'] = array(); 1227 1228 $tests_without_display_errors[ "{$name}_without_display_errors" ] = $test; 1229 } 1230 1231 $tests_without_display_or_log_errors = array(); 1232 foreach ( $tests as $name => $test ) { 1233 $test['ini_config_options']['display_errors'] = false; 1234 $test['ini_config_options']['log_errors'] = false; 1235 $test['expected_displayed_errors'] = array(); 1236 $test['expected_error_log'] = array(); 1237 1238 $tests_without_display_or_log_errors[ "{$name}_without_display_errors_or_log_errors" ] = $test; 1239 } 1240 1241 return array_merge( $tests, $tests_error_reporting_warnings_and_above, $tests_without_display_errors, $tests_without_display_or_log_errors ); 1242 } 1243 1244 /** 1245 * Tests that errors are handled as expected when errors are emitted when filtering wp_template_enhancement_output_buffer or doing the wp_finalize_template_enhancement_output_buffer action. 1246 * 1247 * @ticket 43258 1248 * @ticket 64108 1249 * 1250 * @covers ::wp_finalize_template_enhancement_output_buffer 1251 * 1252 * @dataProvider data_provider_to_test_wp_finalize_template_enhancement_output_buffer_with_errors_while_processing 1253 */ 1254 public function test_wp_finalize_template_enhancement_output_buffer_with_errors_while_processing( array $ini_config_options, ?Closure $emit_filter_errors, ?Closure $emit_action_errors, bool $expected_processed, array $expected_error_log, array $expected_displayed_errors ): void { 1255 // Start a wrapper output buffer so that we can flush the inner buffer. 1256 ob_start(); 1257 1258 ini_set( 'error_log', $this->temp_filename() ); // phpcs:ignore WordPress.PHP.IniSet.log_errors_Blacklisted, WordPress.PHP.IniSet.Risky 1259 foreach ( $ini_config_options as $config => $option ) { 1260 ini_set( $config, $option ); 1261 } 1262 1263 add_filter( 1264 'wp_template_enhancement_output_buffer', 1265 static function ( string $buffer ) use ( $emit_filter_errors ): string { 1266 $buffer = str_replace( 'Hello', 'Goodbye', $buffer ); 1267 if ( $emit_filter_errors ) { 1268 $emit_filter_errors(); 1269 } 1270 return $buffer; 1271 } 1272 ); 1273 1274 if ( $emit_action_errors ) { 1275 add_action( 1276 'wp_finalized_template_enhancement_output_buffer', 1277 static function () use ( $emit_action_errors ): void { 1278 $emit_action_errors(); 1279 } 1280 ); 1281 } 1282 1283 $this->assertTrue( wp_start_template_enhancement_output_buffer(), 'Expected wp_start_template_enhancement_output_buffer() to return true indicating the output buffer started.' ); 1284 1285 ?> 1286 <!DOCTYPE html> 1287 <html lang="en"> 1288 <head> 1289 <title>Greeting</title> 1290 </head> 1291 <body> 1292 <h1>Hello World!</h1> 1293 </body> 1294 </html> 1295 <?php 1296 1297 ob_end_flush(); // End the buffer started by wp_start_template_enhancement_output_buffer(). 1298 1299 $processed_output = ob_get_clean(); // Obtain the output via the wrapper output buffer. 1300 1301 if ( $expected_processed ) { 1302 $this->assertStringContainsString( 'Goodbye', $processed_output, 'Expected the output buffer to have been processed.' ); 1303 } else { 1304 $this->assertStringNotContainsString( 'Goodbye', $processed_output, 'Expected the output buffer to not have been processed.' ); 1305 } 1306 1307 $actual_error_log = array_values( 1308 array_map( 1309 static function ( string $error_log_entry ): string { 1310 $error_log_entry = preg_replace( 1311 '/^\[.+?] /', 1312 '', 1313 $error_log_entry 1314 ); 1315 $error_log_entry = preg_replace( 1316 '#(?<= in ).+?' . preg_quote( basename( __FILE__ ), '#' ) . '(\(\d+\))?#', 1317 '__FILE__', 1318 $error_log_entry 1319 ); 1320 return preg_replace( 1321 '#(?<= on line )\d+#', 1322 '__LINE__', 1323 $error_log_entry 1324 ); 1325 }, 1326 array_filter( explode( "\n", trim( file_get_contents( ini_get( 'error_log' ) ) ) ) ) 1327 ) 1328 ); 1329 1330 $this->assertSame( 1331 $expected_error_log, 1332 $actual_error_log, 1333 'Expected same error log entries. Snapshot: ' . var_export( $actual_error_log, true ) 1334 ); 1335 1336 $displayed_errors = array_values( 1337 array_map( 1338 static function ( string $displayed_error ): string { 1339 $displayed_error = str_replace( '<br />', '', $displayed_error ); 1340 $displayed_error = preg_replace( 1341 '#( in (?:<b>)?).+?' . preg_quote( basename( __FILE__ ), '#' ) . '(\(\d+\))?#', 1342 '$1__FILE__', 1343 $displayed_error 1344 ); 1345 return preg_replace( 1346 '#( on line (?:<b>)?)\d+#', 1347 '$1__LINE__', 1348 $displayed_error 1349 ); 1350 }, 1351 array_filter( 1352 explode( "\n", trim( $processed_output ) ), 1353 static function ( $line ): bool { 1354 return str_contains( $line, ' in ' ); 1355 } 1356 ) 1357 ) 1358 ); 1359 1360 $this->assertSame( 1361 $expected_displayed_errors, 1362 $displayed_errors, 1363 'Expected the displayed errors to be the same. Snapshot: ' . var_export( $displayed_errors, true ) 1364 ); 1365 1366 if ( count( $expected_displayed_errors ) > 0 ) { 1367 $this->assertStringEndsNotWith( '</html>', rtrim( $processed_output ), 'Expected the output to have the error displayed.' ); 1368 } else { 1369 $this->assertStringEndsWith( '</html>', rtrim( $processed_output ), 'Expected the output to not have the error displayed.' ); 1370 } 1371 } 1372 1373 /** 981 1374 * Tests that wp_load_classic_theme_block_styles_on_demand() does not add hooks for block themes. 982 1375 *
Note: See TracChangeset
for help on using the changeset viewer.