PluginProbe
Autoptimize / 2.8.0
Autoptimize v2.8.0
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 2.8.0, at classes/autoptimizeCriticalCSSSettings.php

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