* The frontend GUI class.
* @subpackage LiteSpeed/src
* @author LiteSpeed Technologies <info@litespeedtech.com>
defined('WPINC') || exit();
private static $_clean_counter = 0;
// [ file_tag => [ days, litespeed_only ], ... ]
private $_promo_list = array(
'new_version' => array(7, false),
'score' => array(14, false),
// 'slack' => array( 3, false ),
const LIB_GUEST_JS = 'assets/js/guest.min.js';
const LIB_GUEST_DOCREF_JS = 'assets/js/guest.docref.min.js';
const PHP_GUEST = 'guest.vary.php';
const TYPE_DISMISS_WHM = 'whm';
const TYPE_DISMISS_EXPIRESDEFAULT = 'ExpiresDefault';
const TYPE_DISMISS_PROMO = 'promo';
const TYPE_DISMISS_PIN = 'pin';
const WHM_MSG = 'lscwp_whm_install';
const WHM_MSG_VAL = 'whm_install';
public function __construct()
$this->_summary = self::get_summary();
Debug2::debug2('[GUI] init');
if (is_admin_bar_showing() && current_user_can('manage_options')) {
add_action('wp_enqueue_scripts', array($this, 'frontend_enqueue_style'));
add_action('admin_bar_menu', array($this, 'frontend_shortcut'), 95);
if ($this->conf(self::O_UTIL_INSTANT_CLICK)) {
add_action('wp_enqueue_scripts', array($this, 'frontend_enqueue_style_public'));
// NOTE: this needs to be before optimizer to avoid wrapper being removed
add_filter('litespeed_buffer_finalize', array($this, 'finalize'), 8);
* Print a loading message when redirecting CCSS/UCSS page to avoid whiteboard confusion
public static function print_loading($counter, $type)
echo '<div style="font-size: 25px; text-align: center; padding-top: 150px; width: 100%; position: absolute;">';
echo "<img width='35' src='" . LSWCP_PLUGIN_URL . "assets/img/Litespeed.icon.svg' /> ";
echo sprintf(__('%1$s %2$s files left in queue', 'litespeed-cache'), $counter, $type);
echo '<p><a href="' . admin_url('admin.php?page=litespeed-page_optm') . '">' . __('Cancel', 'litespeed-cache') . '</a></p>';
public static function pie($percent, $width = 50, $finished_tick = false, $without_percentage = false, $append_cls = false)
$percentage = '<text x="50%" y="50%">' . $percent . ($without_percentage ? '' : '%') . '</text>';
if ($percent == 100 && $finished_tick) {
$percentage = '<text x="50%" y="50%" class="litespeed-pie-done">✓</text>';
<svg class='litespeed-pie $append_cls' viewbox='0 0 33.83098862 33.83098862' width='$width' height='$width' xmlns='http://www.w3.org/2000/svg'>
<circle class='litespeed-pie_bg' cx='16.91549431' cy='16.91549431' r='15.91549431' />
<circle class='litespeed-pie_circle' cx='16.91549431' cy='16.91549431' r='15.91549431' stroke-dasharray='$percent,100' />
<g class='litespeed-pie_info'>$percentage</g>
* Display a tiny pie with a tooltip
public static function pie_tiny($percent, $width = 50, $tooltip = '', $tooltip_pos = 'up', $append_cls = false)
$dasharray = 2 * 3.1416 * 9 * ($percent / 100);
<button type='button' data-balloon-break data-balloon-pos='$tooltip_pos' aria-label='$tooltip' class='litespeed-btn-pie'>
<svg class='litespeed-pie litespeed-pie-tiny $append_cls' viewbox='0 0 30 30' width='$width' height='$width' xmlns='http://www.w3.org/2000/svg'>
<circle class='litespeed-pie_bg' cx='15' cy='15' r='9' />
<circle class='litespeed-pie_circle' cx='15' cy='15' r='9' stroke-dasharray='$dasharray,100' />
<g class='litespeed-pie_info'><text x='50%' y='50%'>i</text></g>
* Get classname of PageSpeed Score
public function get_cls_of_pagescore($score)
public static function dismiss()
$_instance = self::cls();
switch (Router::verify_type()) {
case self::TYPE_DISMISS_WHM:
case self::TYPE_DISMISS_EXPIRESDEFAULT:
self::update_option(Admin_Display::DB_DISMISS_MSG, Admin_Display::RULECONFLICT_DISMISSED);
case self::TYPE_DISMISS_PIN:
admin_display::dismiss_pin();
case self::TYPE_DISMISS_PROMO:
if (empty($_GET['promo_tag'])) {
$promo_tag = sanitize_key($_GET['promo_tag']);
if (empty($_instance->_promo_list[$promo_tag])) {
defined('LSCWP_LOG') && Debug2::debug('[GUI] Dismiss promo ' . $promo_tag);
if (!empty($_GET['done'])) {
$_instance->_summary[$promo_tag] = 'done';
} elseif (!empty($_GET['later'])) {
// Delay the banner to half year later
$_instance->_summary[$promo_tag] = time() + 86400 * 180;
// Update welcome banner to 30 days after
$_instance->_summary[$promo_tag] = time() + 86400 * 30;
// All dismiss actions are considered as ajax call, so just exit
exit(\json_encode(array('success' => 1)));
// Plain click link, redirect to referral url
* Check if has rule conflict notice
public static function has_msg_ruleconflict()
$db_dismiss_msg = self::get_option(Admin_Display::DB_DISMISS_MSG);
self::update_option(Admin_Display::DB_DISMISS_MSG, -1);
return $db_dismiss_msg == Admin_Display::RULECONFLICT_ON;
* Check if has whm notice
public static function has_whm_msg()
$val = self::get_option(self::WHM_MSG);
return $val == self::WHM_MSG_VAL;
public static function dismiss_whm()
self::update_option(self::WHM_MSG, -1);
* Set current page a litespeed page
private function _is_litespeed_page()
in_array($_GET['page'], array(
Admin::PAGE_EDIT_HTACCESS,
'litespeed-optimization',
public function show_promo($check_only = false)
$is_litespeed_page = $this->_is_litespeed_page();
// Bypass showing info banner if disabled all in debug
if (defined('LITESPEED_DISABLE_ALL')) {
if ($is_litespeed_page && !$check_only) {
include_once LSCWP_DIR . 'tpl/inc/disabled_all.php';
if (file_exists(ABSPATH . '.litespeed_no_banner')) {
defined('LSCWP_LOG') && Debug2::debug('[GUI] Bypass banners due to silence file');
foreach ($this->_promo_list as $promo_tag => $v) {
list($delay_days, $litespeed_page_only) = $v;
if ($litespeed_page_only && !$is_litespeed_page) {
if (empty($this->_summary[$promo_tag])) {
$this->_summary[$promo_tag] = time() + 86400 * $delay_days;
$promo_timestamp = $this->_summary[$promo_tag];
if ($promo_timestamp == 'done') {
// Not reach the dateline yet
if (time() < $promo_timestamp) {
// try to load, if can pass, will set $this->_promo_true = true
$this->_promo_true = false;
include LSCWP_DIR . "tpl/banner/$promo_tag.php";
// If not defined, means it didn't pass the display workflow in tpl.
if (!$this->_promo_true) {
defined('LSCWP_LOG') && Debug2::debug('[GUI] Show promo ' . $promo_tag);
* Load frontend public script
public function frontend_enqueue_style_public()
wp_enqueue_script(Core::PLUGIN_NAME, LSWCP_PLUGIN_URL . 'assets/js/instant_click.min.js', array(), Core::VER, true);
* Load frontend menu shortcut
public function frontend_enqueue_style()
wp_enqueue_style(Core::PLUGIN_NAME, LSWCP_PLUGIN_URL . 'assets/css/litespeed.css', array(), Core::VER, 'all');
* Load frontend menu shortcut
public function frontend_shortcut()
$wp_admin_bar->add_menu(array(
'id' => 'litespeed-menu',
'title' => '<span class="ab-icon"></span>',
'href' => get_admin_url(null, 'admin.php?page=litespeed'),
'meta' => array('tabindex' => 0, 'class' => 'litespeed-top-toolbar'),
$wp_admin_bar->add_menu(array(
'parent' => 'litespeed-menu',
'id' => 'litespeed-purge-single',
'title' => __('Purge this page', 'litespeed-cache') . ' - LSCache',
'href' => Utility::build_url(Router::ACTION_PURGE, Purge::TYPE_PURGE_FRONT, false, true),
'meta' => array('tabindex' => '0'),
if ($this->has_cache_folder('ucss')) {
$possible_url_tag = UCSS::get_url_tag();
$append_arr['url_tag'] = $possible_url_tag;
$wp_admin_bar->add_menu(array(
'parent' => 'litespeed-menu',
'id' => 'litespeed-purge-single-ucss',
'title' => __('Purge this page', 'litespeed-cache') . ' - UCSS',
'href' => Utility::build_url(Router::ACTION_PURGE, Purge::TYPE_PURGE_UCSS, false, true, $append_arr),
'meta' => array('tabindex' => '0'),
$wp_admin_bar->add_menu(array(
'parent' => 'litespeed-menu',
'id' => 'litespeed-single-action',
'title' => __('Mark this page as ', 'litespeed-cache'),
'meta' => array('tabindex' => '0'),
if (!empty($_SERVER['REQUEST_URI'])) {
Conf::TYPE_SET . '[' . self::O_CACHE_FORCE_URI . '][]' => $_SERVER['REQUEST_URI'] . '$',
'redirect' => $_SERVER['REQUEST_URI'],
$wp_admin_bar->add_menu(array(
'parent' => 'litespeed-single-action',
'id' => 'litespeed-single-forced_cache',
'title' => __('Forced cacheable', 'litespeed-cache'),
'href' => Utility::build_url(Router::ACTION_CONF, Conf::TYPE_SET, false, true, $append_arr),
Conf::TYPE_SET . '[' . self::O_CACHE_EXC . '][]' => $_SERVER['REQUEST_URI'] . '$',
'redirect' => $_SERVER['REQUEST_URI'],
$wp_admin_bar->add_menu(array(
'parent' => 'litespeed-single-action',
'id' => 'litespeed-single-noncache',
'title' => __('Non cacheable', 'litespeed-cache'),
'href' => Utility::build_url(Router::ACTION_CONF, Conf::TYPE_SET, false, true, $append_arr),
Conf::TYPE_SET . '[' . self::O_CACHE_PRIV_URI . '][]' => $_SERVER['REQUEST_URI'] . '$',
'redirect' => $_SERVER['REQUEST_URI'],
$wp_admin_bar->add_menu(array(
'parent' => 'litespeed-single-action',
'id' => 'litespeed-single-private',
'title' => __('Private cache', 'litespeed-cache'),
'href' => Utility::build_url(Router::ACTION_CONF, Conf::TYPE_SET, false, true, $append_arr),
Conf::TYPE_SET . '[' . self::O_OPTM_EXC . '][]' => $_SERVER['REQUEST_URI'] . '$',
'redirect' => $_SERVER['REQUEST_URI'],
$wp_admin_bar->add_menu(array(
'parent' => 'litespeed-single-action',
'id' => 'litespeed-single-nonoptimize',
'title' => __('No optimization', 'litespeed-cache'),
'href' => Utility::build_url(Router::ACTION_CONF, Conf::TYPE_SET, false, true, $append_arr),
$wp_admin_bar->add_menu(array(
'parent' => 'litespeed-single-action',
'id' => 'litespeed-single-more',
'title' => __('More settings', 'litespeed-cache'),
'href' => get_admin_url(null, 'admin.php?page=litespeed-cache'),
$wp_admin_bar->add_menu(array(
'parent' => 'litespeed-menu',
'id' => 'litespeed-purge-all',
'title' => __('Purge All', 'litespeed-cache'),
'href' => Utility::build_url(Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL, false, '_ori'),
'meta' => array('tabindex' => '0'),
$wp_admin_bar->add_menu(array(
'parent' => 'litespeed-menu',
'id' => 'litespeed-purge-all-lscache',
'title' => __('Purge All', 'litespeed-cache') . ' - ' . __('LSCache', 'litespeed-cache'),
'href' => Utility::build_url(Router::ACTION_PURGE, Purge::TYPE_PURGE_ALL_LSCACHE, false, '_ori'),
'meta' => array('tabindex' => '0'),
$wp_admin_bar->add_menu(array(