PluginProbe
Autoptimize / 3.1.16
Autoptimize v3.1.16
3.1.16 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 All 108 releases
← All changes | classes/autoptimizeCriticalCSSCron.php +321 -269 2.7.0 → 3.1.16 View file →
@@ -8,17 +8,18 @@
8 8 exit;
9 9 }
10 10
11 11 class autoptimizeCriticalCSSCron {
12 - public function __construct()
13 - {
14 - // fetch all options at once and populate them individually explicitely as globals.
15 - $all_options = autoptimizeCriticalCSSBase::fetch_options();
16 - foreach ( $all_options as $_option => $_value ) {
17 - global ${$_option};
18 - ${$_option} = $_value;
19 - }
12 + /**
13 + * Critical CSS object.
14 + *
15 + * @var object
16 + */
17 + protected $criticalcss;
20 18
19 + public function __construct() {
20 + $this->criticalcss = autoptimize()->criticalcss();
21 +
21 22 // Add queue control to a registered event.
22 23 add_action( 'ao_ccss_queue', array( $this, 'ao_ccss_queue_control' ) );
23 24 // Add cleaning job to a registered event.
24 25 add_action( 'ao_ccss_maintenance', array( $this, 'ao_ccss_cleaning' ) );
@@ -25,12 +26,13 @@
25 26 }
26 27
27 28 public function ao_ccss_queue_control() {
28 29 // The queue execution backend.
29 - global $ao_ccss_key;
30 - if ( ! isset( $ao_ccss_key ) || empty( $ao_ccss_key ) ) {
30 + $key = $this->criticalcss->get_option( 'key' );
31 +
32 + if ( empty( $key ) ) {
31 33 // no key set, not processing the queue!
32 - autoptimizeCriticalCSSCore::ao_ccss_log( 'No key set, so not processing queue.', 3 );
34 + $this->criticalcss->log( 'No key set, so not processing queue.', 3 );
33 35 return;
34 36 }
35 37
36 38 /**
@@ -55,9 +57,9 @@
55 57 $qdobj = json_decode( $qdobj_raw, true );
56 58 if ( $qdobj ) {
57 59 if ( 1 === $qdobj['enable'] ) {
58 60 $queue_debug = true;
59 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue operating in debug mode with the following settings: <' . $qdobj_raw . '>', 3 );
61 + $this->criticalcss->log( 'Queue operating in debug mode with the following settings: <' . $qdobj_raw . '>', 3 );
60 62 }
61 63 }
62 64 }
63 65
@@ -75,27 +77,39 @@
75 77 // Proceed with the queue if it's not already running.
76 78 if ( ! $queue_lock ) {
77 79
78 80 // Log queue start and create the lock file.
79 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control started', 3 );
81 + $this->criticalcss->log( 'Queue control started', 3 );
80 82 if ( touch( AO_CCSS_LOCK ) ) {
81 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control locked', 3 );
83 + $this->criticalcss->log( 'Queue control locked', 3 );
82 84 }
83 85
84 86 // Attach required variables.
85 - global $ao_ccss_queue;
86 - global $ao_ccss_rlimit;
87 + $queue = $this->criticalcss->get_option( 'queue' );
88 + $rtimelimit = $this->criticalcss->get_option( 'rtimelimit' );
87 89
88 - // Initialize job counters.
89 - $jc = 1;
90 - $jr = 1;
91 - $jt = count( $ao_ccss_queue );
90 + // make sure we have the queue and bail if not.
91 + if ( empty( $queue ) || ! is_array( $queue ) ) {
92 + $this->criticalcss->log( 'Job processing cannot work on an empty queue, aborting.', 3 );
93 + unlink( AO_CCSS_LOCK );
94 + return;
95 + }
92 96
97 + // Initialize counters.
98 + if ( empty( $rtimelimit ) || 0 == $rtimelimit ) {
99 + // no time limit set, let's go with 1000 seconds.
100 + $rtimelimit = 1000;
101 + }
102 + $mt = time() + (int) $rtimelimit; // maxtime queue processing can run.
103 + $jc = 1; // job count number.
104 + $jr = 1; // jobs requests number.
105 + $jt = count( $queue ); // number of jobs in queue.
106 +
93 107 // Sort queue by ascending job status (e.g. ERROR, JOB_ONGOING, JOB_QUEUED, NEW...).
94 - array_multisort( array_column( $ao_ccss_queue, 'jqstat' ), $ao_ccss_queue ); // @codingStandardsIgnoreLine
108 + array_multisort( array_column( $queue, 'jqstat' ), $queue ); // @codingStandardsIgnoreLine
95 109
96 110 // Iterates over the entire queue.
97 - foreach ( $ao_ccss_queue as $path => $jprops ) {
111 + foreach ( $queue as $path => $jprops ) {
98 112 // Prepare flags and target rule.
99 113 $update = false;
100 114 $deljob = false;
101 115 $rule_update = false;
@@ -102,15 +116,15 @@
102 116 $oldccssfile = false;
103 117 $trule = explode( '|', $jprops['rtarget'] );
104 118
105 119 // Log job count.
106 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Processing job ' . $jc . ' of ' . $jt . ' with id <' . $jprops['ljid'] . '> and status <' . $jprops['jqstat'] . '>', 3 );
120 + $this->criticalcss->log( 'Processing job ' . $jc . ' of ' . $jt . ' with id <' . $jprops['ljid'] . '> and status <' . $jprops['jqstat'] . '>', 3 );
107 121
108 122 // Process NEW jobs.
109 123 if ( 'NEW' == $jprops['jqstat'] ) {
110 124
111 125 // Log the new job.
112 - autoptimizeCriticalCSSCore::ao_ccss_log( 'Found NEW job with local ID <' . $jprops['ljid'] . '>, starting its queue processing', 3 );
126 + $this->criticalcss->log( 'Found NEW job with local ID <' . $jprops['ljid'] . '>, starting its queue processing', 3 );
113 127
114 128 // Compare job and rule hashes (if any).
115 129 $hash = $this->ao_ccss_diff_hashes( $jprops['ljid'], $jprops['hash'], $jprops['hashes'], $jprops['rtarget'] );
116 130
@@ -115,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 }