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 +319 -270 2.7.3 → 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 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'] ) {
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 before process next job due criticalcss.com API limits.
191 - if ( $jr > 1 ) {
192 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Waiting ' . AO_CCSS_SLEEP . ' seconds due to criticalcss.com API limits', 3 );
193 - sleep( AO_CCSS_SLEEP );
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,110 +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 - // Add filter to allow the body array to be altered (e.g. to add customPageHeaders).
489 - $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 );
490 517
491 - // Body must be json and log it.
492 - $body = json_encode( $body );
493 - 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 );
494 521
495 - // Prepare the request.
496 - $url = esc_url_raw( AO_CCSS_API . 'generate?aover=' . AO_CCSS_VER );
497 - $args = array(
498 - 'headers' => array(
499 - 'User-Agent' => 'Autoptimize v' . AO_CCSS_VER,
500 - 'Content-type' => 'application/json; charset=utf-8',
501 - 'Authorization' => 'JWT ' . $key,
502 - 'Connection' => 'close',
503 - ),
504 - 'body' => $body,
505 - );
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 + );
506 536
507 - // Dispatch the request and store its response code.
508 - $req = wp_safe_remote_post( $url, $args );
509 - $code = wp_remote_retrieve_response_code( $req );
510 - $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 );
511 541
512 - if ( $debug && $dcode ) {
513 - // If queue debug is active, change response code.
514 - $code = $dcode;
515 - }
542 + if ( $debug && $dcode ) {
543 + // If queue debug is active, change response code.
544 + $code = $dcode;
545 + }
516 546
517 - if ( 200 == $code ) {
518 - // Response code is OK.
519 - // Workaround criticalcss.com non-RESTful reponses.
520 - if ( 'JOB_QUEUED' == $body['job']['status'] || 'JOB_ONGOING' == $body['job']['status'] || 'STATUS_JOB_BAD' == $body['job']['status'] ) {
521 - // Log successful and return encoded request body.
522 - 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 );
523 553
524 - // This code also means the key is valid, so cache key status for 24h if not already cached.
525 - if ( ( ! $key_status || 2 != $key_status ) && $key ) {
526 - update_option( 'autoptimize_ccss_keyst', 2 );
527 - 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;
528 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 );
529 574
530 - // Return the request body.
531 - return $body;
532 - } else {
533 - // Log successful requests with invalid reponses.
534 - 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 );
535 - autoptimizeCriticalCSSCore::ao_ccss_log( print_r( $body, true ), 2 );
536 - return $body;
537 - }
538 - } else {
539 - // Response code is anything else.
540 - // Log failed request with a valid response code and return body.
541 - if ( $code ) {
542 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with error code <' . $code . '>, body follows...', 2 );
543 - 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 + }
544 580
545 - if ( 401 == $code ) {
546 - // If request is unauthorized, also clear key status.
547 - update_option( 'autoptimize_ccss_keyst', 1 );
548 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: API key is invalid, updating key status', 3 );
549 - }
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 + }
550 589
551 - // Return the request body.
552 - return $body;
553 - } else {
554 - // Log failed request with no response and return false.
555 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> has no response, this could be a service timeout', 2 );
556 - if ( is_wp_error( $req ) ) {
557 - autoptimizeCriticalCSSCore::ao_ccss_log( $req->get_error_message(), 2 );
590 + return false;
558 591 }
559 -
560 - return false;
561 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;
562 597 }
563 598 }
564 599
565 600 public function ao_ccss_api_results( $jobid, $debug, $dcode ) {
@@ -564,18 +599,20 @@
564 599
565 600 public function ao_ccss_api_results( $jobid, $debug, $dcode ) {
566 601 // GET jobs from criticalcss.com and return responses
567 602 // Get key.
568 - global $ao_ccss_key;
569 - $key = $ao_ccss_key;
603 + $key = $this->criticalcss->get_option( 'key' );
570 604
571 605 // Prepare the request.
572 606 $url = AO_CCSS_API . 'results?resultId=' . $jobid;
573 607 $args = array(
574 - 'headers' => array(
575 - 'User-Agent' => 'Autoptimize CriticalCSS Power-Up v' . AO_CCSS_VER,
576 - 'Authorization' => 'JWT ' . $key,
577 - '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 + )
578 615 ),
579 616 );
580 617
581 618 // Dispatch the request and store its response code.
@@ -592,19 +629,19 @@
592 629 // Response code is OK.
593 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'] ) ) {
594 631 // Workaround criticalcss.com non-RESTful reponses
595 632 // Log successful and return encoded request body.
596 - 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 );
597 634 return $body;
598 635 } elseif ( is_array( $body ) && ( array_key_exists( 'error', $body ) && 'This css no longer exists. Please re-generate it.' == $body['error'] ) ) {
599 636 // Handle no CSS reply
600 637 // Log no CSS error and return encoded request body.
601 - 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 );
602 639 return $body;
603 640 } else {
604 641 // Log failed request and return false.
605 - 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 );
606 - 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 );
607 644 return false;
608 645 }
609 646 } else {
610 647 // Response code is anything else
@@ -609,14 +646,14 @@
609 646 } else {
610 647 // Response code is anything else
611 648 // Log failed request with a valid response code and return body.
612 649 if ( $code ) {
613 - autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied with error code <' . $code . '>, body follows...', 2 );
614 - 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 );
615 652 if ( 401 == $code ) {
616 653 // If request is unauthorized, also clear key status.
617 654 update_option( 'autoptimize_ccss_keyst', 1 );
618 - 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 );
619 656 }
620 657
621 658 // Return the request body.
622 659 return $body;
@@ -621,9 +658,9 @@
621 658 // Return the request body.
622 659 return $body;
623 660 } else {
624 661 // Log failed request with no response and return false.
625 - 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 );
626 663 return false;
627 664 }
628 665 }
629 666 }
@@ -640,41 +677,42 @@
640 677 // Prepare target rule, filename and content.
641 678 $filename = false;
642 679 $content = $ccss;
643 680
644 - if ( autoptimizeCriticalCSSCore::ao_ccss_check_contents( $content ) ) {
681 + if ( $this->criticalcss->check_contents( $content ) ) {
645 682 // Sanitize content, set filename and try to save file.
646 683 $file = AO_CCSS_DIR . 'ccss_' . md5( $ccss . $target[1] ) . $rmark . '.css';
647 684 $status = file_put_contents( $file, $content, LOCK_EX );
648 685 $filename = pathinfo( $file, PATHINFO_BASENAME );
649 - 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 );
650 687
651 688 if ( ! $status ) {
652 689 // If file has not been saved, reset filename.
653 - 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 );
654 691 $filename = false;
655 692 return $filename;
656 693 }
657 694 } else {
658 - 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 );
659 696 return $filename;
660 697 }
661 698
662 699 // Remove old critical CSS if a previous one existed in the rule and if that file exists in filesystem
663 - // NOTE: out of scope critical CSS file removal (issue #5)
664 700 // Attach required arrays.
665 - global $ao_ccss_rules;
701 + $rules = $this->criticalcss->get_option( 'rules' );
666 702
667 - // Prepare rule variables.
668 - $srule = $ao_ccss_rules[ $target[0] ][ $target[1] ];
669 - $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'];
670 707
671 - if ( $oldfile && $oldfile !== $filename ) {
672 - $delfile = AO_CCSS_DIR . $oldfile;
673 - if ( file_exists( $delfile ) ) {
674 - $unlinkst = unlink( $delfile );
675 - if ( $unlinkst ) {
676 - 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 + }
677 715 }
678 716 }
679 717 }
680 718
@@ -684,21 +722,25 @@
684 722
685 723 public function ao_ccss_rule_update( $ljid, $srule, $file, $hash ) {
686 724 // Update or create a rule
687 725 // Attach required arrays.
688 - global $ao_ccss_rules;
726 + $rules = $this->criticalcss->get_option( 'rules' );
689 727
690 728 // Prepare rule variables.
691 729 $trule = explode( '|', $srule );
692 - $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 + }
693 735 $action = false;
694 736 $rtype = '';
695 737
696 - 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'] ) {
697 739 // manual rule, don't ever overwrite.
698 740 $action = 'NOT UPDATED';
699 741 $rtype = 'MANUAL';
700 - } 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'] ) {
701 743 // If this is an user created AUTO rule with no hash and file yet, update its hash and filename
702 744 // Set rule hash, file and action flag.
703 745 $rule['hash'] = $hash;
704 746 $rule['file'] = $file;
@@ -703,9 +745,9 @@
703 745 $rule['hash'] = $hash;
704 746 $rule['file'] = $file;
705 747 $action = 'UPDATED';
706 748 $rtype = 'AUTO';
707 - } 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'] ) ) {
708 750 // If this is an genuine AUTO rule, update its hash and filename
709 751 // Set rule hash, file and action flag.
710 752 $rule['hash'] = $hash;
711 753 $rule['file'] = $file;
@@ -713,9 +755,9 @@
713 755 $rtype = 'AUTO';
714 756 } else {
715 757 // If rule doesn't exist, create an AUTO rule
716 758 // AUTO rules were only for types, but will now also work for paths.
717 - if ( 'types' == $trule[0] || 'paths' == $trule[0] ) {
759 + if ( ( 'types' == $trule[0] || 'paths' == $trule[0] ) && ! empty( $trule[1] ) ) {
718 760 // Set rule hash and file and action flag.
719 761 $rule['hash'] = $hash;
720 762 $rule['file'] = $file;
721 763 $action = 'CREATED';
@@ -721,20 +763,24 @@
721 763 $action = 'CREATED';
722 764 $rtype = 'AUTO';
723 765 } else {
724 766 // Log that no rule was created.
725 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Exception, no AUTO rule created', 3 );
767 + $this->criticalcss->log( 'Exception, no AUTO rule created', 3 );
726 768 }
727 769 }
728 770
729 771 if ( $action ) {
730 772 // If a rule creation/update is required, persist updated rules object.
731 - $ao_ccss_rules[ $trule[0] ][ $trule[1] ] = $rule;
732 - $ao_ccss_rules_raw = json_encode( $ao_ccss_rules );
733 - update_option( 'autoptimize_ccss_rules', $ao_ccss_rules_raw );
734 - 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, '' );
735 781 } else {
736 - autoptimizeCriticalCSSCore::ao_ccss_log( 'No rule action required', 3 );
782 + $this->criticalcss->log( 'No rule action required', 3 );
737 783 }
738 784 }
739 785
740 786 function ao_ccss_finclude( $finclude_raw ) {
@@ -796,37 +842,40 @@
796 842 wp_schedule_event( time(), apply_filters( 'ao_ccss_queue_schedule', 'ao_ccss' ), 'ao_ccss_queue' );
797 843 }
798 844
799 845 // Queue cleaning.
800 - global $ao_ccss_queue;
801 - $queue_purge_threshold = 100;
802 - $queue_purge_age = 24 * 60 * 60;
803 - $queue_length = count( $ao_ccss_queue );
804 - $timestamp_yesterday = microtime( true ) - $queue_purge_age;
805 - $remove_old_new = false;
806 - $queue_altered = false;
846 + $queue = $this->criticalcss->get_option( 'queue' );
807 847
808 - if ( $queue_length > $queue_purge_threshold ) {
809 - $remove_old_new = true;
810 - }
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;
811 855
812 - foreach ( $ao_ccss_queue as $path => $job ) {
813 - 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' ) ) ) {
814 - unset( $ao_ccss_queue[ $path ] );
815 - $queue_altered = true;
856 + if ( $queue_length > $queue_purge_threshold ) {
857 + $remove_old_new = true;
816 858 }
817 - }
818 859
819 - // save queue to options!
820 - if ( $queue_altered ) {
821 - $ao_ccss_queue_raw = json_encode( $ao_ccss_queue );
822 - update_option( 'autoptimize_ccss_queue', $ao_ccss_queue_raw, false );
823 - 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 + }
824 873 }
825 874
826 875 // re-check key if invalid.
827 - global $ao_ccss_keyst;
828 - if ( 1 == $ao_ccss_keyst ) {
876 + $keyst = $this->criticalcss->get_option( 'keyst' );
877 + if ( 1 == $keyst ) {
829 878 $this->ao_ccss_api_generate( '', '', '' );
830 879 }
831 880 }
832 881 }