if ( $this->has_cache_folder( 'lqip' ) ) {
'parent' => 'litespeed-menu',
'id' => 'litespeed-purge-placeholder',
'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'LQIP Cache', 'litespeed-cache' ),
'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_LQIP ),
'meta' => [ 'tabindex' => '0' ],
if ( $this->has_cache_folder( 'vpi' ) ) {
'parent' => 'litespeed-menu',
'id' => 'litespeed-purge-vpi',
'title' => __( 'Purge All', 'litespeed-cache' ) . ' - VPI',
'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_VPI ),
'meta' => [ 'tabindex' => '0' ],
if ( $this->has_cache_folder( 'avatar' ) ) {
'parent' => 'litespeed-menu',
'id' => 'litespeed-purge-avatar',
'title' => esc_html__( 'Purge All', 'litespeed-cache' ) . ' - ' . esc_html__( 'Gravatar Cache', 'litespeed-cache' ),
'href' => Utility::build_url( Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_AVATAR ),
'meta' => [ 'tabindex' => '0' ],
do_action( 'litespeed_backend_shortcut' );
* Clear unfinished data link/button.
* @param int $unfinished_num Number of unfinished images.
* @return string HTML for action button.
public static function img_optm_clean_up( $unfinished_num ) {
'<a href="%1$s" class="button litespeed-btn-warning" data-balloon-pos="up" aria-label="%2$s"><span class="dashicons dashicons-editor-removeformatting"></span> %3$s</a>',
esc_url( Utility::build_url( Router::ACTION_IMG_OPTM, Img_Optm::TYPE_CLEAN ) ),
esc_attr__( 'Remove all previous unfinished image optimization requests.', 'litespeed-cache' ),
esc_html__( 'Clean Up Unfinished Data', 'litespeed-cache' ) . ( $unfinished_num ? ': ' . Admin_Display::print_plural( $unfinished_num, 'image' ) : '' )
* @param string $title Plugin title.
* @param string $name Slug.
* @param string $v Version (unused, kept for BC).
* @return string HTML link.
public static function plugin_install_link( $title, $name, $v ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $name ), 'install-plugin_' . $name );
'<a href="%1$s" class="install-now" data-slug="%2$s" data-name="%3$s" aria-label="%4$s">%5$s</a>',
esc_attr( sprintf( __( 'Install %s', 'litespeed-cache' ), $title ) ),
esc_html__( 'Install Now', 'litespeed-cache' )
* @param string $title Plugin title.
* @param string $name Slug.
* @param string $v Version string.
* @return string HTML message with links.
public static function plugin_upgrade_link( $title, $name, $v ) {
$details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $name . '§ion=changelog&TB_iframe=true&width=600&height=800' );
$file = $name . '/' . $name . '.php';
/* translators: 1: details URL, 2: class/aria, 3: version, 4: update URL, 5: class/aria */
__('<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'),
'class="thickbox open-plugin-details-modal" aria-label="%s"',
/* translators: 1: plugin title, 2: version */
__( 'View %1$s version %2$s details', 'litespeed-cache' ),
esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $file, 'upgrade-plugin_' . $file ) ),
'class="update-link" aria-label="%s"',
/* translators: %s: plugin title */
__( 'Update %s now', 'litespeed-cache' ),
* Finalize buffer by GUI class.
* @param string $buffer HTML buffer.
* @return string Filtered buffer.
public function finalize( $buffer ) {
$buffer = $this->_clean_wrapper( $buffer );
// Maybe restore doc.ref.
if ( $this->conf( Base::O_GUEST ) && false !== strpos( $buffer, '<head>' ) && defined( 'LITESPEED_IS_HTML' ) ) {
$buffer = $this->_enqueue_guest_docref_js( $buffer );
if ( defined( 'LITESPEED_GUEST' ) && LITESPEED_GUEST && false !== strpos( $buffer, '</body>' ) && defined( 'LITESPEED_IS_HTML' ) ) {
$buffer = $this->_enqueue_guest_js( $buffer );
* Append guest restore doc.ref JS for organic traffic count.
* @param string $buffer HTML buffer.
* @return string Buffer with inline script injected.
private function _enqueue_guest_docref_js( $buffer ) {
$js_con = File::read( LSCWP_DIR . self::LIB_GUEST_DOCREF_JS );
$buffer = preg_replace( '/<head>/', '<head><script data-no-optimize="1">' . $js_con . '</script>', $buffer, 1 );
* Append guest JS to update vary.
* @param string $buffer HTML buffer.
* @return string Buffer with inline script injected.
private function _enqueue_guest_js( $buffer ) {
$js_con = File::read( LSCWP_DIR . self::LIB_GUEST_JS );
// Build path for guest endpoint using wp_parse_url for compatibility.
$guest_update_path = wp_parse_url( LSWCP_PLUGIN_URL . self::PHP_GUEST, PHP_URL_PATH );
$js_con = str_replace( 'litespeed_url', esc_url( $guest_update_path ), $js_con );
$buffer = preg_replace( '/<\/body>/', '<script data-no-optimize="1">' . $js_con . '</script></body>', $buffer, 1 );
* Clean wrapper from buffer.
* @since 1.6 Converted to private with adding prefix _.
* @param string $buffer HTML buffer.
* @return string Cleaned buffer.
private function _clean_wrapper( $buffer ) {
if ( self::$_clean_counter < 1 ) {
self::debug2( 'bypassed by no counter' );
self::debug2( 'start cleaning counter ' . self::$_clean_counter );
for ( $i = 1; $i <= self::$_clean_counter; $i++ ) {
$start = strpos( $buffer, self::clean_wrapper_begin( $i ) );
if ( false === $start ) {
$buffer = str_replace( self::clean_wrapper_end( $i ), '', $buffer );
self::debug2( "lost beginning wrapper $i" );
$end_wrapper = self::clean_wrapper_end( $i );
$end = strpos( $buffer, $end_wrapper );
$buffer = str_replace( self::clean_wrapper_begin( $i ), '', $buffer );
self::debug2( "lost ending wrapper $i" );
// Now replace wrapped content.
$buffer = substr_replace( $buffer, '', $start, $end - $start + strlen( $end_wrapper ) );
self::debug2( "cleaned wrapper $i" );
* Display a to-be-removed HTML wrapper (begin tag).
* @param int|false $counter Optional explicit wrapper id; auto-increment if false.
* @return string Wrapper begin HTML comment.
public static function clean_wrapper_begin( $counter = false ) {
if ( false === $counter ) {
$counter = self::$_clean_counter;
self::debug( 'clean wrapper ' . $counter . ' begin' );
return '<!-- LiteSpeed To Be Removed begin ' . $counter . ' -->';
* Display a to-be-removed HTML wrapper (end tag).
* @param int|false $counter Optional explicit wrapper id; use latest if false.
* @return string Wrapper end HTML comment.
public static function clean_wrapper_end( $counter = false ) {
if ( false === $counter ) {
$counter = self::$_clean_counter;
self::debug( 'clean wrapper ' . $counter . ' end' );
return '<!-- LiteSpeed To Be Removed end ' . $counter . ' -->';