PluginProbe
Autoptimize / 3.0.0
Autoptimize v3.0.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 / autoptimizeCriticalCSSBase.php

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

430 lines 14.4 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 if ( ! wp_next_scheduled( 'ao_ccss_queue' ) ) {
101 // make sure the 10 minutes cron schedule is added.
102 add_filter( 'cron_schedules', array( $this, 'ao_ccss_interval' ) );
103
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
163 * @param int $lvl
164 *
165 * @return void
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
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
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 public function enqueue( $hash = '', $path = '', $type = 'is_page' ) {
215 // Enqueue is sometimes required on wp-admin requests, load it just-in-time.
216 if ( is_null( $this->_enqueue ) && $this->is_api_active() ) {
217 $this->_enqueue = new autoptimizeCriticalCSSEnqueue();
218 }
219
220 return $this->_enqueue->ao_ccss_enqueue( $hash, $path, $type );
221 }
222
223 /**
224 * Check auto-rules in CCSS Settings object
225 */
226 public function has_autorules() {
227 return $this->_settings->ao_ccss_has_autorules();
228 }
229
230 /**
231 * Get a Critical CSS option
232 *
233 * @param string $name The option name
234 *
235 * @return mixed
236 */
237 public function get_option( $name ) {
238 if ( is_null( $this->_options ) ) {
239 $this->fetch_options();
240 }
241
242 if ( isset( $this->_options[ $name ] ) ) {
243 return $this->_options[ $name ];
244 }
245
246 return null;
247 }
248
249 public function flush_options() {
250 $this->_options = null;
251 }
252
253 protected function fetch_options() {
254 if ( ! is_null( $this->_options ) ) {
255 return $this->_options;
256 }
257
258 $this->_options = array(
259 'css_defer' => autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer' ),
260 'css_defer_inline' => autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer_inline' ),
261 'rules_raw' => get_option( 'autoptimize_ccss_rules', false ),
262 'additional' => get_option( 'autoptimize_ccss_additional' ),
263 'queue_raw' => get_option( 'autoptimize_ccss_queue', false ),
264 'viewport' => get_option( 'autoptimize_ccss_viewport', false ),
265 'finclude' => get_option( 'autoptimize_ccss_finclude', false ),
266 'rtimelimit' => get_option( 'autoptimize_ccss_rtimelimit', '30' ),
267 'noptimize' => get_option( 'autoptimize_ccss_noptimize', false ),
268 'debug' => get_option( 'autoptimize_ccss_debug', false ),
269 'key' => apply_filters( 'autoptimize_filter_ccss_key', get_option( 'autoptimize_ccss_key' ) ),
270 'keyst' => get_option( 'autoptimize_ccss_keyst' ),
271 'loggedin' => get_option( 'autoptimize_ccss_loggedin', '1' ),
272 'forcepath' => get_option( 'autoptimize_ccss_forcepath', '1' ),
273 'servicestatus' => get_option( 'autoptimize_service_availablity' ),
274 'deferjquery' => get_option( 'autoptimize_ccss_deferjquery', false ),
275 'domain' => get_option( 'autoptimize_ccss_domain' ),
276 'unloadccss' => get_option( 'autoptimize_ccss_unloadccss', false ),
277 );
278
279 if ( strpos( $this->_options['domain'], 'http' ) === false && strpos( $this->_options['domain'], 'uggc' ) === 0 ) {
280 $this->_options['domain'] = str_rot13( $this->_options['domain'] );
281 } elseif ( strpos( $this->_options['domain'], 'http' ) !== false ) {
282 // not rot13'ed yet, do so now (goal; avoid migration plugins change the bound domain).
283 update_option( 'autoptimize_ccss_domain', str_rot13( $this->_options['domain'] ) );
284 }
285
286 // Setup the rules array.
287 if ( empty( $this->_options['rules_raw'] ) ) {
288 $this->_options['rules'] = array(
289 'paths' => array(),
290 'types' => array(),
291 );
292 } else {
293 $this->_options['rules'] = json_decode( $this->_options['rules_raw'], true );
294 }
295
296 // Setup the queue array.
297 if ( empty( $this->_options['queue_raw'] ) ) {
298 $this->_options['queue'] = array();
299 } else {
300 $this->_options['queue'] = json_decode( $this->_options['queue_raw'], true );
301 }
302
303 // Override API key if constant is defined.
304 if ( defined( 'AUTOPTIMIZE_CRITICALCSS_API_KEY' ) ) {
305 $this->_options['key'] = AUTOPTIMIZE_CRITICALCSS_API_KEY;
306 }
307
308 return $this->_options;
309 }
310
311 public function on_upgrade() {
312 $key = $this->get_option( 'key' );
313
314 // Create the cache directory if it doesn't exist already.
315 if ( ! file_exists( AO_CCSS_DIR ) ) {
316 $this->create_ao_ccss_dir();
317 }
318
319 // Create a scheduled event for the queue.
320 if ( $this->is_api_active() && ! wp_next_scheduled( 'ao_ccss_queue' ) ) {
321 wp_schedule_event( time(), apply_filters( 'ao_ccss_queue_schedule', 'ao_ccss' ), 'ao_ccss_queue' );
322 }
323
324 // Create a scheduled event for log maintenance.
325 if ( $this->is_api_active() && ! wp_next_scheduled( 'ao_ccss_maintenance' ) ) {
326 wp_schedule_event( time(), 'twicedaily', 'ao_ccss_maintenance' );
327 }
328 }
329
330 public function check_upgrade() {
331 $db_version = get_option( 'autoptimize_ccss_version', '' );
332 if ( AO_CCSS_VER !== $db_version ) {
333 // check schedules & re-schedule if needed.
334 $this->on_upgrade();
335 // and update db_version.
336 update_option( 'autoptimize_ccss_version', AO_CCSS_VER );
337 }
338 }
339
340 public function ao_ccss_interval( $schedules ) {
341 // Let interval be configurable.
342 if ( ! defined( 'AO_CCSS_DEBUG_INTERVAL' ) ) {
343 $intsec = 600;
344 $inttxt = '10 minutes';
345 } else {
346 $intsec = AO_CCSS_DEBUG_INTERVAL;
347 if ( $intsec >= 120 ) {
348 $inttxt = $intsec / 60 . ' minutes';
349 } else {
350 $inttxt = $intsec . ' second(s)';
351 }
352 $this->log( 'Using custom WP-Cron interval of ' . $inttxt, 3 );
353 }
354
355 // Attach interval to schedule.
356 $schedules['ao_ccss'] = array(
357 'interval' => $intsec,
358 'display' => __( 'Every ' . $inttxt . ' (Autoptimize Crit. CSS)' ),
359 );
360 return $schedules;
361 }
362
363 public function create_ao_ccss_dir() {
364 // Make sure dir to write ao_ccss exists and is writable.
365 if ( ! is_dir( AO_CCSS_DIR ) ) {
366 // TODO: use wp_mkdir_p()
367 $mkdirresp = @mkdir( AO_CCSS_DIR, 0775, true ); // @codingStandardsIgnoreLine
368 } else {
369 $mkdirresp = true;
370 }
371
372 // Make sure our index.html is there.
373 if ( ! is_file( AO_CCSS_DIR . 'index.html' ) ) {
374 $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>' );
375 } else {
376 $fileresp = true;
377 }
378
379 if ( true === $fileresp && true === $mkdirresp ) {
380 return true;
381 } else {
382 return false;
383 }
384 }
385
386 /**
387 * Helper function to determine if there is an active API key.
388 *
389 * @return bool
390 */
391 public function is_api_active() {
392 // using options instead of more complex $this->key_status (which gave some dependancy issues ... ;-) ).
393 $ao_ccss_key = $this->get_option( 'key' );
394 $ao_ccss_keyst = $this->get_option( 'keyst' );
395
396 if ( ! empty( $ao_ccss_key ) && $ao_ccss_keyst && 2 == $ao_ccss_keyst ) {
397 return true;
398 }
399
400 return false;
401 }
402
403 /**
404 * Helper function to determine if a rule is MANUAL.
405 *
406 * @param array $rule
407 *
408 * @return bool
409 */
410 public function is_rule_manual( $rule ) {
411 if ( is_array( $rule ) && false == $rule['hash'] && false != $rule['file'] ) {
412 return true;
413 }
414
415 return false;
416 }
417
418 /**
419 * Scheduled action to check an inactive key. Not part of autoptimizeCriticalCSSCron.php
420 * to allow us to only load the main cron logic if we have an active key to begin with.
421 *
422 */
423 public function ao_ccss_check_key() {
424 $ao_ccss_key = $this->get_option( 'key' );
425 $_result = $this->_core->ao_ccss_key_validation( $ao_ccss_key );
426 $_resmsg = ( true === $_result) ? 'ok' : 'nok';
427 $this->log( 'Inactive key checked, result was ' . $_resmsg, 3 );
428 }
429 }
430