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/autoptimizeCriticalCSSCron.php +314 -270 2.7.7 → trunk View file →
@@ -8,17 +8,18 @@
8 8 exit;
9 9 }
10 10
11 11 class autoptimizeCriticalCSSCron {
12 - public function __construct()
13 - {
14 - // fetch all options at once and populate them individually explicitely as globals.
15 - $all_options = autoptimizeCriticalCSSBase::fetch_options();
16 - foreach ( $all_options as $_option => $_value ) {
17 - global ${$_option};
18 - ${$_option} = $_value;
19 - }
12 + /**
13 + * Critical CSS object.
14 + *
15 + * @var object
16 + */
17 + protected $criticalcss;
20 18
19 + public function __construct() {
20 + $this->criticalcss = autoptimize()->criticalcss();
21 +
21 22 // Add queue control to a registered event.
22 23 add_action( 'ao_ccss_queue', array( $this, 'ao_ccss_queue_control' ) );
23 24 // Add cleaning job to a registered event.
24 25 add_action( 'ao_ccss_maintenance', array( $this, 'ao_ccss_cleaning' ) );
@@ -25,12 +26,13 @@
25 26 }
26 27
27 28 public function ao_ccss_queue_control() {
28 29 // The queue execution backend.
29 - global $ao_ccss_key;
30 - if ( ! isset( $ao_ccss_key ) || empty( $ao_ccss_key ) ) {
30 + $key = $this->criticalcss->get_option( 'key' );
31 +
32 + if ( empty( $key ) ) {
31 33 // no key set, not processing the queue!
32 - autoptimizeCriticalCSSCore::ao_ccss_log( 'No key set, so not processing queue.', 3 );
34 + $this->criticalcss->log( 'No key set, so not processing queue.', 3 );
33 35 return;
34 36 }
35 37
36 38 /**
@@ -55,9 +57,9 @@
55 57 $qdobj = json_decode( $qdobj_raw, true );
56 58 if ( $qdobj ) {
57 59 if ( 1 === $qdobj['enable'] ) {
58 60 $queue_debug = true;
59 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue operating in debug mode with the following settings: <' . $qdobj_raw . '>', 3 );
61 + $this->criticalcss->log( 'Queue operating in debug mode with the following settings: <' . $qdobj_raw . '>', 3 );
60 62 }
61 63 }
62 64 }
63 65
@@ -75,27 +77,39 @@
75 77 // Proceed with the queue if it's not already running.
76 78 if ( ! $queue_lock ) {
77 79
78 80 // Log queue start and create the lock file.
79 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control started', 3 );
81 + $this->criticalcss->log( 'Queue control started', 3 );
80 82 if ( touch( AO_CCSS_LOCK ) ) {
81 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control locked', 3 );
83 + $this->criticalcss->log( 'Queue control locked', 3 );
82 84 }
83 85
84 86 // Attach required variables.
85 - global $ao_ccss_queue;
86 - global $ao_ccss_rlimit;
87 + $queue = $this->criticalcss->get_option( 'queue' );
88 + $rtimelimit = $this->criticalcss->get_option( 'rtimelimit' );
87 89
88 - // Initialize job counters.
89 - $jc = 1;
90 - $jr = 1;
91 - $jt = count( $ao_ccss_queue );
90 + // make sure we have the queue and bail if not.
91 + if ( empty( $queue ) || ! is_array( $queue ) ) {
92 + $this->criticalcss->log( 'Job processing cannot work on an empty queue, aborting.', 3 );
93 + unlink( AO_CCSS_LOCK );
94 + return;
95 + }
92 96
97 + // Initialize counters.
98 + if ( empty( $rtimelimit ) || 0 == $rtimelimit ) {
99 + // no time limit set, let's go with 1000 seconds.
100 + $rtimelimit = 1000;
101 + }
102 + $mt = time() + (int) $rtimelimit; // maxtime queue processing can run.
103 + $jc = 1; // job count number.
104 + $jr = 1; // jobs requests number.
105 + $jt = count( $queue ); // number of jobs in queue.
106 +
93 107 // Sort queue by ascending job status (e.g. ERROR, JOB_ONGOING, JOB_QUEUED, NEW...).
94 - array_multisort( array_column( $ao_ccss_queue, 'jqstat' ), $ao_ccss_queue ); // @codingStandardsIgnoreLine
108 + array_multisort( array_column( $queue, 'jqstat' ), $queue ); // @codingStandardsIgnoreLine
95 109
96 110 // Iterates over the entire queue.
97 - foreach ( $ao_ccss_queue as $path => $jprops ) {
111 + foreach ( $queue as $path => $jprops ) {
98 112 // Prepare flags and target rule.
99 113 $update = false;
100 114 $deljob = false;
101 115 $rule_update = false;
@@ -102,15 +116,15 @@
102 116 $oldccssfile = false;
103 117 $trule = explode( '|', $jprops['rtarget'] );
104 118
105 119 // Log job count.
106 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Processing job ' . $jc . ' of ' . $jt . ' with id <' . $jprops['ljid'] . '> and status <' . $jprops['jqstat'] . '>', 3 );
120 + $this->criticalcss->log( 'Processing job ' . $jc . ' of ' . $jt . ' with id <' . $jprops['ljid'] . '> and status <' . $jprops['jqstat'] . '>', 3 );
107 121
108 122 // Process NEW jobs.
109 123 if ( 'NEW' == $jprops['jqstat'] ) {
110 124
111 125 // Log the new job.
112 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Found NEW job with local ID <' . $jprops['ljid'] . '>, starting its queue processing', 3 );
126 + $this->criticalcss->log( 'Found NEW job with local ID <' . $jprops['ljid'] . '>, starting its queue processing', 3 );
113 127
114 128 // Compare job and rule hashes (if any).
115 129 $hash = $this->ao_ccss_diff_hashes( $jprops['ljid'], $jprops['hash'], $jprops['hashes'], $jprops['rtarget'] );
116 130
@@ -115,29 +129,46 @@
115 129 $hash = $this->ao_ccss_diff_hashes( $jprops['ljid'], $jprops['hash'], $jprops['hashes'], $jprops['rtarget'] );
116 130
117 131 // If job hash is new or different of a previous one.
118 132 if ( $hash ) {
133 + if ( $jr > 2 ) {
134 + // we already posted 2 jobs to criticalcss.com, don't post more this run
135 + // but we can keep on processing the queue to keep it tidy.
136 + $this->criticalcss->log( 'Holding off on generating request for job with local ID <' . $jprops['ljid'] . '>, maximum number of POSTS reached.', 3 );
137 + continue;
138 + }
139 +
119 140 // Set job hash.
120 141 $jprops['hash'] = $hash;
121 142
122 - // If this is not the first job, wait 10 seconds before process next job due criticalcss.com API limits.
123 - if ( $jr > 1 ) {
124 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Waiting ' . AO_CCSS_SLEEP . ' seconds due to criticalcss.com API limits', 3 );
125 - sleep( AO_CCSS_SLEEP );
126 - }
127 -
128 143 // Dispatch the job generate request and increment request count.
129 144 $apireq = $this->ao_ccss_api_generate( $path, $queue_debug, $qdobj['htcode'] );
130 145 $jr++;
131 146
132 147 // NOTE: All the following conditions maps to the ones in admin_settings_queue.js.php.
133 - if ( 'JOB_QUEUED' == $apireq['job']['status'] || 'JOB_ONGOING' == $apireq['job']['status'] ) {
148 + if ( empty( $apireq ) ) {
149 + // ERROR: no response
150 + // Update job properties.
151 + $jprops['jqstat'] = 'NO_RESPONSE';
152 + $jprops['jrstat'] = 'NONE';
153 + $jprops['jvstat'] = 'NONE';
154 + $jprops['jftime'] = microtime( true );
155 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> request has no response, status now is <' . $jprops['jqstat'] . '>', 3 );
156 + } elseif ( array_key_exists( 'errorCode', $apireq ) && 'INVALID_JWT_TOKEN' == $apireq['errorCode'] ) {
157 + // ERROR: key validation
158 + // Update job properties.
159 + $jprops['jqstat'] = $apireq['errorCode'];
160 + $jprops['jrstat'] = $apireq['error'];
161 + $jprops['jvstat'] = 'NONE';
162 + $jprops['jftime'] = microtime( true );
163 + $this->criticalcss->log( 'API key validation error when processing job id <' . $jprops['ljid'] . '>, job status is now <' . $jprops['jqstat'] . '>', 3 );
164 + } elseif ( array_key_exists( 'job', $apireq ) && array_key_exists( 'status', $apireq['job'] ) && ( 'JOB_QUEUED' == $apireq['job']['status'] || 'JOB_ONGOING' == $apireq['job']['status'] ) ) {
134 165 // SUCCESS: request has a valid result.
135 166 // Update job properties.
136 167 $jprops['jid'] = $apireq['job']['id'];
137 168 $jprops['jqstat'] = $apireq['job']['status'];
138 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> generate request successful, remote id <' . $jprops['jid'] . '>, status now is <' . $jprops['jqstat'] . '>', 3 );
139 - } elseif ( 'STATUS_JOB_BAD' == $apireq['job']['status'] ) {
169 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> generate request successful, remote id <' . $jprops['jid'] . '>, status now is <' . $jprops['jqstat'] . '>', 3 );
170 + } elseif ( array_key_exists( 'job', $apireq ) && array_key_exists( 'status', $apireq['job'] ) && 'STATUS_JOB_BAD' == $apireq['job']['status'] ) {
140 171 // ERROR: concurrent requests
141 172 // Update job properties.
142 173 $jprops['jid'] = $apireq['job']['id'];
143 174 $jprops['jqstat'] = $apireq['job']['status'];
@@ -147,25 +178,9 @@
147 178 $jprops['jrstat'] = 'Baby did a bad bad thing';
148 179 }
149 180 $jprops['jvstat'] = 'NONE';
150 181 $jprops['jftime'] = microtime( true );
151 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Concurrent requests when processing job id <' . $jprops['ljid'] . '>, job status is now <' . $jprops['jqstat'] . '>', 3 );
152 - } elseif ( 'INVALID_JWT_TOKEN' == $apireq['errorCode'] ) {
153 - // ERROR: key validation
154 - // Update job properties.
155 - $jprops['jqstat'] = $apireq['errorCode'];
156 - $jprops['jrstat'] = $apireq['error'];
157 - $jprops['jvstat'] = 'NONE';
158 - $jprops['jftime'] = microtime( true );
159 - autoptimizeCriticalCSSCore::ao_ccss_log( 'API key validation error when processing job id <' . $jprops['ljid'] . '>, job status is now <' . $jprops['jqstat'] . '>', 3 );
160 - } elseif ( empty( $apireq ) ) {
161 - // ERROR: no response
162 - // Update job properties.
163 - $jprops['jqstat'] = 'NO_RESPONSE';
164 - $jprops['jrstat'] = 'NONE';
165 - $jprops['jvstat'] = 'NONE';
166 - $jprops['jftime'] = microtime( true );
167 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> request has no response, status now is <' . $jprops['jqstat'] . '>', 3 );
182 + $this->criticalcss->log( 'Concurrent requests when processing job id <' . $jprops['ljid'] . '>, job status is now <' . $jprops['jqstat'] . '>', 3 );
168 183 } else {
169 184 // UNKNOWN: unhandled generate exception
170 185 // Update job properties.
171 186 $jprops['jqstat'] = 'JOB_UNKNOWN';
@@ -171,10 +186,10 @@
171 186 $jprops['jqstat'] = 'JOB_UNKNOWN';
172 187 $jprops['jrstat'] = 'NONE';
173 188 $jprops['jvstat'] = 'NONE';
174 189 $jprops['jftime'] = microtime( true );
175 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> generate request has an UNKNOWN condition, status now is <' . $jprops['jqstat'] . '>, check log messages above for more information', 2 );
176 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job response was: ' . json_encode( $apireq ), 3 );
190 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> generate request has an UNKNOWN condition, status now is <' . $jprops['jqstat'] . '>, check log messages above for more information', 2 );
191 + $this->criticalcss->log( 'Job response was: ' . json_encode( $apireq ), 3 );
177 192 }
178 193 } else {
179 194 // SUCCESS: Job hash is equal to a previous one, so it's done
180 195 // Update job status and finish time.
@@ -179,9 +194,9 @@
179 194 // SUCCESS: Job hash is equal to a previous one, so it's done
180 195 // Update job status and finish time.
181 196 $jprops['jqstat'] = 'JOB_DONE';
182 197 $jprops['jftime'] = microtime( true );
183 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> requires no further processing, status now is <' . $jprops['jqstat'] . '>', 3 );
198 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> requires no further processing, status now is <' . $jprops['jqstat'] . '>', 3 );
184 199 }
185 200
186 201 // Set queue update flag.
187 202 $update = true;
@@ -188,19 +203,12 @@
188 203
189 204 } elseif ( 'JOB_QUEUED' == $jprops['jqstat'] || 'JOB_ONGOING' == $jprops['jqstat'] ) {
190 205 // Process QUEUED and ONGOING jobs
191 206 // Log the pending job.
192 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Found PENDING job with local ID <' . $jprops['ljid'] . '>, continuing its queue processing', 3 );
207 + $this->criticalcss->log( 'Found PENDING job with local ID <' . $jprops['ljid'] . '>, continuing its queue processing', 3 );
193 208
194 - // If this is not the first job, wait before process next job due criticalcss.com API limits.
195 - if ( $jr > 1 ) {
196 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Waiting ' . AO_CCSS_SLEEP . ' seconds due to criticalcss.com API limits', 3 );
197 - sleep( AO_CCSS_SLEEP );
198 - }
199 -
200 209 // Dispatch the job result request and increment request count.
201 210 $apireq = $this->ao_ccss_api_results( $jprops['jid'], $queue_debug, $qdobj['htcode'] );
202 - $jr++;
203 211
204 212 // NOTE: All the following condigitons maps to the ones in admin_settings_queue.js.php
205 213 // Replace API response values if queue debugging is enabled and some value is set.
206 214 if ( $queue_debug ) {
@@ -214,15 +222,23 @@
214 222 $apireq['validationStatus'] = $qdobj['validationStatus'];
215 223 }
216 224 }
217 225
218 - if ( 'JOB_QUEUED' == $apireq['status'] || 'JOB_ONGOING' == $apireq['status'] ) {
226 + if ( empty( $apireq ) || ! is_array( $apireq ) ) {
227 + // ERROR: no response
228 + // Update job properties.
229 + $jprops['jqstat'] = 'NO_RESPONSE';
230 + $jprops['jrstat'] = 'NONE';
231 + $jprops['jvstat'] = 'NONE';
232 + $jprops['jftime'] = microtime( true );
233 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> request has no response, status now is <' . $jprops['jqstat'] . '>', 3 );
234 + } elseif ( array_key_exists( 'status', $apireq ) && ( 'JOB_QUEUED' == $apireq['status'] || 'JOB_ONGOING' == $apireq['status'] ) ) {
219 235 // SUCCESS: request has a valid result
220 236 // Process a PENDING job
221 237 // Update job properties.
222 238 $jprops['jqstat'] = $apireq['status'];
223 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . '> unchanged', 3 );
224 - } elseif ( 'JOB_DONE' == $apireq['status'] ) {
239 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . '> unchanged', 3 );
240 + } elseif ( array_key_exists( 'status', $apireq ) && 'JOB_DONE' == $apireq['status'] ) {
225 241 // Process a DONE job
226 242 // New resultStatus from ccss.com "HTML_404", consider as "GOOD" for now.
227 243 if ( 'HTML_404' == $apireq['resultStatus'] ) {
228 244 $apireq['resultStatus'] = 'GOOD';
@@ -227,10 +243,10 @@
227 243 if ( 'HTML_404' == $apireq['resultStatus'] ) {
228 244 $apireq['resultStatus'] = 'GOOD';
229 245 }
230 246
231 - if ( 'GOOD' == $apireq['resultStatus'] && 'GOOD' == $apireq['validationStatus'] ) {
232 - // SUCCESS: GOOD job with GOOD validation
247 + if ( 'GOOD' == $apireq['resultStatus'] && ( 'GOOD' == $apireq['validationStatus'] || 'WARN' == $apireq['validationStatus'] ) ) {
248 + // SUCCESS: GOOD job with GOOD or WARN validation
233 249 // Update job properties.
234 250 $jprops['file'] = $this->ao_ccss_save_file( $apireq['css'], $trule, false );
235 251 $jprops['jqstat'] = $apireq['status'];
236 252 $jprops['jrstat'] = $apireq['resultStatus'];
@@ -236,19 +252,25 @@
236 252 $jprops['jrstat'] = $apireq['resultStatus'];
237 253 $jprops['jvstat'] = $apireq['validationStatus'];
238 254 $jprops['jftime'] = microtime( true );
239 255 $rule_update = true;
240 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . '>, file saved <' . $jprops['file'] . '>', 3 );
241 - } elseif ( 'GOOD' == $apireq['resultStatus'] && ( 'WARN' == $apireq['validationStatus'] || 'BAD' == $apireq['validationStatus'] || 'SCREENSHOT_WARN_BLANK' == $apireq['validationStatus'] ) ) {
242 - // SUCCESS: GOOD job with WARN or BAD validation
256 + do_action( 'autoptimize_action_ccss_cron_rule_saved', $jprops['rtarget'], $jprops['file'] );
257 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . '>, file saved <' . $jprops['file'] . '>', 3 );
258 + } elseif ( 'GOOD' == $apireq['resultStatus'] && ( 'BAD' == $apireq['validationStatus'] || 'SCREENSHOT_WARN_BLANK' == $apireq['validationStatus'] ) ) {
259 + // SUCCESS: GOOD job with BAD or SCREENSHOT_WARN_BLANK validation
243 260 // Update job properties.
244 - $jprops['file'] = $this->ao_ccss_save_file( $apireq['css'], $trule, true );
245 261 $jprops['jqstat'] = $apireq['status'];
246 262 $jprops['jrstat'] = $apireq['resultStatus'];
247 263 $jprops['jvstat'] = $apireq['validationStatus'];
248 264 $jprops['jftime'] = microtime( true );
249 - $rule_update = true;
250 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . ', file saved <' . $jprops['file'] . '> but requires REVIEW', 3 );
265 + if ( apply_filters( 'autoptimize_filter_ccss_save_review_rules', true ) ) {
266 + $jprops['file'] = $this->ao_ccss_save_file( $apireq['css'], $trule, true );
267 + $rule_update = true;
268 + do_action( 'autoptimize_action_ccss_cron_rule_saved', $jprops['rtarget'], $jprops['file'] );
269 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . ', file saved <' . $jprops['file'] . '> but requires REVIEW', 3 );
270 + } else {
271 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . ', file not saved because it required REVIEW.', 3 );
272 + }
251 273 } elseif ( 'GOOD' != $apireq['resultStatus'] && ( 'GOOD' != $apireq['validationStatus'] || 'WARN' != $apireq['validationStatus'] || 'BAD' != $apireq['validationStatus'] || 'SCREENSHOT_WARN_BLANK' != $apireq['validationStatus'] ) ) {
252 274 // ERROR: no GOOD, WARN or BAD results
253 275 // Update job properties.
254 276 $jprops['jqstat'] = $apireq['status'];
@@ -254,11 +276,11 @@
254 276 $jprops['jqstat'] = $apireq['status'];
255 277 $jprops['jrstat'] = $apireq['resultStatus'];
256 278 $jprops['jvstat'] = $apireq['validationStatus'];
257 279 $jprops['jftime'] = microtime( true );
258 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful but job FAILED, status now is <' . $jprops['jqstat'] . '>', 3 );
280 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> result request successful but job FAILED, status now is <' . $jprops['jqstat'] . '>', 3 );
259 281 $apireq['css'] = '/* critical css removed for DEBUG logging purposes */';
260 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job response was: ' . json_encode( $apireq ), 3 );
282 + $this->criticalcss->log( 'Job response was: ' . json_encode( $apireq ), 3 );
261 283 } else {
262 284 // UNKNOWN: unhandled JOB_DONE exception
263 285 // Update job properties.
264 286 $jprops['jqstat'] = 'JOB_UNKNOWN';
@@ -264,13 +286,13 @@
264 286 $jprops['jqstat'] = 'JOB_UNKNOWN';
265 287 $jprops['jrstat'] = $apireq['resultStatus'];
266 288 $jprops['jvstat'] = $apireq['validationStatus'];
267 289 $jprops['jftime'] = microtime( true );
268 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful but job is UNKNOWN, status now is <' . $jprops['jqstat'] . '>', 2 );
290 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> result request successful but job is UNKNOWN, status now is <' . $jprops['jqstat'] . '>', 2 );
269 291 $apireq['css'] = '/* critical css removed for DEBUG logging purposes */';
270 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job response was: ' . json_encode( $apireq ), 3 );
292 + $this->criticalcss->log( 'Job response was: ' . json_encode( $apireq ), 3 );
271 293 }
272 - } elseif ( 'JOB_FAILED' == $apireq['job']['status'] || 'STATUS_JOB_BAD' == $apireq['job']['status'] ) {
294 + } elseif ( array_key_exists( 'job', $apireq ) && is_array( $apireq['job'] ) && array_key_exists( 'status', $apireq['job'] ) && ( 'JOB_FAILED' == $apireq['job']['status'] || 'STATUS_JOB_BAD' == $apireq['job']['status'] ) ) {
273 295 // ERROR: failed job
274 296 // Update job properties.
275 297 $jprops['jqstat'] = $apireq['job']['status'];
276 298 if ( $apireq['job']['error'] ) {
@@ -279,10 +301,10 @@
279 301 $jprops['jrstat'] = 'Baby did a bad bad thing';
280 302 }
281 303 $jprops['jvstat'] = 'NONE';
282 304 $jprops['jftime'] = microtime( true );
283 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful but job FAILED, status now is <' . $jprops['jqstat'] . '>', 3 );
284 - } elseif ( 'This css no longer exists. Please re-generate it.' == $apireq['error'] ) {
305 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> result request successful but job FAILED, status now is <' . $jprops['jqstat'] . '>', 3 );
306 + } elseif ( array_key_exists( 'error', $apireq ) && 'This css no longer exists. Please re-generate it.' == $apireq['error'] ) {
285 307 // ERROR: CSS doesn't exist
286 308 // Update job properties.
287 309 $jprops['jqstat'] = 'NO_CSS';
288 310 $jprops['jrstat'] = $apireq['error'];
@@ -287,17 +309,9 @@
287 309 $jprops['jqstat'] = 'NO_CSS';
288 310 $jprops['jrstat'] = $apireq['error'];
289 311 $jprops['jvstat'] = 'NONE';
290 312 $jprops['jftime'] = microtime( true );
291 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful but job FAILED, status now is <' . $jprops['jqstat'] . '>', 3 );
292 - } elseif ( empty( $apireq ) ) {
293 - // ERROR: no response
294 - // Update job properties.
295 - $jprops['jqstat'] = 'NO_RESPONSE';
296 - $jprops['jrstat'] = 'NONE';
297 - $jprops['jvstat'] = 'NONE';
298 - $jprops['jftime'] = microtime( true );
299 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> request has no response, status now is <' . $jprops['jqstat'] . '>', 3 );
313 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> result request successful but job FAILED, status now is <' . $jprops['jqstat'] . '>', 3 );
300 314 } else {
301 315 // UNKNOWN: unhandled results exception
302 316 // Update job properties.
303 317 $jprops['jqstat'] = 'JOB_UNKNOWN';
@@ -303,9 +317,9 @@
303 317 $jprops['jqstat'] = 'JOB_UNKNOWN';
304 318 $jprops['jrstat'] = 'NONE';
305 319 $jprops['jvstat'] = 'NONE';
306 320 $jprops['jftime'] = microtime( true );
307 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request has an UNKNOWN condition, status now is <' . $jprops['jqstat'] . '>, check log messages above for more information', 2 );
321 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> result request has an UNKNOWN condition, status now is <' . $jprops['jqstat'] . '>, check log messages above for more information', 2 );
308 322 }
309 323
310 324 // Set queue update flag.
311 325 $update = true;
@@ -320,33 +334,33 @@
320 334 // Persist updated queue object.
321 335 if ( $update ) {
322 336 if ( ! $deljob ) {
323 337 // Update properties of a NEW or PENDING job...
324 - $ao_ccss_queue[ $path ] = $jprops;
338 + $queue[ $path ] = $jprops;
325 339 } else {
326 340 // ...or remove the DONE job.
327 - unset( $ao_ccss_queue[ $path ] );
328 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> is DONE and was removed from the queue', 3 );
341 + unset( $queue[ $path ] );
342 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> is DONE and was removed from the queue', 3 );
329 343 }
330 344
331 345 // Update queue object.
332 - $ao_ccss_queue_raw = json_encode( $ao_ccss_queue );
333 - update_option( 'autoptimize_ccss_queue', $ao_ccss_queue_raw, false );
334 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue updated by job id <' . $jprops['ljid'] . '>', 3 );
346 + $queue_raw = json_encode( $queue );
347 + update_option( 'autoptimize_ccss_queue', $queue_raw, false );
348 + $this->criticalcss->log( 'Queue updated by job id <' . $jprops['ljid'] . '>', 3 );
335 349
336 350 // Update target rule.
337 351 if ( $rule_update ) {
338 352 $this->ao_ccss_rule_update( $jprops['ljid'], $jprops['rtarget'], $jprops['file'], $jprops['hash'] );
339 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> updated the target rule <' . $jprops['rtarget'] . '>', 3 );
353 + $this->criticalcss->log( 'Job id <' . $jprops['ljid'] . '> updated the target rule <' . $jprops['rtarget'] . '>', 3 );
340 354 }
341 355 } else {
342 356 // Or log no queue action.
343 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Nothing to do on this job', 3 );
357 + $this->criticalcss->log( 'Nothing to do on this job', 3 );
344 358 }
345 359
346 - // Break the loop if request limit is set and was reached.
347 - if ( $ao_ccss_rlimit && $ao_ccss_rlimit == $jr ) {
348 - autoptimizeCriticalCSSCore::ao_ccss_log( 'The limit of ' . $ao_ccss_rlimit . ' request(s) to criticalcss.com was reached, queue control must finish now', 3 );
360 + // Break the loop if request time limit is (almost exceeded).
361 + if ( time() > $mt ) {
362 + $this->criticalcss->log( 'The time limit of ' . $rtimelimit . ' seconds was exceeded, queue control must finish now', 3 );
349 363 break;
350 364 }
351 365
352 366 // Increment job counter.
@@ -355,15 +369,15 @@
355 369
356 370 // Remove the lock file and log the queue end.
357 371 if ( file_exists( AO_CCSS_LOCK ) ) {
358 372 unlink( AO_CCSS_LOCK );
359 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control unlocked', 3 );
373 + $this->criticalcss->log( 'Queue control unlocked', 3 );
360 374 }
361 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control finished', 3 );
375 + $this->criticalcss->log( 'Queue control finished', 3 );
362 376
363 377 // Log that queue is locked.
364 378 } else {
365 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue is already running, skipping the attempt to run it again', 3 );
379 + $this->criticalcss->log( 'Queue is already running, skipping the attempt to run it again', 3 );
366 380 }
367 381 }
368 382
369 383 public function ao_ccss_diff_hashes( $ljid, $hash, $hashes, $rule ) {
@@ -372,9 +386,9 @@
372 386 if ( 1 == count( $hashes ) ) {
373 387 // Job with a single hash
374 388 // Set job hash.
375 389 $hash = $hashes[0];
376 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> updated with SINGLE hash <' . $hash . '>', 3 );
390 + $this->criticalcss->log( 'Job id <' . $ljid . '> updated with SINGLE hash <' . $hash . '>', 3 );
377 391 } else {
378 392 // Job with multiple hashes
379 393 // Loop through hashes to concatenate them.
380 394 $nhash = '';
@@ -383,18 +397,18 @@
383 397 }
384 398
385 399 // Set job hash.
386 400 $hash = md5( $nhash );
387 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> updated with a COMPOSITE hash <' . $hash . '>', 3 );
401 + $this->criticalcss->log( 'Job id <' . $ljid . '> updated with a COMPOSITE hash <' . $hash . '>', 3 );
388 402 }
389 403
390 404 // STEP 2: compare job to existing jobs to prevent double submission for same type+hash.
391 - global $ao_ccss_queue;
405 + $queue = $this->criticalcss->get_option( 'queue' );
392 406
393 - foreach ( $ao_ccss_queue as $queue_item ) {
394 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Comparing <' . $rule . $hash . '> with <' . $queue_item['rtarget'] . $queue_item['hash'] . '>', 3 );
407 + foreach ( $queue as $queue_item ) {
408 + $this->criticalcss->log( 'Comparing <' . $rule . $hash . '> with <' . $queue_item['rtarget'] . $queue_item['hash'] . '>', 3 );
395 409 if ( $queue_item['hash'] == $hash && $queue_item['rtarget'] == $rule && in_array( $queue_item['jqstat'], array( 'JOB_QUEUED', 'JOB_ONGOING', 'JOB_DONE' ) ) ) {
396 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> matches the already pending job <' . $queue_item['ljid'] . '>', 3 );
410 + $this->criticalcss->log( 'Job id <' . $ljid . '> matches the already pending job <' . $queue_item['ljid'] . '>', 3 );
397 411 return false;
398 412 }
399 413 }
400 414
@@ -399,32 +413,42 @@
399 413 }
400 414
401 415 // STEP 3: compare job and existing rule (if any) hashes
402 416 // Attach required arrays.
403 - global $ao_ccss_rules;
417 + $rules = $this->criticalcss->get_option( 'rules' );
404 418
405 419 // Prepare rule variables.
406 420 $trule = explode( '|', $rule );
407 - $srule = $ao_ccss_rules[ $trule[0] ][ $trule[1] ];
421 + if ( is_array( $trule ) && ! empty( $trule ) && array_key_exists( $trule[1], $rules[ $trule[0] ] ) ) {
422 + $srule = $rules[ $trule[0] ][ $trule[1] ];
423 + } else {
424 + $srule = '';
425 + }
408 426
427 + // If hash is empty, set it to now for a "forced job".
428 + if ( empty( $hash ) ) {
429 + $hash = 'new';
430 + $this->criticalcss->log( 'Job id <' . $ljid . '> had no hash, assuming forced job so setting hash to new', 3 );
431 + }
432 +
409 433 // Check if a MANUAL rule exist and return false.
410 434 if ( ! empty( $srule ) && ( 0 == $srule['hash'] && 0 != $srule['file'] ) ) {
411 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> matches the MANUAL rule <' . $trule[0] . '|' . $trule[1] . '>', 3 );
435 + $this->criticalcss->log( 'Job id <' . $ljid . '> matches the MANUAL rule <' . $trule[0] . '|' . $trule[1] . '>', 3 );
412 436 return false;
413 437 } elseif ( ! empty( $srule ) ) {
414 438 // Check if an AUTO rule exist.
415 439 if ( $hash === $srule['hash'] && is_file( AO_CCSS_DIR . $srule['file'] ) && 0 != filesize( AO_CCSS_DIR . $srule['file'] ) ) {
416 440 // Check if job hash matches rule, if the CCSS file exists said file is not empty and return FALSE is so.
417 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> with hash <' . $hash . '> MATCH the one in rule <' . $trule[0] . '|' . $trule[1] . '>', 3 );
441 + $this->criticalcss->log( 'Job id <' . $ljid . '> with hash <' . $hash . '> MATCH the one in rule <' . $trule[0] . '|' . $trule[1] . '>', 3 );
418 442 return false;
419 443 } else {
420 444 // Or return the new hash if they differ.
421 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> with hash <' . $hash . '> DOES NOT MATCH the one in rule <' . $trule[0] . '|' . $trule[1] . '> or rule\'s CCSS file was invalid.', 3 );
445 + $this->criticalcss->log( 'Job id <' . $ljid . '> with hash <' . $hash . '> DOES NOT MATCH the one in rule <' . $trule[0] . '|' . $trule[1] . '> or rule\'s CCSS file was invalid.', 3 );
422 446 return $hash;
423 447 }
424 448 } else {
425 - // Or just return the hash if no rule exist yet.
426 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> with hash <' . $hash . '> has no rule yet', 3 );
449 + // Return the hash for a job that has no rule yet.
450 + $this->criticalcss->log( 'Job id <' . $ljid . '> with hash <' . $hash . '> has no rule yet', 3 );
427 451 return $hash;
428 452 }
429 453 }
430 454
@@ -430,16 +454,13 @@
430 454
431 455 public function ao_ccss_api_generate( $path, $debug, $dcode ) {
432 456 // POST jobs to criticalcss.com and return responses
433 457 // Get key and key status.
434 - global $ao_ccss_key;
435 - global $ao_ccss_keyst;
436 - $key = $ao_ccss_key;
437 - $key_status = $ao_ccss_keyst;
458 + $key = $this->criticalcss->get_option( 'key' );
459 + $key_status = $this->criticalcss->get_option( 'keyst' );
460 + $noptimize = $this->criticalcss->get_option( 'noptimize' );
438 461
439 462 // Prepare full URL to request.
440 - global $ao_ccss_noptimize;
441 -
442 463 $site_host = get_site_url();
443 464 $site_path = parse_url( $site_host, PHP_URL_PATH );
444 465
445 466 if ( ! empty( $site_path ) ) {
@@ -448,15 +469,15 @@
448 469
449 470 // Logic to bind to one domain to avoid site clones of sites would
450 471 // automatically begin spawning requests to criticalcss.com which has
451 472 // a per domain cost.
452 - global $ao_ccss_domain;
453 - if ( empty( $ao_ccss_domain ) ) {
473 + $domain = $this->criticalcss->get_option( 'domain' );
474 + if ( empty( $domain ) ) {
454 475 // first request being done, update option to allow future requests are only allowed if from same domain.
455 476 update_option( 'autoptimize_ccss_domain', str_rot13( $site_host ) );
456 - } elseif ( trim( $ao_ccss_domain, '\'"' ) !== 'none' && parse_url( $site_host, PHP_URL_HOST ) !== parse_url( $ao_ccss_domain, PHP_URL_HOST ) && apply_filters( 'autoptimize_filter_ccss_bind_domain', true ) ) {
477 + } elseif ( trim( $domain, '\'"' ) !== 'none' && parse_url( $site_host, PHP_URL_HOST ) !== parse_url( $domain, PHP_URL_HOST ) && apply_filters( 'autoptimize_filter_ccss_bind_domain', true ) ) {
457 478 // not the same domain, log as error and return without posting to criticalcss.com.
458 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Request for domain ' . $site_host . ' does not match bound domain ' . $ao_ccss_domain . ' so not proceeding.', 2 );
479 + $this->criticalcss->log( 'Request for domain ' . $site_host . ' does not match bound domain ' . $domain . ' so not proceeding.', 2 );
459 480 return false;
460 481 }
461 482
462 483 $src_url = $site_host . $path;
@@ -461,110 +482,119 @@
461 482
462 483 $src_url = $site_host . $path;
463 484
464 485 // Avoid AO optimizations if required by config or avoid lazyload if lazyload is active in AO.
465 - if ( ! empty( $ao_ccss_noptimize ) ) {
486 + if ( ! empty( $noptimize ) ) {
466 487 $src_url .= '?ao_noptirocket=1';
467 - } elseif ( class_exists( 'autoptimizeImages', false ) && autoptimizeImages::should_lazyload_wrapper() ) {
488 + } elseif ( ( class_exists( 'autoptimizeImages', false ) && autoptimizeImages::should_lazyload_wrapper() ) || apply_filters( 'autoptimize_filter_ccss_enforce_nolazy', false ) ) {
468 489 $src_url .= '?ao_nolazy=1';
469 490 }
470 491
471 492 $src_url = apply_filters( 'autoptimize_filter_ccss_cron_srcurl', $src_url );
472 493
473 - // Initialize request body.
474 - $body = array();
475 - $body['url'] = $src_url;
476 - $body['aff'] = 1;
477 - $body['aocssv'] = AO_CCSS_VER;
494 + if ( true !== autoptimizeUtils::is_local_server( parse_url( $src_url, PHP_URL_HOST ) ) ) {
495 + // Initialize request body.
496 + $body = array();
497 + $body['url'] = $src_url;
498 + $body['aff'] = 1;
499 + $body['aocssv'] = AO_CCSS_VER;
478 500
479 - // Prepare and add viewport size to the body if available.
480 - $viewport = autoptimizeCriticalCSSCore::ao_ccss_viewport();
481 - if ( ! empty( $viewport['w'] ) && ! empty( $viewport['h'] ) ) {
482 - $body['width'] = $viewport['w'];
483 - $body['height'] = $viewport['h'];
484 - }
501 + // Prepare and add viewport size to the body if available.
502 + $viewport = $this->criticalcss->viewport();
503 + if ( ! empty( $viewport['w'] ) && ! empty( $viewport['h'] ) ) {
504 + $body['width'] = $viewport['w'];
505 + $body['height'] = $viewport['h'];
506 + }
485 507
486 - // Prepare and add forceInclude to the body if available.
487 - global $ao_ccss_finclude;
488 - $finclude = $this->ao_ccss_finclude( $ao_ccss_finclude );
489 - if ( ! empty( $finclude ) ) {
490 - $body['forceInclude'] = $finclude;
491 - }
508 + // Prepare and add forceInclude to the body if available.
509 + $finclude = $this->criticalcss->get_option( 'finclude' );
510 + $finclude = $this->ao_ccss_finclude( $finclude );
511 + if ( ! empty( $finclude ) ) {
512 + $body['forceInclude'] = $finclude;
513 + }
492 514
493 - // Add filter to allow the body array to be altered (e.g. to add customPageHeaders).
494 - $body = apply_filters( 'autoptimize_ccss_cron_api_generate_body', $body );
515 + // Add filter to allow the body array to be altered (e.g. to add customPageHeaders).
516 + $body = apply_filters( 'autoptimize_ccss_cron_api_generate_body', $body );
495 517
496 - // Body must be json and log it.
497 - $body = json_encode( $body );
498 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request body is ' . $body, 3 );
518 + // Body must be json and log it.
519 + $body = json_encode( $body, JSON_UNESCAPED_SLASHES );
520 + $this->criticalcss->log( 'criticalcss.com: POST generate request body is ' . $body, 3 );
499 521
500 - // Prepare the request.
501 - $url = esc_url_raw( AO_CCSS_API . 'generate?aover=' . AO_CCSS_VER );
502 - $args = array(
503 - 'headers' => array(
504 - 'User-Agent' => 'Autoptimize v' . AO_CCSS_VER,
505 - 'Content-type' => 'application/json; charset=utf-8',
506 - 'Authorization' => 'JWT ' . $key,
507 - 'Connection' => 'close',
508 - ),
509 - 'body' => $body,
510 - );
522 + // Prepare the request.
523 + $url = esc_url_raw( AO_CCSS_API . 'generate?aover=' . AO_CCSS_VER );
524 + $args = array(
525 + 'headers' => apply_filters(
526 + 'autoptimize_ccss_cron_api_generate_headers',
527 + array(
528 + 'User-Agent' => 'Autoptimize v' . AO_CCSS_VER,
529 + 'Content-type' => 'application/json; charset=utf-8',
530 + 'Authorization' => 'JWT ' . $key,
531 + 'Connection' => 'close',
532 + )
533 + ),
534 + 'body' => $body,
535 + );
511 536
512 - // Dispatch the request and store its response code.
513 - $req = wp_safe_remote_post( $url, $args );
514 - $code = wp_remote_retrieve_response_code( $req );
515 - $body = json_decode( wp_remote_retrieve_body( $req ), true );
537 + // Dispatch the request and store its response code.
538 + $req = wp_safe_remote_post( $url, $args );
539 + $code = wp_remote_retrieve_response_code( $req );
540 + $body = json_decode( wp_remote_retrieve_body( $req ), true );
516 541
517 - if ( $debug && $dcode ) {
518 - // If queue debug is active, change response code.
519 - $code = $dcode;
520 - }
542 + if ( $debug && $dcode ) {
543 + // If queue debug is active, change response code.
544 + $code = $dcode;
545 + }
521 546
522 - if ( 200 == $code ) {
523 - // Response code is OK.
524 - // Workaround criticalcss.com non-RESTful reponses.
525 - if ( 'JOB_QUEUED' == $body['job']['status'] || 'JOB_ONGOING' == $body['job']['status'] || 'STATUS_JOB_BAD' == $body['job']['status'] ) {
526 - // Log successful and return encoded request body.
527 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied successfully', 3 );
547 + if ( 200 == $code ) {
548 + // Response code is OK.
549 + // Workaround criticalcss.com non-RESTful reponses.
550 + if ( 'JOB_QUEUED' == $body['job']['status'] || 'JOB_ONGOING' == $body['job']['status'] || 'STATUS_JOB_BAD' == $body['job']['status'] ) {
551 + // Log successful and return encoded request body.
552 + $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied successfully', 3 );
528 553
529 - // This code also means the key is valid, so cache key status for 24h if not already cached.
530 - if ( ( ! $key_status || 2 != $key_status ) && $key ) {
531 - update_option( 'autoptimize_ccss_keyst', 2 );
532 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: API key is valid, updating key status', 3 );
554 + // This code also means the key is valid, so cache key status for 24h if not already cached.
555 + if ( ( ! $key_status || 2 != $key_status ) && $key ) {
556 + update_option( 'autoptimize_ccss_keyst', 2 );
557 + $this->criticalcss->log( 'criticalcss.com: API key is valid, updating key status', 3 );
558 + }
559 +
560 + // Return the request body.
561 + return $body;
562 + } else {
563 + // Log successful requests with invalid reponses.
564 + $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with code <' . $code . '> and an UNKNOWN error condition, body follows...', 2 );
565 + $this->criticalcss->log( print_r( $body, true ), 2 );
566 + return $body;
533 567 }
568 + } else {
569 + // Response code is anything else.
570 + // Log failed request with a valid response code and return body.
571 + if ( $code ) {
572 + $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with error code <' . $code . '>, body follows...', 2 );
573 + $this->criticalcss->log( print_r( $body, true ), 2 );
534 574
535 - // Return the request body.
536 - return $body;
537 - } else {
538 - // Log successful requests with invalid reponses.
539 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with code <' . $code . '> and an UNKNOWN error condition, body follows...', 2 );
540 - autoptimizeCriticalCSSCore::ao_ccss_log( print_r( $body, true ), 2 );
541 - return $body;
542 - }
543 - } else {
544 - // Response code is anything else.
545 - // Log failed request with a valid response code and return body.
546 - if ( $code ) {
547 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with error code <' . $code . '>, body follows...', 2 );
548 - autoptimizeCriticalCSSCore::ao_ccss_log( print_r( $body, true ), 2 );
575 + if ( 401 == $code ) {
576 + // If request is unauthorized, also clear key status.
577 + update_option( 'autoptimize_ccss_keyst', 1 );
578 + $this->criticalcss->log( 'criticalcss.com: API key is invalid, updating key status', 3 );
579 + }
549 580
550 - if ( 401 == $code ) {
551 - // If request is unauthorized, also clear key status.
552 - update_option( 'autoptimize_ccss_keyst', 1 );
553 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: API key is invalid, updating key status', 3 );
554 - }
581 + // Return the request body.
582 + return $body;
583 + } else {
584 + // Log failed request with no response and return false.
585 + $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> has no response, this could be a service timeout', 2 );
586 + if ( is_wp_error( $req ) ) {
587 + $this->criticalcss->log( $req->get_error_message(), 2 );
588 + }
555 589
556 - // Return the request body.
557 - return $body;
558 - } else {
559 - // Log failed request with no response and return false.
560 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> has no response, this could be a service timeout', 2 );
561 - if ( is_wp_error( $req ) ) {
562 - autoptimizeCriticalCSSCore::ao_ccss_log( $req->get_error_message(), 2 );
590 + return false;
563 591 }
564 -
565 - return false;
566 592 }
593 + } else {
594 + // localhost/ private network server, no CCSS possible.
595 + $this->criticalcss->log( 'ccss cron: job not created at ccss.com as for local server', 3 );
596 + return false;
567 597 }
568 598 }
569 599
570 600 public function ao_ccss_api_results( $jobid, $debug, $dcode ) {
@@ -569,18 +599,20 @@
569 599
570 600 public function ao_ccss_api_results( $jobid, $debug, $dcode ) {
571 601 // GET jobs from criticalcss.com and return responses
572 602 // Get key.
573 - global $ao_ccss_key;
574 - $key = $ao_ccss_key;
603 + $key = $this->criticalcss->get_option( 'key' );
575 604
576 605 // Prepare the request.
577 606 $url = AO_CCSS_API . 'results?resultId=' . $jobid;
578 607 $args = array(
579 - 'headers' => array(
580 - 'User-Agent' => 'Autoptimize CriticalCSS Power-Up v' . AO_CCSS_VER,
581 - 'Authorization' => 'JWT ' . $key,
582 - 'Connection' => 'close',
608 + 'headers' => apply_filters(
609 + 'autoptimize_ccss_cron_api_generate_headers',
610 + array(
611 + 'User-Agent' => 'Autoptimize CriticalCSS Power-Up v' . AO_CCSS_VER,
612 + 'Authorization' => 'JWT ' . $key,
613 + 'Connection' => 'close',
614 + )
583 615 ),
584 616 );
585 617
586 618 // Dispatch the request and store its response code.
@@ -597,19 +629,19 @@
597 629 // Response code is OK.
598 630 if ( is_array( $body ) && ( array_key_exists( 'status', $body ) || array_key_exists( 'job', $body ) ) && ( 'JOB_QUEUED' == $body['status'] || 'JOB_ONGOING' == $body['status'] || 'JOB_DONE' == $body['status'] || 'JOB_FAILED' == $body['status'] || 'JOB_UNKNOWN' == $body['status'] || 'STATUS_JOB_BAD' == $body['job']['status'] ) ) {
599 631 // Workaround criticalcss.com non-RESTful reponses
600 632 // Log successful and return encoded request body.
601 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied successfully', 3 );
633 + $this->criticalcss->log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied successfully', 3 );
602 634 return $body;
603 635 } elseif ( is_array( $body ) && ( array_key_exists( 'error', $body ) && 'This css no longer exists. Please re-generate it.' == $body['error'] ) ) {
604 636 // Handle no CSS reply
605 637 // Log no CSS error and return encoded request body.
606 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied successfully but the CSS for it does not exist anymore', 3 );
638 + $this->criticalcss->log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied successfully but the CSS for it does not exist anymore', 3 );
607 639 return $body;
608 640 } else {
609 641 // Log failed request and return false.
610 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied with code <' . $code . '> and an UNKNOWN error condition, body follows...', 2 );
611 - autoptimizeCriticalCSSCore::ao_ccss_log( print_r( $body, true ), 2 );
642 + $this->criticalcss->log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied with code <' . $code . '> and an UNKNOWN error condition, body follows...', 2 );
643 + $this->criticalcss->log( print_r( $body, true ), 2 );
612 644 return false;
613 645 }
614 646 } else {
615 647 // Response code is anything else
@@ -614,14 +646,14 @@
614 646 } else {
615 647 // Response code is anything else
616 648 // Log failed request with a valid response code and return body.
617 649 if ( $code ) {
618 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied with error code <' . $code . '>, body follows...', 2 );
619 - autoptimizeCriticalCSSCore::ao_ccss_log( print_r( $body, true ), 2 );
650 + $this->criticalcss->log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied with error code <' . $code . '>, body follows...', 2 );
651 + $this->criticalcss->log( print_r( $body, true ), 2 );
620 652 if ( 401 == $code ) {
621 653 // If request is unauthorized, also clear key status.
622 654 update_option( 'autoptimize_ccss_keyst', 1 );
623 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: API key is invalid, updating key status', 3 );
655 + $this->criticalcss->log( 'criticalcss.com: API key is invalid, updating key status', 3 );
624 656 }
625 657
626 658 // Return the request body.
627 659 return $body;
@@ -626,9 +658,9 @@
626 658 // Return the request body.
627 659 return $body;
628 660 } else {
629 661 // Log failed request with no response and return false.
630 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> has no response, this could be a service timeout', 2 );
662 + $this->criticalcss->log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> has no response, this could be a service timeout', 2 );
631 663 return false;
632 664 }
633 665 }
634 666 }
@@ -645,41 +677,42 @@
645 677 // Prepare target rule, filename and content.
646 678 $filename = false;
647 679 $content = $ccss;
648 680
649 - if ( autoptimizeCriticalCSSCore::ao_ccss_check_contents( $content ) ) {
681 + if ( $this->criticalcss->check_contents( $content ) ) {
650 682 // Sanitize content, set filename and try to save file.
651 683 $file = AO_CCSS_DIR . 'ccss_' . md5( $ccss . $target[1] ) . $rmark . '.css';
652 684 $status = file_put_contents( $file, $content, LOCK_EX );
653 685 $filename = pathinfo( $file, PATHINFO_BASENAME );
654 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Critical CSS file for the rule <' . $target[0] . '|' . $target[1] . '> was saved as <' . $filename . '>, size in bytes is <' . $status . '>', 3 );
686 + $this->criticalcss->log( 'Critical CSS file for the rule <' . $target[0] . '|' . $target[1] . '> was saved as <' . $filename . '>, size in bytes is <' . $status . '>', 3 );
655 687
656 688 if ( ! $status ) {
657 689 // If file has not been saved, reset filename.
658 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Critical CSS file <' . $filename . '> could not be not saved', 2 );
690 + $this->criticalcss->log( 'Critical CSS file <' . $filename . '> could not be not saved', 2 );
659 691 $filename = false;
660 692 return $filename;
661 693 }
662 694 } else {
663 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Critical CSS received did not pass content check', 2 );
695 + $this->criticalcss->log( 'Critical CSS received did not pass content check', 2 );
664 696 return $filename;
665 697 }
666 698
667 699 // Remove old critical CSS if a previous one existed in the rule and if that file exists in filesystem
668 - // NOTE: out of scope critical CSS file removal (issue #5)
669 700 // Attach required arrays.
670 - global $ao_ccss_rules;
701 + $rules = $this->criticalcss->get_option( 'rules' );
671 702
672 - // Prepare rule variables.
673 - $srule = $ao_ccss_rules[ $target[0] ][ $target[1] ];
674 - $oldfile = $srule['file'];
703 + // Only proceed if the rule already existed.
704 + if ( array_key_exists( $target[1], $rules[ $target[0] ] ) ) {
705 + $srule = $rules[ $target[0] ][ $target[1] ];
706 + $oldfile = $srule['file'];
675 707
676 - if ( $oldfile && $oldfile !== $filename ) {
677 - $delfile = AO_CCSS_DIR . $oldfile;
678 - if ( file_exists( $delfile ) ) {
679 - $unlinkst = unlink( $delfile );
680 - if ( $unlinkst ) {
681 - autoptimizeCriticalCSSCore::ao_ccss_log( 'A previous critical CSS file <' . $oldfile . '> was removed for the rule <' . $target[0] . '|' . $target[1] . '>', 3 );
708 + if ( $oldfile && $oldfile !== $filename ) {
709 + $delfile = AO_CCSS_DIR . $oldfile;
710 + if ( file_exists( $delfile ) ) {
711 + $unlinkst = unlink( $delfile );
712 + if ( $unlinkst ) {
713 + $this->criticalcss->log( 'A previous critical CSS file <' . $oldfile . '> was removed for the rule <' . $target[0] . '|' . $target[1] . '>', 3 );
714 + }
682 715 }
683 716 }
684 717 }
685 718
@@ -689,21 +722,25 @@
689 722
690 723 public function ao_ccss_rule_update( $ljid, $srule, $file, $hash ) {
691 724 // Update or create a rule
692 725 // Attach required arrays.
693 - global $ao_ccss_rules;
726 + $rules = $this->criticalcss->get_option( 'rules' );
694 727
695 728 // Prepare rule variables.
696 729 $trule = explode( '|', $srule );
697 - $rule = $ao_ccss_rules[ $trule[0] ][ $trule[1] ];
730 + if ( array_key_exists( $trule[1], $rules[ $trule[0] ] ) ) {
731 + $rule = $rules[ $trule[0] ][ $trule[1] ];
732 + } else {
733 + $rule = array();
734 + }
698 735 $action = false;
699 736 $rtype = '';
700 737
701 - if ( 0 === $rule['hash'] && 0 !== $rule['file'] ) {
738 + if ( is_array( $rule ) && array_key_exists( 'hash', $rule ) && 0 === $rule['hash'] && array_key_exists( 'file', $rule ) && 0 !== $rule['file'] ) {
702 739 // manual rule, don't ever overwrite.
703 740 $action = 'NOT UPDATED';
704 741 $rtype = 'MANUAL';
705 - } elseif ( 0 === $rule['hash'] && 0 === $rule['file'] ) {
742 + } elseif ( is_array( $rule ) && array_key_exists( 'hash', $rule ) && 0 === $rule['hash'] && array_key_exists( 'file', $rule ) && 0 === $rule['file'] ) {
706 743 // If this is an user created AUTO rule with no hash and file yet, update its hash and filename
707 744 // Set rule hash, file and action flag.
708 745 $rule['hash'] = $hash;
709 746 $rule['file'] = $file;
@@ -708,9 +745,9 @@
708 745 $rule['hash'] = $hash;
709 746 $rule['file'] = $file;
710 747 $action = 'UPDATED';
711 748 $rtype = 'AUTO';
712 - } elseif ( 0 !== $rule['hash'] && ctype_alnum( $rule['hash'] ) ) {
749 + } elseif ( is_array( $rule ) && array_key_exists( 'hash', $rule ) && 0 !== $rule['hash'] && ctype_alnum( $rule['hash'] ) ) {
713 750 // If this is an genuine AUTO rule, update its hash and filename
714 751 // Set rule hash, file and action flag.
715 752 $rule['hash'] = $hash;
716 753 $rule['file'] = $file;
@@ -718,9 +755,9 @@
718 755 $rtype = 'AUTO';
719 756 } else {
720 757 // If rule doesn't exist, create an AUTO rule
721 758 // AUTO rules were only for types, but will now also work for paths.
722 - if ( 'types' == $trule[0] || 'paths' == $trule[0] ) {
759 + if ( ( 'types' == $trule[0] || 'paths' == $trule[0] ) && ! empty( $trule[1] ) ) {
723 760 // Set rule hash and file and action flag.
724 761 $rule['hash'] = $hash;
725 762 $rule['file'] = $file;
726 763 $action = 'CREATED';
@@ -726,20 +763,24 @@
726 763 $action = 'CREATED';
727 764 $rtype = 'AUTO';
728 765 } else {
729 766 // Log that no rule was created.
730 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Exception, no AUTO rule created', 3 );
767 + $this->criticalcss->log( 'Exception, no AUTO rule created', 3 );
731 768 }
732 769 }
733 770
734 771 if ( $action ) {
735 772 // If a rule creation/update is required, persist updated rules object.
736 - $ao_ccss_rules[ $trule[0] ][ $trule[1] ] = $rule;
737 - $ao_ccss_rules_raw = json_encode( $ao_ccss_rules );
738 - update_option( 'autoptimize_ccss_rules', $ao_ccss_rules_raw );
739 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Target rule <' . $srule . '> of type <' . $rtype . '> was ' . $action . ' for job id <' . $ljid . '>', 3 );
773 + $rules[ $trule[0] ][ $trule[1] ] = $rule;
774 + $rules_raw = json_encode( $rules );
775 + update_option( 'autoptimize_ccss_rules', $rules_raw );
776 + $this->criticalcss->flush_options();
777 + $this->criticalcss->log( 'Target rule <' . $srule . '> of type <' . $rtype . '> was ' . $action . ' for job id <' . $ljid . '>', 3 );
778 +
779 + // and trigger action for whoever needs to be aware.
780 + do_action( 'autoptimize_action_ccss_cron_rule_updated', $srule, $file, '' );
740 781 } else {
741 - autoptimizeCriticalCSSCore::ao_ccss_log( 'No rule action required', 3 );
782 + $this->criticalcss->log( 'No rule action required', 3 );
742 783 }
743 784 }
744 785
745 786 function ao_ccss_finclude( $finclude_raw ) {
@@ -801,37 +842,40 @@
801 842 wp_schedule_event( time(), apply_filters( 'ao_ccss_queue_schedule', 'ao_ccss' ), 'ao_ccss_queue' );
802 843 }
803 844
804 845 // Queue cleaning.
805 - global $ao_ccss_queue;
806 - $queue_purge_threshold = 100;
807 - $queue_purge_age = 24 * 60 * 60;
808 - $queue_length = count( $ao_ccss_queue );
809 - $timestamp_yesterday = microtime( true ) - $queue_purge_age;
810 - $remove_old_new = false;
811 - $queue_altered = false;
846 + $queue = $this->criticalcss->get_option( 'queue' );
812 847
813 - if ( $queue_length > $queue_purge_threshold ) {
814 - $remove_old_new = true;
815 - }
848 + if ( isset( $queue ) && is_array( $queue ) ) {
849 + $queue_purge_threshold = 100;
850 + $queue_purge_age = 24 * 60 * 60;
851 + $queue_length = count( $queue );
852 + $timestamp_yesterday = microtime( true ) - $queue_purge_age;
853 + $remove_old_new = false;
854 + $queue_altered = false;
816 855
817 - foreach ( $ao_ccss_queue as $path => $job ) {
818 - if ( ( $remove_old_new && 'NEW' == $job['jqstat'] && $job['jctime'] < $timestamp_yesterday ) || in_array( $job['jqstat'], array( 'JOB_FAILED', 'STATUS_JOB_BAD', 'NO_CSS', 'NO_RESPONSE' ) ) ) {
819 - unset( $ao_ccss_queue[ $path ] );
820 - $queue_altered = true;
856 + if ( $queue_length > $queue_purge_threshold ) {
857 + $remove_old_new = true;
821 858 }
822 - }
823 859
824 - // save queue to options!
825 - if ( $queue_altered ) {
826 - $ao_ccss_queue_raw = json_encode( $ao_ccss_queue );
827 - update_option( 'autoptimize_ccss_queue', $ao_ccss_queue_raw, false );
828 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue cleaning done.', 3 );
860 + foreach ( $queue as $path => $job ) {
861 + if ( ( $remove_old_new && 'NEW' == $job['jqstat'] && $job['jctime'] < $timestamp_yesterday ) || in_array( $job['jqstat'], array( 'JOB_FAILED', 'STATUS_JOB_BAD', 'NO_CSS', 'NO_RESPONSE' ) ) ) {
862 + unset( $queue[ $path ] );
863 + $queue_altered = true;
864 + }
865 + }
866 +
867 + // save queue to options!
868 + if ( $queue_altered ) {
869 + $queue_raw = json_encode( $queue );
870 + update_option( 'autoptimize_ccss_queue', $queue_raw, false );
871 + $this->criticalcss->log( 'Queue cleaning done.', 3 );
872 + }
829 873 }
830 874
831 875 // re-check key if invalid.
832 - global $ao_ccss_keyst;
833 - if ( 1 == $ao_ccss_keyst ) {
876 + $keyst = $this->criticalcss->get_option( 'keyst' );
877 + if ( 1 == $keyst ) {
834 878 $this->ao_ccss_api_generate( '', '', '' );
835 879 }
836 880 }
837 881 }