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 +321 -269 2.7.0 → 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,38 +129,32 @@
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 15 seconds before process next job due criticalcss.com API limits.
123 - if ( $jr > 1 ) {
124 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Waiting 15 seconds due to criticalcss.com API limits', 3 );
125 - sleep( 15 );
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'] ) {
134 - // SUCCESS: request has a valid result.
148 + if ( empty( $apireq ) ) {
149 + // ERROR: no response
135 150 // Update job properties.
136 - $jprops['jid'] = $apireq['job']['id'];
137 - $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'] ) {
140 - // ERROR: concurrent requests
141 - // Update job properties.
142 - $jprops['jid'] = $apireq['job']['id'];
143 - $jprops['jqstat'] = $apireq['job']['status'];
144 - $jprops['jrstat'] = $apireq['error'];
151 + $jprops['jqstat'] = 'NO_RESPONSE';
152 + $jprops['jrstat'] = 'NONE';
145 153 $jprops['jvstat'] = 'NONE';
146 154 $jprops['jftime'] = microtime( true );
147 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Concurrent requests when processing job id <' . $jprops['ljid'] . '>, job status is now <' . $jprops['jqstat'] . '>', 3 );
148 - } elseif ( 'INVALID_JWT_TOKEN' == $apireq['errorCode'] ) {
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'] ) {
149 157 // ERROR: key validation
150 158 // Update job properties.
151 159 $jprops['jqstat'] = $apireq['errorCode'];
152 160 $jprops['jrstat'] = $apireq['error'];
@@ -151,17 +159,28 @@
151 159 $jprops['jqstat'] = $apireq['errorCode'];
152 160 $jprops['jrstat'] = $apireq['error'];
153 161 $jprops['jvstat'] = 'NONE';
154 162 $jprops['jftime'] = microtime( true );
155 - autoptimizeCriticalCSSCore::ao_ccss_log( 'API key validation error when processing job id <' . $jprops['ljid'] . '>, job status is now <' . $jprops['jqstat'] . '>', 3 );
156 - } elseif ( empty( $apireq ) ) {
157 - // ERROR: no response
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'] ) ) {
165 + // SUCCESS: request has a valid result.
158 166 // Update job properties.
159 - $jprops['jqstat'] = 'NO_RESPONSE';
160 - $jprops['jrstat'] = 'NONE';
167 + $jprops['jid'] = $apireq['job']['id'];
168 + $jprops['jqstat'] = $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'] ) {
171 + // ERROR: concurrent requests
172 + // Update job properties.
173 + $jprops['jid'] = $apireq['job']['id'];
174 + $jprops['jqstat'] = $apireq['job']['status'];
175 + if ( $apireq['job']['error'] ) {
176 + $jprops['jrstat'] = $apireq['job']['error'];
177 + } else {
178 + $jprops['jrstat'] = 'Baby did a bad bad thing';
179 + }
161 180 $jprops['jvstat'] = 'NONE';
162 181 $jprops['jftime'] = microtime( true );
163 - 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 );
164 183 } else {
165 184 // UNKNOWN: unhandled generate exception
166 185 // Update job properties.
167 186 $jprops['jqstat'] = 'JOB_UNKNOWN';
@@ -167,10 +186,10 @@
167 186 $jprops['jqstat'] = 'JOB_UNKNOWN';
168 187 $jprops['jrstat'] = 'NONE';
169 188 $jprops['jvstat'] = 'NONE';
170 189 $jprops['jftime'] = microtime( true );
171 - 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 );
172 - 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 );
173 192 }
174 193 } else {
175 194 // SUCCESS: Job hash is equal to a previous one, so it's done
176 195 // Update job status and finish time.
@@ -175,9 +194,9 @@
175 194 // SUCCESS: Job hash is equal to a previous one, so it's done
176 195 // Update job status and finish time.
177 196 $jprops['jqstat'] = 'JOB_DONE';
178 197 $jprops['jftime'] = microtime( true );
179 - 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 );
180 199 }
181 200
182 201 // Set queue update flag.
183 202 $update = true;
@@ -184,19 +203,12 @@
184 203
185 204 } elseif ( 'JOB_QUEUED' == $jprops['jqstat'] || 'JOB_ONGOING' == $jprops['jqstat'] ) {
186 205 // Process QUEUED and ONGOING jobs
187 206 // Log the pending job.
188 - 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 );
189 208
190 - // If this is not the first job, wait 15 seconds before process next job due criticalcss.com API limits.
191 - if ( $jr > 1 ) {
192 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Waiting 15 seconds due to criticalcss.com API limits', 3 );
193 - sleep( 15 );
194 - }
195 -
196 209 // Dispatch the job result request and increment request count.
197 210 $apireq = $this->ao_ccss_api_results( $jprops['jid'], $queue_debug, $qdobj['htcode'] );
198 - $jr++;
199 211
200 212 // NOTE: All the following condigitons maps to the ones in admin_settings_queue.js.php
201 213 // Replace API response values if queue debugging is enabled and some value is set.
202 214 if ( $queue_debug ) {
@@ -210,15 +222,23 @@
210 222 $apireq['validationStatus'] = $qdobj['validationStatus'];
211 223 }
212 224 }
213 225
214 - 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'] ) ) {
215 235 // SUCCESS: request has a valid result
216 236 // Process a PENDING job
217 237 // Update job properties.
218 238 $jprops['jqstat'] = $apireq['status'];
219 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . '> unchanged', 3 );
220 - } 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'] ) {
221 241 // Process a DONE job
222 242 // New resultStatus from ccss.com "HTML_404", consider as "GOOD" for now.
223 243 if ( 'HTML_404' == $apireq['resultStatus'] ) {
224 244 $apireq['resultStatus'] = 'GOOD';
@@ -223,10 +243,10 @@
223 243 if ( 'HTML_404' == $apireq['resultStatus'] ) {
224 244 $apireq['resultStatus'] = 'GOOD';
225 245 }
226 246
227 - if ( 'GOOD' == $apireq['resultStatus'] && 'GOOD' == $apireq['validationStatus'] ) {
228 - // 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
229 249 // Update job properties.
230 250 $jprops['file'] = $this->ao_ccss_save_file( $apireq['css'], $trule, false );
231 251 $jprops['jqstat'] = $apireq['status'];
232 252 $jprops['jrstat'] = $apireq['resultStatus'];
@@ -232,19 +252,25 @@
232 252 $jprops['jrstat'] = $apireq['resultStatus'];
233 253 $jprops['jvstat'] = $apireq['validationStatus'];
234 254 $jprops['jftime'] = microtime( true );
235 255 $rule_update = true;
236 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . '>, file saved <' . $jprops['file'] . '>', 3 );
237 - } elseif ( 'GOOD' == $apireq['resultStatus'] && ( 'WARN' == $apireq['validationStatus'] || 'BAD' == $apireq['validationStatus'] || 'SCREENSHOT_WARN_BLANK' == $apireq['validationStatus'] ) ) {
238 - // 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
239 260 // Update job properties.
240 - $jprops['file'] = $this->ao_ccss_save_file( $apireq['css'], $trule, true );
241 261 $jprops['jqstat'] = $apireq['status'];
242 262 $jprops['jrstat'] = $apireq['resultStatus'];
243 263 $jprops['jvstat'] = $apireq['validationStatus'];
244 264 $jprops['jftime'] = microtime( true );
245 - $rule_update = true;
246 - 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 + }
247 273 } elseif ( 'GOOD' != $apireq['resultStatus'] && ( 'GOOD' != $apireq['validationStatus'] || 'WARN' != $apireq['validationStatus'] || 'BAD' != $apireq['validationStatus'] || 'SCREENSHOT_WARN_BLANK' != $apireq['validationStatus'] ) ) {
248 274 // ERROR: no GOOD, WARN or BAD results
249 275 // Update job properties.
250 276 $jprops['jqstat'] = $apireq['status'];
@@ -250,11 +276,11 @@
250 276 $jprops['jqstat'] = $apireq['status'];
251 277 $jprops['jrstat'] = $apireq['resultStatus'];
252 278 $jprops['jvstat'] = $apireq['validationStatus'];
253 279 $jprops['jftime'] = microtime( true );
254 - 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 );
255 281 $apireq['css'] = '/* critical css removed for DEBUG logging purposes */';
256 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job response was: ' . json_encode( $apireq ), 3 );
282 + $this->criticalcss->log( 'Job response was: ' . json_encode( $apireq ), 3 );
257 283 } else {
258 284 // UNKNOWN: unhandled JOB_DONE exception
259 285 // Update job properties.
260 286 $jprops['jqstat'] = 'JOB_UNKNOWN';
@@ -260,24 +286,25 @@
260 286 $jprops['jqstat'] = 'JOB_UNKNOWN';
261 287 $jprops['jrstat'] = $apireq['resultStatus'];
262 288 $jprops['jvstat'] = $apireq['validationStatus'];
263 289 $jprops['jftime'] = microtime( true );
264 - 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 );
265 291 $apireq['css'] = '/* critical css removed for DEBUG logging purposes */';
266 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job response was: ' . json_encode( $apireq ), 3 );
292 + $this->criticalcss->log( 'Job response was: ' . json_encode( $apireq ), 3 );
267 293 }
268 - } 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'] ) ) {
269 295 // ERROR: failed job
270 296 // Update job properties.
271 297 $jprops['jqstat'] = $apireq['job']['status'];
272 - if ( $apireq['error'] ) {
298 + if ( $apireq['job']['error'] ) {
273 299 $jprops['jrstat'] = $apireq['job']['error'];
274 300 } else {
301 + $jprops['jrstat'] = 'Baby did a bad bad thing';
275 302 }
276 303 $jprops['jvstat'] = 'NONE';
277 304 $jprops['jftime'] = microtime( true );
278 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful but job FAILED, status now is <' . $jprops['jqstat'] . '>', 3 );
279 - } 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'] ) {
280 307 // ERROR: CSS doesn't exist
281 308 // Update job properties.
282 309 $jprops['jqstat'] = 'NO_CSS';
283 310 $jprops['jrstat'] = $apireq['error'];
@@ -282,17 +309,9 @@
282 309 $jprops['jqstat'] = 'NO_CSS';
283 310 $jprops['jrstat'] = $apireq['error'];
284 311 $jprops['jvstat'] = 'NONE';
285 312 $jprops['jftime'] = microtime( true );
286 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful but job FAILED, status now is <' . $jprops['jqstat'] . '>', 3 );
287 - } elseif ( empty( $apireq ) ) {
288 - // ERROR: no response
289 - // Update job properties.
290 - $jprops['jqstat'] = 'NO_RESPONSE';
291 - $jprops['jrstat'] = 'NONE';
292 - $jprops['jvstat'] = 'NONE';
293 - $jprops['jftime'] = microtime( true );
294 - 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 );
295 314 } else {
296 315 // UNKNOWN: unhandled results exception
297 316 // Update job properties.
298 317 $jprops['jqstat'] = 'JOB_UNKNOWN';
@@ -298,9 +317,9 @@
298 317 $jprops['jqstat'] = 'JOB_UNKNOWN';
299 318 $jprops['jrstat'] = 'NONE';
300 319 $jprops['jvstat'] = 'NONE';
301 320 $jprops['jftime'] = microtime( true );
302 - 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 );
303 322 }
304 323
305 324 // Set queue update flag.
306 325 $update = true;
@@ -315,33 +334,33 @@
315 334 // Persist updated queue object.
316 335 if ( $update ) {
317 336 if ( ! $deljob ) {
318 337 // Update properties of a NEW or PENDING job...
319 - $ao_ccss_queue[ $path ] = $jprops;
338 + $queue[ $path ] = $jprops;
320 339 } else {
321 340 // ...or remove the DONE job.
322 - unset( $ao_ccss_queue[ $path ] );
323 - 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 );
324 343 }
325 344
326 345 // Update queue object.
327 - $ao_ccss_queue_raw = json_encode( $ao_ccss_queue );
328 - update_option( 'autoptimize_ccss_queue', $ao_ccss_queue_raw, false );
329 - 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 );
330 349
331 350 // Update target rule.
332 351 if ( $rule_update ) {
333 352 $this->ao_ccss_rule_update( $jprops['ljid'], $jprops['rtarget'], $jprops['file'], $jprops['hash'] );
334 - 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 );
335 354 }
336 355 } else {
337 356 // Or log no queue action.
338 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Nothing to do on this job', 3 );
357 + $this->criticalcss->log( 'Nothing to do on this job', 3 );
339 358 }
340 359
341 - // Break the loop if request limit is set and was reached.
342 - if ( $ao_ccss_rlimit && $ao_ccss_rlimit == $jr ) {
343 - 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 );
344 363 break;
345 364 }
346 365
347 366 // Increment job counter.
@@ -350,15 +369,15 @@
350 369
351 370 // Remove the lock file and log the queue end.
352 371 if ( file_exists( AO_CCSS_LOCK ) ) {
353 372 unlink( AO_CCSS_LOCK );
354 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control unlocked', 3 );
373 + $this->criticalcss->log( 'Queue control unlocked', 3 );
355 374 }
356 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control finished', 3 );
375 + $this->criticalcss->log( 'Queue control finished', 3 );
357 376
358 377 // Log that queue is locked.
359 378 } else {
360 - 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 );
361 380 }
362 381 }
363 382
364 383 public function ao_ccss_diff_hashes( $ljid, $hash, $hashes, $rule ) {
@@ -367,9 +386,9 @@
367 386 if ( 1 == count( $hashes ) ) {
368 387 // Job with a single hash
369 388 // Set job hash.
370 389 $hash = $hashes[0];
371 - 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 );
372 391 } else {
373 392 // Job with multiple hashes
374 393 // Loop through hashes to concatenate them.
375 394 $nhash = '';
@@ -378,18 +397,18 @@
378 397 }
379 398
380 399 // Set job hash.
381 400 $hash = md5( $nhash );
382 - 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 );
383 402 }
384 403
385 404 // STEP 2: compare job to existing jobs to prevent double submission for same type+hash.
386 - global $ao_ccss_queue;
405 + $queue = $this->criticalcss->get_option( 'queue' );
387 406
388 - foreach ( $ao_ccss_queue as $queue_item ) {
389 - 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 );
390 409 if ( $queue_item['hash'] == $hash && $queue_item['rtarget'] == $rule && in_array( $queue_item['jqstat'], array( 'JOB_QUEUED', 'JOB_ONGOING', 'JOB_DONE' ) ) ) {
391 - 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 );
392 411 return false;
393 412 }
394 413 }
395 414
@@ -394,32 +413,42 @@
394 413 }
395 414
396 415 // STEP 3: compare job and existing rule (if any) hashes
397 416 // Attach required arrays.
398 - global $ao_ccss_rules;
417 + $rules = $this->criticalcss->get_option( 'rules' );
399 418
400 419 // Prepare rule variables.
401 420 $trule = explode( '|', $rule );
402 - $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 + }
403 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 +
404 433 // Check if a MANUAL rule exist and return false.
405 434 if ( ! empty( $srule ) && ( 0 == $srule['hash'] && 0 != $srule['file'] ) ) {
406 - 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 );
407 436 return false;
408 437 } elseif ( ! empty( $srule ) ) {
409 438 // Check if an AUTO rule exist.
410 439 if ( $hash === $srule['hash'] && is_file( AO_CCSS_DIR . $srule['file'] ) && 0 != filesize( AO_CCSS_DIR . $srule['file'] ) ) {
411 440 // Check if job hash matches rule, if the CCSS file exists said file is not empty and return FALSE is so.
412 - 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 );
413 442 return false;
414 443 } else {
415 444 // Or return the new hash if they differ.
416 - 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 );
417 446 return $hash;
418 447 }
419 448 } else {
420 - // Or just return the hash if no rule exist yet.
421 - 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 );
422 451 return $hash;
423 452 }
424 453 }
425 454
@@ -425,16 +454,13 @@
425 454
426 455 public function ao_ccss_api_generate( $path, $debug, $dcode ) {
427 456 // POST jobs to criticalcss.com and return responses
428 457 // Get key and key status.
429 - global $ao_ccss_key;
430 - global $ao_ccss_keyst;
431 - $key = $ao_ccss_key;
432 - $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' );
433 461
434 462 // Prepare full URL to request.
435 - global $ao_ccss_noptimize;
436 -
437 463 $site_host = get_site_url();
438 464 $site_path = parse_url( $site_host, PHP_URL_PATH );
439 465
440 466 if ( ! empty( $site_path ) ) {
@@ -443,15 +469,15 @@
443 469
444 470 // Logic to bind to one domain to avoid site clones of sites would
445 471 // automatically begin spawning requests to criticalcss.com which has
446 472 // a per domain cost.
447 - global $ao_ccss_domain;
448 - if ( empty( $ao_ccss_domain ) ) {
473 + $domain = $this->criticalcss->get_option( 'domain' );
474 + if ( empty( $domain ) ) {
449 475 // first request being done, update option to allow future requests are only allowed if from same domain.
450 476 update_option( 'autoptimize_ccss_domain', str_rot13( $site_host ) );
451 - } 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 ) ) {
452 478 // not the same domain, log as error and return without posting to criticalcss.com.
453 - 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 );
454 480 return false;
455 481 }
456 482
457 483 $src_url = $site_host . $path;
@@ -456,107 +482,119 @@
456 482
457 483 $src_url = $site_host . $path;
458 484
459 485 // Avoid AO optimizations if required by config or avoid lazyload if lazyload is active in AO.
460 - if ( ! empty( $ao_ccss_noptimize ) ) {
486 + if ( ! empty( $noptimize ) ) {
461 487 $src_url .= '?ao_noptirocket=1';
462 - } 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 ) ) {
463 489 $src_url .= '?ao_nolazy=1';
464 490 }
465 491
466 492 $src_url = apply_filters( 'autoptimize_filter_ccss_cron_srcurl', $src_url );
467 493
468 - // Initialize request body.
469 - $body = array();
470 - $body['url'] = $src_url;
471 - $body['aff'] = 1;
472 - $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;
473 500
474 - // Prepare and add viewport size to the body if available.
475 - $viewport = autoptimizeCriticalCSSCore::ao_ccss_viewport();
476 - if ( ! empty( $viewport['w'] ) && ! empty( $viewport['h'] ) ) {
477 - $body['width'] = $viewport['w'];
478 - $body['height'] = $viewport['h'];
479 - }
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 + }
480 507
481 - // Prepare and add forceInclude to the body if available.
482 - global $ao_ccss_finclude;
483 - $finclude = $this->ao_ccss_finclude( $ao_ccss_finclude );
484 - if ( ! empty( $finclude ) ) {
485 - $body['forceInclude'] = $finclude;
486 - }
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 + }
487 514
488 - // Body must be json and log it.
489 - $body = json_encode( $body );
490 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request body is ' . $body, 3 );
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 );
491 517
492 - // Prepare the request.
493 - $url = esc_url_raw( AO_CCSS_API . 'generate?aover=' . AO_CCSS_VER );
494 - $args = array(
495 - 'headers' => array(
496 - 'User-Agent' => 'Autoptimize v' . AO_CCSS_VER,
497 - 'Content-type' => 'application/json; charset=utf-8',
498 - 'Authorization' => 'JWT ' . $key,
499 - 'Connection' => 'close',
500 - ),
501 - 'body' => $body,
502 - );
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 );
503 521
504 - // Dispatch the request and store its response code.
505 - $req = wp_safe_remote_post( $url, $args );
506 - $code = wp_remote_retrieve_response_code( $req );
507 - $body = json_decode( wp_remote_retrieve_body( $req ), true );
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 + );
508 536
509 - if ( $debug && $dcode ) {
510 - // If queue debug is active, change response code.
511 - $code = $dcode;
512 - }
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 );
513 541
514 - if ( 200 == $code ) {
515 - // Response code is OK.
516 - // Workaround criticalcss.com non-RESTful reponses.
517 - if ( 'JOB_QUEUED' == $body['job']['status'] || 'JOB_ONGOING' == $body['job']['status'] || 'STATUS_JOB_BAD' == $body['job']['status'] ) {
518 - // Log successful and return encoded request body.
519 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied successfully', 3 );
542 + if ( $debug && $dcode ) {
543 + // If queue debug is active, change response code.
544 + $code = $dcode;
545 + }
520 546
521 - // This code also means the key is valid, so cache key status for 24h if not already cached.
522 - if ( ( ! $key_status || 2 != $key_status ) && $key ) {
523 - update_option( 'autoptimize_ccss_keyst', 2 );
524 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: API key is valid, updating key status', 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 );
553 +
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;
525 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 );
526 574
527 - // Return the request body.
528 - return $body;
529 - } else {
530 - // Log successful requests with invalid reponses.
531 - 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 );
532 - autoptimizeCriticalCSSCore::ao_ccss_log( print_r( $body, true ), 2 );
533 - return $body;
534 - }
535 - } else {
536 - // Response code is anything else.
537 - // Log failed request with a valid response code and return body.
538 - if ( $code ) {
539 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with error code <' . $code . '>, body follows...', 2 );
540 - 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 + }
541 580
542 - if ( 401 == $code ) {
543 - // If request is unauthorized, also clear key status.
544 - update_option( 'autoptimize_ccss_keyst', 1 );
545 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: API key is invalid, updating key status', 3 );
546 - }
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 + }
547 589
548 - // Return the request body.
549 - return $body;
550 - } else {
551 - // Log failed request with no response and return false.
552 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> has no response, this could be a service timeout', 2 );
553 - if ( is_wp_error( $req ) ) {
554 - autoptimizeCriticalCSSCore::ao_ccss_log( $req->get_error_message(), 2 );
590 + return false;
555 591 }
556 -
557 - return false;
558 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;
559 597 }
560 598 }
561 599
562 600 public function ao_ccss_api_results( $jobid, $debug, $dcode ) {
@@ -561,18 +599,20 @@
561 599
562 600 public function ao_ccss_api_results( $jobid, $debug, $dcode ) {
563 601 // GET jobs from criticalcss.com and return responses
564 602 // Get key.
565 - global $ao_ccss_key;
566 - $key = $ao_ccss_key;
603 + $key = $this->criticalcss->get_option( 'key' );
567 604
568 605 // Prepare the request.
569 606 $url = AO_CCSS_API . 'results?resultId=' . $jobid;
570 607 $args = array(
571 - 'headers' => array(
572 - 'User-Agent' => 'Autoptimize CriticalCSS Power-Up v' . AO_CCSS_VER,
573 - 'Authorization' => 'JWT ' . $key,
574 - '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 + )
575 615 ),
576 616 );
577 617
578 618 // Dispatch the request and store its response code.
@@ -589,19 +629,19 @@
589 629 // Response code is OK.
590 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'] ) ) {
591 631 // Workaround criticalcss.com non-RESTful reponses
592 632 // Log successful and return encoded request body.
593 - 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 );
594 634 return $body;
595 635 } elseif ( is_array( $body ) && ( array_key_exists( 'error', $body ) && 'This css no longer exists. Please re-generate it.' == $body['error'] ) ) {
596 636 // Handle no CSS reply
597 637 // Log no CSS error and return encoded request body.
598 - 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 );
599 639 return $body;
600 640 } else {
601 641 // Log failed request and return false.
602 - 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 );
603 - 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 );
604 644 return false;
605 645 }
606 646 } else {
607 647 // Response code is anything else
@@ -606,14 +646,14 @@
606 646 } else {
607 647 // Response code is anything else
608 648 // Log failed request with a valid response code and return body.
609 649 if ( $code ) {
610 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied with error code <' . $code . '>, body follows...', 2 );
611 - 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 );
612 652 if ( 401 == $code ) {
613 653 // If request is unauthorized, also clear key status.
614 654 update_option( 'autoptimize_ccss_keyst', 1 );
615 - 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 );
616 656 }
617 657
618 658 // Return the request body.
619 659 return $body;
@@ -618,9 +658,9 @@
618 658 // Return the request body.
619 659 return $body;
620 660 } else {
621 661 // Log failed request with no response and return false.
622 - 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 );
623 663 return false;
624 664 }
625 665 }
626 666 }
@@ -637,41 +677,42 @@
637 677 // Prepare target rule, filename and content.
638 678 $filename = false;
639 679 $content = $ccss;
640 680
641 - if ( autoptimizeCriticalCSSCore::ao_ccss_check_contents( $content ) ) {
681 + if ( $this->criticalcss->check_contents( $content ) ) {
642 682 // Sanitize content, set filename and try to save file.
643 683 $file = AO_CCSS_DIR . 'ccss_' . md5( $ccss . $target[1] ) . $rmark . '.css';
644 684 $status = file_put_contents( $file, $content, LOCK_EX );
645 685 $filename = pathinfo( $file, PATHINFO_BASENAME );
646 - 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 );
647 687
648 688 if ( ! $status ) {
649 689 // If file has not been saved, reset filename.
650 - 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 );
651 691 $filename = false;
652 692 return $filename;
653 693 }
654 694 } else {
655 - 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 );
656 696 return $filename;
657 697 }
658 698
659 699 // Remove old critical CSS if a previous one existed in the rule and if that file exists in filesystem
660 - // NOTE: out of scope critical CSS file removal (issue #5)
661 700 // Attach required arrays.
662 - global $ao_ccss_rules;
701 + $rules = $this->criticalcss->get_option( 'rules' );
663 702
664 - // Prepare rule variables.
665 - $srule = $ao_ccss_rules[ $target[0] ][ $target[1] ];
666 - $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'];
667 707
668 - if ( $oldfile && $oldfile !== $filename ) {
669 - $delfile = AO_CCSS_DIR . $oldfile;
670 - if ( file_exists( $delfile ) ) {
671 - $unlinkst = unlink( $delfile );
672 - if ( $unlinkst ) {
673 - 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 + }
674 715 }
675 716 }
676 717 }
677 718
@@ -681,21 +722,25 @@
681 722
682 723 public function ao_ccss_rule_update( $ljid, $srule, $file, $hash ) {
683 724 // Update or create a rule
684 725 // Attach required arrays.
685 - global $ao_ccss_rules;
726 + $rules = $this->criticalcss->get_option( 'rules' );
686 727
687 728 // Prepare rule variables.
688 729 $trule = explode( '|', $srule );
689 - $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 + }
690 735 $action = false;
691 736 $rtype = '';
692 737
693 - 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'] ) {
694 739 // manual rule, don't ever overwrite.
695 740 $action = 'NOT UPDATED';
696 741 $rtype = 'MANUAL';
697 - } 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'] ) {
698 743 // If this is an user created AUTO rule with no hash and file yet, update its hash and filename
699 744 // Set rule hash, file and action flag.
700 745 $rule['hash'] = $hash;
701 746 $rule['file'] = $file;
@@ -700,9 +745,9 @@
700 745 $rule['hash'] = $hash;
701 746 $rule['file'] = $file;
702 747 $action = 'UPDATED';
703 748 $rtype = 'AUTO';
704 - } 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'] ) ) {
705 750 // If this is an genuine AUTO rule, update its hash and filename
706 751 // Set rule hash, file and action flag.
707 752 $rule['hash'] = $hash;
708 753 $rule['file'] = $file;
@@ -710,9 +755,9 @@
710 755 $rtype = 'AUTO';
711 756 } else {
712 757 // If rule doesn't exist, create an AUTO rule
713 758 // AUTO rules were only for types, but will now also work for paths.
714 - if ( 'types' == $trule[0] || 'paths' == $trule[0] ) {
759 + if ( ( 'types' == $trule[0] || 'paths' == $trule[0] ) && ! empty( $trule[1] ) ) {
715 760 // Set rule hash and file and action flag.
716 761 $rule['hash'] = $hash;
717 762 $rule['file'] = $file;
718 763 $action = 'CREATED';
@@ -718,20 +763,24 @@
718 763 $action = 'CREATED';
719 764 $rtype = 'AUTO';
720 765 } else {
721 766 // Log that no rule was created.
722 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Exception, no AUTO rule created', 3 );
767 + $this->criticalcss->log( 'Exception, no AUTO rule created', 3 );
723 768 }
724 769 }
725 770
726 771 if ( $action ) {
727 772 // If a rule creation/update is required, persist updated rules object.
728 - $ao_ccss_rules[ $trule[0] ][ $trule[1] ] = $rule;
729 - $ao_ccss_rules_raw = json_encode( $ao_ccss_rules );
730 - update_option( 'autoptimize_ccss_rules', $ao_ccss_rules_raw );
731 - 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, '' );
732 781 } else {
733 - autoptimizeCriticalCSSCore::ao_ccss_log( 'No rule action required', 3 );
782 + $this->criticalcss->log( 'No rule action required', 3 );
734 783 }
735 784 }
736 785
737 786 function ao_ccss_finclude( $finclude_raw ) {
@@ -772,9 +821,9 @@
772 821 return false;
773 822 }
774 823 }
775 824
776 - public static function ao_ccss_cleaning() {
825 + public function ao_ccss_cleaning() {
777 826 // Perform plugin maintenance
778 827 // Truncate log file >= 1MB .
779 828 if ( file_exists( AO_CCSS_LOG ) ) {
780 829 if ( filesize( AO_CCSS_LOG ) >= 1048576 ) {
@@ -793,37 +842,40 @@
793 842 wp_schedule_event( time(), apply_filters( 'ao_ccss_queue_schedule', 'ao_ccss' ), 'ao_ccss_queue' );
794 843 }
795 844
796 845 // Queue cleaning.
797 - global $ao_ccss_queue;
798 - $queue_purge_threshold = 100;
799 - $queue_purge_age = 24 * 60 * 60;
800 - $queue_length = count( $ao_ccss_queue );
801 - $timestamp_yesterday = microtime( true ) - $queue_purge_age;
802 - $remove_old_new = false;
803 - $queue_altered = false;
846 + $queue = $this->criticalcss->get_option( 'queue' );
804 847
805 - if ( $queue_length > $queue_purge_threshold ) {
806 - $remove_old_new = true;
807 - }
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;
808 855
809 - foreach ( $ao_ccss_queue as $path => $job ) {
810 - 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' ) ) ) {
811 - unset( $ao_ccss_queue[ $path ] );
812 - $queue_altered = true;
856 + if ( $queue_length > $queue_purge_threshold ) {
857 + $remove_old_new = true;
813 858 }
814 - }
815 859
816 - // save queue to options!
817 - if ( $queue_altered ) {
818 - $ao_ccss_queue_raw = json_encode( $ao_ccss_queue );
819 - update_option( 'autoptimize_ccss_queue', $ao_ccss_queue_raw, false );
820 - 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 + }
821 873 }
822 874
823 875 // re-check key if invalid.
824 - global $ao_ccss_keyst;
825 - if ( 1 == $ao_ccss_keyst ) {
876 + $keyst = $this->criticalcss->get_option( 'keyst' );
877 + if ( 1 == $keyst ) {
826 878 $this->ao_ccss_api_generate( '', '', '' );
827 879 }
828 880 }
829 881 }