Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add page reloading in offline.php templates #697

Merged
merged 8 commits into from
Feb 24, 2022
66 changes: 66 additions & 0 deletions tests/test-template.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* Tests for template.php
*
* @package PWA
*/

use Yoast\WPTestUtils\WPIntegration\TestCase;

/**
* Tests for template.php
*/
class Test_Template extends TestCase {
/**
* Test if function adding script on GET method, is_offline() or is_500 is true
*
* @covers ::wp_service_worker_offline_page_reload()
*/
public function test_wp_service_worker_offline_page_reload() {
$this->assertEquals( 10, has_action( 'wp_footer', 'wp_service_worker_offline_page_reload' ) );
$this->assertEquals( 10, has_action( 'error_footer', 'wp_service_worker_offline_page_reload' ) );

// Check when method is GET but not offline or 500.
$actual_script = wp_service_worker_offline_page_reload();
$this->assertEquals( $_SERVER['REQUEST_METHOD'], 'GET' );
$this->assertFalse( is_offline() );
$this->assertFalse( is_500() );
$this->assertEmpty( $actual_script );

// Check if script is added when offline.
$error_template_url = add_query_arg( 'wp_error_template', 'offline', home_url( '/', 'relative' ) );
$this->go_to( $error_template_url );

ob_start();
wp_service_worker_offline_page_reload();
$actual_script = ob_get_clean();
$this->assertEquals( $_SERVER['REQUEST_METHOD'], 'GET' );
$this->assertTrue( is_offline() );
$this->assertFalse( is_500() );
$this->assertStringContainsString( '<script type="module">', $actual_script );
$this->assertStringContainsString( 'await fetch(location.href, {method: \'HEAD\'})', $actual_script );

// Check if script is added when 500.
$error_template_url = add_query_arg( 'wp_error_template', '500', home_url( '/', 'relative' ) );
$this->go_to( $error_template_url );

ob_start();
wp_service_worker_offline_page_reload();
$actual_script = ob_get_clean();
$this->assertEquals( $_SERVER['REQUEST_METHOD'], 'GET' );
$this->assertFalse( is_offline() );
$this->assertTrue( is_500() );
$this->assertStringContainsString( '<script type="module">', $actual_script );
$this->assertStringContainsString( 'await fetch(location.href, {method: \'HEAD\'})', $actual_script );

$this->go_to( home_url( '/', 'relative' ) );

// Check when method is not GET.
$_SERVER['REQUEST_METHOD'] = 'POST';
$actual_script = wp_service_worker_offline_page_reload();
$this->assertEquals( $_SERVER['REQUEST_METHOD'], 'POST' );
$this->assertFalse( is_offline() );
$this->assertFalse( is_500() );
$this->assertEmpty( $actual_script );
}
}
52 changes: 52 additions & 0 deletions wp-includes/template.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,55 @@ function wp_service_worker_error_details_template( $output = '' ) {
function wp_service_worker_error_message_placeholder() {
echo '<p><!--WP_SERVICE_WORKER_ERROR_MESSAGE--></p>';
}

/**
* Reload the offline page and check if user comes online.
*
* @since 0.7
*/
function wp_service_worker_offline_page_reload() {
if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'GET' !== $_SERVER['REQUEST_METHOD'] ) {
return;
}

if ( ! is_offline() && ! is_500() ) {
return;
}

?>
<script type="module">
/**
* Listen to changes in the network state, reload when online.
* This handles the case when the device is completely offline.
*/
window.addEventListener('online', () => {
window.location.reload();
});

// Create a counter to implement exponential backoff.
let count = 0;

/**
* Check if the server is responding and reload the page if it is.
* This handles the case when the device is online, but the server is offline or misbehaving.
*/
async function checkNetworkAndReload() {
try {
const response = await fetch(location.href, {method: 'HEAD'});
// Verify we get a valid response from the server
if (response.status >= 200 && response.status < 500) {
window.location.reload();
return;
}
} catch {
// Unable to connect so do nothing.
}
window.setTimeout(checkNetworkAndReload, Math.pow(2, count++) * 2500);
}
checkNetworkAndReload();
thelovekesh marked this conversation as resolved.
Show resolved Hide resolved
</script>
<?php
}

add_action( 'wp_footer', 'wp_service_worker_offline_page_reload' );
add_action( 'error_footer', 'wp_service_worker_offline_page_reload' );