PluginProbe
Autoptimize / 3.1.4
Autoptimize v3.1.4
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.4, at classes/autoptimizeCriticalCSSSettings.php

436 lines 23.5 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' => apply_filters( 'autoptimize_filter_ccss_tab_text', 'âš¡ ' . __( '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 if ( autoptimizeUtils::is_local_server() && isset( $ao_ccss_key ) ) { ?>
136 <div class="notice-warning notice"><p>
137 <?php
138 echo __( 'The Critical CSS service does not work on locally hosted sites or when the server is on a private network.', 'autoptimize' );
139 ?>
140 </p></div>
141 <?php }
142
143 $mkdirresult = $this->criticalcss->create_ao_ccss_dir();
144
145 // Warn if we could not create those files.
146 if ( ( true !== $mkdirresult ) ) {
147 ?>
148 <div class="notice-error notice"><p>
149 <?php
150 _e( 'Could not create the required directory. Make sure the webserver can write to the wp-content/uploads directory.', 'autoptimize' );
151 ?>
152 </p></div>
153 <?php
154 }
155
156 // Check if CSS optimization is on.
157 if ( 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_css' ) || 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer' ) ) {
158 ?>
159 <div class="notice-info notice"><p>
160 <?php
161 _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' );
162 ?>
163 </p></div>
164 <?php
165 }
166
167 // Check for "inline & defer CSS" being active in Autoptimize.
168 if ( ! empty( $ao_ccss_key ) && ! $ao_css_defer && empty( $ao_ccss_keyst ) ) {
169 // no keystate so likely in activation-process of CCSS, let's enable "inline & defer CSS" immediately to make things easier!
170 autoptimizeOptionWrapper::update_option( 'autoptimize_css_defer', 'on' );
171 ?>
172 <div class="notice-info notice"><p>
173 <?php
174 _e( 'The "Eliminate render-blocking CSS" option was activated to allow critical CSS to be used.', 'autoptimize' );
175 ?>
176 </p></div>
177 <?php
178 }
179
180 // check if WordPress cron is disabled and warn if so.
181 if ( ! empty( $ao_ccss_key ) && defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON && PAnD::is_admin_notice_active( 'i-know-about-disable-cron-forever' ) ) {
182 ?>
183 <div data-dismissible="i-know-about-disable-cron-forever" class="notice-warning notice is-dismissible"><p>
184 <?php
185 _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' );
186 ?>
187 </p></div>
188 <?php
189 }
190
191 // check if defer jQuery is active and warn if so.
192 if ( 1 == $ao_ccss_deferjquery && PAnD::is_admin_notice_active( 'i-know-about-defer-inline-forever' ) ) {
193 ?>
194 <div data-dismissible="i-know-about-defer-inline-forever" class="notice-warning notice is-dismissible"><p>
195 <?php
196 _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' );
197 ?>
198 </p></div>
199 <?php
200 }
201
202 // warn if it looks as though the queue processing job looks isn't running
203 // but store result in transient as to not to have to go through 2 arrays each and every time.
204 $_warn_cron = get_transient( 'ao_ccss_cronwarning' );
205 if ( ! empty( $ao_ccss_key ) && false === $_warn_cron ) {
206 $_jobs_all_new = true;
207 $_oldest_job_timestamp = microtime( true ); // now.
208 $_jobs_too_old = true;
209
210 // go over queue array.
211 if ( empty( $ao_ccss_queue ) ) {
212 // no jobs, then no warning.
213 $_jobs_all_new = false;
214 } else {
215 foreach ( $ao_ccss_queue as $job ) {
216 if ( $job['jctime'] < $_oldest_job_timestamp ) {
217 // we need to catch the oldest job's timestamp.
218 $_oldest_job_timestamp = $job['jctime'];
219 }
220
221 if ( 'NEW' !== $job['jqstat'] && 'firstrun' !== $job['ljid'] ) {
222 // we have a non-"NEW" job which is not our pending firstrun job either, break the loop.
223 $_jobs_all_new = false;
224 break;
225 }
226 }
227 }
228
229 // is the oldest job too old (4h)?
230 if ( $_oldest_job_timestamp > microtime( true ) - 60 * 60 * 4 ) {
231 $_jobs_too_old = false;
232 }
233
234 if ( $_jobs_all_new && ! $this->ao_ccss_has_autorules() && $_jobs_too_old ) {
235 $_warn_cron = 'on';
236 $_transient_multiplier = 1; // store for 1 hour.
237 } else {
238 $_warn_cron = 'off';
239 $_transient_multiplier = 4; // store for 4 hours.
240 }
241 // and set transient.
242 set_transient( 'ao_ccss_cronwarning', $_warn_cron, $_transient_multiplier * HOUR_IN_SECONDS );
243 }
244
245 if ( ! empty( $ao_ccss_key ) && 'on' == $_warn_cron && PAnD::is_admin_notice_active( 'i-know-about-cron-1' ) ) {
246 ?>
247 <div data-dismissible="i-know-about-cron-1" class="notice-warning notice is-dismissible"><p>
248 <?php
249 _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' );
250 ?>
251 </p></div>
252 <?php
253 } elseif ( ! empty( $ao_ccss_key ) && '2' == $ao_ccss_keyst && 'on' != $_warn_cron && ! $this->ao_ccss_has_autorules() ) {
254 ?>
255 <div class="notice-success notice"><p>
256 <?php
257 _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' );
258 echo ' ';
259 _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' );
260 ?>
261 </p></div>
262 <?php
263 }
264
265 // warn if service is down.
266 if ( ! empty( $ao_ccss_key ) && ! empty( $ao_ccss_servicestatus ) && is_array( $ao_ccss_servicestatus ) && 'down' === $ao_ccss_servicestatus['critcss']['status'] ) {
267 ?>
268 <div class="notice-warning notice"><p>
269 <?php
270 _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' );
271 ?>
272 </p></div>
273 <?php
274 }
275
276 // warn if too many rules (based on length of ao_ccss_rules option) as that might cause issues at e.g. wpengine
277 // see https://wpengine.com/support/database-optimization-best-practices/#Autoloaded_Data .
278 $_raw_rules_length = strlen( get_option( 'autoptimize_ccss_rules', '' ) );
279 if ( $_raw_rules_length > apply_filters( 'autoptimize_ccss_rules_length_warning', 500000 ) ) {
280 ?>
281 <div class="notice-warning notice"><p>
282 <?php
283 _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' );
284 ?>
285 </p></div>
286 <?php
287 }
288
289 // Settings Form.
290 ?>
291 <form id="settings" method="post" action="options.php">
292 <?php
293 settings_fields( 'ao_ccss_options_group' );
294
295 // Get API key status.
296 $key = $this->criticalcss->key_status( true );
297
298 if ( $this->is_multisite_network_admin() ) {
299 ?>
300 <ul id="key-panel">
301 <li class="itemDetail">
302 <?php
303 // translators: the placesholder is for a line of code in wp-config.php.
304 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>' );
305 ?>
306 </li>
307 </ul>
308 <?php
309 } else {
310 if ( 'valid' == $key['status'] || ( defined( 'AO_PRO_VERSION' ) && has_filter( 'autoptimize_filter_ccss_key' ) ) ) {
311 // If key status is valid, render other panels.
312 // Render rules section.
313 ao_ccss_render_rules();
314 // Render queue section.
315 ao_ccss_render_queue();
316 // Render advanced panel.
317 ao_ccss_render_adv();
318 } else {
319 if ( apply_filters( 'autoptimize_filter_ccss_rules_without_api', true ) ) {
320 // Render rules section for manual rules.
321 ao_ccss_render_rules();
322 } else {
323 echo "<input class='hidden' name='autoptimize_ccss_rules' value='" . json_encode( $ao_ccss_rules, JSON_FORCE_OBJECT ) . "'>";
324 }
325
326 // But if key is other than valid, add hidden fields to persist settings when submitting form
327 // Show explanation of why and how to get a API key.
328 ao_ccss_render_explain();
329
330 // Get viewport size.
331 $viewport = $this->criticalcss->viewport();
332
333 // Add hidden fields.
334 echo "<input class='hidden' name='autoptimize_ccss_queue' value='" . json_encode( $ao_ccss_queue, JSON_FORCE_OBJECT ) . "'>";
335 echo '<input class="hidden" name="autoptimize_ccss_viewport[w]" value="' . esc_attr( $viewport['w'] ) . '">';
336 echo '<input class="hidden" name="autoptimize_ccss_viewport[h]" value="' . esc_attr( $viewport['h'] ) . '">';
337 echo '<input class="hidden" name="autoptimize_ccss_finclude" value="' . esc_attr( $ao_ccss_finclude ) . '">';
338 echo '<input class="hidden" name="autoptimize_ccss_rtimelimit" value="' . esc_attr( $ao_ccss_rtimelimit ) . '">';
339 echo '<input class="hidden" name="autoptimize_ccss_debug" value="' . esc_attr( $ao_ccss_debug ) . '">';
340 echo '<input class="hidden" name="autoptimize_ccss_noptimize" value="' . esc_attr( $ao_ccss_noptimize ) . '">';
341 echo '<input class="hidden" name="autoptimize_css_defer_inline" value="' . esc_attr( $ao_css_defer_inline ) . '">';
342 echo '<input class="hidden" name="autoptimize_ccss_loggedin" value="' . esc_attr( $ao_ccss_loggedin ) . '">';
343 echo '<input class="hidden" name="autoptimize_ccss_forcepath" value="' . esc_attr( $ao_ccss_forcepath ) . '">';
344 echo '<input class="hidden" name="autoptimize_ccss_domain" id="autoptimize_ccss_domain" value="' . esc_attr( $ao_ccss_domain ) . '">';
345 }
346 // Render key panel unconditionally.
347 ao_ccss_render_key( $ao_ccss_key, $key['status'], $key['stmsg'], $key['msg'], $key['color'] );
348 ?>
349 <p class="submit left">
350 <input type="submit" class="button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" />
351 </p>
352 <?php
353 }
354 ?>
355 </form>
356 <script>
357 jQuery("form#settings").submit(function(){
358 var input = jQuery("#autoptimize_ccss_domain");
359 input.val(rot(input.val(), 13));
360 });
361 // rot JS from http://stackoverflow.com/a/617685/987044 .
362 function rot(domainstring, itype) {
363 return domainstring.toString().replace(/[a-zA-Z]/g, function (letter) {
364 return String.fromCharCode((letter <= 'Z' ? 90 : 122) >= (letter = letter.charCodeAt(0) + itype) ? letter : letter - 26);
365 });
366 }
367 </script>
368 <form id="importSettingsForm"<?php if ( $this->is_multisite_network_admin() ) { echo ' class="hidden"'; } // @codingStandardsIgnoreLine ?>>
369 <span id="exportSettings" class="button-secondary"><?php _e( 'Export Settings', 'autoptimize' ); ?></span>
370 <input class="button-secondary" id="importSettings" type="button" value="<?php _e( 'Import Settings', 'autoptimize' ); ?>" onclick="upload();return false;" />
371 <input class="button-secondary" id="settingsfile" name="settingsfile" type="file" />
372 </form>
373 <div id="importdialog"></div>
374 </div><!-- /#autoptimize_main -->
375 </div><!-- /#wrap -->
376 <?php
377 if ( ! $this->is_multisite_network_admin() ) {
378 // Include debug panel if debug mode is enable.
379 if ( $ao_ccss_debug ) {
380 ?>
381 <div id="debug">
382 <?php
383 // Include debug panel.
384 include( 'critcss-inc/admin_settings_debug.php' );
385 ?>
386 </div><!-- /#debug -->
387 <?php
388 }
389 echo '<script>';
390 include( 'critcss-inc/admin_settings_rules.js.php' );
391 include( 'critcss-inc/admin_settings_queue.js.php' );
392 include( 'critcss-inc/admin_settings_impexp.js.php' );
393 echo '</script>';
394 }
395 }
396
397 public function ao_ccss_has_autorules() {
398 static $_has_auto_rules = null;
399
400 if ( null === $_has_auto_rules ) {
401 $ao_ccss_rules = $this->criticalcss->get_option( 'rules' );
402 $_has_auto_rules = false;
403 if ( ! empty( $ao_ccss_rules ) ) {
404 foreach ( array( 'types', 'paths' ) as $_typat ) {
405 foreach ( $ao_ccss_rules[ $_typat ] as $rule ) {
406 if ( ! empty( $rule['hash'] ) ) {
407 // we have at least one AUTO job, so all is fine.
408 $_has_auto_rules = true;
409 break;
410 }
411 }
412 if ( $_has_auto_rules ) {
413 break;
414 }
415 }
416 }
417 }
418
419 return $_has_auto_rules;
420 }
421
422 public static function is_multisite_network_admin() {
423 static $_multisite_network_admin = null;
424
425 if ( null === $_multisite_network_admin ) {
426 if ( is_multisite() && is_network_admin() ) {
427 $_multisite_network_admin = true;
428 } else {
429 $_multisite_network_admin = false;
430 }
431 }
432
433 return $_multisite_network_admin;
434 }
435 }
436