PluginProbe
Autoptimize / 3.1.1
Autoptimize v3.1.1
2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 All 107 releases
autoptimize / classes / autoptimizeCriticalCSSSettings.php

autoptimizeCriticalCSSSettings.php in Autoptimize 3.1.1, at classes/autoptimizeCriticalCSSSettings.php

428 lines 22.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Critical CSS Options page.
4 */
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit;
8 }
9
10 class autoptimizeCriticalCSSSettings {
11 /**
12 * Options.
13 *
14 * @var bool
15 */
16 private $settings_screen_do_remote_http = true;
17
18 public function __construct() {
19 $this->criticalcss = autoptimize()->criticalcss();
20 $this->settings_screen_do_remote_http = apply_filters( 'autoptimize_settingsscreen_remotehttp', $this->settings_screen_do_remote_http );
21 $this->run();
22 }
23
24 protected function enabled()
25 {
26 return apply_filters( 'autoptimize_filter_show_criticalcss_tabs', true );
27 }
28
29 public function run()
30 {
31 if ( $this->enabled() ) {
32 add_filter( 'autoptimize_filter_settingsscreen_tabs', array( $this, 'add_critcss_tabs' ), 10, 1 );
33 add_action( 'admin_enqueue_scripts', array( $this, 'admin_assets' ) );
34
35 if ( $this->is_multisite_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network() ) {
36 add_action( 'network_admin_menu', array( $this, 'add_critcss_admin_menu' ) );
37 } else {
38 add_action( 'admin_menu', array( $this, 'add_critcss_admin_menu' ) );
39 }
40
41 $criticalcss_ajax = new autoptimizeCriticalCSSSettingsAjax();
42
43 // if debug logging is off but the file is present, then remove the debug log file.
44 if ( empty( $this->criticalcss->get_option( 'debug' ) ) && file_exists( AO_CCSS_LOG ) ) {
45 unlink( AO_CCSS_LOG );
46 }
47 }
48 }
49
50 public function add_critcss_tabs( $in )
51 {
52 $in = array_merge( $in, array( 'ao_critcss' => 'âš¡ ' . __( 'Critical CSS', 'autoptimize' ) ) );
53
54 return $in;
55 }
56
57 public function add_critcss_admin_menu()
58 {
59 // Register settings.
60 register_setting( 'ao_ccss_options_group', 'autoptimize_css_defer_inline' );
61 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_rules' );
62 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_additional' );
63 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_queue' );
64 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_viewport' );
65 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_finclude' );
66 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_rtimelimit' );
67 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_noptimize' );
68 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_debug' );
69 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_key' );
70 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_keyst' );
71 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_loggedin' );
72 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_forcepath' );
73 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_deferjquery' );
74 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_domain' );
75 register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_unloadccss' );
76
77 // And add submenu-page.
78 add_submenu_page( '', 'Critical CSS', 'Critical CSS', 'manage_options', 'ao_critcss', array( $this, 'ao_criticalcsssettings_page' ) );
79 }
80
81 public function admin_assets( $hook ) {
82 // Return if plugin is not hooked.
83 if ( 'settings_page_ao_critcss' != $hook && 'admin_page_ao_critcss' != $hook ) {
84 return;
85 }
86
87 // Stylesheets to add.
88 wp_enqueue_style( 'wp-jquery-ui-dialog' );
89 wp_enqueue_style( 'ao-tablesorter', plugins_url( 'critcss-inc/css/ao-tablesorter/style.css', __FILE__ ) );
90 wp_enqueue_style( 'ao-ccss-admin-css', plugins_url( 'critcss-inc/css/admin_styles.css', __FILE__ ) );
91
92 // Scripts to add.
93 wp_enqueue_script( 'jquery-ui-dialog', array( 'jquery' ) );
94 wp_enqueue_script( 'md5', plugins_url( 'critcss-inc/js/md5.min.js', __FILE__ ), null, null, true );
95 wp_enqueue_script( 'tablesorter', plugins_url( 'critcss-inc/js/jquery.tablesorter.min.js', __FILE__ ), array( 'jquery' ), null, true );
96 wp_enqueue_script( 'ao-ccss-admin-license', plugins_url( 'critcss-inc/js/admin_settings.js', __FILE__ ), array( 'jquery' ), null, true );
97 }
98
99 public function ao_criticalcsssettings_page()
100 {
101 // these are not OO yet, simply require for now.
102 require_once( 'critcss-inc/admin_settings_rules.php' );
103 require_once( 'critcss-inc/admin_settings_queue.php' );
104 require_once( 'critcss-inc/admin_settings_key.php' );
105 require_once( 'critcss-inc/admin_settings_adv.php' );
106 require_once( 'critcss-inc/admin_settings_explain.php' );
107
108 $ao_ccss_key = $this->criticalcss->get_option( 'key' );
109 $ao_ccss_keyst = $this->criticalcss->get_option( 'keyst' );
110 $ao_css_defer = $this->criticalcss->get_option( 'css_defer' );
111 $ao_ccss_deferjquery = $this->criticalcss->get_option( 'deferjquery' );
112 $ao_ccss_queue = $this->criticalcss->get_option( 'queue' );
113 $ao_ccss_rules = $this->criticalcss->get_option( 'rules' );
114 $ao_ccss_servicestatus = $this->criticalcss->get_option( 'servicestatus' );
115 $ao_ccss_finclude = $this->criticalcss->get_option( 'finclude' );
116 $ao_ccss_rtimelimit = $this->criticalcss->get_option( 'rtimelimit' );
117 $ao_ccss_debug = $this->criticalcss->get_option( 'debug' );
118 $ao_ccss_noptimize = $this->criticalcss->get_option( 'noptimize' );
119 $ao_css_defer_inline = $this->criticalcss->get_option( 'css_defer_inline' );
120 $ao_ccss_loggedin = $this->criticalcss->get_option( 'loggedin' );
121 $ao_ccss_forcepath = $this->criticalcss->get_option( 'forcepath' );
122 $ao_ccss_domain = $this->criticalcss->get_option( 'domain' );
123 ?>
124 <script>document.title = "Autoptimize: <?php _e( 'Critical CSS', 'autoptimize' ); ?> " + document.title;</script>
125 <div class="wrap">
126 <div id="autoptimize_main">
127 <div id="ao_title_and_button">
128 <h1><?php apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? _e( 'Autoptimize Pro Settings', 'autoptimize' ) : _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
129 </div>
130
131 <?php
132 // Print AO settings tabs.
133 echo autoptimizeConfig::ao_admin_tabs();
134
135 $mkdirresult = $this->criticalcss->create_ao_ccss_dir();
136
137 // Warn if we could not create those files.
138 if ( ( true !== $mkdirresult ) ) {
139 ?>
140 <div class="notice-error notice"><p>
141 <?php
142 _e( 'Could not create the required directory. Make sure the webserver can write to the wp-content/uploads directory.', 'autoptimize' );
143 ?>
144 </p></div>
145 <?php
146 }
147
148 // Check if CSS optimization is on.
149 if ( 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_css' ) || 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer' ) ) {
150 ?>
151 <div class="notice-info notice"><p>
152 <?php
153 _e( 'To be able to use Critical CSS you will have to enable CSS optimization and make sure "eliminate render-blocking CSS" is active on the main Autoptimize settings page.', 'autoptimize' );
154 ?>
155 </p></div>
156 <?php
157 }
158
159 // Check for "inline & defer CSS" being active in Autoptimize.
160 if ( ! empty( $ao_ccss_key ) && ! $ao_css_defer && empty( $ao_ccss_keyst ) ) {
161 // no keystate so likely in activation-process of CCSS, let's enable "inline & defer CSS" immediately to make things easier!
162 autoptimizeOptionWrapper::update_option( 'autoptimize_css_defer', 'on' );
163 ?>
164 <div class="notice-info notice"><p>
165 <?php
166 _e( 'The "Eliminate render-blocking CSS" option was activated to allow critical CSS to be used.', 'autoptimize' );
167 ?>
168 </p></div>
169 <?php
170 }
171
172 // check if WordPress cron is disabled and warn if so.
173 if ( ! empty( $ao_ccss_key ) && defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON && PAnD::is_admin_notice_active( 'i-know-about-disable-cron-forever' ) ) {
174 ?>
175 <div data-dismissible="i-know-about-disable-cron-forever" class="notice-warning notice is-dismissible"><p>
176 <?php
177 _e( 'WordPress cron (for task scheduling) seems to be disabled. Have a look at <a href="https://wordpress.org/plugins/autoptimize-criticalcss/faq/" target="_blank">the FAQ</a> or the info in the Job Queue instructions if all jobs remain in "N" status and no rules are created.', 'autoptimize' );
178 ?>
179 </p></div>
180 <?php
181 }
182
183 // check if defer jQuery is active and warn if so.
184 if ( 1 == $ao_ccss_deferjquery && PAnD::is_admin_notice_active( 'i-know-about-defer-inline-forever' ) ) {
185 ?>
186 <div data-dismissible="i-know-about-defer-inline-forever" class="notice-warning notice is-dismissible"><p>
187 <?php
188 _e( 'You have "defer jQuery and other non-aggregated JS-files" active (under Advanced Settings), but that functionality is deprecated and will be removed in the next major version of Autoptimize. Consider using the new "Do not aggregate but defer" and "Also defer inline JS" options on the main settings page instead.', 'autoptimize' );
189 ?>
190 </p></div>
191 <?php
192 }
193
194 // warn if it looks as though the queue processing job looks isn't running
195 // but store result in transient as to not to have to go through 2 arrays each and every time.
196 $_warn_cron = get_transient( 'ao_ccss_cronwarning' );
197 if ( ! empty( $ao_ccss_key ) && false === $_warn_cron ) {
198 $_jobs_all_new = true;
199 $_oldest_job_timestamp = microtime( true ); // now.
200 $_jobs_too_old = true;
201
202 // go over queue array.
203 if ( empty( $ao_ccss_queue ) ) {
204 // no jobs, then no warning.
205 $_jobs_all_new = false;
206 } else {
207 foreach ( $ao_ccss_queue as $job ) {
208 if ( $job['jctime'] < $_oldest_job_timestamp ) {
209 // we need to catch the oldest job's timestamp.
210 $_oldest_job_timestamp = $job['jctime'];
211 }
212
213 if ( 'NEW' !== $job['jqstat'] && 'firstrun' !== $job['ljid'] ) {
214 // we have a non-"NEW" job which is not our pending firstrun job either, break the loop.
215 $_jobs_all_new = false;
216 break;
217 }
218 }
219 }
220
221 // is the oldest job too old (4h)?
222 if ( $_oldest_job_timestamp > microtime( true ) - 60 * 60 * 4 ) {
223 $_jobs_too_old = false;
224 }
225
226 if ( $_jobs_all_new && ! $this->ao_ccss_has_autorules() && $_jobs_too_old ) {
227 $_warn_cron = 'on';
228 $_transient_multiplier = 1; // store for 1 hour.
229 } else {
230 $_warn_cron = 'off';
231 $_transient_multiplier = 4; // store for 4 hours.
232 }
233 // and set transient.
234 set_transient( 'ao_ccss_cronwarning', $_warn_cron, $_transient_multiplier * HOUR_IN_SECONDS );
235 }
236
237 if ( ! empty( $ao_ccss_key ) && 'on' == $_warn_cron && PAnD::is_admin_notice_active( 'i-know-about-cron-1' ) ) {
238 ?>
239 <div data-dismissible="i-know-about-cron-1" class="notice-warning notice is-dismissible"><p>
240 <?php
241 _e( 'It looks like there might be a problem with WordPress cron (task scheduling). Have a look at <a href="https://wordpress.org/plugins/autoptimize-criticalcss/faq/" target="_blank">the FAQ</a> or the info in the Job Queue instructions if all jobs remain in "N" status and no rules are created.', 'autoptimize' );
242 ?>
243 </p></div>
244 <?php
245 } elseif ( ! empty( $ao_ccss_key ) && '2' == $ao_ccss_keyst && 'on' != $_warn_cron && ! $this->ao_ccss_has_autorules() ) {
246 ?>
247 <div class="notice-success notice"><p>
248 <?php
249 _e( 'Great, Autoptimize will now automatically start creating new critical CSS rules, you should see those appearing below in the next couple of hours.', 'autoptimize' );
250 echo ' ';
251 _e( 'In the meantime you might want to <strong>edit default rule CSS now</strong>, to avoid all CSS being inlined when no (applicable) rules are found.', 'autoptimize' );
252 ?>
253 </p></div>
254 <?php
255 }
256
257 // warn if service is down.
258 if ( ! empty( $ao_ccss_key ) && ! empty( $ao_ccss_servicestatus ) && is_array( $ao_ccss_servicestatus ) && 'down' === $ao_ccss_servicestatus['critcss']['status'] ) {
259 ?>
260 <div class="notice-warning notice"><p>
261 <?php
262 _e( 'The critical CSS service has been reported to be down. Although no new rules will be created for now, this does not prevent existing rules from being applied.', 'autoptimize' );
263 ?>
264 </p></div>
265 <?php
266 }
267
268 // warn if too many rules (based on length of ao_ccss_rules option) as that might cause issues at e.g. wpengine
269 // see https://wpengine.com/support/database-optimization-best-practices/#Autoloaded_Data .
270 $_raw_rules_length = strlen( get_option( 'autoptimize_ccss_rules', '' ) );
271 if ( $_raw_rules_length > apply_filters( 'autoptimize_ccss_rules_length_warning', 500000 ) ) {
272 ?>
273 <div class="notice-warning notice"><p>
274 <?php
275 _e( 'It looks like the amount of Critical CSS rules is very high, it is recommended to reconfigure Autoptimize (e.g. by manually creating broader rules) to ensure less rules are created.', 'autoptimize' );
276 ?>
277 </p></div>
278 <?php
279 }
280
281 // Settings Form.
282 ?>
283 <form id="settings" method="post" action="options.php">
284 <?php
285 settings_fields( 'ao_ccss_options_group' );
286
287 // Get API key status.
288 $key = $this->criticalcss->key_status( true );
289
290 if ( $this->is_multisite_network_admin() ) {
291 ?>
292 <ul id="key-panel">
293 <li class="itemDetail">
294 <?php
295 // translators: the placesholder is for a line of code in wp-config.php.
296 echo sprintf( __( '<p>Critical CSS settings cannot be set at network level as critical CSS is specific to each sub-site.</p><p>You can however provide the critical CSS API key for use by all sites by adding this your wp-config.php as %s</p>', 'autoptimize' ), '<br/><code>define(\'AUTOPTIMIZE_CRITICALCSS_API_KEY\', \'eyJhbGmorestringsherexHa7MkOQFtDFkZgLmBLe-LpcHx4\');</code>' );
297 ?>
298 </li>
299 </ul>
300 <?php
301 } else {
302 if ( 'valid' == $key['status'] ) {
303 // If key status is valid, render other panels.
304 // Render rules section.
305 ao_ccss_render_rules();
306 // Render queue section.
307 ao_ccss_render_queue();
308 // Render advanced panel.
309 ao_ccss_render_adv();
310 } else {
311 if ( apply_filters( 'autoptimize_filter_ccss_rules_without_api', true ) ) {
312 // Render rules section for manual rules.
313 ao_ccss_render_rules();
314 } else {
315 echo "<input class='hidden' name='autoptimize_ccss_rules' value='" . json_encode( $ao_ccss_rules, JSON_FORCE_OBJECT ) . "'>";
316 }
317
318 // But if key is other than valid, add hidden fields to persist settings when submitting form
319 // Show explanation of why and how to get a API key.
320 ao_ccss_render_explain();
321
322 // Get viewport size.
323 $viewport = $this->criticalcss->viewport();
324
325 // Add hidden fields.
326 echo "<input class='hidden' name='autoptimize_ccss_queue' value='" . json_encode( $ao_ccss_queue, JSON_FORCE_OBJECT ) . "'>";
327 echo '<input class="hidden" name="autoptimize_ccss_viewport[w]" value="' . esc_attr( $viewport['w'] ) . '">';
328 echo '<input class="hidden" name="autoptimize_ccss_viewport[h]" value="' . esc_attr( $viewport['h'] ) . '">';
329 echo '<input class="hidden" name="autoptimize_ccss_finclude" value="' . esc_attr( $ao_ccss_finclude ) . '">';
330 echo '<input class="hidden" name="autoptimize_ccss_rtimelimit" value="' . esc_attr( $ao_ccss_rtimelimit ) . '">';
331 echo '<input class="hidden" name="autoptimize_ccss_debug" value="' . esc_attr( $ao_ccss_debug ) . '">';
332 echo '<input class="hidden" name="autoptimize_ccss_noptimize" value="' . esc_attr( $ao_ccss_noptimize ) . '">';
333 echo '<input class="hidden" name="autoptimize_css_defer_inline" value="' . esc_attr( $ao_css_defer_inline ) . '">';
334 echo '<input class="hidden" name="autoptimize_ccss_loggedin" value="' . esc_attr( $ao_ccss_loggedin ) . '">';
335 echo '<input class="hidden" name="autoptimize_ccss_forcepath" value="' . esc_attr( $ao_ccss_forcepath ) . '">';
336 echo '<input class="hidden" name="autoptimize_ccss_domain" id="autoptimize_ccss_domain" value="' . esc_attr( $ao_ccss_domain ) . '">';
337 }
338 // Render key panel unconditionally.
339 ao_ccss_render_key( $ao_ccss_key, $key['status'], $key['stmsg'], $key['msg'], $key['color'] );
340 ?>
341 <p class="submit left">
342 <input type="submit" class="button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" />
343 </p>
344 <?php
345 }
346 ?>
347 </form>
348 <script>
349 jQuery("form#settings").submit(function(){
350 var input = jQuery("#autoptimize_ccss_domain");
351 input.val(rot(input.val(), 13));
352 });
353 // rot JS from http://stackoverflow.com/a/617685/987044 .
354 function rot(domainstring, itype) {
355 return domainstring.toString().replace(/[a-zA-Z]/g, function (letter) {
356 return String.fromCharCode((letter <= 'Z' ? 90 : 122) >= (letter = letter.charCodeAt(0) + itype) ? letter : letter - 26);
357 });
358 }
359 </script>
360 <form id="importSettingsForm"<?php if ( $this->is_multisite_network_admin() ) { echo ' class="hidden"'; } // @codingStandardsIgnoreLine ?>>
361 <span id="exportSettings" class="button-secondary"><?php _e( 'Export Settings', 'autoptimize' ); ?></span>
362 <input class="button-secondary" id="importSettings" type="button" value="<?php _e( 'Import Settings', 'autoptimize' ); ?>" onclick="upload();return false;" />
363 <input class="button-secondary" id="settingsfile" name="settingsfile" type="file" />
364 </form>
365 <div id="importdialog"></div>
366 </div><!-- /#autoptimize_main -->
367 </div><!-- /#wrap -->
368 <?php
369 if ( ! $this->is_multisite_network_admin() ) {
370 // Include debug panel if debug mode is enable.
371 if ( $ao_ccss_debug ) {
372 ?>
373 <div id="debug">
374 <?php
375 // Include debug panel.
376 include( 'critcss-inc/admin_settings_debug.php' );
377 ?>
378 </div><!-- /#debug -->
379 <?php
380 }
381 echo '<script>';
382 include( 'critcss-inc/admin_settings_rules.js.php' );
383 include( 'critcss-inc/admin_settings_queue.js.php' );
384 include( 'critcss-inc/admin_settings_impexp.js.php' );
385 echo '</script>';
386 }
387 }
388
389 public function ao_ccss_has_autorules() {
390 static $_has_auto_rules = null;
391
392 if ( null === $_has_auto_rules ) {
393 $ao_ccss_rules = $this->criticalcss->get_option( 'rules' );
394 $_has_auto_rules = false;
395 if ( ! empty( $ao_ccss_rules ) ) {
396 foreach ( array( 'types', 'paths' ) as $_typat ) {
397 foreach ( $ao_ccss_rules[ $_typat ] as $rule ) {
398 if ( ! empty( $rule['hash'] ) ) {
399 // we have at least one AUTO job, so all is fine.
400 $_has_auto_rules = true;
401 break;
402 }
403 }
404 if ( $_has_auto_rules ) {
405 break;
406 }
407 }
408 }
409 }
410
411 return $_has_auto_rules;
412 }
413
414 public static function is_multisite_network_admin() {
415 static $_multisite_network_admin = null;
416
417 if ( null === $_multisite_network_admin ) {
418 if ( is_multisite() && is_network_admin() ) {
419 $_multisite_network_admin = true;
420 } else {
421 $_multisite_network_admin = false;
422 }
423 }
424
425 return $_multisite_network_admin;
426 }
427 }
428