Skip to content

Commit 3db5886

Browse files
committed
Improve far-future headers checks by adding detailed failure reasons and updating the extensions table generation
1 parent 35e7977 commit 3db5886

File tree

1 file changed

+88
-29
lines changed
  • plugins/performance-lab/includes/site-health/far-future-headers

1 file changed

+88
-29
lines changed

plugins/performance-lab/includes/site-health/far-future-headers/helper.php

Lines changed: 88 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
8989
function 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

Comments
 (0)