Skip to content

Commit

Permalink
Merge pull request #1826 from WordPress/fix/bfcache-conditions
Browse files Browse the repository at this point in the history
Remove `no-cache` and `max-age=0` from bfcache failure conditions
  • Loading branch information
westonruter authored Jan 26, 2025
2 parents 2b1bf18 + ffa9c25 commit e2effe6
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function perflab_bfcache_compatibility_headers_check(): array {
'color' => 'blue',
),
'description' => '<p>' . wp_kses(
__( 'If the <code>Cache-Control</code> page response header includes directives like <code>no-store</code>, <code>no-cache</code>, or <code>max-age=0</code> then it can prevent instant back/forward navigations (using the browser bfcache). These are not present for unauthenticated requests on your site, so it is configured properly. Note that WordPress adds these directives for logged-in page responses.', 'performance-lab' ),
__( "If the <code>Cache-Control</code> page response header includes the <code>no-store</code> directive then it can prevent instant back/forward navigations (using the browser's bfcache). This is not present for unauthenticated requests on your site, so it is configured properly. Note that there are other ways that bfcache can be disabled (e.g. you have JavaScript which uses a <code>unload</code> event listener). Also note that WordPress adds this directive for logged-in page responses for privacy/security reasons.", 'performance-lab' ),
array( 'code' => array() )
) . '</p>',
'actions' => '',
Expand Down Expand Up @@ -66,41 +66,17 @@ function perflab_bfcache_compatibility_headers_check(): array {
}

foreach ( (array) $cache_control_headers as $cache_control_header ) {
$cache_control_header = strtolower( $cache_control_header );
$found_directives = array();
foreach ( array( 'no-store', 'no-cache', 'max-age=0' ) as $directive ) {
if ( str_contains( $cache_control_header, $directive ) ) {
$found_directives[] = $directive;
}
}

if ( count( $found_directives ) > 0 ) {
if ( str_contains( strtolower( $cache_control_header ), 'no-store' ) ) {
$result['label'] = __( 'The Cache-Control page header is preventing fast back/forward navigations', 'performance-lab' );
$result['status'] = 'recommended';
$result['description'] = sprintf(
'<p>%s %s</p>',
wp_kses(
sprintf(
/* translators: %s: problematic directive(s) */
_n(
'The <code>Cache-Control</code> response header for an unauthenticated request to the home page includes the following directive: %s.',
'The <code>Cache-Control</code> response header for an unauthenticated request to the home page includes the following directives: %s.',
count( $found_directives ),
'performance-lab'
),
implode(
', ',
array_map(
static function ( $header ) {
return "<code>$header</code>";
},
$found_directives
)
)
),
array( 'code' => array() )
),
esc_html__( 'This can affect the performance of your site by preventing fast back/forward navigations (via browser bfcache).', 'performance-lab' )
'<p>%s</p>',
sprintf(
/* translators: 1: Cache-Control, 2: no-store */
esc_html__( 'The %1$s response header for an unauthenticated request to the home page includes the %2$s directive. This can affect the performance of your site by preventing fast back/forward navigations (via the browser\'s bfcache).', 'performance-lab' ),
'<code>Cache-Control</code>',
'<code>no-store</code>'
)
);
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,6 @@

class Test_BFCache_Compatibility_Headers extends WP_UnitTestCase {

/**
* Holds mocked response headers for different test scenarios.
*
* @var array<string, array<string, mixed>>
*/
protected $mocked_responses = array();

/**
* Setup each test.
*/
public function setUp(): void {
parent::setUp();

// Clear any filters or mocks.
remove_all_filters( 'pre_http_request' );

// Add the filter to mock HTTP requests.
add_filter( 'pre_http_request', array( $this, 'mock_http_requests' ), 10, 3 );
}

/**
* Test that the bfcache compatibility test is added to the site health tests.
*
Expand Down Expand Up @@ -64,7 +44,7 @@ public function test_perflab_bfcache_compatibility_headers_add_test_is_attached(
* @param string $expected_message The expected message.
*/
public function test_perflab_bfcache_compatibility_headers_check( $response, string $expected_status, string $expected_message ): void {
$this->mocked_responses = array( home_url( '/' ) => $response );
$this->mock_http_request( $response, home_url( '/' ) );

$result = perflab_bfcache_compatibility_headers_check();

Expand All @@ -82,27 +62,27 @@ public function data_test_bfcache_compatibility(): array {
'headers_not_set' => array(
$this->build_response( 200, array( 'cache-control' => '' ) ),
'good',
'If the <code>Cache-Control</code> page response header includes directives like',
'If the <code>Cache-Control</code> page response header includes',
),
'no_store' => array(
$this->build_response( 200, array( 'cache-control' => 'no-store' ) ),
'recommended',
'<p>The <code>Cache-Control</code> response header for an unauthenticated request to the home page includes the following directive: <code>no-store</code>',
'<p>The <code>Cache-Control</code> response header for an unauthenticated request to the home page includes',
),
'no_cache' => array(
$this->build_response( 200, array( 'cache-control' => 'no-cache' ) ),
'recommended',
'<p>The <code>Cache-Control</code> response header for an unauthenticated request to the home page includes the following directive: <code>no-cache</code>',
'good',
'If the <code>Cache-Control</code> page response header includes',
),
'max_age_0' => array(
$this->build_response( 200, array( 'cache-control' => 'max-age=0' ) ),
'recommended',
'<p>The <code>Cache-Control</code> response header for an unauthenticated request to the home page includes the following directive: <code>max-age=0</code>',
$this->build_response( 200, array( 'cache-control' => 'no-cache' ) ),
'good',
'If the <code>Cache-Control</code> page response header includes',
),
'max_age_0_no_store' => array(
$this->build_response( 200, array( 'cache-control' => 'max-age=0, no-store' ) ),
'recommended',
'<p>The <code>Cache-Control</code> response header for an unauthenticated request to the home page includes the following directives: <code>no-store</code>, <code>max-age=0</code>',
'<p>The <code>Cache-Control</code> response header for an unauthenticated request to the home page includes',
),
'error' => array(
new WP_Error( 'http_request_failed', 'HTTP request failed' ),
Expand All @@ -113,20 +93,23 @@ public function data_test_bfcache_compatibility(): array {
}

/**
* Mock HTTP requests for assets to simulate different responses.
* Mock HTTP response for a given URL.
*
* @param bool $response A preemptive return value of an HTTP request. Default false.
* @param array<string, mixed> $args Request arguments.
* @param string $url The request URL.
* @return array<string, mixed>|WP_Error Mocked response.
* @param array<string, mixed>|WP_Error $mocked_response The mocked response.
* @param non-empty-string $url The request URL.
*/
public function mock_http_requests( bool $response, array $args, string $url ) {
if ( isset( $this->mocked_responses[ $url ] ) ) {
return $this->mocked_responses[ $url ];
}

// If no specific mock set, default to a generic success with no caching.
return $this->build_response( 200 );
public function mock_http_request( $mocked_response, string $url ): void {
add_filter(
'pre_http_request',
static function ( $pre, $args, $request_url ) use ( $url, $mocked_response ) {
if ( $url === $request_url ) {
return $mocked_response;
}
return $pre;
},
10,
3
);
}

/**
Expand Down

0 comments on commit e2effe6

Please sign in to comment.