@@ -61,11 +61,11 @@ function perflab_ffh_assets_test(): array {
6161 $ result ['label ' ] = __ ( 'Your site does not serve static assets with recommended far-future expiration headers ' , 'performance-lab ' );
6262
6363 if ( count ( $ results ['details ' ] ) > 0 ) {
64- $ table_html = perflab_ffh_get_extensions_table ( $ results ['details ' ] );
6564 $ result ['actions ' ] = sprintf (
66- '<p>%s</p>%s ' ,
65+ '<p>%s</p>%s<p>%s</p> ' ,
6766 esc_html__ ( 'The following file types do not have the recommended far-future headers. Consider adding or adjusting Cache-Control or Expires headers for these asset types. ' , 'performance-lab ' ),
68- $ table_html
67+ perflab_ffh_get_extensions_table ( $ results ['details ' ] ),
68+ esc_html__ ( 'Note: "Conditionally cached" means that the browser can re-validate the resource using ETag or Last-Modified headers. This results in fewer full downloads but still requires the browser to make requests, unlike far-future expiration headers that allow the browser to fully rely on its local cache for a longer duration. ' , 'performance-lab ' )
6969 );
7070 } else {
7171 $ result ['actions ' ] = sprintf (
@@ -84,11 +84,11 @@ function perflab_ffh_assets_test(): array {
8484 * @since n.e.x.t
8585 *
8686 * @param string[] $assets List of asset URLs to check.
87- * @return array{final_status: string, details: string[]} Final status and details.
87+ * @return array{final_status: string, details: array{extension: string, reason: string} []} Final status and details.
8888 */
8989function perflab_ffh_check_assets ( array $ assets ): array {
90- $ final_status = 'good ' ;
91- $ extension_results = array (); // Extensions that need improvement .
90+ $ final_status = 'good ' ;
91+ $ fail_details = array (); // Array of arrays with 'extension' and 'reason' .
9292
9393 foreach ( $ assets as $ asset ) {
9494 $ response = wp_remote_get ( $ asset , array ( 'sslverify ' => false ) );
@@ -98,30 +98,62 @@ function perflab_ffh_check_assets( array $assets ): array {
9898 $ extension = isset ( $ path_info ['extension ' ] ) ? strtolower ( $ path_info ['extension ' ] ) : 'unknown ' ;
9999
100100 if ( is_wp_error ( $ response ) ) {
101+ // Can't determine headers if request failed, consider it a fail.
102+ $ final_status = 'recommended ' ;
103+ $ fail_details [] = array (
104+ 'extension ' => $ extension ,
105+ 'reason ' => __ ( 'Could not retrieve headers ' , 'performance-lab ' ),
106+ );
101107 continue ;
102108 }
103109
104110 $ headers = wp_remote_retrieve_headers ( $ response );
105111 if ( ! is_object ( $ headers ) ) {
112+ // No valid headers retrieved.
113+ $ final_status = 'recommended ' ;
114+ $ fail_details [] = array (
115+ 'extension ' => $ extension ,
116+ 'reason ' => __ ( 'No valid headers retrieved ' , 'performance-lab ' ),
117+ );
106118 continue ;
107119 }
108120
109- if ( ! perflab_ffh_check_headers ( $ headers ) ) {
110- if ( ! perflab_ffh_try_conditional_request ( $ asset , $ headers ) ) {
111- $ final_status = 'recommended ' ;
112- $ extension_results [] = $ extension ;
113- continue ;
114- }
121+ $ check = perflab_ffh_check_headers ( $ headers );
122+ if ( isset ( $ check ['passed ' ] ) && $ check ['passed ' ] ) {
123+ // This asset passed far-future headers test, no action needed.
124+ continue ;
125+ }
115126
116- // Conditional pass means still recommended, not fully good.
117- $ final_status = 'recommended ' ;
118- $ extension_results [] = $ extension ;
127+ // If not passed, decide whether to try conditional request.
128+ if ( false === $ check ) {
129+ // Only if no far-future headers at all, we try conditional request.
130+ $ conditional_pass = perflab_ffh_try_conditional_request ( $ asset , $ headers );
131+ if ( ! $ conditional_pass ) {
132+ $ final_status = 'recommended ' ;
133+ $ fail_details [] = array (
134+ 'extension ' => $ extension ,
135+ 'reason ' => __ ( 'No far-future headers and no conditional caching ' , 'performance-lab ' ),
136+ );
137+ } else {
138+ $ final_status = 'recommended ' ;
139+ $ fail_details [] = array (
140+ 'extension ' => $ extension ,
141+ 'reason ' => __ ( 'No far-future headers but conditionally cached ' , 'performance-lab ' ),
142+ );
143+ }
144+ } else {
145+ // If there's a max-age or expires but below threshold, we skip conditional.
146+ $ final_status = 'recommended ' ;
147+ $ fail_details [] = array (
148+ 'extension ' => $ extension ,
149+ 'reason ' => $ check ['reason ' ],
150+ );
119151 }
120152 }
121153
122154 return array (
123155 'final_status ' => $ final_status ,
124- 'details ' => $ extension_results ,
156+ 'details ' => $ fail_details ,
125157 );
126158}
127159
@@ -131,9 +163,9 @@ function perflab_ffh_check_assets( array $assets ): array {
131163 * @since n.e.x.t
132164 *
133165 * @param WpOrg\Requests\Utility\CaseInsensitiveDictionary $headers Response headers.
134- * @return bool True if far-future headers are enabled, false otherwise .
166+ * @return array{passed: bool, reason: string}|false Detailed result. If passed=false, reason explains why it failed and false if no headers found .
135167 */
136- function perflab_ffh_check_headers ( WpOrg \Requests \Utility \CaseInsensitiveDictionary $ headers ): bool {
168+ function perflab_ffh_check_headers ( WpOrg \Requests \Utility \CaseInsensitiveDictionary $ headers ) {
137169 /**
138170 * Filters the threshold for far-future headers.
139171 *
@@ -161,19 +193,46 @@ function perflab_ffh_check_headers( WpOrg\Requests\Utility\CaseInsensitiveDictio
161193
162194 // If max-age meets or exceeds the threshold, we consider it good.
163195 if ( $ max_age >= $ threshold ) {
164- return true ;
196+ return array (
197+ 'passed ' => true ,
198+ 'reason ' => '' ,
199+ );
165200 }
166201
167- // If max-age is not sufficient, check Expires.
168- // Expires is a date; we want to ensure it's far in the future.
202+ // If max-age is too low or not present, check Expires.
169203 if ( is_string ( $ expires ) && '' !== $ expires ) {
170204 $ expires_time = strtotime ( $ expires );
171205 if ( (bool ) $ expires_time && ( $ expires_time - time () ) >= $ threshold ) {
172- return true ;
206+ // Good - Expires far in the future.
207+ return array (
208+ 'passed ' => true ,
209+ 'reason ' => '' ,
210+ );
211+ }
212+
213+ // Expires header exists but not far enough in the future.
214+ if ( $ max_age > 0 && $ max_age < $ threshold ) {
215+ return array (
216+ 'passed ' => false ,
217+ 'reason ' => __ ( 'max-age below threshold ' , 'performance-lab ' ),
218+ );
173219 }
220+ return array (
221+ 'passed ' => false ,
222+ 'reason ' => __ ( 'expires below threshold ' , 'performance-lab ' ),
223+ );
174224 }
175225
176- return false ;
226+ // No max-age or expires found at all or max-age < threshold and no expires.
227+ if ( 0 === $ max_age ) {
228+ return false ;
229+ } else {
230+ // max-age was present but below threshold and no expires.
231+ return array (
232+ 'passed ' => false ,
233+ 'reason ' => __ ( 'max-age below threshold ' , 'performance-lab ' ),
234+ );
235+ }
177236}
178237
179238/**
@@ -212,25 +271,25 @@ function perflab_ffh_try_conditional_request( string $url, WpOrg\Requests\Utilit
212271}
213272
214273/**
215- * Generate a table listing file extensions that need far-future headers.
274+ * Generate a table listing file extensions that need far-future headers, including reasons .
216275 *
217276 * @since n.e.x.t
218277 *
219- * @param string[] $extensions Array of file extensions needing improvement .
278+ * @param array<array{extension: string, reason: string}> $fail_details Array of arrays with 'extension' and 'reason' .
220279 * @return string HTML formatted table.
221280 */
222- function perflab_ffh_get_extensions_table ( array $ extensions ): string {
281+ function perflab_ffh_get_extensions_table ( array $ fail_details ): string {
223282 $ html_table = sprintf (
224283 '<table class="widefat striped"><thead><tr><th scope="col">%s</th><th scope="col">%s</th></tr></thead><tbody> ' ,
225284 esc_html__ ( 'File Extension ' , 'performance-lab ' ),
226285 esc_html__ ( 'Status ' , 'performance-lab ' )
227286 );
228287
229- foreach ( $ extensions as $ extension ) {
288+ foreach ( $ fail_details as $ detail ) {
230289 $ html_table .= sprintf (
231290 '<tr><td>%s</td><td>%s</td></tr> ' ,
232- esc_html ( $ extension ),
233- esc_html__ ( ' Needs far-future headers ' , ' performance-lab ' )
291+ esc_html ( $ detail [ ' extension ' ] ),
292+ esc_html ( $ detail [ ' reason ' ] )
234293 );
235294 }
236295
0 commit comments