PluginProbe ʕ •ᴥ•ʔ
LiteSpeed Cache / 7.8.1
LiteSpeed Cache v7.8.1
trunk 1.0.15 1.9.1.1 2.9.9.2 3.6.4 4.6 5.7.0.1 6.5.4 7.0.0.1 7.0.1 7.1 7.2 7.3 7.3.0.1 7.4 7.5 7.5.0.1 7.6 7.6.1 7.6.2 7.7 7.8 7.8.0.1 7.8.1
litespeed-cache / src / css.cls.php
litespeed-cache / src Last commit date
cdn 2 months ago data_structure 2 months ago activation.cls.php 2 months ago admin-display.cls.php 2 months ago admin-settings.cls.php 2 months ago admin.cls.php 2 months ago api.cls.php 2 months ago avatar.cls.php 2 months ago base.cls.php 2 months ago cdn.cls.php 2 months ago cloud-auth-callback.trait.php 2 months ago cloud-auth-ip.trait.php 2 months ago cloud-auth.trait.php 2 months ago cloud-misc.trait.php 2 months ago cloud-node.trait.php 2 months ago cloud-request.trait.php 2 months ago cloud.cls.php 2 months ago conf.cls.php 2 months ago control.cls.php 2 months ago core.cls.php 2 months ago crawler-map.cls.php 2 months ago crawler.cls.php 2 months ago css.cls.php 2 months ago data.cls.php 2 months ago data.upgrade.func.php 2 months ago db-optm.cls.php 2 months ago debug2.cls.php 2 months ago doc.cls.php 2 months ago error.cls.php 2 months ago esi.cls.php 2 months ago file.cls.php 2 months ago guest.cls.php 2 months ago gui.cls.php 2 months ago health.cls.php 2 months ago htaccess.cls.php 2 months ago img-optm-manage.trait.php 2 months ago img-optm-pull.trait.php 2 months ago img-optm-send.trait.php 2 months ago img-optm.cls.php 2 months ago import.cls.php 2 months ago import.preset.cls.php 2 months ago lang.cls.php 2 months ago localization.cls.php 2 months ago media.cls.php 2 months ago metabox.cls.php 2 months ago object-cache-wp.cls.php 2 months ago object-cache.cls.php 2 months ago object.lib.php 2 months ago optimize.cls.php 2 months ago optimizer.cls.php 2 months ago placeholder.cls.php 2 months ago purge.cls.php 2 months ago report.cls.php 2 months ago rest.cls.php 2 months ago root.cls.php 2 months ago router.cls.php 2 months ago str.cls.php 2 months ago tag.cls.php 2 months ago task.cls.php 2 months ago tool.cls.php 2 months ago ucss.cls.php 2 months ago utility.cls.php 2 months ago vary.cls.php 2 months ago vpi.cls.php 2 months ago
css.cls.php
680 lines
1 <?php
2 /**
3 * Optimize CSS handler.
4 *
5 * @package LiteSpeed
6 * @since 2.3
7 */
8
9 namespace LiteSpeed;
10
11 defined( 'WPINC' ) || exit();
12
13 /**
14 * Optimize CSS handler class.
15 */
16 class CSS extends Base {
17
18 const LOG_TAG = '[CSS]';
19
20 const TYPE_GEN_CCSS = 'gen_ccss';
21 const TYPE_CLEAR_Q_CCSS = 'clear_q_ccss';
22
23 /**
24 * Summary cache.
25 *
26 * @var array
27 */
28 protected $_summary;
29
30 /**
31 * Cached CCSS whitelist.
32 *
33 * @var array|null
34 */
35 private $_ccss_whitelist;
36
37 /**
38 * Request queue.
39 *
40 * @var array
41 */
42 private $_queue;
43
44 /**
45 * Init.
46 *
47 * @since 3.0
48 */
49 public function __construct() {
50 $this->_summary = self::get_summary();
51
52 add_filter( 'litespeed_ccss_whitelist', [ $this->cls( 'Data' ), 'load_ccss_whitelist' ] );
53 }
54
55 /**
56 * HTML lazyload CSS.
57 *
58 * @since 4.0
59 * @return string
60 */
61 public function prepare_html_lazy() {
62 return '<style>' . implode( ',', $this->conf( self::O_OPTM_HTML_LAZY ) ) . '{content-visibility:auto;contain-intrinsic-size:1px 1000px;}</style>';
63 }
64
65 /**
66 * Output critical CSS.
67 *
68 * @since 1.3
69 * @access public
70 * @return string|null
71 */
72 public function prepare_ccss() {
73 // Get critical css for current page
74 // Note: need to consider mobile
75 $rules = $this->_ccss();
76 if ( ! $rules ) {
77 return null;
78 }
79
80 $error_tag = '';
81 if ( substr( $rules, 0, 2 ) === '/*' && substr( $rules, -2 ) === '*/' ) {
82 Core::comment( 'QUIC.cloud CCSS bypassed due to generation error ❌' );
83 $error_tag = ' data-error="failed to generate"';
84 }
85
86 // Append default critical css
87 $rules .= $this->conf( self::O_OPTM_CCSS_CON );
88
89 return '<style id="litespeed-ccss"' . $error_tag . '>' . $rules . '</style>';
90 }
91
92 /**
93 * Generate CCSS url tag.
94 *
95 * @since 4.0
96 * @param string $request_url Current request URL.
97 * @return string
98 */
99 private function _gen_ccss_file_tag( $request_url ) {
100 if ( is_404() ) {
101 return '404';
102 }
103
104 if ( $this->conf( self::O_OPTM_CCSS_PER_URL ) ) {
105 return $request_url;
106 }
107
108 $sep_uri = $this->conf( self::O_OPTM_CCSS_SEP_URI );
109 $hit = false;
110 if ( $sep_uri ) {
111 $hit = Utility::str_hit_array( $request_url, $sep_uri );
112 }
113 if ( $sep_uri && $hit ) {
114 Debug2::debug( '[CCSS] Separate CCSS due to separate URI setting: ' . $hit );
115 return $request_url;
116 }
117
118 $pt = Utility::page_type();
119
120 $sep_pt = $this->conf( self::O_OPTM_CCSS_SEP_POSTTYPE );
121 if ( in_array( $pt, $sep_pt, true ) ) {
122 Debug2::debug( '[CCSS] Separate CCSS due to posttype setting: ' . $pt );
123 return $request_url;
124 }
125
126 // Per posttype
127 return $pt;
128 }
129
130 /**
131 * The critical css content of the current page.
132 *
133 * @since 2.3
134 * @return string|null
135 */
136 private function _ccss() {
137 global $wp;
138
139 // get current request url
140 $permalink_structure = get_option( 'permalink_structure' );
141 if ( ! empty( $permalink_structure ) ) {
142 $request_url = trailingslashit( home_url( $wp->request ) );
143 } else {
144 $qs_add = $wp->query_string ? '?' . (string) $wp->query_string : '' ;
145 $request_url = home_url( $wp->request ) . $qs_add;
146 }
147
148 $filepath_prefix = $this->_build_filepath_prefix( 'ccss' );
149 $url_tag = $this->_gen_ccss_file_tag( $request_url );
150 $vary = $this->cls( 'Vary' )->finalize_full_varies();
151 $filename = $this->cls( 'Data' )->load_url_file( $url_tag, $vary, 'ccss' );
152 if ( $filename ) {
153 $static_file = LITESPEED_STATIC_DIR . $filepath_prefix . $filename . '.css';
154
155 if ( file_exists( $static_file ) ) {
156 Debug2::debug2( '[CSS] existing ccss ' . $static_file );
157 Core::comment( 'QUIC.cloud CCSS loaded �
158 ' . $filepath_prefix . $filename . '.css' );
159 return File::read( $static_file );
160 }
161 }
162
163 $uid = get_current_user_id();
164
165 $ua = isset( $_SERVER['HTTP_USER_AGENT'] )
166 ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) )
167 : '';
168
169 // Store it to prepare for cron
170 Core::comment( 'QUIC.cloud CCSS in queue' );
171 $this->_queue = $this->load_queue( 'ccss' );
172
173 if ( count( $this->_queue ) > 500 ) {
174 self::debug( 'CCSS Queue is full - 500' );
175 return null;
176 }
177
178 $queue_k = ( strlen( $vary ) > 32 ? md5( $vary ) : $vary ) . ' ' . $url_tag;
179 $this->_queue[ $queue_k ] = [
180 'url' => apply_filters( 'litespeed_ccss_url', $request_url ),
181 'user_agent' => substr( $ua, 0, 200 ),
182 'is_mobile' => $this->_separate_mobile(),
183 'is_webp' => $this->cls( 'Media' )->webp_support() ? 1 : 0,
184 'uid' => $uid,
185 'vary' => $vary,
186 'url_tag' => $url_tag,
187 ]; // Current UA will be used to request
188 $this->save_queue( 'ccss', $this->_queue );
189 self::debug( 'Added queue_ccss [url_tag] ' . $url_tag . ' [UA] ' . $ua . ' [vary] ' . $vary . ' [uid] ' . $uid );
190
191 // Prepare cache tag for later purge
192 Tag::add( 'CCSS.' . md5( $queue_k ) );
193
194 return null;
195 }
196
197 /**
198 * Cron ccss generation.
199 *
200 * @since 2.3
201 * @access private
202 *
203 * @param bool $should_continue Continue processing multiple items.
204 * @return mixed
205 */
206 public static function cron_ccss( $should_continue = false ) {
207 $_instance = self::cls();
208 return $_instance->_cron_handler( 'ccss', $should_continue );
209 }
210
211 /**
212 * Handle UCSS/CCSS cron.
213 *
214 * @since 4.2
215 *
216 * @param string $type Job type: 'ccss' or 'ucss'.
217 * @param bool $should_continue Continue processing multiple items.
218 * @return void
219 */
220 private function _cron_handler( $type, $should_continue ) {
221 $this->_queue = $this->load_queue( $type );
222
223 if ( empty( $this->_queue ) ) {
224 return;
225 }
226
227 $type_tag = strtoupper( $type );
228
229 // For cron, need to check request interval too
230 if ( ! $should_continue ) {
231 if ( ! empty( $this->_summary[ 'curr_request_' . $type ] ) && time() - (int) $this->_summary[ 'curr_request_' . $type ] < 300 && ! $this->conf( self::O_DEBUG ) ) {
232 Debug2::debug( '[' . $type_tag . '] Last request not done' );
233 return;
234 }
235 }
236
237 $i = 0;
238 foreach ( $this->_queue as $k => $v ) {
239 if ( ! empty( $v['_status'] ) ) {
240 continue;
241 }
242
243 Debug2::debug( '[' . $type_tag . '] cron job [tag] ' . $k . ' [url] ' . $v['url'] . ( $v['is_mobile'] ? ' 📱 ' : '' ) . ' [UA] ' . $v['user_agent'] );
244
245 if ( 'ccss' === $type && empty( $v['url_tag'] ) ) {
246 unset( $this->_queue[ $k ] );
247 $this->save_queue( $type, $this->_queue );
248 Debug2::debug( '[CCSS] wrong queue_ccss format' );
249 continue;
250 }
251
252 if ( ! isset( $v['is_webp'] ) ) {
253 $v['is_webp'] = false;
254 }
255
256 ++$i;
257 $res = $this->_send_req( $v['url'], $k, $v['uid'], $v['user_agent'], $v['vary'], $v['url_tag'], $type, $v['is_mobile'], $v['is_webp'] );
258 if ( ! $res ) {
259 // Status is wrong, drop this this->_queue
260 unset( $this->_queue[ $k ] );
261 $this->save_queue( $type, $this->_queue );
262
263 if ( ! $should_continue ) {
264 return;
265 }
266
267 if ( $i > 3 ) {
268 GUI::print_loading( count( $this->_queue ), $type_tag );
269 return Router::self_redirect( Router::ACTION_CSS, self::TYPE_GEN_CCSS );
270 }
271
272 continue;
273 }
274
275 // Exit queue if out of quota or service is hot
276 if ( 'out_of_quota' === $res || 'svc_hot' === $res ) {
277 return;
278 }
279
280 $this->_queue[ $k ]['_status'] = 'requested';
281 $this->save_queue( $type, $this->_queue );
282
283 // only request first one
284 if ( ! $should_continue ) {
285 return;
286 }
287
288 if ( $i > 3 ) {
289 GUI::print_loading( count( $this->_queue ), $type_tag );
290 return Router::self_redirect( Router::ACTION_CSS, self::TYPE_GEN_CCSS );
291 }
292 }
293 }
294
295 /**
296 * Send to QC API to generate CCSS/UCSS.
297 *
298 * @since 2.3
299 * @access private
300 *
301 * @param string $request_url Request URL.
302 * @param string $queue_k Queue key.
303 * @param int $uid WP User ID.
304 * @param string $user_agent User agent string.
305 * @param string $vary Vary string.
306 * @param string $url_tag URL tag.
307 * @param string $type Type: 'ccss' or 'ucss'.
308 * @param bool $is_mobile Is mobile.
309 * @param bool $is_webp Has webp support.
310 * @return bool|string True on success, 'out_of_quota' / 'svc_hot' on special cases, false on failure.
311 */
312 private function _send_req( $request_url, $queue_k, $uid, $user_agent, $vary, $url_tag, $type, $is_mobile, $is_webp ) {
313 // Check if has credit to push or not
314 $err = false;
315 $allowance = $this->cls( 'Cloud' )->allowance( Cloud::SVC_CCSS, $err );
316 if ( ! $allowance ) {
317 Debug2::debug( '[CCSS] No credit: ' . $err );
318 $err && Admin_Display::error( Error::msg( $err ) );
319 return 'out_of_quota';
320 }
321
322 set_time_limit( 120 );
323
324 // Update css request status
325 $this->_summary[ 'curr_request_' . $type ] = time();
326 self::save_summary();
327
328 // Gather guest HTML to send
329 $html = $this->prepare_html( $request_url, $user_agent, $uid );
330
331 if ( ! $html ) {
332 return false;
333 }
334
335 // Parse HTML to gather all CSS content before requesting
336 list( $css, $html ) = $this->prepare_css( $html, $is_webp );
337
338 if ( ! $css ) {
339 $type_tag = strtoupper( $type );
340 Debug2::debug( '[' . $type_tag . '] No combined css' );
341 return false;
342 }
343
344 // Generate critical css
345 $data = [
346 'url' => $request_url,
347 'queue_k' => $queue_k,
348 'user_agent' => $user_agent,
349 'is_mobile' => $is_mobile ? 1 : 0, // todo:compatible w/ tablet
350 'is_webp' => $is_webp ? 1 : 0,
351 'html' => $html,
352 'css' => $css,
353 ];
354 if ( ! isset( $this->_ccss_whitelist ) ) {
355 $this->_ccss_whitelist = $this->_filter_whitelist();
356 }
357 $data['whitelist'] = $this->_ccss_whitelist;
358
359 self::debug( 'Generating: ', $data );
360
361 $json = Cloud::post( Cloud::SVC_CCSS, $data, 30 );
362 if ( ! is_array( $json ) ) {
363 return $json;
364 }
365
366 // Old version compatibility
367 if ( empty( $json['status'] ) ) {
368 if ( ! empty( $json[ $type ] ) ) {
369 $this->_save_con( $type, $json[ $type ], $queue_k, $is_mobile, $is_webp );
370 }
371
372 // Delete the row
373 return false;
374 }
375
376 // Unknown status, remove this line
377 if ( 'queued' !== $json['status'] ) {
378 return false;
379 }
380
381 // Save summary data
382 $this->_summary[ 'last_spent_' . $type ] = time() - (int) $this->_summary[ 'curr_request_' . $type ];
383 $this->_summary[ 'last_request_' . $type ] = $this->_summary[ 'curr_request_' . $type ];
384 $this->_summary[ 'curr_request_' . $type ] = 0;
385 self::save_summary();
386
387 return true;
388 }
389
390 /**
391 * Save CCSS/UCSS content.
392 *
393 * @since 4.2
394 *
395 * @param string $type Type: 'ccss' or 'ucss'.
396 * @param string $css CSS content.
397 * @param string $queue_k Queue key.
398 * @param bool $mobile Is mobile.
399 * @param bool $webp Has webp support.
400 * @return void
401 */
402 private function _save_con( $type, $css, $queue_k, $mobile, $webp ) {
403 // Add filters
404 $css = apply_filters( 'litespeed_' . $type, $css, $queue_k );
405 // Sanitize: CSS must not contain HTML tags
406 $css = wp_strip_all_tags( $css );
407 Debug2::debug2( '[CSS] con: ' . $css );
408
409 if ( substr( $css, 0, 2 ) === '/*' && substr( $css, -2 ) === '*/' ) {
410 self::debug( ' empty ' . $type . ' [content] ' . $css );
411 // continue; // Save the error info too
412 }
413
414 // Write to file
415 $filecon_md5 = md5( $css );
416
417 $filepath_prefix = $this->_build_filepath_prefix( $type );
418 $static_file = LITESPEED_STATIC_DIR . $filepath_prefix . $filecon_md5 . '.css';
419
420 File::save( $static_file, $css, true );
421
422 $url_tag = $this->_queue[ $queue_k ]['url_tag'];
423 $vary = $this->_queue[ $queue_k ]['vary'];
424 Debug2::debug2( "[CSS] Save URL to file [file] $static_file [vary] $vary" );
425
426 $this->cls( 'Data' )->save_url( $url_tag, $vary, $type, $filecon_md5, dirname( $static_file ), $mobile, $webp );
427
428 Purge::add( strtoupper( $type ) . '.' . md5( $queue_k ) );
429 }
430
431 /**
432 * Play for fun.
433 *
434 * @since 3.4.3
435 *
436 * @param string $request_url URL to test.
437 * @return void
438 */
439 public function test_url( $request_url ) {
440 $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
441 $html = $this->prepare_html( $request_url, $user_agent );
442 list( $css, $html ) = $this->prepare_css( $html, true, true );
443
444 $data = [
445 'url' => $request_url,
446 'ccss_type' => 'test',
447 'user_agent' => $user_agent,
448 'is_mobile' => 0,
449 'html' => $html,
450 'css' => $css,
451 'type' => 'CCSS',
452 ];
453
454 $json = Cloud::post( Cloud::SVC_CCSS, $data, 180 );
455
456 Debug2::debug2( '[CSS][test_url] response', $json );
457 }
458
459 /**
460 * Prepare HTML from URL.
461 *
462 * @since 3.4.3
463 *
464 * @param string $request_url URL to fetch.
465 * @param string $user_agent User agent to use.
466 * @param int|bool $uid Optional user ID for simulation.
467 * @return string|false
468 */
469 public function prepare_html( $request_url, $user_agent, $uid = false ) {
470 $html = $this->cls( 'Crawler' )->self_curl( add_query_arg( 'LSCWP_CTRL', 'before_optm', $request_url ), $user_agent, $uid );
471 Debug2::debug2( '[CSS] self_curl result....', $html );
472
473 if ( ! $html ) {
474 return false;
475 }
476
477 $html = $this->cls( 'Optimizer' )->html_min( $html, true );
478 // Drop <noscript>xxx</noscript>
479 $html = preg_replace( '#<noscript>.*</noscript>#isU', '', $html );
480
481 return $html;
482 }
483
484 /**
485 * Prepare CSS from HTML for CCSS generation only. UCSS will use combined CSS directly.
486 * Prepare refined HTML for both CCSS and UCSS.
487 *
488 * @since 3.4.3
489 *
490 * @param string $html HTML content.
491 * @param bool $is_webp Convert backgrounds to WebP when supported.
492 * @param bool $dryrun If true, do not fetch external CSS files.
493 * @return array{0:string,1:string} [combined CSS, refined HTML]
494 */
495 public function prepare_css( $html, $is_webp = false, $dryrun = false ) {
496 $css = '';
497 preg_match_all( '#<link ([^>]+)/?>|<style([^>]*)>([^<]+)</style>#isU', $html, $matches, PREG_SET_ORDER );
498 foreach ( $matches as $match ) {
499 $debug_info = '';
500 if ( strpos( $match[0], '<link' ) === 0 ) {
501 $attrs = Utility::parse_attr( $match[1] );
502
503 if ( empty( $attrs['rel'] ) ) {
504 continue;
505 }
506
507 if ( 'stylesheet' !== $attrs['rel'] ) {
508 if ( 'preload' !== $attrs['rel'] || empty( $attrs['as'] ) || 'style' !== $attrs['as'] ) {
509 continue;
510 }
511 }
512
513 if ( ! empty( $attrs['media'] ) && false !== strpos( $attrs['media'], 'print' ) ) {
514 continue;
515 }
516
517 if ( empty( $attrs['href'] ) ) {
518 continue;
519 }
520
521 // Check Google fonts hit
522 if ( false !== strpos( $attrs['href'], 'fonts.googleapis.com' ) ) {
523 $html = str_replace( $match[0], '', $html );
524 continue;
525 }
526
527 $debug_info = $attrs['href'];
528
529 // Load CSS content
530 if ( ! $dryrun ) {
531 // Dryrun will not load CSS but just drop them
532 $con = $this->cls( 'Optimizer' )->load_file( $attrs['href'] );
533 if ( ! $con ) {
534 continue;
535 }
536 } else {
537 $con = '';
538 }
539 } else {
540 // Inline style
541 $attrs = Utility::parse_attr( $match[2] );
542
543 if ( ! empty( $attrs['media'] ) && false !== strpos( $attrs['media'], 'print' ) ) {
544 continue;
545 }
546
547 Debug2::debug2( '[CSS] Load inline CSS ' . substr( $match[3], 0, 100 ) . '...', $attrs );
548 $con = $match[3];
549
550 $debug_info = '__INLINE__';
551 }
552
553 $con = Optimizer::minify_css( $con );
554 if ( $is_webp && $this->cls( 'Media' )->webp_support() ) {
555 $con = $this->cls( 'Media' )->replace_background_webp( $con );
556 }
557
558 if ( ! empty( $attrs['media'] ) && 'all' !== $attrs['media'] ) {
559 $con = '@media ' . $attrs['media'] . '{' . $con . "}\n";
560 } else {
561 $con = $con . "\n";
562 }
563
564 $con = '/* ' . $debug_info . ' */' . $con;
565 $css .= $con;
566
567 $html = str_replace( $match[0], '', $html );
568 }
569
570 return [ $css, $html ];
571 }
572
573 /**
574 * Filter the comment content, add quotes to selector from whitelist. Return the json.
575 *
576 * @since 7.1
577 * @return array
578 */
579 private function _filter_whitelist() {
580 $whitelist = [];
581 $list = apply_filters( 'litespeed_ccss_whitelist', $this->conf( self::O_OPTM_CCSS_SELECTOR_WHITELIST ) );
582 foreach ( $list as $v ) {
583 if ( substr( $v, 0, 2 ) === '//' ) {
584 continue;
585 }
586 $whitelist[] = $v;
587 }
588
589 return $whitelist;
590 }
591
592 /**
593 * Notify finished from server.
594 *
595 * @since 7.1
596 * @return array
597 */
598 public function notify() {
599 // phpcs:ignore WordPress.Security.NonceVerification.Missing
600 $post_data = \json_decode( file_get_contents( 'php://input' ), true );
601 if ( is_null( $post_data ) ) {
602 // Fallback for form-encoded payloads
603 // phpcs:ignore WordPress.Security.NonceVerification.Missing
604 $post_data = $_POST;
605 }
606 self::debug( 'notify() data', $post_data );
607
608 $this->_queue = $this->load_queue( 'ccss' );
609
610 list( $post_data ) = $this->cls( 'Cloud' )->extract_msg( $post_data, 'ccss' );
611
612 $notified_data = $post_data['data'];
613 if ( empty( $notified_data ) || ! is_array( $notified_data ) ) {
614 self::debug( '❌ notify exit: no notified data' );
615 return Cloud::err( 'no notified data' );
616 }
617
618 // Check if its in queue or not
619 $valid_i = 0;
620 foreach ( $notified_data as $v ) {
621 if ( empty( $v['request_url'] ) ) {
622 self::debug( '❌ notify bypass: no request_url', $v );
623 continue;
624 }
625 if ( empty( $v['queue_k'] ) ) {
626 self::debug( '❌ notify bypass: no queue_k', $v );
627 continue;
628 }
629
630 if ( empty( $this->_queue[ $v['queue_k'] ] ) ) {
631 self::debug( '❌ notify bypass: no this queue [q_k]' . $v['queue_k'] );
632 continue;
633 }
634
635 // Save data
636 if ( ! empty( $v['data_ccss'] ) ) {
637 $is_mobile = $this->_queue[ $v['queue_k'] ]['is_mobile'];
638 $is_webp = $this->_queue[ $v['queue_k'] ]['is_webp'];
639 $this->_save_con( 'ccss', $v['data_ccss'], $v['queue_k'], $is_mobile, $is_webp );
640
641 ++$valid_i;
642 }
643
644 unset( $this->_queue[ $v['queue_k'] ] );
645 self::debug( 'notify data handled, unset queue [q_k] ' . $v['queue_k'] );
646 }
647 $this->save_queue( 'ccss', $this->_queue );
648
649 self::debug( 'notified' );
650
651 return Cloud::ok( [ 'count' => $valid_i ] );
652 }
653
654 /**
655 * Handle all request actions from main cls.
656 *
657 * @since 2.3
658 * @access public
659 * @return void
660 */
661 public function handler() {
662 $type = Router::verify_type();
663
664 switch ( $type ) {
665 case self::TYPE_GEN_CCSS:
666 self::cron_ccss( true );
667 break;
668
669 case self::TYPE_CLEAR_Q_CCSS:
670 $this->clear_q( 'ccss' );
671 break;
672
673 default:
674 break;
675 }
676
677 Admin::redirect();
678 }
679 }
680