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 +324 -84 2.7.3 → 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,133 +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.
35 - define( 'AO_CCSS_LOCK', AO_CCSS_DIR . 'queue.lock' );
36 - define( 'AO_CCSS_LOG', AO_CCSS_DIR . 'queuelog.html' );
37 - define( 'AO_CCSS_DEBUG', AO_CCSS_DIR . 'queue.json' );
38 -
39 70 // Define constants for criticalcss.com base path and API endpoints.
40 71 // fixme: AO_CCSS_URL should be read from the autoptimize availability json stored as option.
41 72 define( 'AO_CCSS_URL', 'https://criticalcss.com' );
42 - define( 'AO_CCSS_API', AO_CCSS_URL . '/api/premium/' );
73 + define( 'AO_CCSS_API', apply_filters( 'autoptimize_filter_ccss_service_url', AO_CCSS_URL . '/api/premium/' ) );
43 74 define( 'AO_CCSS_SLEEP', 10 );
44 75 }
45 76
77 + // Define support files locations, in case they are not already defined.
78 + if ( ! defined( 'AO_CCSS_LOCK' ) ) {
79 + define( 'AO_CCSS_LOCK', AO_CCSS_DIR . 'queue.lock' );
80 + }
81 + if ( ! defined( 'AO_CCSS_LOG' ) ) {
82 + define( 'AO_CCSS_LOG', AO_CCSS_DIR . 'queuelog.html' );
83 + }
84 + if ( ! defined( 'AO_CCSS_DEBUG' ) ) {
85 + define( 'AO_CCSS_DEBUG', AO_CCSS_DIR . 'queue.json' );
86 + }
87 +
46 88 $this->filepath = __FILE__;
47 89
48 - $this->setup();
49 - $this->load_requires();
90 + // Add keychecker action for scheduled use.
91 + add_action( 'ao_ccss_keychecker', array( $this, 'ao_ccss_check_key' ) );
50 92 }
51 93
52 - public function setup()
53 - {
54 - // get all options.
55 - $all_options = $this->fetch_options();
56 - foreach ( $all_options as $option => $value ) {
57 - ${$option} = $value;
58 - }
94 + public function setup() {
95 + // check if we need to upgrade.
96 + $this->check_upgrade();
59 97
60 - // make sure the 10 minutes cron schedule is added.
61 - 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' ) );
62 102
63 - // check if we need to upgrade.
64 - $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 + }
65 107
66 - // make sure ao_ccss_queue is scheduled OK if an API key is set.
67 - if ( isset( $ao_ccss_key ) && ! empty( $ao_ccss_key ) && ! wp_next_scheduled( 'ao_ccss_queue' ) ) {
68 - 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 + }
69 134 }
135 +
136 + // check/ create AO_CCSS_DIR.
137 + if ( ! file_exists( AO_CCSS_DIR ) ) {
138 + $this->create_ao_ccss_dir();
139 + }
70 140 }
71 141
72 142 public function load_requires() {
73 143 // Required libs, core is always needed.
74 - $criticalcss_core = new autoptimizeCriticalCSSCore();
144 + $this->_core = new autoptimizeCriticalCSSCore();
75 145
76 - if ( defined( 'DOING_CRON' ) || is_admin() ) {
77 - // TODO: also include if overridden somehow to force queue processing to be executed?
78 - $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();
79 149 }
80 150
81 151 if ( is_admin() ) {
82 - $criticalcss_settings = new autoptimizeCriticalCSSSettings();
83 - } else {
84 - // enqueuing only done when not wp-admin.
85 - $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();
86 156 }
87 157 }
88 158
89 - public static function fetch_options() {
90 - static $autoptimize_ccss_options = null;
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 + }
91 170
92 - if ( null === $autoptimize_ccss_options ) {
93 - // not cached yet, fetching from WordPress options.
94 - $autoptimize_ccss_options['ao_css_defer'] = autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer' );
95 - $autoptimize_ccss_options['ao_css_defer_inline'] = autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer_inline' );
96 - $autoptimize_ccss_options['ao_ccss_rules_raw'] = get_option( 'autoptimize_ccss_rules', false );
97 - $autoptimize_ccss_options['ao_ccss_additional'] = get_option( 'autoptimize_ccss_additional' );
98 - $autoptimize_ccss_options['ao_ccss_queue_raw'] = get_option( 'autoptimize_ccss_queue', false );
99 - $autoptimize_ccss_options['ao_ccss_viewport'] = get_option( 'autoptimize_ccss_viewport', false );
100 - $autoptimize_ccss_options['ao_ccss_finclude'] = get_option( 'autoptimize_ccss_finclude', false );
101 - $autoptimize_ccss_options['ao_ccss_rlimit'] = get_option( 'autoptimize_ccss_rlimit', '5' );
102 - $autoptimize_ccss_options['ao_ccss_noptimize'] = get_option( 'autoptimize_ccss_noptimize', false );
103 - $autoptimize_ccss_options['ao_ccss_debug'] = get_option( 'autoptimize_ccss_debug', false );
104 - $autoptimize_ccss_options['ao_ccss_key'] = get_option( 'autoptimize_ccss_key' );
105 - $autoptimize_ccss_options['ao_ccss_keyst'] = get_option( 'autoptimize_ccss_keyst' );
106 - $autoptimize_ccss_options['ao_ccss_loggedin'] = get_option( 'autoptimize_ccss_loggedin', '1' );
107 - $autoptimize_ccss_options['ao_ccss_forcepath'] = get_option( 'autoptimize_ccss_forcepath', '1' );
108 - $autoptimize_ccss_options['ao_ccss_servicestatus'] = get_option( 'autoptimize_service_availablity' );
109 - $autoptimize_ccss_options['ao_ccss_deferjquery'] = get_option( 'autoptimize_ccss_deferjquery', false );
110 - $autoptimize_ccss_options['ao_ccss_domain'] = get_option( 'autoptimize_ccss_domain' );
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 + }
111 179
112 - if ( strpos( $autoptimize_ccss_options['ao_ccss_domain'], 'http' ) === false && strpos( $autoptimize_ccss_options['ao_ccss_domain'], 'uggc' ) === 0 ) {
113 - $autoptimize_ccss_options['ao_ccss_domain'] = str_rot13( $autoptimize_ccss_options['ao_ccss_domain'] );
114 - } elseif ( strpos( $autoptimize_ccss_options['ao_ccss_domain'], 'http' ) !== false ) {
115 - // not rot13'ed yet, do so now (goal; avoid migration plugins change the bound domain).
116 - update_option( 'autoptimize_ccss_domain', str_rot13( $autoptimize_ccss_options['ao_ccss_domain'] ) );
117 - }
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 + }
118 190
119 - // Setup the rules array.
120 - if ( empty( $autoptimize_ccss_options['ao_ccss_rules_raw'] ) ) {
121 - $autoptimize_ccss_options['ao_ccss_rules']['paths'] = array();
122 - $autoptimize_ccss_options['ao_ccss_rules']['types'] = array();
123 - } else {
124 - $autoptimize_ccss_options['ao_ccss_rules'] = json_decode( $autoptimize_ccss_options['ao_ccss_rules_raw'], true );
125 - }
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 + }
126 201
127 - // Setup the queue array.
128 - if ( empty( $autoptimize_ccss_options['ao_ccss_queue_raw'] ) ) {
129 - $autoptimize_ccss_options['ao_ccss_queue'] = array();
130 - } else {
131 - $autoptimize_ccss_options['ao_ccss_queue'] = json_decode( $autoptimize_ccss_options['ao_ccss_queue_raw'], true );
132 - }
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 + }
133 210
134 - // Override API key if constant is defined.
135 - if ( defined( 'AUTOPTIMIZE_CRITICALCSS_API_KEY' ) ) {
136 - $autoptimize_ccss_options['ao_ccss_key'] = AUTOPTIMIZE_CRITICALCSS_API_KEY;
137 - }
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();
138 222 }
139 223
140 - return $autoptimize_ccss_options;
224 + return $this->_enqueue->ao_ccss_enqueue( $hash, $path, $type );
141 225 }
142 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 ) {
286 + // not rot13'ed yet, do so now (goal; avoid migration plugins change the bound domain).
287 + update_option( 'autoptimize_ccss_domain', str_rot13( $this->_options['domain'] ) );
288 + }
289 +
290 + // Setup the rules array.
291 + if ( empty( $this->_options['rules_raw'] ) ) {
292 + $this->_options['rules'] = array(
293 + 'paths' => array(),
294 + 'types' => array(),
295 + );
296 + } else {
297 + $this->_options['rules'] = json_decode( $this->_options['rules_raw'], true );
298 + }
299 +
300 + // Setup the queue array.
301 + if ( empty( $this->_options['queue_raw'] ) ) {
302 + $this->_options['queue'] = array();
303 + } else {
304 + $this->_options['queue'] = json_decode( $this->_options['queue_raw'], true );
305 + }
306 +
307 + // Override API key if constant is defined.
308 + if ( defined( 'AUTOPTIMIZE_CRITICALCSS_API_KEY' ) ) {
309 + $this->_options['key'] = AUTOPTIMIZE_CRITICALCSS_API_KEY;
310 + }
311 +
312 + return $this->_options;
313 + }
314 +
143 315 public function on_upgrade() {
144 - global $ao_ccss_key;
316 + $key = $this->get_option( 'key' );
145 317
146 318 // Create the cache directory if it doesn't exist already.
147 319 if ( ! file_exists( AO_CCSS_DIR ) ) {
148 - mkdir( AO_CCSS_DIR, 0755, true );
320 + $this->create_ao_ccss_dir();
149 321 }
150 322
151 323 // Create a scheduled event for the queue.
152 - 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' ) ) {
153 325 wp_schedule_event( time(), apply_filters( 'ao_ccss_queue_schedule', 'ao_ccss' ), 'ao_ccss_queue' );
154 326 }
155 327
156 328 // Create a scheduled event for log maintenance.
157 - 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' ) ) {
158 330 wp_schedule_event( time(), 'twicedaily', 'ao_ccss_maintenance' );
159 331 }
160 332 }
161 333
@@ -172,8 +344,9 @@
172 344 public function ao_ccss_interval( $schedules ) {
173 345 // Let interval be configurable.
174 346 if ( ! defined( 'AO_CCSS_DEBUG_INTERVAL' ) ) {
175 347 $intsec = 600;
348 + $inttxt = '10 minutes';
176 349 } else {
177 350 $intsec = AO_CCSS_DEBUG_INTERVAL;
178 351 if ( $intsec >= 120 ) {
179 352 $inttxt = $intsec / 60 . ' minutes';
@@ -179,15 +352,82 @@
179 352 $inttxt = $intsec / 60 . ' minutes';
180 353 } else {
181 354 $inttxt = $intsec . ' second(s)';
182 355 }
183 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Using custom WP-Cron interval of ' . $inttxt, 3 );
356 + $this->log( 'Using custom WP-Cron interval of ' . $inttxt, 3 );
184 357 }
185 358
186 359 // Attach interval to schedule.
187 360 $schedules['ao_ccss'] = array(
188 361 'interval' => $intsec,
189 - '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 ),
190 364 );
191 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 );
192 432 }
193 433 }