PluginProbe
Autoptimize / trunk
Autoptimize vtrunk
3.1.16 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 All 108 releases
← All changes | classes/autoptimizeCriticalCSSBase.php +316 -71 2.7.2 → trunk View file →
@@ -15,15 +15,47 @@
15 15 * @var string
16 16 */
17 17 protected $filepath = null;
18 18
19 + /**
20 + * Critical CSS options
21 + *
22 + * @var array
23 + */
24 + protected $_options = null;
25 +
26 + /**
27 + * Core object
28 + *
29 + * @var object
30 + */
31 + protected $_core = null;
32 +
33 + /**
34 + * Cron object
35 + *
36 + * @var object
37 + */
38 + protected $_cron = null;
39 +
40 + /**
41 + * Settings object
42 + *
43 + * @var object
44 + */
45 + protected $_settings = null;
46 +
47 + /**
48 + * Enqueue object
49 + *
50 + * @var object
51 + */
52 + protected $_enqueue = null;
53 +
19 54 public function __construct()
20 55 {
21 56 // define constant, but only once.
22 57 if ( ! defined( 'AO_CCSS_DIR' ) ) {
23 - // Define plugin version.
24 - define( 'AO_CCSS_VER', 'AO_' . AUTOPTIMIZE_PLUGIN_VERSION );
25 -
26 58 // Define a constant with the directory to store critical CSS in.
27 59 if ( is_multisite() ) {
28 60 $blog_id = get_current_blog_id();
29 61 define( 'AO_CCSS_DIR', WP_CONTENT_DIR . '/uploads/ao_ccss/' . $blog_id . '/' );
@@ -29,128 +61,273 @@
29 61 define( 'AO_CCSS_DIR', WP_CONTENT_DIR . '/uploads/ao_ccss/' . $blog_id . '/' );
30 62 } else {
31 63 define( 'AO_CCSS_DIR', WP_CONTENT_DIR . '/uploads/ao_ccss/' );
32 64 }
65 + }
66 + if ( ! defined( 'AO_CCSS_VER' ) ) {
67 + // Define plugin version.
68 + define( 'AO_CCSS_VER', 'AO_' . AUTOPTIMIZE_PLUGIN_VERSION );
33 69
34 - // Define support files locations.
70 + // Define constants for criticalcss.com base path and API endpoints.
71 + // fixme: AO_CCSS_URL should be read from the autoptimize availability json stored as option.
72 + define( 'AO_CCSS_URL', 'https://criticalcss.com' );
73 + define( 'AO_CCSS_API', apply_filters( 'autoptimize_filter_ccss_service_url', AO_CCSS_URL . '/api/premium/' ) );
74 + define( 'AO_CCSS_SLEEP', 10 );
75 + }
76 +
77 + // Define support files locations, in case they are not already defined.
78 + if ( ! defined( 'AO_CCSS_LOCK' ) ) {
35 79 define( 'AO_CCSS_LOCK', AO_CCSS_DIR . 'queue.lock' );
80 + }
81 + if ( ! defined( 'AO_CCSS_LOG' ) ) {
36 82 define( 'AO_CCSS_LOG', AO_CCSS_DIR . 'queuelog.html' );
83 + }
84 + if ( ! defined( 'AO_CCSS_DEBUG' ) ) {
37 85 define( 'AO_CCSS_DEBUG', AO_CCSS_DIR . 'queue.json' );
38 -
39 - // Define constants for criticalcss.com base path and API endpoints.
40 - // fixme: AO_CCSS_URL should be read from the autoptimize availability json stored as option.
41 - define( 'AO_CCSS_URL', 'https://criticalcss.com' );
42 - define( 'AO_CCSS_API', AO_CCSS_URL . '/api/premium/' );
43 86 }
44 87
45 88 $this->filepath = __FILE__;
46 89
47 - $this->setup();
48 - $this->load_requires();
90 + // Add keychecker action for scheduled use.
91 + add_action( 'ao_ccss_keychecker', array( $this, 'ao_ccss_check_key' ) );
49 92 }
50 93
51 - public function setup()
52 - {
53 - // get all options.
54 - $all_options = $this->fetch_options();
55 - foreach ( $all_options as $option => $value ) {
56 - ${$option} = $value;
57 - }
94 + public function setup() {
95 + // check if we need to upgrade.
96 + $this->check_upgrade();
58 97
59 - // make sure the 10 minutes cron schedule is added.
60 - add_filter( 'cron_schedules', array( $this, 'ao_ccss_interval' ) );
98 + // add/ remove scheduled jobs.
99 + if ( $this->is_api_active() ) {
100 + // make sure the 10 minutes cron schedule is added.
101 + add_filter( 'cron_schedules', array( $this, 'ao_ccss_interval' ) );
61 102
62 - // check if we need to upgrade.
63 - $this->check_upgrade();
103 + if ( ! wp_next_scheduled( 'ao_ccss_queue' ) ) {
104 + // make sure ao_ccss_queue is scheduled OK if an API key is active.
105 + wp_schedule_event( time(), apply_filters( 'ao_ccss_queue_schedule', 'ao_ccss' ), 'ao_ccss_queue' );
106 + }
64 107
65 - // make sure ao_ccss_queue is scheduled OK if an API key is set.
66 - if ( isset( $ao_ccss_key ) && ! empty( $ao_ccss_key ) && ! wp_next_scheduled( 'ao_ccss_queue' ) ) {
67 - wp_schedule_event( time(), apply_filters( 'ao_ccss_queue_schedule', 'ao_ccss' ), 'ao_ccss_queue' );
108 + if ( ! wp_next_scheduled( 'ao_ccss_maintenance' ) ) {
109 + // and schedule maintenance job.
110 + wp_schedule_event( time(), 'twicedaily', 'ao_ccss_maintenance' );
111 + }
112 +
113 + if ( wp_next_scheduled( 'ao_ccss_keychecker' ) ) {
114 + // api is active now, no need to check key as it is checked by using the API.
115 + wp_clear_scheduled_hook( 'ao_ccss_keychecker' );
116 + }
117 + } else {
118 + if ( wp_next_scheduled( 'ao_ccss_queue' ) ) {
119 + wp_clear_scheduled_hook( 'ao_ccss_queue' );
120 + }
121 +
122 + if ( wp_next_scheduled( 'ao_ccss_maintenance' ) ) {
123 + wp_clear_scheduled_hook( 'ao_ccss_maintenance' );
124 + }
125 +
126 + // add keychecker logic if api is not active but we have a key so maybe this is a temporary issue, check if key is OK daily.
127 + $ao_ccss_key = $this->get_option( 'key' );
128 + if ( ! empty( $ao_ccss_key ) && ! wp_next_scheduled( 'ao_ccss_keychecker' ) ) {
129 + wp_schedule_event( time(), 'twicedaily', 'ao_ccss_keychecker' );
130 + } else if ( empty( $ao_ccss_key ) && wp_next_scheduled( 'ao_ccss_keychecker' ) ) {
131 + // edge case: we had a inactive key that was checked daily, but it is now removed, so remove keychecker from schedule.
132 + wp_clear_scheduled_hook( 'ao_ccss_keychecker' );
133 + }
68 134 }
135 +
136 + // check/ create AO_CCSS_DIR.
137 + if ( ! file_exists( AO_CCSS_DIR ) ) {
138 + $this->create_ao_ccss_dir();
139 + }
69 140 }
70 141
71 142 public function load_requires() {
72 143 // Required libs, core is always needed.
73 - $criticalcss_core = new autoptimizeCriticalCSSCore();
144 + $this->_core = new autoptimizeCriticalCSSCore();
74 145
75 - if ( defined( 'DOING_CRON' ) || is_admin() ) {
76 - // TODO: also include if overridden somehow to force queue processing to be executed?
77 - $criticalcss_cron = new autoptimizeCriticalCSSCron();
146 + if ( ( defined( 'WP_CLI' ) || defined( 'DOING_CRON' ) || is_admin() ) && $this->is_api_active() ) {
147 + // cron only initiated when doing cron (or wp_cli or is_amdin) and when we have an active API key.
148 + $this->_cron = new autoptimizeCriticalCSSCron();
78 149 }
79 150
80 151 if ( is_admin() ) {
81 - $criticalcss_settings = new autoptimizeCriticalCSSSettings();
82 - } else {
83 - // enqueuing only done when not wp-admin.
84 - $criticalcss_enqueue = new autoptimizeCriticalCSSEnqueue();
152 + $this->_settings = new autoptimizeCriticalCSSSettings();
153 + } else if ( $this->is_api_active() ) {
154 + // enqueuing only done when not wp-admin and when API is active.
155 + $this->_enqueue = new autoptimizeCriticalCSSEnqueue();
85 156 }
86 157 }
87 158
88 - public static function fetch_options() {
89 - // Get options.
90 - $autoptimize_ccss_options['ao_css_defer'] = autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer' );
91 - $autoptimize_ccss_options['ao_css_defer_inline'] = autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer_inline' );
92 - $autoptimize_ccss_options['ao_ccss_rules_raw'] = get_option( 'autoptimize_ccss_rules', false );
93 - $autoptimize_ccss_options['ao_ccss_additional'] = get_option( 'autoptimize_ccss_additional' );
94 - $autoptimize_ccss_options['ao_ccss_queue_raw'] = get_option( 'autoptimize_ccss_queue', false );
95 - $autoptimize_ccss_options['ao_ccss_viewport'] = get_option( 'autoptimize_ccss_viewport', false );
96 - $autoptimize_ccss_options['ao_ccss_finclude'] = get_option( 'autoptimize_ccss_finclude', false );
97 - $autoptimize_ccss_options['ao_ccss_rlimit'] = get_option( 'autoptimize_ccss_rlimit', '5' );
98 - $autoptimize_ccss_options['ao_ccss_noptimize'] = get_option( 'autoptimize_ccss_noptimize', false );
99 - $autoptimize_ccss_options['ao_ccss_debug'] = get_option( 'autoptimize_ccss_debug', false );
100 - $autoptimize_ccss_options['ao_ccss_key'] = get_option( 'autoptimize_ccss_key' );
101 - $autoptimize_ccss_options['ao_ccss_keyst'] = get_option( 'autoptimize_ccss_keyst' );
102 - $autoptimize_ccss_options['ao_ccss_loggedin'] = get_option( 'autoptimize_ccss_loggedin', '1' );
103 - $autoptimize_ccss_options['ao_ccss_forcepath'] = get_option( 'autoptimize_ccss_forcepath', '1' );
104 - $autoptimize_ccss_options['ao_ccss_servicestatus'] = get_option( 'autoptimize_service_availablity' );
105 - $autoptimize_ccss_options['ao_ccss_deferjquery'] = get_option( 'autoptimize_ccss_deferjquery', false );
106 - $autoptimize_ccss_options['ao_ccss_domain'] = get_option( 'autoptimize_ccss_domain' );
159 + /**
160 + * Log a message via CCSS Core object
161 + *
162 + * @param string $msg Message to log.
163 + * @param int $lvl Loglevel.
164 + *
165 + * @return empty
166 + */
167 + public function log( $msg, $lvl ) {
168 + return $this->_core->ao_ccss_log( $msg, $lvl );
169 + }
107 170
108 - if ( strpos( $autoptimize_ccss_options['ao_ccss_domain'], 'http' ) === false && strpos( $autoptimize_ccss_options['ao_ccss_domain'], 'uggc' ) === 0 ) {
109 - $autoptimize_ccss_options['ao_ccss_domain'] = str_rot13( $autoptimize_ccss_options['ao_ccss_domain'] );
110 - } elseif ( strpos( $autoptimize_ccss_options['ao_ccss_domain'], 'http' ) !== false ) {
171 + /**
172 + * Get viewport from CCSS Core object
173 + *
174 + * @return array
175 + */
176 + public function viewport() {
177 + return $this->_core->ao_ccss_viewport();
178 + }
179 +
180 + /**
181 + * Check CCSS contents from Core object
182 + *
183 + * @param string $ccss Critical CSS to be checked.
184 + *
185 + * @return bool
186 + */
187 + public function check_contents( $ccss ) {
188 + return $this->_core->ao_ccss_check_contents( $ccss );
189 + }
190 +
191 + /**
192 + * Get key status from Core object
193 + *
194 + * @param bool $render Indicates if key status is to be rendered.
195 + *
196 + * @return array
197 + */
198 + public function key_status( $render ) {
199 + return $this->_core->ao_ccss_key_status( $render );
200 + }
201 +
202 + /**
203 + * Return valid types from core object
204 + *
205 + * @return array
206 + */
207 + public function get_types() {
208 + return $this->_core->get_types();
209 + }
210 +
211 + /**
212 + * Run enqueue in CCSS Enqueue object
213 + *
214 + * @param string $hash Hash (default empty).
215 + * @param string $path Path (default empty).
216 + * @param string $type (default is_page).
217 + */
218 + public function enqueue( $hash = '', $path = '', $type = 'is_page' ) {
219 + // Enqueue is sometimes required on wp-admin requests, load it just-in-time.
220 + if ( is_null( $this->_enqueue ) && $this->is_api_active() ) {
221 + $this->_enqueue = new autoptimizeCriticalCSSEnqueue();
222 + }
223 +
224 + return $this->_enqueue->ao_ccss_enqueue( $hash, $path, $type );
225 + }
226 +
227 + /**
228 + * Check auto-rules in CCSS Settings object
229 + */
230 + public function has_autorules() {
231 + return $this->_settings->ao_ccss_has_autorules();
232 + }
233 +
234 + /**
235 + * Get a Critical CSS option
236 + *
237 + * @param string $name The option name.
238 + *
239 + * @return mixed
240 + */
241 + public function get_option( $name ) {
242 + if ( is_null( $this->_options ) ) {
243 + $this->fetch_options();
244 + }
245 +
246 + if ( isset( $this->_options[ $name ] ) ) {
247 + return $this->_options[ $name ];
248 + }
249 +
250 + return null;
251 + }
252 +
253 + public function flush_options() {
254 + $this->_options = null;
255 + }
256 +
257 + protected function fetch_options() {
258 + if ( ! is_null( $this->_options ) ) {
259 + return $this->_options;
260 + }
261 +
262 + $this->_options = array(
263 + 'css_defer' => autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer' ),
264 + 'css_defer_inline' => autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer_inline' ),
265 + 'rules_raw' => get_option( 'autoptimize_ccss_rules', false ),
266 + 'additional' => get_option( 'autoptimize_ccss_additional' ),
267 + 'queue_raw' => get_option( 'autoptimize_ccss_queue', false ),
268 + 'viewport' => get_option( 'autoptimize_ccss_viewport', false ),
269 + 'finclude' => get_option( 'autoptimize_ccss_finclude', false ),
270 + 'rtimelimit' => get_option( 'autoptimize_ccss_rtimelimit', '30' ),
271 + 'noptimize' => get_option( 'autoptimize_ccss_noptimize', false ),
272 + 'debug' => get_option( 'autoptimize_ccss_debug', false ),
273 + 'key' => apply_filters( 'autoptimize_filter_ccss_key', get_option( 'autoptimize_ccss_key' ) ),
274 + 'keyst' => get_option( 'autoptimize_ccss_keyst' ),
275 + 'loggedin' => get_option( 'autoptimize_ccss_loggedin', '1' ),
276 + 'forcepath' => get_option( 'autoptimize_ccss_forcepath', '1' ),
277 + 'servicestatus' => get_option( 'autoptimize_service_availablity' ),
278 + 'deferjquery' => get_option( 'autoptimize_ccss_deferjquery', false ),
279 + 'domain' => get_option( 'autoptimize_ccss_domain' ),
280 + 'unloadccss' => get_option( 'autoptimize_ccss_unloadccss', false ),
281 + );
282 +
283 + if ( ( strpos( $this->_options['domain'], 'http' ) === false && strpos( $this->_options['domain'], 'uggc' ) === 0 ) || 'abar' === $this->_options['domain'] ) {
284 + $this->_options['domain'] = str_rot13( $this->_options['domain'] );
285 + } elseif ( strpos( $this->_options['domain'], 'http' ) !== false ) {
111 286 // not rot13'ed yet, do so now (goal; avoid migration plugins change the bound domain).
112 - update_option( 'autoptimize_ccss_domain', str_rot13( $autoptimize_ccss_options['ao_ccss_domain'] ) );
287 + update_option( 'autoptimize_ccss_domain', str_rot13( $this->_options['domain'] ) );
113 288 }
114 289
115 290 // Setup the rules array.
116 - if ( empty( $autoptimize_ccss_options['ao_ccss_rules_raw'] ) ) {
117 - $autoptimize_ccss_options['ao_ccss_rules']['paths'] = array();
118 - $autoptimize_ccss_options['ao_ccss_rules']['types'] = array();
291 + if ( empty( $this->_options['rules_raw'] ) ) {
292 + $this->_options['rules'] = array(
293 + 'paths' => array(),
294 + 'types' => array(),
295 + );
119 296 } else {
120 - $autoptimize_ccss_options['ao_ccss_rules'] = json_decode( $autoptimize_ccss_options['ao_ccss_rules_raw'], true );
297 + $this->_options['rules'] = json_decode( $this->_options['rules_raw'], true );
121 298 }
122 299
123 300 // Setup the queue array.
124 - if ( empty( $autoptimize_ccss_options['ao_ccss_queue_raw'] ) ) {
125 - $autoptimize_ccss_options['ao_ccss_queue'] = array();
301 + if ( empty( $this->_options['queue_raw'] ) ) {
302 + $this->_options['queue'] = array();
126 303 } else {
127 - $autoptimize_ccss_options['ao_ccss_queue'] = json_decode( $autoptimize_ccss_options['ao_ccss_queue_raw'], true );
304 + $this->_options['queue'] = json_decode( $this->_options['queue_raw'], true );
128 305 }
129 306
130 307 // Override API key if constant is defined.
131 308 if ( defined( 'AUTOPTIMIZE_CRITICALCSS_API_KEY' ) ) {
132 - $autoptimize_ccss_options['ao_ccss_key'] = AUTOPTIMIZE_CRITICALCSS_API_KEY;
309 + $this->_options['key'] = AUTOPTIMIZE_CRITICALCSS_API_KEY;
133 310 }
134 311
135 - return $autoptimize_ccss_options;
312 + return $this->_options;
136 313 }
137 314
138 315 public function on_upgrade() {
139 - global $ao_ccss_key;
316 + $key = $this->get_option( 'key' );
140 317
141 318 // Create the cache directory if it doesn't exist already.
142 319 if ( ! file_exists( AO_CCSS_DIR ) ) {
143 - mkdir( AO_CCSS_DIR, 0755, true );
320 + $this->create_ao_ccss_dir();
144 321 }
145 322
146 323 // Create a scheduled event for the queue.
147 - if ( isset( $ao_ccss_key ) && ! empty( $ao_ccss_key ) && ! wp_next_scheduled( 'ao_ccss_queue' ) ) {
324 + if ( $this->is_api_active() && ! wp_next_scheduled( 'ao_ccss_queue' ) ) {
148 325 wp_schedule_event( time(), apply_filters( 'ao_ccss_queue_schedule', 'ao_ccss' ), 'ao_ccss_queue' );
149 326 }
150 327
151 328 // Create a scheduled event for log maintenance.
152 - if ( isset( $ao_ccss_key ) && ! empty( $ao_ccss_key ) && ! wp_next_scheduled( 'ao_ccss_maintenance' ) ) {
329 + if ( $this->is_api_active() && ! wp_next_scheduled( 'ao_ccss_maintenance' ) ) {
153 330 wp_schedule_event( time(), 'twicedaily', 'ao_ccss_maintenance' );
154 331 }
155 332 }
156 333
@@ -167,8 +344,9 @@
167 344 public function ao_ccss_interval( $schedules ) {
168 345 // Let interval be configurable.
169 346 if ( ! defined( 'AO_CCSS_DEBUG_INTERVAL' ) ) {
170 347 $intsec = 600;
348 + $inttxt = '10 minutes';
171 349 } else {
172 350 $intsec = AO_CCSS_DEBUG_INTERVAL;
173 351 if ( $intsec >= 120 ) {
174 352 $inttxt = $intsec / 60 . ' minutes';
@@ -174,15 +352,82 @@
174 352 $inttxt = $intsec / 60 . ' minutes';
175 353 } else {
176 354 $inttxt = $intsec . ' second(s)';
177 355 }
178 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Using custom WP-Cron interval of ' . $inttxt, 3 );
356 + $this->log( 'Using custom WP-Cron interval of ' . $inttxt, 3 );
179 357 }
180 358
181 359 // Attach interval to schedule.
182 360 $schedules['ao_ccss'] = array(
183 361 'interval' => $intsec,
184 - 'display' => __( 'Autoptimize CriticalCSS' ),
362 + // translators: the variable contains a string describing the insterval.
363 + 'display' => sprintf( esc_html__( 'Every %s (Autoptimize Crit. CSS)', 'autoptimize' ), $inttxt ),
185 364 );
186 365 return $schedules;
366 + }
367 +
368 + public function create_ao_ccss_dir() {
369 + // Make sure dir to write ao_ccss exists and is writable.
370 + if ( ! is_dir( AO_CCSS_DIR ) ) {
371 + // TODO: use wp_mkdir_p() ?
372 + $mkdirresp = @mkdir( AO_CCSS_DIR, 0775, true ); // @codingStandardsIgnoreLine
373 + } else {
374 + $mkdirresp = true;
375 + }
376 +
377 + // Make sure our index.html is there.
378 + if ( ! is_file( AO_CCSS_DIR . 'index.html' ) ) {
379 + $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>' );
380 + } else {
381 + $fileresp = true;
382 + }
383 +
384 + if ( true === $fileresp && true === $mkdirresp ) {
385 + return true;
386 + } else {
387 + return false;
388 + }
389 + }
390 +
391 + /**
392 + * Helper function to determine if there is an active API key.
393 + *
394 + * @return bool
395 + */
396 + public function is_api_active() {
397 + // using options instead of more complex $this->key_status (which gave some dependancy issues ... ;-) ).
398 + $ao_ccss_key = $this->get_option( 'key' );
399 + $ao_ccss_keyst = $this->get_option( 'keyst' );
400 +
401 + if ( ! empty( $ao_ccss_key ) && $ao_ccss_keyst && 2 == $ao_ccss_keyst ) {
402 + return true;
403 + }
404 +
405 + return false;
406 + }
407 +
408 + /**
409 + * Helper function to determine if a rule is MANUAL.
410 + *
411 + * @param array $rule Rule to check.
412 + *
413 + * @return bool
414 + */
415 + public function is_rule_manual( $rule ) {
416 + if ( is_array( $rule ) && false == $rule['hash'] && false != $rule['file'] ) {
417 + return true;
418 + }
419 +
420 + return false;
421 + }
422 +
423 + /**
424 + * Scheduled action to check an inactive key. Not part of autoptimizeCriticalCSSCron.php
425 + * to allow us to only load the main cron logic if we have an active key to begin with.
426 + */
427 + public function ao_ccss_check_key() {
428 + $ao_ccss_key = $this->get_option( 'key' );
429 + $_result = $this->_core->ao_ccss_key_validation( $ao_ccss_key );
430 + $_resmsg = ( true === $_result ) ? 'ok' : 'nok';
431 + $this->log( 'Inactive key checked, result was ' . $_resmsg, 3 );
187 432 }
188 433 }