defined('WPINC') || exit();
class Optimizer extends Root {
private $_conf_css_font_display;
public function __construct() {
$this->_conf_css_font_display = $this->conf(Base::O_OPTM_CSS_FONT_DISPLAY);
* Run HTML minify process and return final content
public function html_min( $content, $force_inline_minify = false ) {
if (!apply_filters('litespeed_html_min', true)) {
Debug2::debug2('[Optmer] html_min bypassed via litespeed_html_min filter');
if ($force_inline_minify) {
$options['jsMinifier'] = __CLASS__ . '::minify_js';
$skip_comments = $this->conf(Base::O_OPTM_HTML_SKIP_COMMENTS);
$options['skipComments'] = $skip_comments;
* Added exception capture when minify
$obj = new Lib\HTML_MIN($content, $options);
$content_final = $obj->process();
// check if content from minification is empty
if ($content_final == '') {
Debug2::debug('Failed to minify HTML: HTML minification resulted in empty HTML');
if (!defined('LSCACHE_ESI_SILENCE')) {
$content_final .= "\n" . '<!-- Page optimized by LiteSpeed Cache @' . date('Y-m-d H:i:s', time() + LITESPEED_TIME_OFFSET) . ' -->';
} catch (\Exception $e) {
Debug2::debug('******[Optmer] html_min failed: ' . $e->getMessage());
error_log('****** LiteSpeed Optimizer html_min failed: ' . $e->getMessage());
* Run minify process and save content
public function serve( $request_url, $file_type, $minify, $src_list ) {
if ($file_type == 'css') {
if (defined('LITESPEED_GUEST_OPTM') || $this->conf(Base::O_OPTM_UCSS)) {
$filename = $this->cls('UCSS')->load($request_url);
return array( $filename, 'ucss' );
// Before generated, don't know the contented hash filename yet, so used url hash as tmp filename
$file_path_prefix = $this->_build_filepath_prefix($file_type);
$url_tag_for_file = md5($request_url);
$url_tag_for_file = $url_tag = '404';
} elseif ($file_type == 'css' && apply_filters('litespeed_ucss_per_pagetype', false)) {
$url_tag_for_file = $url_tag = Utility::page_type();
$static_file = LITESPEED_STATIC_DIR . $file_path_prefix . $url_tag_for_file . '.' . $file_type;
// Create tmp file to avoid conflict
$tmp_static_file = $static_file . '.tmp';
if (file_exists($tmp_static_file) && time() - filemtime($tmp_static_file) <= 600) {
// some other request is generating
// File::save( $tmp_static_file, '/* ' . ( is_404() ? '404' : $request_url ) . ' */', true ); // Can't use this bcos this will get filecon md5 changed
File::save($tmp_static_file, '', true);
foreach ($src_list as $src_info) {
if (!empty($src_info['inl'])) {
$content = $src_info['src'];
$content = $this->load_file($src_info['src'], $file_type);
$is_min = $this->is_min($src_info['src']);
$content = $this->optm_snippet($content, $file_type, $minify && !$is_min, $src_info['src'], !empty($src_info['media']) ? $src_info['media'] : false);
File::save($tmp_static_file, $content, true, true);
// if CSS - run the minification on the saved file.
// Will move imports to the top of file and remove extra spaces.
if ($file_type == 'css') {
$obj = new Lib\CSS_JS_MIN\Minify\CSS();
$file_content_combined = $obj->moveImportsToTop(File::read($tmp_static_file));
File::save($tmp_static_file, $file_content_combined);
$filecon_md5 = md5_file($tmp_static_file);
$final_file_path = $file_path_prefix . $filecon_md5 . '.' . $file_type;
$realfile = LITESPEED_STATIC_DIR . $final_file_path;
if (!file_exists($realfile)) {
rename($tmp_static_file, $realfile);
Debug2::debug2('[Optmer] Saved static file [path] ' . $realfile);
unlink($tmp_static_file);
$vary = $this->cls('Vary')->finalize_full_varies();
Debug2::debug2("[Optmer] Save URL to file for [file_type] $file_type [file] $filecon_md5 [vary] $vary ");
$this->cls('Data')->save_url($url_tag, $vary, $file_type, $filecon_md5, dirname($realfile));
return array( $filecon_md5 . '.' . $file_type, $file_type );
public function optm_snippet( $content, $file_type, $minify, $src, $media = false ) {
if ($file_type == 'css') {
if ($this->_conf_css_font_display) {
$content = preg_replace('#(@font\-face\s*\{)#isU', '${1}font-display:swap;', $content);
$content = preg_replace('/@charset[^;]+;\\s*/', '', $content);
$content = '@media ' . $media . '{' . $content . "\n}";
$content = self::minify_css($content);
$content = $this->cls('CDN')->finalize($content);
if ((defined('LITESPEED_GUEST_OPTM') || $this->conf(Base::O_IMG_OPTM_WEBP)) && $this->cls('Media')->webp_support()) {
$content = $this->cls('Media')->replace_background_webp($content);
$content = self::minify_js($content);
$content = $this->_null_minifier($content);
$content = apply_filters('litespeed_optm_cssjs', $content, $file_type, $src);
* Load remote resource from cache if existed
private function load_cached_file( $url, $file_type ) {
$file_path_prefix = $this->_build_filepath_prefix($file_type);
$folder_name = LITESPEED_STATIC_DIR . $file_path_prefix;
$to_be_deleted_folder = $folder_name . date('Ymd', strtotime('-2 days'));
if (file_exists($to_be_deleted_folder)) {
Debug2::debug('[Optimizer] ❌ Clearing folder [name] ' . $to_be_deleted_folder);
File::rrmdir($to_be_deleted_folder);
$today_file = $folder_name . date('Ymd') . '/' . md5($url);
if (file_exists($today_file)) {
return File::read($today_file);
$res = wp_safe_remote_get($url);
$res_code = wp_remote_retrieve_response_code($res);
if (is_wp_error($res) || $res_code != 200) {
Debug2::debug2('[Optimizer] ❌ Load Remote error [code] ' . $res_code);
$con = wp_remote_retrieve_body($res);
Debug2::debug('[Optimizer] ✅ Save remote file to cache [name] ' . $today_file);
File::save($today_file, $con, true);
* Load remote/local resource
public function load_file( $src, $file_type = 'css' ) {
$real_file = Utility::is_internal_file($src);
$postfix = pathinfo(parse_url($src, PHP_URL_PATH), PATHINFO_EXTENSION);
if (!$real_file || $postfix != $file_type) {
Debug2::debug2('[CSS] Load Remote [' . $file_type . '] ' . $src);
$this_url = substr($src, 0, 2) == '//' ? set_url_scheme($src) : $src;
$con = $this->load_cached_file($this_url, $file_type);
if ($file_type == 'css') {
$dirname = dirname($this_url) . '/';
$con = Lib\UriRewriter::prepend($con, $dirname);
Debug2::debug2('[CSS] Load local [' . $file_type . '] ' . $real_file[0]);
$con = File::read($real_file[0]);
if ($file_type == 'css') {
$dirname = dirname($real_file[0]);
$con = Lib\UriRewriter::rewrite($con, $dirname);
public static function minify_css( $data ) {
$obj = new Lib\CSS_JS_MIN\Minify\CSS();
} catch (\Exception $e) {
Debug2::debug('******[Optmer] minify_css failed: ' . $e->getMessage());
error_log('****** LiteSpeed Optimizer minify_css failed: ' . $e->getMessage());
* Added exception capture when minify
public static function minify_js( $data, $js_type = '' ) {
// For inline JS optimize, need to check if it's js type
preg_match('#type=([\'"])(.+)\g{1}#isU', $js_type, $matches);
if ($matches && $matches[2] != 'text/javascript') {
Debug2::debug('******[Optmer] minify_js bypass due to type: ' . $matches[2]);
$obj = new Lib\CSS_JS_MIN\Minify\JS();
} catch (\Exception $e) {
Debug2::debug('******[Optmer] minify_js failed: ' . $e->getMessage());
// error_log( '****** LiteSpeed Optimizer minify_js failed: ' . $e->getMessage() );
private function _null_minifier( $content ) {
$content = str_replace("\r\n", "\n", $content);
* Check if the file is already min file
public function is_min( $filename ) {
$basename = basename($filename);
if (preg_match('/[-\.]min\.(?:[a-zA-Z]+)$/i', $basename)) {