-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathforce-https.php
More file actions
378 lines (318 loc) · 14.2 KB
/
Copy pathforce-https.php
File metadata and controls
378 lines (318 loc) · 14.2 KB
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
<?php
/*
Plugin Name: Force HTTPS
Plugin URI: https://www.littlebizzy.com/plugins/force-https
Description: HTTPS enforcement for WordPress
Version: 4.2.0
Author: LittleBizzy
Author URI: https://www.littlebizzy.com
Requires PHP: 7.0
Tested up to: 7.0
License: GPLv3
License URI: http://www.gnu.org/licenses/gpl-3.0.html
Update URI: false
GitHub Plugin URI: littlebizzy/force-https
Primary Branch: master
Text Domain: force-https
*/
// prevent direct access
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// override wordpress.org with git updater
add_filter( 'gu_override_dot_org', function( $overrides ) {
$overrides[] = 'force-https/force-https.php';
return $overrides;
}, 999 );
// force wordpress admin ssl handling at runtime without defining constants
if ( function_exists( 'force_ssl_admin' ) ) {
force_ssl_admin( true );
}
// check whether core url option filtering should be bypassed
function force_https_bypass_core_url_option_filtering() {
return defined( 'WP_CLI' ) || defined( 'DOING_CRON' );
}
// normalize an early core url option value only when it resolves to https
function force_https_normalize_core_url_pre_option_value( $value ) {
// reject empty, missing, or non-string values so wordpress can continue normal option retrieval
if ( ! is_string( $value ) || '' === $value ) {
return false;
}
// upgrade http values before validating the final scheme
$value = force_https_securize_url( $value );
// only allow early short-circuiting with a confirmed https url
if ( stripos( $value, 'https://' ) !== 0 ) {
return false;
}
return $value;
}
// enforce https on WP_HOME before wordpress queries the home option
function force_https_pre_option_home( $pre_option ) {
// bypass if running via cli or cron to prevent issues with commands or internal loopback requests
if ( force_https_bypass_core_url_option_filtering() ) {
return $pre_option;
}
// respect any earlier short-circuited value only if it resolves to https
if ( false !== $pre_option ) {
return force_https_normalize_core_url_pre_option_value( $pre_option );
}
// safely force the hardcoded constant when available, such as on SlickStack servers
if ( defined( 'WP_HOME' ) ) {
$home = force_https_normalize_core_url_pre_option_value( WP_HOME );
if ( false !== $home ) {
return $home;
}
}
// let wordpress query the normal option value when no safe early value exists
return $pre_option;
}
// enforce https on WP_SITEURL before wordpress queries the siteurl option
function force_https_pre_option_siteurl( $pre_option ) {
// bypass if running via cli or cron to prevent issues with commands or internal loopback requests
if ( force_https_bypass_core_url_option_filtering() ) {
return $pre_option;
}
// respect any earlier short-circuited value only if it resolves to https
if ( false !== $pre_option ) {
return force_https_normalize_core_url_pre_option_value( $pre_option );
}
// safely force the hardcoded constant when available, such as on SlickStack servers
if ( defined( 'WP_SITEURL' ) ) {
$siteurl = force_https_normalize_core_url_pre_option_value( WP_SITEURL );
if ( false !== $siteurl ) {
return $siteurl;
}
}
// let wordpress query the normal option value when no safe early value exists
return $pre_option;
}
// enforce https on database-backed home and siteurl option values after normal retrieval
function force_https_filter_core_url_option( $value ) {
// bypass if running via cli or cron to prevent issues with commands or internal loopback requests
if ( force_https_bypass_core_url_option_filtering() ) {
return $value;
}
return force_https_securize_url( $value );
}
// pre_option filters are used only when a safe constant or earlier short-circuited value exists
add_filter( 'pre_option_home', 'force_https_pre_option_home', 10, 1 );
add_filter( 'pre_option_siteurl', 'force_https_pre_option_siteurl', 10, 1 );
// option filters cover normal database-backed installs without constants
add_filter( 'option_home', 'force_https_filter_core_url_option', 999 );
add_filter( 'option_siteurl', 'force_https_filter_core_url_option', 999 );
// enforce https by redirecting non-ssl requests on frontend, admin, and login pages
function force_https_redirect() {
// exit if already using https
if ( is_ssl() ) {
return;
}
// exit if headers are sent, running via cli, cron, ajax, or if no request uri exists
if ( headers_sent() || defined( 'WP_CLI' ) || defined( 'DOING_CRON' ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) || ! isset( $_SERVER['REQUEST_URI'] ) ) {
return;
}
// sanitize request uri before building redirect url
$request_uri = sanitize_url( wp_unslash( $_SERVER['REQUEST_URI'] ) );
// redirect to https version of the requested url
wp_safe_redirect( set_url_scheme( home_url( $request_uri ), 'https' ), 301 );
exit;
}
// apply https redirect during initialization, admin, and login
add_action( 'init', 'force_https_redirect', 10 );
add_action( 'admin_init', 'force_https_redirect', 10 );
add_action( 'login_init', 'force_https_redirect', 10 );
// enforce https for valid urls only
function force_https_securize_url( $value ) {
// return unchanged if not a string or does not start with http
if ( ! is_string( $value ) || stripos( $value, 'http://' ) !== 0 ) {
return $value;
}
// convert to https
return set_url_scheme( $value, 'https' );
}
// enforce https on nav menu links
function force_https_fix_nav_menu_link_attributes( $atts ) {
// return unchanged if attributes are not an array
if ( ! is_array( $atts ) ) {
return $atts;
}
// enforce https on href attribute only
if ( isset( $atts['href'] ) ) {
$atts['href'] = force_https_securize_url( $atts['href'] );
}
return $atts;
}
// apply https to urls used across wordpress
add_filter( 'admin_url', 'force_https_securize_url', 10 );
add_filter( 'attachment_link', 'force_https_securize_url', 10 );
add_filter( 'author_feed_link', 'force_https_securize_url', 10 );
add_filter( 'author_link', 'force_https_securize_url', 10 );
add_filter( 'category_feed_link', 'force_https_securize_url', 10 );
add_filter( 'category_link', 'force_https_securize_url', 10 );
add_filter( 'content_url', 'force_https_securize_url', 10 );
add_filter( 'day_link', 'force_https_securize_url', 10 );
add_filter( 'embed_oembed_html', 'force_https_filter_output', 10 );
add_filter( 'feed_link', 'force_https_securize_url', 10 );
add_filter( 'get_avatar_url', 'force_https_securize_url', 10 );
add_filter( 'get_custom_logo', 'force_https_filter_output', 10 );
add_filter( 'get_shortlink', 'force_https_securize_url', 10 );
add_filter( 'home_url', 'force_https_securize_url', 10 );
add_filter( 'includes_url', 'force_https_securize_url', 10 );
add_filter( 'login_redirect', 'force_https_securize_url', 10 );
add_filter( 'logout_redirect', 'force_https_securize_url', 10 );
add_filter( 'logout_url', 'force_https_securize_url', 10 );
add_filter( 'month_link', 'force_https_securize_url', 10 );
add_filter( 'nav_menu_link_attributes', 'force_https_fix_nav_menu_link_attributes', 10 );
add_filter( 'network_home_url', 'force_https_securize_url', 10 );
add_filter( 'network_site_url', 'force_https_securize_url', 10 );
add_filter( 'page_link', 'force_https_securize_url', 10 );
add_filter( 'plugins_url', 'force_https_securize_url', 10 );
add_filter( 'post_comments_feed_link', 'force_https_securize_url', 10 );
add_filter( 'post_link', 'force_https_securize_url', 10 );
add_filter( 'post_type_archive_link', 'force_https_securize_url', 10 );
add_filter( 'post_type_link', 'force_https_securize_url', 10 );
add_filter( 'rest_url', 'force_https_securize_url', 10 );
add_filter( 'script_loader_src', 'force_https_securize_url', 10 );
add_filter( 'search_link', 'force_https_securize_url', 10 );
add_filter( 'site_url', 'force_https_securize_url', 10 );
add_filter( 'style_loader_src', 'force_https_securize_url', 10 );
add_filter( 'stylesheet_directory_uri', 'force_https_securize_url', 10 );
add_filter( 'tag_link', 'force_https_securize_url', 10 );
add_filter( 'template_directory_uri', 'force_https_securize_url', 10 );
add_filter( 'term_link', 'force_https_securize_url', 10 );
add_filter( 'theme_file_uri', 'force_https_securize_url', 10 );
add_filter( 'theme_root_uri', 'force_https_securize_url', 10 );
add_filter( 'wp_get_attachment_url', 'force_https_securize_url', 10 );
add_filter( 'wp_redirect', 'force_https_securize_url', 999 );
add_filter( 'year_link', 'force_https_securize_url', 10 );
// register woocommerce filters after plugins are loaded
add_action( 'plugins_loaded', 'force_https_register_woocommerce_filters' );
function force_https_register_woocommerce_filters() {
// return if woocommerce is not active
if ( ! class_exists( 'WooCommerce' ) ) {
return;
}
// apply https to woocommerce urls and content
add_filter( 'woocommerce_get_endpoint_url', 'force_https_securize_url', 10 );
add_filter( 'woocommerce_email_footer_text', 'force_https_filter_output', 999 );
}
// enforce https on strings and nested arrays
function force_https_filter_value( $value ) {
// replace http with https in strings
if ( is_string( $value ) ) {
return str_replace( 'http://', 'https://', $value );
}
// recursively process arrays
if ( is_array( $value ) ) {
foreach ( $value as $key => $item ) {
$value[$key] = force_https_filter_value( $item );
}
}
return $value;
}
// enforce https on html content that may contain urls
function force_https_filter_output( $content ) {
// return unchanged if not a string
if ( ! is_string( $content ) ) {
return $content;
}
// replace http with https in text or html output
return force_https_filter_value( $content );
}
// enforce https on rest response object data before final output
function force_https_filter_rest_response_object( $response, $server, $request ) {
// return unchanged if response is not a wordpress http response object
if ( ! $response instanceof WP_HTTP_Response ) {
return $response;
}
// enforce https on response data only
$response->set_data( force_https_filter_value( $response->get_data() ) );
return $response;
}
// enforce https on rest response values
function force_https_filter_rest_response( $response ) {
return force_https_filter_value( $response );
}
// apply https enforcement to html content
add_filter( 'comment_text', 'force_https_filter_output', 20 );
add_filter( 'post_thumbnail_html', 'force_https_filter_output', 10 );
add_filter( 'render_block', 'force_https_filter_output', 20 );
add_filter( 'rest_post_dispatch', 'force_https_filter_rest_response_object', 999, 3 );
add_filter( 'rest_pre_echo_response', 'force_https_filter_rest_response', 999 );
add_filter( 'walker_nav_menu_start_el', 'force_https_filter_output', 10 );
add_filter( 'widget_text', 'force_https_filter_output', 20 );
add_filter( 'widget_text_content', 'force_https_filter_output', 20 );
// enforce https on elements and inline content
add_filter( 'the_content', 'force_https_process_content', 20 );
function force_https_process_content( $content ) {
// match elements with common url, media, and lazy-load attributes
static $element_pattern = '#(?i)(<(?:a|img|iframe|video|audio|source|form|link|embed|object|track|script|meta|input|button)\b[^>]*\s(?:href|src|srcset|poster|action|content|formaction|data-src|data-srcset)=["\'])([^"\']*)#';
// match script and style content
static $script_style_pattern = '#(<(?i:script|style)\b[^>]*>)(.*?)</(?i:script|style)>#s';
// replace http values in supported elements
$content = preg_replace_callback(
$element_pattern,
function ( $matches ) {
return $matches[1] . str_replace( 'http://', 'https://', $matches[2] );
},
$content
);
// replace http and escaped http in script and style blocks
return preg_replace_callback(
$script_style_pattern,
function ( $matches ) {
preg_match('/<\s*(script|style)/i', $matches[1], $tag_match);
return $matches[1] . str_replace(
['http://', 'http:\/\/'],
['https://', 'https:\/\/'],
$matches[2]
) . '</' . $tag_match[1] . '>';
},
$content
);
}
// enforce https on wp resource hints to prevent mixed content issues
add_filter( 'wp_resource_hints', 'force_https_fix_resource_hints', 20 );
function force_https_fix_resource_hints( $urls ) {
// return unchanged if not an array
if ( ! is_array( $urls ) ) {
return $urls;
}
// loop through each url and enforce https where needed
foreach ( $urls as $key => $url ) {
if ( is_string( $url ) ) {
$urls[$key] = force_https_securize_url( $url );
} elseif ( is_array( $url ) && isset( $url['href'] ) && is_string( $url['href'] ) ) {
$urls[$key]['href'] = force_https_securize_url( $url['href'] );
}
}
return $urls;
}
// enforce https on image srcsets to prevent mixed content issues
add_filter( 'wp_calculate_image_srcset', 'force_https_fix_image_srcsets', 999 );
function force_https_fix_image_srcsets( $sources ) {
// return unchanged if sources is not an array
if ( ! is_array( $sources ) ) {
return $sources;
}
// loop through each source and enforce https on urls
foreach ( $sources as $key => $source ) {
// check if url is set and enforce https
if ( isset( $source['url'] ) && is_string( $source['url'] ) ) {
$sources[$key]['url'] = force_https_securize_url( $source['url'] );
}
}
return $sources;
}
// enforce https on urls in the upload directory to avoid insecure media links
add_filter( 'upload_dir', 'force_https_fix_upload_dir', 999 );
function force_https_fix_upload_dir( $uploads ) {
// enforce https on the main upload url
if ( isset( $uploads['url'] ) && is_string( $uploads['url'] ) ) {
$uploads['url'] = force_https_securize_url( $uploads['url'] );
}
// enforce https on the base upload url
if ( isset( $uploads['baseurl'] ) && is_string( $uploads['baseurl'] ) ) {
$uploads['baseurl'] = force_https_securize_url( $uploads['baseurl'] );
}
return $uploads;
}