PluginProbe
Autoptimize / 3.1.11
Autoptimize v3.1.11
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.11, at classes/autoptimizeCriticalCSSSettings.php

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