1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Critical CSS Core logic: |
4
|
|
|
* gets called by AO core, checks the rules and if a matching rule is found returns the associated CCSS. |
5
|
|
|
*/ |
6
|
|
|
|
7
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
8
|
|
|
exit; |
9
|
|
|
} |
10
|
|
|
|
11
|
|
|
class autoptimizeCriticalCSSCore { |
12
|
|
View Code Duplication |
public function __construct() |
|
|
|
|
13
|
|
|
{ |
14
|
|
|
// fetch all options at once and populate them individually explicitely as globals. |
15
|
|
|
$all_options = autoptimizeCriticalCSSBase::fetch_options(); |
16
|
|
|
foreach ( $all_options as $_option => $_value ) { |
17
|
|
|
global ${$_option}; |
18
|
|
|
${$_option} = $_value; |
19
|
|
|
} |
20
|
|
|
|
21
|
|
|
$this->run(); |
22
|
|
|
} |
23
|
|
|
|
24
|
|
|
public function run() { |
25
|
|
|
global $ao_css_defer; |
26
|
|
|
global $ao_ccss_deferjquery; |
27
|
|
|
global $ao_ccss_key; |
28
|
|
|
|
29
|
|
|
// add all filters to do CCSS if key present. |
30
|
|
|
if ( $ao_css_defer && isset( $ao_ccss_key ) && ! empty( $ao_ccss_key ) ) { |
31
|
|
|
// Set AO behavior: disable minification to avoid double minifying and caching. |
32
|
|
|
add_filter( 'autoptimize_filter_css_critcss_minify', '__return_false' ); |
33
|
|
|
add_filter( 'autoptimize_filter_css_defer_inline', array( $this, 'ao_ccss_frontend' ), 10, 1 ); |
34
|
|
|
|
35
|
|
|
// Add the action to enqueue jobs for CriticalCSS cron. |
36
|
|
|
add_action( 'autoptimize_action_css_hash', array( 'autoptimizeCriticalCSSEnqueue', 'ao_ccss_enqueue' ), 10, 1 ); |
37
|
|
|
|
38
|
|
|
// conditionally add the filter to defer jquery and others. |
39
|
|
|
if ( $ao_ccss_deferjquery ) { |
40
|
|
|
add_filter( 'autoptimize_html_after_minify', array( $this, 'ao_ccss_defer_jquery' ), 11, 1 ); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
// Order paths by length, as longest ones have greater priority in the rules. |
44
|
|
|
if ( ! empty( $ao_ccss_rules['paths'] ) ) { |
|
|
|
|
45
|
|
|
$keys = array_map( 'strlen', array_keys( $ao_ccss_rules['paths'] ) ); |
46
|
|
|
array_multisort( $keys, SORT_DESC, $ao_ccss_rules['paths'] ); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
// Add an array with default WordPress's conditional tags |
50
|
|
|
// NOTE: these tags are sorted. |
51
|
|
|
global $ao_ccss_types; |
52
|
|
|
$ao_ccss_types = $this->get_ao_ccss_core_types(); |
53
|
|
|
|
54
|
|
|
// Extend conditional tags on plugin initalization. |
55
|
|
|
add_action( apply_filters( 'autoptimize_filter_ccss_extend_types_hook', 'init' ), array( $this, 'ao_ccss_extend_types' ) ); |
56
|
|
|
} |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
public function ao_ccss_frontend( $inlined ) { |
60
|
|
|
// Apply CriticalCSS to frontend pages |
61
|
|
|
// Attach types and settings arrays. |
62
|
|
|
global $ao_ccss_types; |
63
|
|
|
global $ao_ccss_rules; |
64
|
|
|
global $ao_ccss_additional; |
65
|
|
|
global $ao_ccss_loggedin; |
66
|
|
|
global $ao_ccss_debug; |
67
|
|
|
global $ao_ccss_keyst; |
68
|
|
|
$no_ccss = ''; |
69
|
|
|
|
70
|
|
|
// Only if keystatus is OK and option to add CCSS for logged on users is on or user is not logged in. |
71
|
|
|
if ( ( $ao_ccss_keyst && 2 == $ao_ccss_keyst ) && ( $ao_ccss_loggedin || ! is_user_logged_in() ) ) { |
72
|
|
|
// Check for a valid CriticalCSS based on path to return its contents. |
73
|
|
|
$req_path = strtok( urldecode( $_SERVER['REQUEST_URI'] ), '?' ); |
74
|
|
|
if ( ! empty( $ao_ccss_rules['paths'] ) ) { |
75
|
|
|
foreach ( $ao_ccss_rules['paths'] as $path => $rule ) { |
76
|
|
|
// explicit match OR partial match if MANUAL rule. |
77
|
|
|
if ( $req_path == $path || ( false == $rule['hash'] && false != $rule['file'] && strpos( $req_path, str_replace( site_url(), '', $path ) ) !== false ) ) { |
78
|
|
|
if ( file_exists( AO_CCSS_DIR . $rule['file'] ) ) { |
79
|
|
|
$_ccss_contents = file_get_contents( AO_CCSS_DIR . $rule['file'] ); |
80
|
|
|
if ( 'none' != $_ccss_contents ) { |
81
|
|
|
if ( $ao_ccss_debug ) { |
82
|
|
|
$_ccss_contents = '/* PATH: ' . $path . ' hash: ' . $rule['hash'] . ' file: ' . $rule['file'] . ' */ ' . $_ccss_contents; |
83
|
|
|
} |
84
|
|
|
return apply_filters( 'autoptimize_filter_ccss_core_ccss', $_ccss_contents . $ao_ccss_additional ); |
85
|
|
|
} else { |
86
|
|
|
$no_ccss = 'none'; |
87
|
|
|
} |
88
|
|
|
} |
89
|
|
|
} |
90
|
|
|
} |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
// Check for a valid CriticalCSS based on conditional tags to return its contents. |
94
|
|
|
if ( ! empty( $ao_ccss_rules['types'] ) && 'none' !== $no_ccss ) { |
95
|
|
|
// order types-rules by the order of the original $ao_ccss_types array so as not to depend on the order in which rules were added. |
96
|
|
|
$ao_ccss_rules['types'] = array_replace( array_intersect_key( array_flip( $ao_ccss_types ), $ao_ccss_rules['types'] ), $ao_ccss_rules['types'] ); |
97
|
|
|
$is_front_page = is_front_page(); |
98
|
|
|
|
99
|
|
|
foreach ( $ao_ccss_rules['types'] as $type => $rule ) { |
100
|
|
|
if ( in_array( $type, $ao_ccss_types ) && file_exists( AO_CCSS_DIR . $rule['file'] ) ) { |
101
|
|
|
$_ccss_contents = file_get_contents( AO_CCSS_DIR . $rule['file'] ); |
102
|
|
|
if ( $is_front_page && 'is_front_page' == $type ) { |
103
|
|
|
if ( 'none' != $_ccss_contents ) { |
104
|
|
|
if ( $ao_ccss_debug ) { |
105
|
|
|
$_ccss_contents = '/* TYPES: ' . $type . ' hash: ' . $rule['hash'] . ' file: ' . $rule['file'] . ' */ ' . $_ccss_contents; |
106
|
|
|
} |
107
|
|
|
return apply_filters( 'autoptimize_filter_ccss_core_ccss', $_ccss_contents . $ao_ccss_additional ); |
108
|
|
|
} else { |
109
|
|
|
$no_ccss = 'none'; |
110
|
|
|
} |
111
|
|
|
} elseif ( strpos( $type, 'custom_post_' ) === 0 && ! $is_front_page ) { |
112
|
|
|
if ( get_post_type( get_the_ID() ) === substr( $type, 12 ) ) { |
113
|
|
|
if ( 'none' != $_ccss_contents ) { |
114
|
|
|
if ( $ao_ccss_debug ) { |
115
|
|
|
$_ccss_contents = '/* TYPES: ' . $type . ' hash: ' . $rule['hash'] . ' file: ' . $rule['file'] . ' */ ' . $_ccss_contents; |
116
|
|
|
} |
117
|
|
|
return apply_filters( 'autoptimize_filter_ccss_core_ccss', $_ccss_contents . $ao_ccss_additional ); |
118
|
|
|
} else { |
119
|
|
|
$no_ccss = 'none'; |
120
|
|
|
} |
121
|
|
|
} |
122
|
|
|
} elseif ( 0 === strpos( $type, 'template_' ) && ! $is_front_page ) { |
123
|
|
View Code Duplication |
if ( is_page_template( substr( $type, 9 ) ) ) { |
|
|
|
|
124
|
|
|
if ( 'none' != $_ccss_contents ) { |
125
|
|
|
if ( $ao_ccss_debug ) { |
126
|
|
|
$_ccss_contents = '/* TYPES: ' . $type . ' hash: ' . $rule['hash'] . ' file: ' . $rule['file'] . ' */ ' . $_ccss_contents; |
127
|
|
|
} |
128
|
|
|
return apply_filters( 'autoptimize_filter_ccss_core_ccss', $_ccss_contents . $ao_ccss_additional ); |
129
|
|
|
} else { |
130
|
|
|
$no_ccss = 'none'; |
131
|
|
|
} |
132
|
|
|
} |
133
|
|
|
} elseif ( ! $is_front_page ) { |
134
|
|
|
// all "normal" conditional tags, core + woo + buddypress + edd + bbpress |
135
|
|
|
// but we have to remove the prefix for the non-core ones for them to function. |
136
|
|
|
$type = str_replace( array( 'woo_', 'bp_', 'bbp_', 'edd_' ), '', $type ); |
137
|
|
View Code Duplication |
if ( function_exists( $type ) && call_user_func( $type ) ) { |
|
|
|
|
138
|
|
|
if ( 'none' != $_ccss_contents ) { |
139
|
|
|
if ( $ao_ccss_debug ) { |
140
|
|
|
$_ccss_contents = '/* TYPES: ' . $type . ' hash: ' . $rule['hash'] . ' file: ' . $rule['file'] . ' */ ' . $_ccss_contents; |
141
|
|
|
} |
142
|
|
|
return apply_filters( 'autoptimize_filter_ccss_core_ccss', $_ccss_contents . $ao_ccss_additional ); |
143
|
|
|
} else { |
144
|
|
|
$no_ccss = 'none'; |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
} |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
// Finally, inline the default CriticalCSS if any or else the entire CSS for the page |
154
|
|
|
// This also applies to logged in users if the option to add CCSS for logged in users has been disabled. |
155
|
|
|
if ( ! empty( $inlined ) && 'none' !== $no_ccss ) { |
156
|
|
|
return apply_filters( 'autoptimize_filter_ccss_core_ccss', $inlined . $ao_ccss_additional ); |
157
|
|
|
} else { |
158
|
|
|
add_filter( 'autoptimize_filter_css_inline', '__return_true' ); |
159
|
|
|
return; |
160
|
|
|
} |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
public function ao_ccss_defer_jquery( $in ) { |
164
|
|
|
// try to defer all JS (main goal being jquery.js as AO by default does not aggregate that). |
165
|
|
|
if ( ( ! is_user_logged_in() || $ao_ccss_loggedin ) && preg_match_all( '#<script.*>(.*)</script>#Usmi', $in, $matches, PREG_SET_ORDER ) ) { |
|
|
|
|
166
|
|
|
foreach ( $matches as $match ) { |
167
|
|
|
if ( ( ! preg_match( '/<script.* type\s?=.*>/', $match[0] ) || preg_match( '/type\s*=\s*[\'"]?(?:text|application)\/(?:javascript|ecmascript)[\'"]?/i', $match[0] ) ) && '' !== $match[1] && ( false !== strpos( $match[1], 'jQuery' ) || false !== strpos( $match[1], '$' ) ) ) { |
168
|
|
|
// inline js that requires jquery, wrap deferring JS around it to defer it. |
169
|
|
|
$new_match = 'var aoDeferInlineJQuery=function(){' . $match[1] . '}; if (document.readyState === "loading") {document.addEventListener("DOMContentLoaded", aoDeferInlineJQuery);} else {aoDeferInlineJQuery();}'; |
170
|
|
|
$in = str_replace( $match[1], $new_match, $in ); |
171
|
|
|
} elseif ( '' === $match[1] && false !== strpos( $match[0], 'src=' ) && false === strpos( $match[0], 'defer' ) ) { |
172
|
|
|
// linked non-aggregated JS, defer it. |
173
|
|
|
$new_match = str_replace( '<script ', '<script defer ', $match[0] ); |
174
|
|
|
$in = str_replace( $match[0], $new_match, $in ); |
175
|
|
|
} |
176
|
|
|
} |
177
|
|
|
} |
178
|
|
|
return $in; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
public function ao_ccss_extend_types() { |
182
|
|
|
// Extend contidional tags |
183
|
|
|
// Attach the conditional tags array. |
184
|
|
|
global $ao_ccss_types; |
185
|
|
|
|
186
|
|
|
// in some cases $ao_ccss_types is empty and/or not an array, this should work around that problem. |
187
|
|
|
if ( empty( $ao_ccss_types ) || ! is_array( $ao_ccss_types ) ) { |
188
|
|
|
$ao_ccss_types = get_ao_ccss_core_types(); |
189
|
|
|
autoptimizeCriticalCSSCore::ao_ccss_log( 'Empty types array in extend, refetching array with core conditionals.', 3 ); |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
// Custom Post Types. |
193
|
|
|
$cpts = get_post_types( |
194
|
|
|
array( |
195
|
|
|
'public' => true, |
196
|
|
|
'_builtin' => false, |
197
|
|
|
), |
198
|
|
|
'names', |
199
|
|
|
'and' |
200
|
|
|
); |
201
|
|
|
foreach ( $cpts as $cpt ) { |
202
|
|
|
array_unshift( $ao_ccss_types, 'custom_post_' . $cpt ); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
// Templates. |
206
|
|
|
$templates = wp_get_theme()->get_page_templates(); |
207
|
|
|
foreach ( $templates as $tplfile => $tplname ) { |
208
|
|
|
array_unshift( $ao_ccss_types, 'template_' . $tplfile ); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
// bbPress tags. |
212
|
|
|
if ( function_exists( 'is_bbpress' ) ) { |
213
|
|
|
$ao_ccss_types = array_merge( |
214
|
|
|
array( |
215
|
|
|
'bbp_is_bbpress', |
216
|
|
|
'bbp_is_favorites', |
217
|
|
|
'bbp_is_forum_archive', |
218
|
|
|
'bbp_is_replies_created', |
219
|
|
|
'bbp_is_reply_edit', |
220
|
|
|
'bbp_is_reply_move', |
221
|
|
|
'bbp_is_search', |
222
|
|
|
'bbp_is_search_results', |
223
|
|
|
'bbp_is_single_forum', |
224
|
|
|
'bbp_is_single_reply', |
225
|
|
|
'bbp_is_single_topic', |
226
|
|
|
'bbp_is_single_user', |
227
|
|
|
'bbp_is_single_user_edit', |
228
|
|
|
'bbp_is_single_view', |
229
|
|
|
'bbp_is_subscriptions', |
230
|
|
|
'bbp_is_topic_archive', |
231
|
|
|
'bbp_is_topic_edit', |
232
|
|
|
'bbp_is_topic_merge', |
233
|
|
|
'bbp_is_topic_split', |
234
|
|
|
'bbp_is_topic_tag', |
235
|
|
|
'bbp_is_topic_tag_edit', |
236
|
|
|
'bbp_is_topics_created', |
237
|
|
|
'bbp_is_user_home', |
238
|
|
|
'bbp_is_user_home_edit', |
239
|
|
|
), $ao_ccss_types |
240
|
|
|
); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
// BuddyPress tags. |
244
|
|
|
if ( function_exists( 'is_buddypress' ) ) { |
245
|
|
|
$ao_ccss_types = array_merge( |
246
|
|
|
array( |
247
|
|
|
'bp_is_activation_page', |
248
|
|
|
'bp_is_activity', |
249
|
|
|
'bp_is_blogs', |
250
|
|
|
'bp_is_buddypress', |
251
|
|
|
'bp_is_change_avatar', |
252
|
|
|
'bp_is_create_blog', |
253
|
|
|
'bp_is_friend_requests', |
254
|
|
|
'bp_is_friends', |
255
|
|
|
'bp_is_friends_activity', |
256
|
|
|
'bp_is_friends_screen', |
257
|
|
|
'bp_is_group_admin_page', |
258
|
|
|
'bp_is_group_create', |
259
|
|
|
'bp_is_group_forum', |
260
|
|
|
'bp_is_group_forum_topic', |
261
|
|
|
'bp_is_group_home', |
262
|
|
|
'bp_is_group_invites', |
263
|
|
|
'bp_is_group_leave', |
264
|
|
|
'bp_is_group_members', |
265
|
|
|
'bp_is_group_single', |
266
|
|
|
'bp_is_groups', |
267
|
|
|
'bp_is_messages', |
268
|
|
|
'bp_is_messages_compose_screen', |
269
|
|
|
'bp_is_messages_conversation', |
270
|
|
|
'bp_is_messages_inbox', |
271
|
|
|
'bp_is_messages_sentbox', |
272
|
|
|
'bp_is_my_activity', |
273
|
|
|
'bp_is_my_blogs', |
274
|
|
|
'bp_is_notices', |
275
|
|
|
'bp_is_profile_edit', |
276
|
|
|
'bp_is_register_page', |
277
|
|
|
'bp_is_settings_component', |
278
|
|
|
'bp_is_user', |
279
|
|
|
'bp_is_user_profile', |
280
|
|
|
'bp_is_wire', |
281
|
|
|
), $ao_ccss_types |
282
|
|
|
); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
// Easy Digital Downloads (EDD) tags. |
286
|
|
|
if ( function_exists( 'edd_is_checkout' ) ) { |
287
|
|
|
$ao_ccss_types = array_merge( |
288
|
|
|
array( |
289
|
|
|
'edd_is_checkout', |
290
|
|
|
'edd_is_failed_transaction_page', |
291
|
|
|
'edd_is_purchase_history_page', |
292
|
|
|
'edd_is_success_page', |
293
|
|
|
), $ao_ccss_types |
294
|
|
|
); |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
// WooCommerce tags. |
298
|
|
|
if ( class_exists( 'WooCommerce' ) ) { |
299
|
|
|
$ao_ccss_types = array_merge( |
300
|
|
|
array( |
301
|
|
|
'woo_is_account_page', |
302
|
|
|
'woo_is_cart', |
303
|
|
|
'woo_is_checkout', |
304
|
|
|
'woo_is_product', |
305
|
|
|
'woo_is_product_category', |
306
|
|
|
'woo_is_product_tag', |
307
|
|
|
'woo_is_shop', |
308
|
|
|
'woo_is_wc_endpoint_url', |
309
|
|
|
'woo_is_woocommerce', |
310
|
|
|
), $ao_ccss_types |
311
|
|
|
); |
312
|
|
|
} |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
public function get_ao_ccss_core_types() { |
316
|
|
|
global $ao_ccss_types; |
317
|
|
|
if ( empty( $ao_ccss_types ) || ! is_array( $ao_ccss_types ) ) { |
318
|
|
|
return array( |
319
|
|
|
'is_404', |
320
|
|
|
'is_archive', |
321
|
|
|
'is_author', |
322
|
|
|
'is_category', |
323
|
|
|
'is_front_page', |
324
|
|
|
'is_home', |
325
|
|
|
'is_page', |
326
|
|
|
'is_post', |
327
|
|
|
'is_search', |
328
|
|
|
'is_attachment', |
329
|
|
|
'is_single', |
330
|
|
|
'is_sticky', |
331
|
|
|
'is_paged', |
332
|
|
|
); |
333
|
|
|
} else { |
334
|
|
|
return $ao_ccss_types; |
335
|
|
|
} |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
public static function ao_ccss_key_status( $render ) { |
339
|
|
|
// Provide key status |
340
|
|
|
// Get key and key status. |
341
|
|
|
global $ao_ccss_key; |
342
|
|
|
global $ao_ccss_keyst; |
343
|
|
|
$self = new self(); |
344
|
|
|
$key = $ao_ccss_key; |
345
|
|
|
$key_status = $ao_ccss_keyst; |
346
|
|
|
|
347
|
|
|
// Prepare returned variables. |
348
|
|
|
$key_return = array(); |
349
|
|
|
$status = false; |
|
|
|
|
350
|
|
|
|
351
|
|
|
if ( $key && 2 == $key_status ) { |
352
|
|
|
// Key exists and its status is valid. |
353
|
|
|
// Set valid key status. |
354
|
|
|
$status = 'valid'; |
355
|
|
|
$status_msg = __( 'Valid' ); |
356
|
|
|
$color = '#46b450'; // Green. |
357
|
|
|
$message = null; |
358
|
|
View Code Duplication |
} elseif ( $key && 1 == $key_status ) { |
|
|
|
|
359
|
|
|
// Key exists but its validation has failed. |
360
|
|
|
// Set invalid key status. |
361
|
|
|
$status = 'invalid'; |
362
|
|
|
$status_msg = __( 'Invalid' ); |
363
|
|
|
$color = '#dc3232'; // Red. |
364
|
|
|
$message = __( 'Your API key is invalid. Please enter a valid <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> key.', 'autoptimize' ); |
365
|
|
|
} elseif ( $key && ! $key_status ) { |
366
|
|
|
// Key exists but it has no valid status yet |
367
|
|
|
// Perform key validation. |
368
|
|
|
$key_check = $self->ao_ccss_key_validation( $key ); |
369
|
|
|
|
370
|
|
|
// Key is valid, set valid status. |
371
|
|
|
if ( $key_check ) { |
372
|
|
|
$status = 'valid'; |
373
|
|
|
$status_msg = __( 'Valid' ); |
374
|
|
|
$color = '#46b450'; // Green. |
375
|
|
|
$message = null; |
376
|
|
|
} else { |
377
|
|
|
// Key is invalid, set invalid status. |
378
|
|
|
$status = 'invalid'; |
379
|
|
|
$status_msg = __( 'Invalid' ); |
380
|
|
|
$color = '#dc3232'; // Red. |
381
|
|
|
if ( get_option( 'autoptimize_ccss_keyst' ) == 1 ) { |
382
|
|
|
$message = __( 'Your API key is invalid. Please enter a valid <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> key.', 'autoptimize' ); |
383
|
|
|
} else { |
384
|
|
|
$message = __( 'Something went wrong when checking your API key, make sure you server can communicate with https://criticalcss.com and/ or try again later.', 'autoptimize' ); |
385
|
|
|
} |
386
|
|
|
} |
387
|
|
View Code Duplication |
} else { |
|
|
|
|
388
|
|
|
// No key nor status |
389
|
|
|
// Set no key status. |
390
|
|
|
$status = 'nokey'; |
391
|
|
|
$status_msg = __( 'None' ); |
392
|
|
|
$color = '#ffb900'; // Yellow. |
393
|
|
|
$message = __( 'Please enter a valid <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> API key to start.', 'autoptimize' ); |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
// Fill returned values. |
397
|
|
|
$key_return['status'] = $status; |
398
|
|
|
// Provide rendering information if required. |
399
|
|
|
if ( $render ) { |
400
|
|
|
$key_return['stmsg'] = $status_msg; |
401
|
|
|
$key_return['color'] = $color; |
402
|
|
|
$key_return['msg'] = $message; |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
// Return key status. |
406
|
|
|
return $key_return; |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
public function ao_ccss_key_validation( $key ) { |
410
|
|
|
// POST a dummy job to criticalcss.com to check for key validation |
411
|
|
|
// Prepare home URL for the request. |
412
|
|
|
$src_url = get_home_url(); |
413
|
|
|
$src_url = apply_filters( 'autoptimize_filter_ccss_cron_srcurl', $src_url ); |
414
|
|
|
|
415
|
|
|
// Prepare the request. |
416
|
|
|
$url = esc_url_raw( AO_CCSS_API . 'generate' ); |
417
|
|
|
$args = array( |
418
|
|
|
'headers' => array( |
419
|
|
|
'User-Agent' => 'Autoptimize CriticalCSS Power-Up v' . AO_CCSS_VER, |
420
|
|
|
'Content-type' => 'application/json; charset=utf-8', |
421
|
|
|
'Authorization' => 'JWT ' . $key, |
422
|
|
|
'Connection' => 'close', |
423
|
|
|
), |
424
|
|
|
// Body must be JSON. |
425
|
|
|
'body' => json_encode( |
426
|
|
|
array( |
427
|
|
|
'url' => $src_url, |
428
|
|
|
'aff' => 1, |
429
|
|
|
'aocssv' => AO_CCSS_VER, |
430
|
|
|
) |
431
|
|
|
), |
432
|
|
|
); |
433
|
|
|
|
434
|
|
|
// Dispatch the request and store its response code. |
435
|
|
|
$req = wp_safe_remote_post( $url, $args ); |
436
|
|
|
$code = wp_remote_retrieve_response_code( $req ); |
437
|
|
|
$body = json_decode( wp_remote_retrieve_body( $req ), true ); |
438
|
|
|
|
439
|
|
|
if ( 200 == $code ) { |
440
|
|
|
// Response is OK. |
441
|
|
|
// Set key status as valid and log key check. |
442
|
|
|
update_option( 'autoptimize_ccss_keyst', 2 ); |
443
|
|
|
autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: API key is valid, updating key status', 3 ); |
444
|
|
|
|
445
|
|
|
// extract job-id from $body and put it in the queue as a P job |
446
|
|
|
// but only if no jobs and no rules! |
447
|
|
|
global $ao_ccss_queue; |
448
|
|
|
global $ao_ccss_rules; |
449
|
|
|
|
450
|
|
|
if ( 0 == count( $ao_ccss_queue ) && 0 == count( $ao_ccss_rules['types'] ) && 0 == count( $ao_ccss_rules['paths'] ) ) { |
451
|
|
|
if ( 'JOB_QUEUED' == $body['job']['status'] || 'JOB_ONGOING' == $body['job']['status'] ) { |
452
|
|
|
$jprops['ljid'] = 'firstrun'; |
|
|
|
|
453
|
|
|
$jprops['rtarget'] = 'types|is_front_page'; |
454
|
|
|
$jprops['ptype'] = 'is_front_page'; |
455
|
|
|
$jprops['hashes'][] = 'dummyhash'; |
456
|
|
|
$jprops['hash'] = 'dummyhash'; |
457
|
|
|
$jprops['file'] = null; |
458
|
|
|
$jprops['jid'] = $body['job']['id']; |
459
|
|
|
$jprops['jqstat'] = $body['job']['status']; |
460
|
|
|
$jprops['jrstat'] = null; |
461
|
|
|
$jprops['jvstat'] = null; |
462
|
|
|
$jprops['jctime'] = microtime( true ); |
463
|
|
|
$jprops['jftime'] = null; |
464
|
|
|
$ao_ccss_queue['/'] = $jprops; |
465
|
|
|
$ao_ccss_queue_raw = json_encode( $ao_ccss_queue ); |
466
|
|
|
update_option( 'autoptimize_ccss_queue', $ao_ccss_queue_raw, false ); |
467
|
|
|
autoptimizeCriticalCSSCore::ao_ccss_log( 'Created P job for is_front_page based on API key check response.', 3 ); |
468
|
|
|
} |
469
|
|
|
} |
470
|
|
|
return true; |
471
|
|
|
} elseif ( 401 == $code ) { |
472
|
|
|
// Response is unauthorized |
473
|
|
|
// Set key status as invalid and log key check. |
474
|
|
|
update_option( 'autoptimize_ccss_keyst', 1 ); |
475
|
|
|
autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: API key is invalid, updating key status', 3 ); |
476
|
|
|
return false; |
477
|
|
|
} else { |
478
|
|
|
// Response unkown |
479
|
|
|
// Log key check attempt. |
480
|
|
|
autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: could not check API key status, this is a service error, body follows if any...', 2 ); |
481
|
|
|
if ( ! empty( $body ) ) { |
482
|
|
|
autoptimizeCriticalCSSCore::ao_ccss_log( print_r( $body, true ), 2 ); |
483
|
|
|
} |
484
|
|
|
if ( is_wp_error( $req ) ) { |
485
|
|
|
autoptimizeCriticalCSSCore::ao_ccss_log( $req->get_error_message(), 2 ); |
486
|
|
|
} |
487
|
|
|
return false; |
488
|
|
|
} |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
public static function ao_ccss_viewport() { |
492
|
|
|
// Get viewport size |
493
|
|
|
// Attach viewport option. |
494
|
|
|
global $ao_ccss_viewport; |
495
|
|
|
|
496
|
|
|
// Prepare viewport array. |
497
|
|
|
$viewport = array(); |
498
|
|
|
|
499
|
|
|
// Viewport Width. |
500
|
|
|
if ( ! empty( $ao_ccss_viewport['w'] ) ) { |
501
|
|
|
$viewport['w'] = $ao_ccss_viewport['w']; |
502
|
|
|
} else { |
503
|
|
|
$viewport['w'] = ''; |
504
|
|
|
} |
505
|
|
|
|
506
|
|
|
// Viewport Height. |
507
|
|
|
if ( ! empty( $ao_ccss_viewport['h'] ) ) { |
508
|
|
|
$viewport['h'] = $ao_ccss_viewport['h']; |
509
|
|
|
} else { |
510
|
|
|
$viewport['h'] = ''; |
511
|
|
|
} |
512
|
|
|
|
513
|
|
|
return $viewport; |
514
|
|
|
} |
515
|
|
|
|
516
|
|
|
public static function ao_ccss_check_contents( $ccss ) { |
517
|
|
|
// Perform basic exploit avoidance and CSS validation. |
518
|
|
|
if ( ! empty( $ccss ) ) { |
519
|
|
|
// Try to avoid code injection. |
520
|
|
|
$blacklist = array( '#!/', 'function(', '<script', '<?php' ); |
521
|
|
|
foreach ( $blacklist as $blacklisted ) { |
522
|
|
|
if ( strpos( $ccss, $blacklisted ) !== false ) { |
523
|
|
|
autoptimizeCriticalCSSCore::ao_ccss_log( 'Critical CSS received contained blacklisted content.', 2 ); |
524
|
|
|
return false; |
525
|
|
|
} |
526
|
|
|
} |
527
|
|
|
|
528
|
|
|
// Check for most basics CSS structures. |
529
|
|
|
$pinklist = array( '{', '}', ':' ); |
530
|
|
|
foreach ( $pinklist as $needed ) { |
531
|
|
|
if ( false === strpos( $ccss, $needed ) && 'none' !== $ccss ) { |
532
|
|
|
autoptimizeCriticalCSSCore::ao_ccss_log( 'Critical CSS received did not seem to contain real CSS.', 2 ); |
533
|
|
|
return false; |
534
|
|
|
} |
535
|
|
|
} |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
// Return true if file critical CSS is sane. |
539
|
|
|
return true; |
540
|
|
|
} |
541
|
|
|
|
542
|
|
|
public static function ao_ccss_log( $msg, $lvl ) { |
543
|
|
|
// Commom logging facility |
544
|
|
|
// Attach debug option. |
545
|
|
|
global $ao_ccss_debug; |
546
|
|
|
|
547
|
|
|
// Prepare log levels, where accepted $lvl are: |
548
|
|
|
// 1: II (for info) |
549
|
|
|
// 2: EE (for error) |
550
|
|
|
// 3: DD (for debug) |
551
|
|
|
// Default: UU (for unkown). |
552
|
|
|
$level = false; |
553
|
|
|
switch ( $lvl ) { |
554
|
|
|
case 1: |
555
|
|
|
$level = 'II'; |
556
|
|
|
break; |
557
|
|
|
case 2: |
558
|
|
|
$level = 'EE'; |
559
|
|
|
break; |
560
|
|
|
case 3: |
561
|
|
|
// Output debug messages only if debug mode is enabled. |
562
|
|
|
if ( $ao_ccss_debug ) { |
563
|
|
|
$level = 'DD'; |
564
|
|
|
} |
565
|
|
|
break; |
566
|
|
|
default: |
567
|
|
|
$level = 'UU'; |
568
|
|
|
} |
569
|
|
|
|
570
|
|
|
// Prepare and write a log message if there's a valid level. |
571
|
|
|
if ( $level ) { |
|
|
|
|
572
|
|
|
|
573
|
|
|
// Prepare message. |
574
|
|
|
$message = date( 'c' ) . ' - [' . $level . '] ' . htmlentities( $msg ) . '<br>'; |
575
|
|
|
|
576
|
|
|
// Write message to log file. |
577
|
|
|
error_log( $message, 3, AO_CCSS_LOG ); |
578
|
|
|
} |
579
|
|
|
} |
580
|
|
|
} |
581
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.