-
Notifications
You must be signed in to change notification settings - Fork 100
/
class-wp-service-workers.php
163 lines (141 loc) · 5.2 KB
/
class-wp-service-workers.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
<?php
/**
* WP_Service_Workers class.
*
* @since 0.2
* @package PWA
*/
/**
* Class used to register service workers.
*
* @since 0.1
*
* @see WP_Dependencies
*/
class WP_Service_Workers implements WP_Service_Worker_Registry_Aware {
/**
* Param for service workers.
*
* @var string
*/
const QUERY_VAR = 'wp_service_worker';
/**
* Scope for front.
*
* @var int
*/
const SCOPE_FRONT = 1;
/**
* Scope for admin.
*
* @var int
*/
const SCOPE_ADMIN = 2;
/**
* Scope for both front and admin.
*
* @var int
*/
const SCOPE_ALL = 3;
/**
* Service worker scripts registry.
*
* @var WP_Service_Worker_Scripts
*/
protected $scripts;
/**
* Constructor.
*
* Instantiates the service worker scripts registry.
*/
public function __construct() {
$components = array(
'configuration' => new WP_Service_Worker_Configuration_Component(),
'navigation_routing' => new WP_Service_Worker_Navigation_Routing_Component(),
'precaching_routes' => new WP_Service_Worker_Precaching_Routes_Component(),
'caching_routes' => new WP_Service_Worker_Caching_Routes_Component(),
);
$this->scripts = new WP_Service_Worker_Scripts( $components );
}
/**
* Gets the service worker scripts registry.
*
* @return WP_Service_Worker_Scripts Scripts registry instance.
*/
public function get_registry() {
return $this->scripts;
}
/**
* Get the current scope for the service worker request.
*
* @todo We don't really need this. A simple call to is_admin() is all that is required.
* @return int Scope. Either SCOPE_FRONT or SCOPE_ADMIN.
*/
public function get_current_scope() {
return is_admin() ? self::SCOPE_ADMIN : self::SCOPE_FRONT;
}
/**
* Get service worker logic for scope.
*
* @see wp_service_worker_loaded()
*/
public function serve_request() {
/*
* Clear the currently-authenticated user to ensure that the service worker doesn't vary between users.
* Note that clearing the authenticated user in this way is in keeping with REST API requests wherein the
* WP_REST_Server::serve_request() method calls WP_REST_Server::check_authentication() which in turn applies
* the rest_authentication_errors filter which runs rest_cookie_check_errors() which is then responsible for
* calling wp_set_current_user( 0 ) if it was previously-determined a user was logged-in with the required
* nonce cookie set when wp_validate_auth_cookie() triggers one of the auth_cookie_* actions.
*/
wp_set_current_user( 0 );
// See wp_debug_mode() for how this is also done for REST API responses.
@ini_set( 'display_errors', 0 ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set, WordPress.PHP.IniSet.display_errors_Blacklisted
/*
* Per Workbox <https://developers.google.com/web/tools/workbox/guides/service-worker-checklist#cache-control_of_your_service_worker_file>:
* "Generally, most developers will want to set the Cache-Control header to no-cache,
* forcing browsers to always check the server for a new service worker file."
* Nevertheless, an ETag header is also sent with support for Conditional Requests
* to save on needlessly re-downloading the same service worker with each page load.
*/
@header( 'Cache-Control: no-cache' ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.NoSilencedErrors.Discouraged
@header( 'Content-Type: text/javascript; charset=utf-8' ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.NoSilencedErrors.Discouraged
if ( ! is_admin() ) {
wp_enqueue_scripts();
/**
* Fires before serving the frontend service worker, when its scripts should be registered, caching routes established, and assets precached.
*
* @since 0.2
*
* @param WP_Service_Worker_Scripts $scripts Instance to register service worker behavior with.
*/
do_action( 'wp_front_service_worker', $this->scripts );
} else {
$hook_name = 'service-worker';
set_current_screen( $hook_name );
/** This action is documented in wp-admin/admin-header.php */
do_action( 'admin_enqueue_scripts', $hook_name );
/**
* Fires before serving the wp-admin service worker, when its scripts should be registered, caching routes established, and assets precached.
*
* @since 0.2
*
* @param WP_Service_Worker_Scripts $scripts Instance to register service worker behavior with.
*/
do_action( 'wp_admin_service_worker', $this->scripts );
}
ob_start();
printf( "/* PWA v%s-%s */\n\n", esc_html( PWA_VERSION ), is_admin() ? 'admin' : 'front' );
$this->scripts->do_items( array_keys( $this->scripts->registered ) );
$output = ob_get_clean();
$file_hash = md5( $output );
$etag = sprintf( '"%s"', $file_hash );
@header( "ETag: $etag" ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.NoSilencedErrors.Discouraged
$if_none_match = isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ? trim( wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) : false;
if ( $if_none_match === $etag ) {
status_header( 304 );
return;
}
echo $output; // phpcs:ignore WordPress.XSS.EscapeOutput, WordPress.Security.EscapeOutput
}
}