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