PluginProbe
Autoptimize / 3.1.6
Autoptimize v3.1.6
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 / autoptimizeCriticalCSSBase.php

autoptimizeCriticalCSSBase.php in Autoptimize 3.1.6, at classes/autoptimizeCriticalCSSBase.php

433 lines 14.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Critical CSS base file (initializes all ccss files).
4 */
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit;
8 }
9
10 class autoptimizeCriticalCSSBase {
11 /**
12 * Main plugin filepath.
13 * Used for activation/deactivation/uninstall hooks.
14 *
15 * @var string
16 */
17 protected $filepath = null;
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
54 public function __construct()
55 {
56 // define constant, but only once.
57 if ( ! defined( 'AO_CCSS_DIR' ) ) {
58 // Define a constant with the directory to store critical CSS in.
59 if ( is_multisite() ) {
60 $blog_id = get_current_blog_id();
61 define( 'AO_CCSS_DIR', WP_CONTENT_DIR . '/uploads/ao_ccss/' . $blog_id . '/' );
62 } else {
63 define( 'AO_CCSS_DIR', WP_CONTENT_DIR . '/uploads/ao_ccss/' );
64 }
65 }
66 if ( ! defined( 'AO_CCSS_VER' ) ) {
67 // Define plugin version.
68 define( 'AO_CCSS_VER', 'AO_' . AUTOPTIMIZE_PLUGIN_VERSION );
69
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' ) ) {
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
88 $this->filepath = __FILE__;
89
90 // Add keychecker action for scheduled use.
91 add_action( 'ao_ccss_keychecker', array( $this, 'ao_ccss_check_key' ) );
92 }
93
94 public function setup() {
95 // check if we need to upgrade.
96 $this->check_upgrade();
97
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' ) );
102
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 }
107
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 }
134 }
135
136 // check/ create AO_CCSS_DIR.
137 if ( ! file_exists( AO_CCSS_DIR ) ) {
138 $this->create_ao_ccss_dir();
139 }
140 }
141
142 public function load_requires() {
143 // Required libs, core is always needed.
144 $this->_core = new autoptimizeCriticalCSSCore();
145
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();
149 }
150
151 if ( is_admin() ) {
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();
156 }
157 }
158
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 }
170
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 ) {
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
315 public function on_upgrade() {
316 $key = $this->get_option( 'key' );
317
318 // Create the cache directory if it doesn't exist already.
319 if ( ! file_exists( AO_CCSS_DIR ) ) {
320 $this->create_ao_ccss_dir();
321 }
322
323 // Create a scheduled event for the queue.
324 if ( $this->is_api_active() && ! wp_next_scheduled( 'ao_ccss_queue' ) ) {
325 wp_schedule_event( time(), apply_filters( 'ao_ccss_queue_schedule', 'ao_ccss' ), 'ao_ccss_queue' );
326 }
327
328 // Create a scheduled event for log maintenance.
329 if ( $this->is_api_active() && ! wp_next_scheduled( 'ao_ccss_maintenance' ) ) {
330 wp_schedule_event( time(), 'twicedaily', 'ao_ccss_maintenance' );
331 }
332 }
333
334 public function check_upgrade() {
335 $db_version = get_option( 'autoptimize_ccss_version', '' );
336 if ( AO_CCSS_VER !== $db_version ) {
337 // check schedules & re-schedule if needed.
338 $this->on_upgrade();
339 // and update db_version.
340 update_option( 'autoptimize_ccss_version', AO_CCSS_VER );
341 }
342 }
343
344 public function ao_ccss_interval( $schedules ) {
345 // Let interval be configurable.
346 if ( ! defined( 'AO_CCSS_DEBUG_INTERVAL' ) ) {
347 $intsec = 600;
348 $inttxt = '10 minutes';
349 } else {
350 $intsec = AO_CCSS_DEBUG_INTERVAL;
351 if ( $intsec >= 120 ) {
352 $inttxt = $intsec / 60 . ' minutes';
353 } else {
354 $inttxt = $intsec . ' second(s)';
355 }
356 $this->log( 'Using custom WP-Cron interval of ' . $inttxt, 3 );
357 }
358
359 // Attach interval to schedule.
360 $schedules['ao_ccss'] = array(
361 'interval' => $intsec,
362 'display' => sprintf( __( 'Every %s (Autoptimize Crit. CSS)', 'autoptimize' ), $inttxt ),
363 );
364 return $schedules;
365 }
366
367 public function create_ao_ccss_dir() {
368 // Make sure dir to write ao_ccss exists and is writable.
369 if ( ! is_dir( AO_CCSS_DIR ) ) {
370 // TODO: use wp_mkdir_p() ?
371 $mkdirresp = @mkdir( AO_CCSS_DIR, 0775, true ); // @codingStandardsIgnoreLine
372 } else {
373 $mkdirresp = true;
374 }
375
376 // Make sure our index.html is there.
377 if ( ! is_file( AO_CCSS_DIR . 'index.html' ) ) {
378 $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>' );
379 } else {
380 $fileresp = true;
381 }
382
383 if ( true === $fileresp && true === $mkdirresp ) {
384 return true;
385 } else {
386 return false;
387 }
388 }
389
390 /**
391 * Helper function to determine if there is an active API key.
392 *
393 * @return bool
394 */
395 public function is_api_active() {
396 // using options instead of more complex $this->key_status (which gave some dependancy issues ... ;-) ).
397 $ao_ccss_key = $this->get_option( 'key' );
398 $ao_ccss_keyst = $this->get_option( 'keyst' );
399
400 if ( ! empty( $ao_ccss_key ) && $ao_ccss_keyst && 2 == $ao_ccss_keyst ) {
401 return true;
402 }
403
404 return false;
405 }
406
407 /**
408 * Helper function to determine if a rule is MANUAL.
409 *
410 * @param array $rule Rule to check.
411 *
412 * @return bool
413 */
414 public function is_rule_manual( $rule ) {
415 if ( is_array( $rule ) && false == $rule['hash'] && false != $rule['file'] ) {
416 return true;
417 }
418
419 return false;
420 }
421
422 /**
423 * Scheduled action to check an inactive key. Not part of autoptimizeCriticalCSSCron.php
424 * to allow us to only load the main cron logic if we have an active key to begin with.
425 */
426 public function ao_ccss_check_key() {
427 $ao_ccss_key = $this->get_option( 'key' );
428 $_result = $this->_core->ao_ccss_key_validation( $ao_ccss_key );
429 $_resmsg = ( true === $_result ) ? 'ok' : 'nok';
430 $this->log( 'Inactive key checked, result was ' . $_resmsg, 3 );
431 }
432 }
433