PluginProbe
Autoptimize / 3.1.16
Autoptimize v3.1.16
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 → 3.1.16 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 }