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 / gui.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
gui.cls.php
1267 lines
1 <?php
2 /**
3 * The frontend GUI class.
4 *
5 * Provides front-end and admin-bar UI helpers for LiteSpeed Cache.
6 *
7 * @package LiteSpeed
8 * @since 1.3
9 */
10
11 namespace LiteSpeed;
12
13 defined( 'WPINC' ) || exit();
14
15 /**
16 * GUI helpers for LiteSpeed Cache.
17 */
18 class GUI extends Base {
19 const LOG_TAG = '[GUI]';
20
21 /**
22 * Counter for temporary HTML wrappers.
23 *
24 * @var int Counter for temporary HTML wrappers to remove from the buffer.
25 */
26 private static $_clean_counter = 0;
27
28 /**
29 * Promo display flag.
30 *
31 * @var bool Internal flag used by promo templates to decide whether to display.
32 */
33 private $_promo_true = false;
34
35 /**
36 * Promo list configuration.
37 *
38 * Format: [ file_tag => [ days, litespeed_only ], ... ]
39 *
40 * @var array<string, array{0:int,1:bool}>
41 */
42 private $_promo_list = [
43 'new_version' => [ 7, false ],
44 'score' => [ 14, false ],
45 // 'slack' => [ 3, false ],
46 ];
47
48 /** Path to guest JavaScript file. */
49 const LIB_GUEST_JS = 'assets/js/guest.min.js';
50
51 /** Path to guest document.referrer JavaScript file. */
52 const LIB_GUEST_DOCREF_JS = 'assets/js/guest.docref.min.js';
53
54 /** Path to guest vary endpoint. */
55 const PHP_GUEST = 'guest.vary.php';
56
57 /** Dismiss type: WHM. */
58 const TYPE_DISMISS_WHM = 'whm';
59
60 /** Dismiss type: ExpiresDefault. */
61 const TYPE_DISMISS_EXPIRESDEFAULT = 'ExpiresDefault';
62
63 /** Dismiss type: Promo. */
64 const TYPE_DISMISS_PROMO = 'promo';
65
66 /** Dismiss type: PIN. */
67 const TYPE_DISMISS_PIN = 'pin';
68
69 /** WHM message option name. */
70 const WHM_MSG = 'lscwp_whm_install';
71
72 /** WHM message option value. */
73 const WHM_MSG_VAL = 'whm_install';
74
75 /**
76 * Summary options cache.
77 *
78 * @var array<string,mixed> Summary/options cache.
79 */
80 protected $_summary;
81
82 /**
83 * Instance.
84 *
85 * @since 1.3
86 */
87 public function __construct() {
88 $this->_summary = self::get_summary();
89 }
90
91 /**
92 * Frontend init.
93 *
94 * @since 3.0
95 */
96 public function init() {
97 self::debug2( 'init' );
98
99 if ( is_admin_bar_showing() && current_user_can( 'manage_options' ) ) {
100 add_action( 'wp_enqueue_scripts', [ $this, 'frontend_enqueue_style' ] );
101 add_action( 'admin_bar_menu', [ $this, 'frontend_shortcut' ], 95 );
102 }
103
104 /**
105 * Turn on instant click.
106 *
107 * @since 1.8.2
108 */
109 if ( $this->conf( self::O_UTIL_INSTANT_CLICK ) ) {
110 add_action( 'wp_enqueue_scripts', [ $this, 'frontend_enqueue_style_public' ] );
111 }
112
113 // NOTE: this needs to be before optimizer to avoid wrapper being removed.
114 add_filter( 'litespeed_buffer_finalize', [ $this, 'finalize' ], 8 );
115 }
116
117 /**
118 * Print a loading message when redirecting CCSS/UCSS page to avoid blank page confusion.
119 *
120 * @param int $counter Files left in queue.
121 * @param string $type Queue type label.
122 * @return void
123 */
124 public static function print_loading( $counter, $type ) {
125 echo '<div style="font-size:25px;text-align:center;padding-top:150px;width:100%;position:absolute;">';
126 echo "<img width='35' src='" . esc_url( LSWCP_PLUGIN_URL . 'assets/img/Litespeed.icon.svg' ) . "' alt='' /> ";
127 printf(
128 /* translators: 1: number, 2: text */
129 esc_html__( '%1$s %2$s files left in queue', 'litespeed-cache' ),
130 esc_html( number_format_i18n( $counter ) ),
131 esc_html( $type )
132 );
133 echo '<p><a href="' . esc_url( admin_url( 'admin.php?page=litespeed-page_optm' ) ) . '">' . esc_html__( 'Cancel', 'litespeed-cache' ) . '</a></p>';
134 echo '</div>';
135 }
136
137 /**
138 * Display the tab list.
139 *
140 * @since 7.3
141 *
142 * @param array<string,string> $tabs Key => Label pairs.
143 * @return void
144 */
145 public static function display_tab_list( $tabs ) {
146 $i = 1;
147 foreach ( $tabs as $k => $val ) {
148 $accesskey = $i <= 9 ? $i : '';
149 printf(
150 '<a class="litespeed-tab nav-tab" href="#%1$s" data-litespeed-tab="%1$s" litespeed-accesskey="%2$s">%3$s</a>',
151 esc_attr( $k ),
152 esc_attr( $accesskey ),
153 esc_html( $val )
154 );
155 ++$i;
156 }
157 }
158
159 /**
160 * Render a pie chart SVG string.
161 *
162 * @since 1.6.6
163 *
164 * @param int $percent Percentage 0-100.
165 * @param int $width Width/height in pixels.
166 * @param bool $finished_tick Show a tick when 100%.
167 * @param bool $without_percentage Hide the % label.
168 * @param string|bool $append_cls Extra CSS class.
169 * @return string SVG markup.
170 */
171 public static function pie( $percent, $width = 50, $finished_tick = false, $without_percentage = false, $append_cls = false ) {
172 $label = $without_percentage ? $percent : ( $percent . '%' );
173 $percentage = '<text x="50%" y="50%">' . esc_html( $label ) . '</text>';
174
175 if ( 100 === $percent && $finished_tick ) {
176 $percentage = '<text x="50%" y="50%" class="litespeed-pie-done">✓</text>';
177 }
178
179 $svg = sprintf(
180 "<svg class='litespeed-pie %1\$s' viewbox='0 0 33.83098862 33.83098862' width='%2\$d' height='%2\$d' xmlns='http://www.w3.org/2000/svg'>
181 <circle class='litespeed-pie_bg' cx='16.91549431' cy='16.91549431' r='15.91549431' />
182 <circle class='litespeed-pie_circle' cx='16.91549431' cy='16.91549431' r='15.91549431' stroke-dasharray='%3\$d,100' />
183 <g class='litespeed-pie_info'>%4\$s</g>
184 </svg>",
185 esc_attr( $append_cls ),
186 $width,
187 $percent,
188 $percentage
189 );
190
191 return $svg;
192 }
193
194 /**
195 * Allowed SVG tags/attributes for kses.
196 *
197 * @since 7.3
198 *
199 * @return array<string,array<string,bool>> Allowed tags/attributes.
200 */
201 public static function allowed_svg_tags() {
202 return [
203 'svg' => [
204 'width' => true,
205 'height' => true,
206 'viewbox' => true, // Note: SVG standard uses 'viewBox', but wp_kses normalizes to lowercase.
207 'xmlns' => true,
208 'class' => true,
209 'id' => true,
210 ],
211 'circle' => [
212 'cx' => true,
213 'cy' => true,
214 'r' => true,
215 'fill' => true,
216 'stroke' => true,
217 'class' => true,
218 'stroke-width' => true,
219 'stroke-dasharray' => true,
220 ],
221 'path' => [
222 'd' => true,
223 'fill' => true,
224 'stroke' => true,
225 ],
226 'text' => [
227 'x' => true,
228 'y' => true,
229 'dx' => true,
230 'dy' => true,
231 'font-size' => true,
232 'font-family' => true,
233 'font-weight' => true,
234 'fill' => true,
235 'stroke' => true,
236 'stroke-width' => true,
237 'text-anchor' => true,
238 'class' => true,
239 'id' => true,
240 ],
241 'g' => [
242 'transform' => true,
243 'fill' => true,
244 'stroke' => true,
245 'stroke-width' => true,
246 'class' => true,
247 'id' => true,
248 ],
249 'button' => [
250 'type' => true,
251 'data-balloon-break' => true,
252 'data-balloon-pos' => true,
253 'aria-label' => true,
254 'class' => true,
255 ],
256 ];
257 }
258
259 /**
260 * Display a tiny pie with a tooltip.
261 *
262 * @since 3.0
263 *
264 * @param int $percent Percentage 0-100.
265 * @param int $width Width/height in pixels.
266 * @param string $tooltip Tooltip text.
267 * @param string $tooltip_pos Tooltip position (e.g., 'up').
268 * @param string|bool $append_cls Extra CSS class.
269 * @return string HTML/SVG.
270 */
271 public static function pie_tiny( $percent, $width = 50, $tooltip = '', $tooltip_pos = 'up', $append_cls = false ) {
272 // formula C = 2πR.
273 $dasharray = 2 * 3.1416 * 9 * ( $percent / 100 );
274
275 return sprintf(
276 "
277 <button type='button' data-balloon-break data-balloon-pos='%1\$s' aria-label='%2\$s' class='litespeed-btn-pie'>
278 <svg class='litespeed-pie litespeed-pie-tiny %3\$s' viewbox='0 0 30 30' width='%4\$d' height='%4\$d' xmlns='http://www.w3.org/2000/svg'>
279 <circle class='litespeed-pie_bg' cx='15' cy='15' r='9' />
280 <circle class='litespeed-pie_circle' cx='15' cy='15' r='9' stroke-dasharray='%5\$s,100' />
281 <g class='litespeed-pie_info'><text x='50%%' y='50%%'>i</text></g>
282 </svg>
283 </button>
284 ",
285 esc_attr( $tooltip_pos ),
286 esc_attr( $tooltip ),
287 esc_attr( $append_cls ),
288 $width,
289 esc_attr( $dasharray )
290 );
291 }
292
293 /**
294 * Get CSS class name for PageSpeed score.
295 *
296 * Scale:
297 * 90-100 (fast)
298 * 50-89 (average)
299 * 0-49 (slow)
300 *
301 * @since 2.9
302 * @access public
303 *
304 * @param int $score Score 0-100.
305 * @return string Class name: success|warning|danger.
306 */
307 public function get_cls_of_pagescore( $score ) {
308 if ( $score >= 90 ) {
309 return 'success';
310 }
311
312 if ( $score >= 50 ) {
313 return 'warning';
314 }
315
316 return 'danger';
317 }
318
319 /**
320 * Handle dismiss actions for banners and notices.
321 *
322 * @since 1.0
323 * @access public
324 * @return void
325 */
326 public static function dismiss() {
327 $_instance = self::cls();
328
329 switch ( Router::verify_type() ) {
330 case self::TYPE_DISMISS_WHM:
331 self::dismiss_whm();
332 break;
333
334 case self::TYPE_DISMISS_EXPIRESDEFAULT:
335 self::update_option( Admin_Display::DB_DISMISS_MSG, Admin_Display::RULECONFLICT_DISMISSED );
336 break;
337
338 case self::TYPE_DISMISS_PIN:
339 Admin_Display::dismiss_pin();
340 break;
341
342 case self::TYPE_DISMISS_PROMO:
343 if ( empty( $_GET['promo_tag'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
344 break;
345 }
346
347 $promo_tag = sanitize_key( wp_unslash( $_GET['promo_tag'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
348 if ( empty( $_instance->_promo_list[ $promo_tag ] ) ) {
349 break;
350 }
351
352 defined( 'LSCWP_LOG' ) && self::debug( 'Dismiss promo ' . $promo_tag );
353
354 // Forever dismiss.
355 if ( ! empty( $_GET['done'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
356 $_instance->_summary[ $promo_tag ] = 'done';
357 } elseif ( ! empty( $_GET['later'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
358 // Delay the banner to half year later.
359 $_instance->_summary[ $promo_tag ] = time() + ( 86400 * 180 );
360 } else {
361 // Update welcome banner to 30 days after.
362 $_instance->_summary[ $promo_tag ] = time() + ( 86400 * 30 );
363 }
364
365 self::save_summary();
366
367 break;
368
369 default:
370 break;
371 }
372
373 if ( Router::is_ajax() ) {
374 // All dismiss actions are considered as ajax call, so just exit.
375 exit( wp_json_encode( [ 'success' => 1 ] ) );
376 }
377
378 // Plain click link, redirect to referral url.
379 Admin::redirect();
380 }
381
382 /**
383 * Check if has rule conflict notice.
384 *
385 * @since 1.1.5
386 * @access public
387 *
388 * @return bool True if message should be shown.
389 */
390 public static function has_msg_ruleconflict() {
391 $db_dismiss_msg = self::get_option( Admin_Display::DB_DISMISS_MSG );
392 if ( ! $db_dismiss_msg ) {
393 self::update_option( Admin_Display::DB_DISMISS_MSG, -1 );
394 }
395 return Admin_Display::RULECONFLICT_ON === $db_dismiss_msg;
396 }
397
398 /**
399 * Check if has WHM notice.
400 *
401 * @since 1.1.1
402 * @access public
403 *
404 * @return bool True if message should be shown.
405 */
406 public static function has_whm_msg() {
407 $val = self::get_option( self::WHM_MSG );
408 if ( ! $val ) {
409 self::dismiss_whm();
410 return false;
411 }
412 return self::WHM_MSG_VAL === $val;
413 }
414
415 /**
416 * Delete WHM message tag.
417 *
418 * @since 1.1.1
419 * @access public
420 * @return void
421 */
422 public static function dismiss_whm() {
423 self::update_option( self::WHM_MSG, -1 );
424 }
425
426 /**
427 * Whether current request is a LiteSpeed admin page.
428 *
429 * @since 2.9
430 *
431 * @return bool True if LiteSpeed page.
432 */
433 private function _is_litespeed_page() {
434 if (
435 ! empty( $_GET['page'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended
436 in_array(
437 (string) $_GET['page'], // phpcs:ignore WordPress.Security.NonceVerification.Recommended
438 [
439 'litespeed-settings',
440 'litespeed-dash',
441 Admin::PAGE_EDIT_HTACCESS,
442 'litespeed-optimization',
443 'litespeed-crawler',
444 'litespeed-import',
445 'litespeed-report',
446 ],
447 true
448 )
449 ) {
450 return true;
451 }
452
453 return false;
454 }
455
456 /**
457 * Display promo banner (or check-only mode to know which promo would display).
458 *
459 * @since 2.1
460 * @access public
461 *
462 * @param bool $check_only If true, only return the promo tag that would be shown.
463 * @return false|string False if none, or the promo tag string.
464 */
465 public function show_promo( $check_only = false ) {
466 $is_litespeed_page = $this->_is_litespeed_page();
467
468 // Bypass showing info banner if disabled all in debug.
469 if ( defined( 'LITESPEED_DISABLE_ALL' ) && LITESPEED_DISABLE_ALL ) {
470 return false;
471 }
472
473 if ( file_exists( ABSPATH . '.litespeed_no_banner' ) ) {
474 defined( 'LSCWP_LOG' ) && self::debug( 'Bypass banners due to silence file' );
475 return false;
476 }
477
478 foreach ( $this->_promo_list as $promo_tag => $v ) {
479 list( $delay_days, $litespeed_page_only ) = $v;
480
481 if ( $litespeed_page_only && ! $is_litespeed_page ) {
482 continue;
483 }
484
485 // First time check.
486 if ( empty( $this->_summary[ $promo_tag ] ) ) {
487 $this->_summary[ $promo_tag ] = time() + 86400 * $delay_days;
488 self::save_summary();
489 continue;
490 }
491
492 $promo_timestamp = $this->_summary[ $promo_tag ];
493
494 // Was ticked as done.
495 if ( 'done' === $promo_timestamp ) {
496 continue;
497 }
498
499 // Not reach the dateline yet.
500 if ( time() < $promo_timestamp ) {
501 continue;
502 }
503
504 // Try to load, if can pass, will set $this->_promo_true = true.
505 $this->_promo_true = false;
506 include LSCWP_DIR . "tpl/banner/$promo_tag.php";
507
508 // If not defined, means it didn't pass the display workflow in tpl.
509 if ( ! $this->_promo_true ) {
510 continue;
511 }
512
513 if ( $check_only ) {
514 return $promo_tag;
515 }
516
517 defined( 'LSCWP_LOG' ) && self::debug( 'Show promo ' . $promo_tag );
518
519 // Only contain one.
520 break;
521 }
522
523 return false;
524 }
525
526 /**
527 * Load frontend public script.
528 *
529 * @since 1.8.2
530 * @access public
531 * @return void
532 */
533 public function frontend_enqueue_style_public() {
534 wp_enqueue_script(
535 Core::PLUGIN_NAME,
536 LSWCP_PLUGIN_URL . 'assets/js/instant_click.min.js',
537 [],
538 Core::VER,
539 [
540 'strategy' => 'defer',
541 'in_footer' => true,
542 ]
543 );
544 }
545
546 /**
547 * Load frontend stylesheet.
548 *
549 * @since 1.3
550 * @access public
551 * @return void
552 */
553 public function frontend_enqueue_style() {
554 wp_enqueue_style( Core::PLUGIN_NAME, LSWCP_PLUGIN_URL . 'assets/css/litespeed.css', [], Core::VER, 'all' );
555 }
556
557 /**
558 * Load frontend menu shortcut items in the admin bar.
559 *
560 * @since 1.3
561 * @since 7.6 Add VPI clear.
562 * @access public
563 * @return void
564 */
565 public function frontend_shortcut() {
566 global $wp_admin_bar;
567
568 $wp_admin_bar->add_menu(
569 [
570 'id' => 'litespeed-menu',
571 'title' => '<span class="ab-icon"></span>',
572 'href' => get_admin_url( null, 'admin.php?page=litespeed' ),
573 'meta' => [
574 'tabindex' => 0,
575 'class' => 'litespeed-top-toolbar',
576 ],
577 ]
578 );
579
580 $wp_admin_bar->add_menu(
581 [
582 'parent' => 'litespeed-menu',
583 'id' => 'litespeed-purge-single',
584 'title' => esc_html__( 'Purge this page', 'litespeed-cache' ) . ' - LSCache',
585 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_FRONT, false, true ),
586 'meta' => [ 'tabindex' => '0' ],
587 ]
588 );
589
590 if ( $this->has_cache_folder( 'ucss' ) ) {
591 $possible_url_tag = UCSS::get_url_tag();
592 $append_arr = [];
593 if ( $possible_url_tag ) {
594 $append_arr['url_tag'] = $possible_url_tag;
595 }
596
597 $wp_admin_bar->add_menu(
598 [
599 'parent' => 'litespeed-menu',
600 'id' => 'litespeed-purge-single-ucss',
601 'title' => esc_html__( 'Purge this page', 'litespeed-cache' ) . ' - UCSS',
602 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_UCSS, false, true, $append_arr ),
603 'meta' => [ 'tabindex' => '0' ],
604 ]
605 );
606 }
607
608 $wp_admin_bar->add_menu(
609 [
610 'parent' => 'litespeed-menu',
611 'id' => 'litespeed-single-action',
612 'title' => esc_html__( 'Mark this page as ', 'litespeed-cache' ),
613 'meta' => [ 'tabindex' => '0' ],
614 ]
615 );
616
617 $current_uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
618
619 if ( $current_uri ) {
620 $append_arr = [
621 Conf::TYPE_SET . '[' . self::O_CACHE_FORCE_URI . '][]' => $current_uri . '$',
622 'redirect' => $current_uri,
623 ];
624 $wp_admin_bar->add_menu(
625 [
626 'parent' => 'litespeed-single-action',
627 'id' => 'litespeed-single-forced_cache',
628 'title' => esc_html__( 'Forced cacheable', 'litespeed-cache' ),
629 'href' => Utility::build_url( Router::ACTION_CONF, Conf::TYPE_SET, false, true, $append_arr ),
630 ]
631 );
632
633 $append_arr = [
634 Conf::TYPE_SET . '[' . self::O_CACHE_EXC . '][]' => $current_uri . '$',
635 'redirect' => $current_uri,
636 ];
637 $wp_admin_bar->add_menu(
638 [
639 'parent' => 'litespeed-single-action',
640 'id' => 'litespeed-single-noncache',
641 'title' => esc_html__( 'Non cacheable', 'litespeed-cache' ),
642 'href' => Utility::build_url( Router::ACTION_CONF, Conf::TYPE_SET, false, true, $append_arr ),
643 ]
644 );
645
646 $append_arr = [
647 Conf::TYPE_SET . '[' . self::O_CACHE_PRIV_URI . '][]' => $current_uri . '$',
648 'redirect' => $current_uri,
649 ];
650 $wp_admin_bar->add_menu(
651 [
652 'parent' => 'litespeed-single-action',
653 'id' => 'litespeed-single-private',
654 'title' => esc_html__( 'Private cache', 'litespeed-cache' ),
655 'href' => Utility::build_url( Router::ACTION_CONF, Conf::TYPE_SET, false, true, $append_arr ),
656 ]
657 );
658
659 $append_arr = [
660 Conf::TYPE_SET . '[' . self::O_OPTM_EXC . '][]' => $current_uri . '$',
661 'redirect' => $current_uri,
662 ];
663 $wp_admin_bar->add_menu(
664 [
665 'parent' => 'litespeed-single-action',
666 'id' => 'litespeed-single-nonoptimize',
667 'title' => esc_html__( 'No optimization', 'litespeed-cache' ),
668 'href' => Utility::build_url( Router::ACTION_CONF, Conf::TYPE_SET, false, true, $append_arr ),
669 ]
670 );
671 }
672
673 $wp_admin_bar->add_menu(
674 [
675 'parent' => 'litespeed-single-action',
676 'id' => 'litespeed-single-more',
677 'title' => esc_html__( 'More settings', 'litespeed-cache' ),
678 'href' => get_admin_url( null, 'admin.php?page=litespeed-cache' ),
679 ]
680 );
681
682 $wp_admin_bar->add_menu(
683 [
684 'parent' => 'litespeed-menu',
685 'id' => 'litespeed-purge-all',
686 'title' => esc_html__( 'Purge All', 'litespeed-cache' ),
687 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL, false, '_ori' ),
688 'meta' => [ 'tabindex' => '0' ],
689 ]
690 );
691
692 $wp_admin_bar->add_menu(
693 [
694 'parent' => 'litespeed-menu',
695 'id' => 'litespeed-purge-all-lscache',
696 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'LSCache', 'litespeed-cache' ),
697 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_LSCACHE, false, '_ori' ),
698 'meta' => [ 'tabindex' => '0' ],
699 ]
700 );
701
702 $wp_admin_bar->add_menu(
703 [
704 'parent' => 'litespeed-menu',
705 'id' => 'litespeed-purge-cssjs',
706 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'CSS/JS Cache', 'litespeed-cache' ),
707 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_CSSJS, false, '_ori' ),
708 'meta' => [ 'tabindex' => '0' ],
709 ]
710 );
711
712 if ( $this->conf( self::O_CDN_CLOUDFLARE ) ) {
713 $wp_admin_bar->add_menu(
714 [
715 'parent' => 'litespeed-menu',
716 'id' => 'litespeed-purge-cloudflare',
717 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'Cloudflare', 'litespeed-cache' ),
718 'href' => Utility::build_url( Router::ACTION_CDN_CLOUDFLARE, CDN\Cloudflare::TYPE_PURGE_ALL ),
719 'meta' => [ 'tabindex' => '0' ],
720 ]
721 );
722 }
723
724 if ( defined( 'LSCWP_OBJECT_CACHE' ) ) {
725 $wp_admin_bar->add_menu(
726 [
727 'parent' => 'litespeed-menu',
728 'id' => 'litespeed-purge-object',
729 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'Object Cache', 'litespeed-cache' ),
730 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_OBJECT, false, '_ori' ),
731 'meta' => [ 'tabindex' => '0' ],
732 ]
733 );
734 }
735
736 if ( Router::opcache_enabled() ) {
737 $wp_admin_bar->add_menu(
738 [
739 'parent' => 'litespeed-menu',
740 'id' => 'litespeed-purge-opcache',
741 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'Opcode Cache', 'litespeed-cache' ),
742 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_OPCACHE, false, '_ori' ),
743 'meta' => [ 'tabindex' => '0' ],
744 ]
745 );
746 }
747
748 if ( $this->has_cache_folder( 'ccss' ) ) {
749 $wp_admin_bar->add_menu(
750 [
751 'parent' => 'litespeed-menu',
752 'id' => 'litespeed-purge-ccss',
753 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - CCSS',
754 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_CCSS, false, '_ori' ),
755 'meta' => [ 'tabindex' => '0' ],
756 ]
757 );
758 }
759
760 if ( $this->has_cache_folder( 'ucss' ) ) {
761 $wp_admin_bar->add_menu(
762 [
763 'parent' => 'litespeed-menu',
764 'id' => 'litespeed-purge-ucss',
765 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - UCSS',
766 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_UCSS, false, '_ori' ),
767 ]
768 );
769 }
770
771 if ( $this->has_cache_folder( 'localres' ) ) {
772 $wp_admin_bar->add_menu(
773 [
774 'parent' => 'litespeed-menu',
775 'id' => 'litespeed-purge-localres',
776 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'Localized Resources', 'litespeed-cache' ),
777 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_LOCALRES, false, '_ori' ),
778 'meta' => [ 'tabindex' => '0' ],
779 ]
780 );
781 }
782
783 if ( $this->has_cache_folder( 'lqip' ) ) {
784 $wp_admin_bar->add_menu(
785 [
786 'parent' => 'litespeed-menu',
787 'id' => 'litespeed-purge-placeholder',
788 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'LQIP Cache', 'litespeed-cache' ),
789 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_LQIP, false, '_ori' ),
790 'meta' => [ 'tabindex' => '0' ],
791 ]
792 );
793 }
794
795 if ( $this->has_cache_folder( 'vpi' ) ) {
796 $wp_admin_bar->add_menu(
797 [
798 'parent' => 'litespeed-menu',
799 'id' => 'litespeed-purge-vpi',
800 'title' => __( 'Purge All', 'litespeed-cache' ) . ' - VPI',
801 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_VPI, false, '_ori' ),
802 'meta' => [ 'tabindex' => '0' ],
803 ]
804 );
805 }
806
807 if ( $this->has_cache_folder( 'avatar' ) ) {
808 $wp_admin_bar->add_menu(
809 [
810 'parent' => 'litespeed-menu',
811 'id' => 'litespeed-purge-avatar',
812 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'Gravatar Cache', 'litespeed-cache' ),
813 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_AVATAR, false, '_ori' ),
814 'meta' => [ 'tabindex' => '0' ],
815 ]
816 );
817 }
818
819 do_action( 'litespeed_frontend_shortcut' );
820 }
821
822 /**
823 * Hooked to wp_before_admin_bar_render.
824 * Adds links to the admin bar so users can quickly manage/purge.
825 *
826 * @since 1.7.2 Moved from admin_display.cls to gui.cls; Renamed from `add_quick_purge` to `backend_shortcut`.
827 * @access public
828 * @global \WP_Admin_Bar $wp_admin_bar
829 * @return void
830 */
831 public function backend_shortcut() {
832 global $wp_admin_bar;
833
834 if ( defined( 'LITESPEED_DISABLE_ALL' ) && LITESPEED_DISABLE_ALL ) {
835 $wp_admin_bar->add_menu(
836 [
837 'id' => 'litespeed-menu',
838 'title' => '<span class="ab-icon icon_disabled" title="LiteSpeed Cache"></span>',
839 'href' => 'admin.php?page=litespeed-toolbox#settings-debug',
840 'meta' => [
841 'tabindex' => 0,
842 'class' => 'litespeed-top-toolbar',
843 ],
844 ]
845 );
846 $wp_admin_bar->add_menu(
847 [
848 'parent' => 'litespeed-menu',
849 'id' => 'litespeed-enable_all',
850 'title' => esc_html__( 'Enable All Features', 'litespeed-cache' ),
851 'href' => 'admin.php?page=litespeed-toolbox#settings-debug',
852 'meta' => [ 'tabindex' => '0' ],
853 ]
854 );
855 return;
856 }
857
858 $wp_admin_bar->add_menu(
859 [
860 'id' => 'litespeed-menu',
861 'title' => '<span class="ab-icon" title="' . esc_attr__( 'LiteSpeed Cache Purge All', 'litespeed-cache' ) . ' - ' . esc_attr__( 'LSCache', 'litespeed-cache' ) . '"></span>',
862 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_LSCACHE ),
863 'meta' => [
864 'tabindex' => 0,
865 'class' => 'litespeed-top-toolbar',
866 ],
867 ]
868 );
869
870 $wp_admin_bar->add_menu(
871 [
872 'parent' => 'litespeed-menu',
873 'id' => 'litespeed-bar-manage',
874 'title' => esc_html__( 'Manage', 'litespeed-cache' ),
875 'href' => 'admin.php?page=litespeed',
876 'meta' => [ 'tabindex' => '0' ],
877 ]
878 );
879
880 $wp_admin_bar->add_menu(
881 [
882 'parent' => 'litespeed-menu',
883 'id' => 'litespeed-bar-setting',
884 'title' => esc_html__( 'Settings', 'litespeed-cache' ),
885 'href' => 'admin.php?page=litespeed-cache',
886 'meta' => [ 'tabindex' => '0' ],
887 ]
888 );
889
890 if ( ! is_network_admin() ) {
891 $wp_admin_bar->add_menu(
892 [
893 'parent' => 'litespeed-menu',
894 'id' => 'litespeed-bar-imgoptm',
895 'title' => esc_html__( 'Image Optimization', 'litespeed-cache' ),
896 'href' => 'admin.php?page=litespeed-img_optm',
897 'meta' => [ 'tabindex' => '0' ],
898 ]
899 );
900 }
901
902 $wp_admin_bar->add_menu(
903 [
904 'parent' => 'litespeed-menu',
905 'id' => 'litespeed-purge-all',
906 'title' => esc_html__( 'Purge All', 'litespeed-cache' ),
907 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL ),
908 'meta' => [ 'tabindex' => '0' ],
909 ]
910 );
911
912 $wp_admin_bar->add_menu(
913 [
914 'parent' => 'litespeed-menu',
915 'id' => 'litespeed-purge-all-lscache',
916 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'LSCache', 'litespeed-cache' ),
917 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_LSCACHE ),
918 'meta' => [ 'tabindex' => '0' ],
919 ]
920 );
921
922 $wp_admin_bar->add_menu(
923 [
924 'parent' => 'litespeed-menu',
925 'id' => 'litespeed-purge-cssjs',
926 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'CSS/JS Cache', 'litespeed-cache' ),
927 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_CSSJS ),
928 'meta' => [ 'tabindex' => '0' ],
929 ]
930 );
931
932 if ( $this->conf( self::O_CDN_CLOUDFLARE ) ) {
933 $wp_admin_bar->add_menu(
934 [
935 'parent' => 'litespeed-menu',
936 'id' => 'litespeed-purge-cloudflare',
937 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'Cloudflare', 'litespeed-cache' ),
938 'href' => Utility::build_url( Router::ACTION_CDN_CLOUDFLARE, CDN\Cloudflare::TYPE_PURGE_ALL ),
939 'meta' => [ 'tabindex' => '0' ],
940 ]
941 );
942 }
943
944 if ( defined( 'LSCWP_OBJECT_CACHE' ) ) {
945 $wp_admin_bar->add_menu(
946 [
947 'parent' => 'litespeed-menu',
948 'id' => 'litespeed-purge-object',
949 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'Object Cache', 'litespeed-cache' ),
950 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_OBJECT ),
951 'meta' => [ 'tabindex' => '0' ],
952 ]
953 );
954 }
955
956 if ( Router::opcache_enabled() ) {
957 $wp_admin_bar->add_menu(
958 [
959 'parent' => 'litespeed-menu',
960 'id' => 'litespeed-purge-opcache',
961 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'Opcode Cache', 'litespeed-cache' ),
962 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_OPCACHE ),
963 'meta' => [ 'tabindex' => '0' ],
964 ]
965 );
966 }
967
968 if ( $this->has_cache_folder( 'ccss' ) ) {
969 $wp_admin_bar->add_menu(
970 [
971 'parent' => 'litespeed-menu',
972 'id' => 'litespeed-purge-ccss',
973 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - CCSS',
974 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_CCSS ),
975 'meta' => [ 'tabindex' => '0' ],
976 ]
977 );
978 }
979
980 if ( $this->has_cache_folder( 'ucss' ) ) {
981 $wp_admin_bar->add_menu(
982 [
983 'parent' => 'litespeed-menu',
984 'id' => 'litespeed-purge-ucss',
985 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - UCSS',
986 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_UCSS ),
987 ]
988 );
989 }
990
991 if ( $this->has_cache_folder( 'localres' ) ) {
992 $wp_admin_bar->add_menu(
993 [
994 'parent' => 'litespeed-menu',
995 'id' => 'litespeed-purge-localres',
996 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'Localized Resources', 'litespeed-cache' ),
997 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_LOCALRES ),
998 'meta' => [ 'tabindex' => '0' ],
999 ]
1000 );
1001 }
1002
1003 if ( $this->has_cache_folder( 'lqip' ) ) {
1004 $wp_admin_bar->add_menu(
1005 [
1006 'parent' => 'litespeed-menu',
1007 'id' => 'litespeed-purge-placeholder',
1008 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'LQIP Cache', 'litespeed-cache' ),
1009 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_LQIP ),
1010 'meta' => [ 'tabindex' => '0' ],
1011 ]
1012 );
1013 }
1014
1015 if ( $this->has_cache_folder( 'vpi' ) ) {
1016 $wp_admin_bar->add_menu(
1017 [
1018 'parent' => 'litespeed-menu',
1019 'id' => 'litespeed-purge-vpi',
1020 'title' => __( 'Purge All', 'litespeed-cache' ) . ' - VPI',
1021 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_VPI ),
1022 'meta' => [ 'tabindex' => '0' ],
1023 ]
1024 );
1025 }
1026
1027 if ( $this->has_cache_folder( 'avatar' ) ) {
1028 $wp_admin_bar->add_menu(
1029 [
1030 'parent' => 'litespeed-menu',
1031 'id' => 'litespeed-purge-avatar',
1032 'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'Gravatar Cache', 'litespeed-cache' ),
1033 'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_AVATAR ),
1034 'meta' => [ 'tabindex' => '0' ],
1035 ]
1036 );
1037 }
1038
1039 do_action( 'litespeed_backend_shortcut' );
1040 }
1041
1042 /**
1043 * Clear unfinished data link/button.
1044 *
1045 * @since 2.4.2
1046 * @access public
1047 *
1048 * @param int $unfinished_num Number of unfinished images.
1049 * @return string HTML for action button.
1050 */
1051 public static function img_optm_clean_up( $unfinished_num ) {
1052 return sprintf(
1053 '<a href="%1$s" class="button litespeed-btn-warning" data-balloon-pos="up" aria-label="%2$s"><span class="dashicons dashicons-editor-removeformatting"></span>&nbsp;%3$s</a>',
1054 esc_url( Utility::build_url( Router::ACTION_IMG_OPTM, Img_Optm::TYPE_CLEAN ) ),
1055 esc_attr__( 'Remove all previous unfinished image optimization requests.', 'litespeed-cache' ),
1056 esc_html__( 'Clean Up Unfinished Data', 'litespeed-cache' ) . ( $unfinished_num ? ': ' . Admin_Display::print_plural( $unfinished_num, 'image' ) : '' )
1057 );
1058 }
1059
1060 /**
1061 * Generate install link.
1062 *
1063 * @since 2.4.2
1064 * @access public
1065 *
1066 * @param string $title Plugin title.
1067 * @param string $name Slug.
1068 * @param string $v Version (unused, kept for BC).
1069 * @return string HTML link.
1070 */
1071 public static function plugin_install_link( $title, $name, $v ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
1072 $url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $name ), 'install-plugin_' . $name );
1073
1074 $action = sprintf(
1075 '<a href="%1$s" class="install-now" data-slug="%2$s" data-name="%3$s" aria-label="%4$s">%5$s</a>',
1076 esc_url( $url ),
1077 esc_attr( $name ),
1078 esc_attr( $title ),
1079 esc_attr( sprintf( __( 'Install %s', 'litespeed-cache' ), $title ) ),
1080 esc_html__( 'Install Now', 'litespeed-cache' )
1081 );
1082
1083 return $action;
1084 }
1085
1086 /**
1087 * Generate upgrade link.
1088 *
1089 * @since 2.4.2
1090 * @access public
1091 *
1092 * @param string $title Plugin title.
1093 * @param string $name Slug.
1094 * @param string $v Version string.
1095 * @return string HTML message with links.
1096 */
1097 public static function plugin_upgrade_link( $title, $name, $v ) {
1098 $details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $name . '&section=changelog&TB_iframe=true&width=600&height=800' );
1099 $file = $name . '/' . $name . '.php';
1100
1101 $msg = sprintf(
1102 /* translators: 1: details URL, 2: class/aria, 3: version, 4: update URL, 5: class/aria */
1103 __('<a href="%1$s" %2$s>View version %3$s details</a> or <a href="%4$s" %5$s target="_blank">update now</a>.', 'litespeed-cache'),
1104 esc_url( $details_url ),
1105 sprintf(
1106 'class="thickbox open-plugin-details-modal" aria-label="%s"',
1107 esc_attr(
1108 sprintf(
1109 /* translators: 1: plugin title, 2: version */
1110 __( 'View %1$s version %2$s details', 'litespeed-cache' ),
1111 $title,
1112 $v
1113 )
1114 )
1115 ),
1116 esc_html( $v ),
1117 esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $file, 'upgrade-plugin_' . $file ) ),
1118 sprintf(
1119 'class="update-link" aria-label="%s"',
1120 esc_attr(
1121 sprintf(
1122 /* translators: %s: plugin title */
1123 __( 'Update %s now', 'litespeed-cache' ),
1124 $title
1125 )
1126 )
1127 )
1128 );
1129
1130 return $msg;
1131 }
1132
1133 /**
1134 * Finalize buffer by GUI class.
1135 *
1136 * @since 1.6
1137 * @access public
1138 *
1139 * @param string $buffer HTML buffer.
1140 * @return string Filtered buffer.
1141 */
1142 public function finalize( $buffer ) {
1143 $buffer = $this->_clean_wrapper( $buffer );
1144
1145 // Maybe restore doc.ref.
1146 if ( $this->conf( Base::O_GUEST ) && false !== strpos( $buffer, '<head>' ) && defined( 'LITESPEED_IS_HTML' ) ) {
1147 $buffer = $this->_enqueue_guest_docref_js( $buffer );
1148 }
1149
1150 if ( defined( 'LITESPEED_GUEST' ) && LITESPEED_GUEST && false !== strpos( $buffer, '</body>' ) && defined( 'LITESPEED_IS_HTML' ) ) {
1151 $buffer = $this->_enqueue_guest_js( $buffer );
1152 }
1153
1154 return $buffer;
1155 }
1156
1157 /**
1158 * Append guest restore doc.ref JS for organic traffic count.
1159 *
1160 * @since 4.4.6
1161 *
1162 * @param string $buffer HTML buffer.
1163 * @return string Buffer with inline script injected.
1164 */
1165 private function _enqueue_guest_docref_js( $buffer ) {
1166 $js_con = File::read( LSCWP_DIR . self::LIB_GUEST_DOCREF_JS );
1167 $buffer = preg_replace( '/<head>/', '<head><script data-no-optimize="1">' . $js_con . '</script>', $buffer, 1 );
1168 return $buffer;
1169 }
1170
1171 /**
1172 * Append guest JS to update vary.
1173 *
1174 * @since 4.0
1175 *
1176 * @param string $buffer HTML buffer.
1177 * @return string Buffer with inline script injected.
1178 */
1179 private function _enqueue_guest_js( $buffer ) {
1180 $js_con = File::read( LSCWP_DIR . self::LIB_GUEST_JS );
1181 // Build path for guest endpoint using wp_parse_url for compatibility.
1182 $guest_update_path = wp_parse_url( LSWCP_PLUGIN_URL . self::PHP_GUEST, PHP_URL_PATH );
1183 $js_con = str_replace( 'litespeed_url', esc_url( $guest_update_path ), $js_con );
1184 $buffer = preg_replace( '/<\/body>/', '<script data-no-optimize="1">' . $js_con . '</script></body>', $buffer, 1 );
1185 return $buffer;
1186 }
1187
1188 /**
1189 * Clean wrapper from buffer.
1190 *
1191 * @since 1.4
1192 * @since 1.6 Converted to private with adding prefix _.
1193 * @access private
1194 *
1195 * @param string $buffer HTML buffer.
1196 * @return string Cleaned buffer.
1197 */
1198 private function _clean_wrapper( $buffer ) {
1199 if ( self::$_clean_counter < 1 ) {
1200 self::debug2( 'bypassed by no counter' );
1201 return $buffer;
1202 }
1203
1204 self::debug2( 'start cleaning counter ' . self::$_clean_counter );
1205
1206 for ( $i = 1; $i <= self::$_clean_counter; $i++ ) {
1207 // If miss beginning.
1208 $start = strpos( $buffer, self::clean_wrapper_begin( $i ) );
1209 if ( false === $start ) {
1210 $buffer = str_replace( self::clean_wrapper_end( $i ), '', $buffer );
1211 self::debug2( "lost beginning wrapper $i" );
1212 continue;
1213 }
1214
1215 // If miss end.
1216 $end_wrapper = self::clean_wrapper_end( $i );
1217 $end = strpos( $buffer, $end_wrapper );
1218 if ( false === $end ) {
1219 $buffer = str_replace( self::clean_wrapper_begin( $i ), '', $buffer );
1220 self::debug2( "lost ending wrapper $i" );
1221 continue;
1222 }
1223
1224 // Now replace wrapped content.
1225 $buffer = substr_replace( $buffer, '', $start, $end - $start + strlen( $end_wrapper ) );
1226 self::debug2( "cleaned wrapper $i" );
1227 }
1228
1229 return $buffer;
1230 }
1231
1232 /**
1233 * Display a to-be-removed HTML wrapper (begin tag).
1234 *
1235 * @since 1.4
1236 * @access public
1237 *
1238 * @param int|false $counter Optional explicit wrapper id; auto-increment if false.
1239 * @return string Wrapper begin HTML comment.
1240 */
1241 public static function clean_wrapper_begin( $counter = false ) {
1242 if ( false === $counter ) {
1243 ++self::$_clean_counter;
1244 $counter = self::$_clean_counter;
1245 self::debug( 'clean wrapper ' . $counter . ' begin' );
1246 }
1247 return '<!-- LiteSpeed To Be Removed begin ' . $counter . ' -->';
1248 }
1249
1250 /**
1251 * Display a to-be-removed HTML wrapper (end tag).
1252 *
1253 * @since 1.4
1254 * @access public
1255 *
1256 * @param int|false $counter Optional explicit wrapper id; use latest if false.
1257 * @return string Wrapper end HTML comment.
1258 */
1259 public static function clean_wrapper_end( $counter = false ) {
1260 if ( false === $counter ) {
1261 $counter = self::$_clean_counter;
1262 self::debug( 'clean wrapper ' . $counter . ' end' );
1263 }
1264 return '<!-- LiteSpeed To Be Removed end ' . $counter . ' -->';
1265 }
1266 }
1267