Version Description
- fix for images in CSS not all being translated to correct path, leading to 404s as reported by Jeff Inho
- fix for "[] operator not supported for strings" error in PHP7.1 as reported by falk-wussow.de
- fix for security hash busting AO's cache in some cases (esp. in 2.1.1)
Download this release
Release Info
Developer | futtta |
Plugin | Autoptimize |
Version | 2.2.1 |
Comparing to | |
See all releases |
Code changes from version 2.1.2 to 2.2.1
- autoptimize.php +38 -13
- classes/autoptimizeBase.php +95 -5
- classes/autoptimizeCache.php +16 -11
- classes/autoptimizeConfig.php +52 -15
- classes/autoptimizeHTML.php +6 -0
- classes/autoptimizeScripts.php +102 -44
- classes/autoptimizeStyles.php +143 -107
- classes/autoptimizeToolbar.php +39 -41
- classes/external/php/minify-html.php +1 -1
- classes/external/php/yui-php-cssmin-2.4.8-4.php +0 -777
- classes/external/php/yui-php-cssmin-2.4.8-4_fgo.php +4 -4
- classes/external/php/yui-php-cssmin-2.4.8-p10/cssmin.php +1112 -0
- classes/external/php/yui-php-cssmin-2.4.8-p10/data/hex-to-named-color-map.php +37 -0
- classes/external/php/yui-php-cssmin-2.4.8-p10/data/named-to-hex-color-map.php +108 -0
- classes/static/toolbar.js +39 -30
- classlesses/autoptimizeCacheChecker.php +4 -3
- classlesses/autoptimizeFontRegex.php +0 -7
- classlesses/autoptimizePageCacheFlush.php +4 -0
- classlesses/autoptimizePartners.php +5 -3
- classlesses/autoptimizeSpeedupper.php +103 -0
- classlesses/autoptimizeUpdateCode.php +2 -0
- config/default.php +1 -1
- config/delayed.php +1 -1
- readme.txt +62 -47
autoptimize.php
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
<?php
|
2 |
/*
|
3 |
Plugin Name: Autoptimize
|
4 |
-
Plugin URI: http://
|
5 |
Description: Optimizes your website, concatenating the CSS and JavaScript code, and compressing it.
|
6 |
-
Version: 2.1
|
7 |
Author: Frank Goossens (futtta)
|
8 |
Author URI: http://blog.futtta.be/
|
9 |
Domain Path: localization/
|
@@ -54,7 +54,7 @@ $conf = autoptimizeConfig::instance();
|
|
54 |
/* Check if we're updating, in which case we might need to do stuff and flush the cache
|
55 |
to avoid old versions of aggregated files lingering around */
|
56 |
|
57 |
-
$autoptimize_version="2.
|
58 |
$autoptimize_db_version=get_option('autoptimize_version','none');
|
59 |
|
60 |
if ($autoptimize_db_version !== $autoptimize_version) {
|
@@ -78,17 +78,17 @@ add_action( 'init', 'autoptimize_load_plugin_textdomain' );
|
|
78 |
function autoptimize_uninstall(){
|
79 |
autoptimizeCache::clearall();
|
80 |
|
81 |
-
$delete_options=array("autoptimize_cache_clean", "autoptimize_cache_nogzip", "autoptimize_css", "autoptimize_css_datauris", "autoptimize_css_justhead", "autoptimize_css_defer", "autoptimize_css_defer_inline", "autoptimize_css_inline", "autoptimize_css_exclude", "autoptimize_html", "autoptimize_html_keepcomments", "autoptimize_js", "autoptimize_js_exclude", "autoptimize_js_forcehead", "autoptimize_js_justhead", "autoptimize_js_trycatch", "autoptimize_version", "autoptimize_show_adv", "autoptimize_cdn_url", "autoptimize_cachesize_notice","autoptimize_css_include_inline","autoptimize_js_include_inline","autoptimize_css_nogooglefont");
|
82 |
|
83 |
if ( !is_multisite() ) {
|
84 |
-
foreach ($delete_options as $del_opt) {
|
85 |
} else {
|
86 |
global $wpdb;
|
87 |
$blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );
|
88 |
$original_blog_id = get_current_blog_id();
|
89 |
foreach ( $blog_ids as $blog_id ) {
|
90 |
switch_to_blog( $blog_id );
|
91 |
-
foreach ($delete_options as $del_opt) {
|
92 |
}
|
93 |
switch_to_blog( $original_blog_id );
|
94 |
}
|
@@ -112,7 +112,7 @@ function autoptimize_update_config_notice() {
|
|
112 |
|
113 |
function autoptimize_cache_unavailable_notice() {
|
114 |
echo '<div class="error"><p>';
|
115 |
-
|
116 |
echo '</p></div>';
|
117 |
}
|
118 |
|
@@ -132,10 +132,31 @@ function autoptimize_start_buffering() {
|
|
132 |
$ao_noptimize = true;
|
133 |
}
|
134 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
// filter you can use to block autoptimization on your own terms
|
136 |
$ao_noptimize = (bool) apply_filters( 'autoptimize_filter_noptimize', $ao_noptimize );
|
137 |
|
138 |
if (!is_feed() && !$ao_noptimize && !is_admin() && ( !function_exists('is_customize_preview') || !is_customize_preview() ) ) {
|
|
|
|
|
|
|
|
|
|
|
139 |
// Config element
|
140 |
$conf = autoptimizeConfig::instance();
|
141 |
|
@@ -178,7 +199,7 @@ function autoptimize_start_buffering() {
|
|
178 |
}
|
179 |
} else {
|
180 |
if (!class_exists('CSSmin')) {
|
181 |
-
@include(AUTOPTIMIZE_PLUGIN_DIR.'classes/external/php/yui-php-cssmin-2.4.8-
|
182 |
}
|
183 |
}
|
184 |
if ( ! defined( 'COMPRESS_CSS' )) {
|
@@ -192,7 +213,6 @@ function autoptimize_start_buffering() {
|
|
192 |
ob_end_clean();
|
193 |
}
|
194 |
}
|
195 |
-
|
196 |
// Now, start the real thing!
|
197 |
ob_start('autoptimize_end_buffering');
|
198 |
}
|
@@ -201,7 +221,7 @@ function autoptimize_start_buffering() {
|
|
201 |
// Action on end, this is where the magic happens
|
202 |
function autoptimize_end_buffering($content) {
|
203 |
if ( ((stripos($content,"<html") === false) && (stripos($content,"<!DOCTYPE html") === false)) || preg_match('/<html[^>]*(?:amp|⚡)/',$content) === 1 || stripos($content,"<xsl:stylesheet") !== false ) { return $content; }
|
204 |
-
|
205 |
// load URL constants as late as possible to allow domain mapper to kick in
|
206 |
if (function_exists("domain_mapping_siteurl")) {
|
207 |
define('AUTOPTIMIZE_WP_SITE_URL',domain_mapping_siteurl(get_current_blog_id()));
|
@@ -218,7 +238,7 @@ function autoptimize_end_buffering($content) {
|
|
218 |
define('AUTOPTIMIZE_CACHE_URL',AUTOPTIMIZE_WP_CONTENT_URL.AUTOPTIMIZE_CACHE_CHILD_DIR);
|
219 |
}
|
220 |
define('AUTOPTIMIZE_WP_ROOT_URL',str_replace(AUTOPTIMIZE_WP_CONTENT_NAME,'',AUTOPTIMIZE_WP_CONTENT_URL));
|
221 |
-
define('AUTOPTIMIZE_HASH',wp_hash(AUTOPTIMIZE_CACHE_DIR
|
222 |
|
223 |
// Config element
|
224 |
$conf = autoptimizeConfig::instance();
|
@@ -282,14 +302,19 @@ if ( autoptimizeCache::cacheavail() ) {
|
|
282 |
if (defined('AUTOPTIMIZE_INIT_EARLIER')) {
|
283 |
add_action('init','autoptimize_start_buffering',-1);
|
284 |
} else {
|
285 |
-
|
|
|
286 |
}
|
287 |
}
|
288 |
} else {
|
289 |
add_action('admin_notices', 'autoptimize_cache_unavailable_notice');
|
290 |
}
|
291 |
|
292 |
-
|
|
|
|
|
|
|
|
|
293 |
include_once('classlesses/autoptimizeCacheChecker.php');
|
294 |
|
295 |
// Do not pollute other plugins
|
1 |
<?php
|
2 |
/*
|
3 |
Plugin Name: Autoptimize
|
4 |
+
Plugin URI: http://autoptimize.com/
|
5 |
Description: Optimizes your website, concatenating the CSS and JavaScript code, and compressing it.
|
6 |
+
Version: 2.2.1
|
7 |
Author: Frank Goossens (futtta)
|
8 |
Author URI: http://blog.futtta.be/
|
9 |
Domain Path: localization/
|
54 |
/* Check if we're updating, in which case we might need to do stuff and flush the cache
|
55 |
to avoid old versions of aggregated files lingering around */
|
56 |
|
57 |
+
$autoptimize_version="2.2.0";
|
58 |
$autoptimize_db_version=get_option('autoptimize_version','none');
|
59 |
|
60 |
if ($autoptimize_db_version !== $autoptimize_version) {
|
78 |
function autoptimize_uninstall(){
|
79 |
autoptimizeCache::clearall();
|
80 |
|
81 |
+
$delete_options=array("autoptimize_cache_clean", "autoptimize_cache_nogzip", "autoptimize_css", "autoptimize_css_datauris", "autoptimize_css_justhead", "autoptimize_css_defer", "autoptimize_css_defer_inline", "autoptimize_css_inline", "autoptimize_css_exclude", "autoptimize_html", "autoptimize_html_keepcomments", "autoptimize_js", "autoptimize_js_exclude", "autoptimize_js_forcehead", "autoptimize_js_justhead", "autoptimize_js_trycatch", "autoptimize_version", "autoptimize_show_adv", "autoptimize_cdn_url", "autoptimize_cachesize_notice","autoptimize_css_include_inline","autoptimize_js_include_inline","autoptimize_css_nogooglefont","autoptimize_optimize_logged","autoptimize_optimize_checkout");
|
82 |
|
83 |
if ( !is_multisite() ) {
|
84 |
+
foreach ($delete_options as $del_opt) { delete_option( $del_opt ); }
|
85 |
} else {
|
86 |
global $wpdb;
|
87 |
$blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );
|
88 |
$original_blog_id = get_current_blog_id();
|
89 |
foreach ( $blog_ids as $blog_id ) {
|
90 |
switch_to_blog( $blog_id );
|
91 |
+
foreach ($delete_options as $del_opt) { delete_option( $del_opt ); }
|
92 |
}
|
93 |
switch_to_blog( $original_blog_id );
|
94 |
}
|
112 |
|
113 |
function autoptimize_cache_unavailable_notice() {
|
114 |
echo '<div class="error"><p>';
|
115 |
+
printf( __( 'Autoptimize cannot write to the cache directory (%s), please fix to enable CSS/ JS optimization!', 'autoptimize' ), AUTOPTIMIZE_CACHE_DIR );
|
116 |
echo '</p></div>';
|
117 |
}
|
118 |
|
132 |
$ao_noptimize = true;
|
133 |
}
|
134 |
|
135 |
+
// if setting says not to optimize logged in user and user is logged in
|
136 |
+
if ( get_option('autoptimize_optimize_logged','on') !== 'on' && is_user_logged_in() && current_user_can('edit_posts') ) {
|
137 |
+
$ao_noptimize = true;
|
138 |
+
}
|
139 |
+
|
140 |
+
// if setting says not to optimize cart/ checkout
|
141 |
+
if ( get_option('autoptimize_optimize_checkout','on') !== 'on' ) {
|
142 |
+
// checking for woocommerce, easy digital downloads and wp ecommerce
|
143 |
+
foreach ( array("is_checkout","is_cart","edd_is_checkout","wpsc_is_cart","wpsc_is_checkout") as $shopCond ) {
|
144 |
+
if ( function_exists($shopCond) && $shopCond() ) {
|
145 |
+
$ao_noptimize = true;
|
146 |
+
break;
|
147 |
+
}
|
148 |
+
}
|
149 |
+
}
|
150 |
+
|
151 |
// filter you can use to block autoptimization on your own terms
|
152 |
$ao_noptimize = (bool) apply_filters( 'autoptimize_filter_noptimize', $ao_noptimize );
|
153 |
|
154 |
if (!is_feed() && !$ao_noptimize && !is_admin() && ( !function_exists('is_customize_preview') || !is_customize_preview() ) ) {
|
155 |
+
// load speedupper conditionally (true by default?)
|
156 |
+
if ( apply_filters('autoptimize_filter_speedupper', true) ) {
|
157 |
+
include(AUTOPTIMIZE_PLUGIN_DIR.'classlesses/autoptimizeSpeedupper.php');
|
158 |
+
}
|
159 |
+
|
160 |
// Config element
|
161 |
$conf = autoptimizeConfig::instance();
|
162 |
|
199 |
}
|
200 |
} else {
|
201 |
if (!class_exists('CSSmin')) {
|
202 |
+
@include(AUTOPTIMIZE_PLUGIN_DIR.'classes/external/php/yui-php-cssmin-2.4.8-p10/cssmin.php');
|
203 |
}
|
204 |
}
|
205 |
if ( ! defined( 'COMPRESS_CSS' )) {
|
213 |
ob_end_clean();
|
214 |
}
|
215 |
}
|
|
|
216 |
// Now, start the real thing!
|
217 |
ob_start('autoptimize_end_buffering');
|
218 |
}
|
221 |
// Action on end, this is where the magic happens
|
222 |
function autoptimize_end_buffering($content) {
|
223 |
if ( ((stripos($content,"<html") === false) && (stripos($content,"<!DOCTYPE html") === false)) || preg_match('/<html[^>]*(?:amp|⚡)/',$content) === 1 || stripos($content,"<xsl:stylesheet") !== false ) { return $content; }
|
224 |
+
|
225 |
// load URL constants as late as possible to allow domain mapper to kick in
|
226 |
if (function_exists("domain_mapping_siteurl")) {
|
227 |
define('AUTOPTIMIZE_WP_SITE_URL',domain_mapping_siteurl(get_current_blog_id()));
|
238 |
define('AUTOPTIMIZE_CACHE_URL',AUTOPTIMIZE_WP_CONTENT_URL.AUTOPTIMIZE_CACHE_CHILD_DIR);
|
239 |
}
|
240 |
define('AUTOPTIMIZE_WP_ROOT_URL',str_replace(AUTOPTIMIZE_WP_CONTENT_NAME,'',AUTOPTIMIZE_WP_CONTENT_URL));
|
241 |
+
define('AUTOPTIMIZE_HASH',wp_hash(AUTOPTIMIZE_CACHE_DIR));
|
242 |
|
243 |
// Config element
|
244 |
$conf = autoptimizeConfig::instance();
|
302 |
if (defined('AUTOPTIMIZE_INIT_EARLIER')) {
|
303 |
add_action('init','autoptimize_start_buffering',-1);
|
304 |
} else {
|
305 |
+
if (!defined('AUTOPTIMIZE_HOOK_INTO')) { define('AUTOPTIMIZE_HOOK_INTO', 'template_redirect'); }
|
306 |
+
add_action(constant("AUTOPTIMIZE_HOOK_INTO"),'autoptimize_start_buffering',2);
|
307 |
}
|
308 |
}
|
309 |
} else {
|
310 |
add_action('admin_notices', 'autoptimize_cache_unavailable_notice');
|
311 |
}
|
312 |
|
313 |
+
function autoptimize_activate() {
|
314 |
+
register_uninstall_hook( __FILE__, 'autoptimize_uninstall' );
|
315 |
+
}
|
316 |
+
register_activation_hook( __FILE__, 'autoptimize_activate' );
|
317 |
+
|
318 |
include_once('classlesses/autoptimizeCacheChecker.php');
|
319 |
|
320 |
// Do not pollute other plugins
|
classes/autoptimizeBase.php
CHANGED
@@ -30,6 +30,7 @@ abstract class autoptimizeBase {
|
|
30 |
}
|
31 |
|
32 |
$siteHost=parse_url(AUTOPTIMIZE_WP_SITE_URL,PHP_URL_HOST);
|
|
|
33 |
|
34 |
// normalize
|
35 |
if (strpos($url,'//')===0) {
|
@@ -46,6 +47,10 @@ abstract class autoptimizeBase {
|
|
46 |
$url = AUTOPTIMIZE_WP_SITE_URL.str_repeat("/..",$subdir_levels).$url;
|
47 |
}
|
48 |
}
|
|
|
|
|
|
|
|
|
49 |
|
50 |
// first check; hostname wp site should be hostname of url
|
51 |
$thisHost=@parse_url($url,PHP_URL_HOST);
|
@@ -82,17 +87,28 @@ abstract class autoptimizeBase {
|
|
82 |
|
83 |
// try to remove "wp root url" from url while not minding http<>https
|
84 |
$tmp_ao_root = preg_replace('/https?:/','',AUTOPTIMIZE_WP_ROOT_URL);
|
|
|
|
|
|
|
|
|
85 |
$tmp_url = preg_replace('/https?:/','',$url);
|
86 |
$path = str_replace($tmp_ao_root,'',$tmp_url);
|
87 |
|
88 |
-
//
|
89 |
if (preg_match('#^:?//#',$path)) {
|
90 |
/** External script/css (adsense, etc) */
|
91 |
return false;
|
92 |
}
|
93 |
|
|
|
94 |
$path = str_replace('//','/',WP_ROOT_DIR.$path);
|
95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
}
|
97 |
|
98 |
// needed for WPML-filter
|
@@ -283,12 +299,12 @@ abstract class autoptimizeBase {
|
|
283 |
protected function inject_minified($in) {
|
284 |
if ( strpos( $in, '%%INJECTLATER%%' ) !== false ) {
|
285 |
$out = preg_replace_callback(
|
286 |
-
'
|
287 |
create_function(
|
288 |
'$matches',
|
289 |
'$filepath=base64_decode(strtok($matches[1],"|"));
|
290 |
$filecontent=file_get_contents($filepath);
|
291 |
-
|
292 |
// remove BOM
|
293 |
$filecontent = preg_replace("#\x{EF}\x{BB}\x{BF}#","",$filecontent);
|
294 |
|
@@ -300,7 +316,7 @@ abstract class autoptimizeBase {
|
|
300 |
$filecontent=preg_replace("#^\s*\/\*[^!].*\*\/\s?#Um","",$filecontent);
|
301 |
$filecontent=preg_replace("#(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+#", "\n", $filecontent);
|
302 |
|
303 |
-
//
|
304 |
if (substr($filepath,-3,3)===".js") {
|
305 |
if ((substr($filecontent,-1,1)!==";")&&(substr($filecontent,-1,1)!=="}")) {
|
306 |
$filecontent.=";";
|
@@ -325,4 +341,78 @@ abstract class autoptimizeBase {
|
|
325 |
}
|
326 |
return $out;
|
327 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
}
|
30 |
}
|
31 |
|
32 |
$siteHost=parse_url(AUTOPTIMIZE_WP_SITE_URL,PHP_URL_HOST);
|
33 |
+
$contentHost=parse_url(AUTOPTIMIZE_WP_ROOT_URL,PHP_URL_HOST);
|
34 |
|
35 |
// normalize
|
36 |
if (strpos($url,'//')===0) {
|
47 |
$url = AUTOPTIMIZE_WP_SITE_URL.str_repeat("/..",$subdir_levels).$url;
|
48 |
}
|
49 |
}
|
50 |
+
|
51 |
+
if ($siteHost !== $contentHost) {
|
52 |
+
$url=str_replace(AUTOPTIMIZE_WP_CONTENT_URL,AUTOPTIMIZE_WP_SITE_URL.AUTOPTIMIZE_WP_CONTENT_NAME,$url);
|
53 |
+
}
|
54 |
|
55 |
// first check; hostname wp site should be hostname of url
|
56 |
$thisHost=@parse_url($url,PHP_URL_HOST);
|
87 |
|
88 |
// try to remove "wp root url" from url while not minding http<>https
|
89 |
$tmp_ao_root = preg_replace('/https?:/','',AUTOPTIMIZE_WP_ROOT_URL);
|
90 |
+
if ($siteHost !== $contentHost) {
|
91 |
+
// as we replaced the content-domain with the site-domain, we should match against that
|
92 |
+
$tmp_ao_root = preg_replace('/https?:/','',AUTOPTIMIZE_WP_SITE_URL);
|
93 |
+
}
|
94 |
$tmp_url = preg_replace('/https?:/','',$url);
|
95 |
$path = str_replace($tmp_ao_root,'',$tmp_url);
|
96 |
|
97 |
+
// if path starts with :// or //, this is not a URL in the WP context and we have to assume we can't aggregate
|
98 |
if (preg_match('#^:?//#',$path)) {
|
99 |
/** External script/css (adsense, etc) */
|
100 |
return false;
|
101 |
}
|
102 |
|
103 |
+
// prepend with WP_ROOT_DIR to have full path to file
|
104 |
$path = str_replace('//','/',WP_ROOT_DIR.$path);
|
105 |
+
|
106 |
+
// final check: does file exist and is it readable
|
107 |
+
if (file_exists($path) && is_file($path) && is_readable($path)) {
|
108 |
+
return $path;
|
109 |
+
} else {
|
110 |
+
return false;
|
111 |
+
}
|
112 |
}
|
113 |
|
114 |
// needed for WPML-filter
|
299 |
protected function inject_minified($in) {
|
300 |
if ( strpos( $in, '%%INJECTLATER%%' ) !== false ) {
|
301 |
$out = preg_replace_callback(
|
302 |
+
'#\/\*\!%%INJECTLATER'.AUTOPTIMIZE_HASH.'%%(.*?)%%INJECTLATER%%\*\/#is',
|
303 |
create_function(
|
304 |
'$matches',
|
305 |
'$filepath=base64_decode(strtok($matches[1],"|"));
|
306 |
$filecontent=file_get_contents($filepath);
|
307 |
+
|
308 |
// remove BOM
|
309 |
$filecontent = preg_replace("#\x{EF}\x{BB}\x{BF}#","",$filecontent);
|
310 |
|
316 |
$filecontent=preg_replace("#^\s*\/\*[^!].*\*\/\s?#Um","",$filecontent);
|
317 |
$filecontent=preg_replace("#(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+#", "\n", $filecontent);
|
318 |
|
319 |
+
// differentiate between JS, CSS and other files
|
320 |
if (substr($filepath,-3,3)===".js") {
|
321 |
if ((substr($filecontent,-1,1)!==";")&&(substr($filecontent,-1,1)!=="}")) {
|
322 |
$filecontent.=";";
|
341 |
}
|
342 |
return $out;
|
343 |
}
|
344 |
+
|
345 |
+
protected function minify_single($pathIn) {
|
346 |
+
// determine JS or CSS and set var (also mimetype), return false if neither
|
347 |
+
if ( $this->str_ends_in($pathIn,".js") === true ) {
|
348 |
+
$codeType="js";
|
349 |
+
$codeMime="text/javascript";
|
350 |
+
} else if ( $this->str_ends_in($pathIn,".css") === true ) {
|
351 |
+
$codeType="css";
|
352 |
+
$codeMime="text/css";
|
353 |
+
} else {
|
354 |
+
return false;
|
355 |
+
}
|
356 |
+
|
357 |
+
// if min.js or min.css return false
|
358 |
+
if (( $this->str_ends_in($pathIn,"-min.".$codeType) === true ) || ( $this->str_ends_in($pathIn,".min.".$codeType) === true ) || ( $this->str_ends_in($pathIn,"js/jquery/jquery.js") === true ) ) {
|
359 |
+
return false;
|
360 |
+
}
|
361 |
+
|
362 |
+
// read file, return false if empty
|
363 |
+
$_toMinify = file_get_contents($pathIn);
|
364 |
+
if ( empty($_toMinify) ) return false;
|
365 |
+
|
366 |
+
// check cache
|
367 |
+
$_md5hash = "single_".md5($_toMinify);
|
368 |
+
$_cache = new autoptimizeCache($_md5hash,$codeType);
|
369 |
+
if ($_cache->check() ) {
|
370 |
+
$_CachedMinifiedUrl = AUTOPTIMIZE_CACHE_URL.$_cache->getname();
|
371 |
+
} else {
|
372 |
+
// if not in cache first minify
|
373 |
+
$_Minified = $_toMinify;
|
374 |
+
if ($codeType === "js") {
|
375 |
+
if (class_exists('JSMin') && apply_filters( 'autoptimize_js_do_minify' , true)) {
|
376 |
+
if (@is_callable(array("JSMin","minify"))) {
|
377 |
+
$tmp_code = trim(JSMin::minify($_toMinify));
|
378 |
+
}
|
379 |
+
}
|
380 |
+
} else if ($codeType === "css") {
|
381 |
+
if (class_exists('Minify_CSS_Compressor')) {
|
382 |
+
$tmp_code = trim(Minify_CSS_Compressor::process($_toMinify));
|
383 |
+
} else if(class_exists('CSSmin')) {
|
384 |
+
$cssmin = new CSSmin();
|
385 |
+
if (method_exists($cssmin,"run")) {
|
386 |
+
$tmp_code = trim($cssmin->run($_toMinify));
|
387 |
+
} elseif (@is_callable(array($cssmin,"minify"))) {
|
388 |
+
$tmp_code = trim(CssMin::minify($_toMinify));
|
389 |
+
}
|
390 |
+
}
|
391 |
+
}
|
392 |
+
if (!empty($tmp_code)) {
|
393 |
+
$_Minified = $tmp_code;
|
394 |
+
unset($tmp_code);
|
395 |
+
}
|
396 |
+
// and then cache
|
397 |
+
$_cache->cache($_Minified,$codeMime);
|
398 |
+
$_CachedMinifiedUrl = AUTOPTIMIZE_CACHE_URL.$_cache->getname();
|
399 |
+
}
|
400 |
+
unset($_cache);
|
401 |
+
|
402 |
+
// if CDN, then CDN
|
403 |
+
$_CachedMinifiedUrl = $this->url_replace_cdn($_CachedMinifiedUrl);
|
404 |
+
|
405 |
+
return $_CachedMinifiedUrl;
|
406 |
+
}
|
407 |
+
|
408 |
+
protected function str_ends_in($haystack,$needle) {
|
409 |
+
$needleLength = strlen($needle);
|
410 |
+
$haystackLength = strlen($haystack);
|
411 |
+
$lastPos=strrpos($haystack,$needle);
|
412 |
+
if ($lastPos === $haystackLength - $needleLength) {
|
413 |
+
return true;
|
414 |
+
} else {
|
415 |
+
return false;
|
416 |
+
}
|
417 |
+
}
|
418 |
}
|
classes/autoptimizeCache.php
CHANGED
@@ -59,7 +59,7 @@ class autoptimizeCache {
|
|
59 |
file_put_contents($this->cachedir.$this->filename,$code, LOCK_EX);
|
60 |
if (apply_filters('autoptimize_filter_cache_create_static_gzip', false)) {
|
61 |
// Create an additional cached gzip file
|
62 |
-
file_put_contents($this->cachedir.$this->filename.'.
|
63 |
}
|
64 |
}
|
65 |
}
|
@@ -104,6 +104,13 @@ class autoptimizeCache {
|
|
104 |
include_once(AUTOPTIMIZE_PLUGIN_DIR.'classlesses/autoptimizePageCacheFlush.php');
|
105 |
add_action("autoptimize_action_cachepurged","autoptimize_flush_pagecache",10,0);
|
106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
return true;
|
108 |
}
|
109 |
|
@@ -179,16 +186,15 @@ class autoptimizeCache {
|
|
179 |
if (is_file($htaccess_tmpl)) {
|
180 |
$htAccessContent=file_get_contents($htaccess_tmpl);
|
181 |
} else if (is_multisite() || AUTOPTIMIZE_CACHE_NOGZIP == false) {
|
182 |
-
$htAccessContent='<IfModule
|
183 |
-
Header set Vary "Accept-Encoding"
|
184 |
-
Header set Cache-Control "max-age=10672000, must-revalidate"
|
185 |
-
</IfModule>
|
186 |
-
<IfModule mod_expires.c>
|
187 |
ExpiresActive On
|
188 |
ExpiresByType text/css A30672000
|
189 |
ExpiresByType text/javascript A30672000
|
190 |
ExpiresByType application/javascript A30672000
|
191 |
</IfModule>
|
|
|
|
|
|
|
192 |
<IfModule mod_deflate.c>
|
193 |
<FilesMatch "\.(js|css)$">
|
194 |
SetOutputFilter DEFLATE
|
@@ -206,16 +212,15 @@ class autoptimizeCache {
|
|
206 |
</Files>
|
207 |
</IfModule>';
|
208 |
} else {
|
209 |
-
$htAccessContent='<IfModule
|
210 |
-
Header set Vary "Accept-Encoding"
|
211 |
-
Header set Cache-Control "max-age=10672000, must-revalidate"
|
212 |
-
</IfModule>
|
213 |
-
<IfModule mod_expires.c>
|
214 |
ExpiresActive On
|
215 |
ExpiresByType text/css A30672000
|
216 |
ExpiresByType text/javascript A30672000
|
217 |
ExpiresByType application/javascript A30672000
|
218 |
</IfModule>
|
|
|
|
|
|
|
219 |
<IfModule mod_deflate.c>
|
220 |
<FilesMatch "\.(js|css)$">
|
221 |
SetOutputFilter DEFLATE
|
59 |
file_put_contents($this->cachedir.$this->filename,$code, LOCK_EX);
|
60 |
if (apply_filters('autoptimize_filter_cache_create_static_gzip', false)) {
|
61 |
// Create an additional cached gzip file
|
62 |
+
file_put_contents($this->cachedir.$this->filename.'.gz', gzencode($code,9,FORCE_GZIP), LOCK_EX);
|
63 |
}
|
64 |
}
|
65 |
}
|
104 |
include_once(AUTOPTIMIZE_PLUGIN_DIR.'classlesses/autoptimizePageCacheFlush.php');
|
105 |
add_action("autoptimize_action_cachepurged","autoptimize_flush_pagecache",10,0);
|
106 |
|
107 |
+
// warm cache (part of speedupper)?
|
108 |
+
if ( apply_filters('autoptimize_filter_speedupper', true) ) {
|
109 |
+
$warmCacheUrl = site_url()."/?ao_speedup_cachebuster=".rand(1,100000);
|
110 |
+
$warmCache = @wp_remote_get($warmCacheUrl);
|
111 |
+
unset($warmCache);
|
112 |
+
}
|
113 |
+
|
114 |
return true;
|
115 |
}
|
116 |
|
186 |
if (is_file($htaccess_tmpl)) {
|
187 |
$htAccessContent=file_get_contents($htaccess_tmpl);
|
188 |
} else if (is_multisite() || AUTOPTIMIZE_CACHE_NOGZIP == false) {
|
189 |
+
$htAccessContent='<IfModule mod_expires.c>
|
|
|
|
|
|
|
|
|
190 |
ExpiresActive On
|
191 |
ExpiresByType text/css A30672000
|
192 |
ExpiresByType text/javascript A30672000
|
193 |
ExpiresByType application/javascript A30672000
|
194 |
</IfModule>
|
195 |
+
<IfModule mod_headers.c>
|
196 |
+
Header append Cache-Control "public, immutable"
|
197 |
+
</IfModule>
|
198 |
<IfModule mod_deflate.c>
|
199 |
<FilesMatch "\.(js|css)$">
|
200 |
SetOutputFilter DEFLATE
|
212 |
</Files>
|
213 |
</IfModule>';
|
214 |
} else {
|
215 |
+
$htAccessContent='<IfModule mod_expires.c>
|
|
|
|
|
|
|
|
|
216 |
ExpiresActive On
|
217 |
ExpiresByType text/css A30672000
|
218 |
ExpiresByType text/javascript A30672000
|
219 |
ExpiresByType application/javascript A30672000
|
220 |
</IfModule>
|
221 |
+
<IfModule mod_headers.c>
|
222 |
+
Header append Cache-Control "public, immutable"
|
223 |
+
</IfModule>
|
224 |
<IfModule mod_deflate.c>
|
225 |
<FilesMatch "\.(js|css)$">
|
226 |
SetOutputFilter DEFLATE
|
classes/autoptimizeConfig.php
CHANGED
@@ -70,6 +70,14 @@ class autoptimizeConfig {
|
|
70 |
content: "\f108 \f140";
|
71 |
}
|
72 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
/* form */
|
74 |
.itemDetail {
|
75 |
background: #fff;
|
@@ -151,7 +159,7 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
151 |
<div class="wrap">
|
152 |
|
153 |
<?php if (version_compare(PHP_VERSION, '5.3.0') < 0) { ?>
|
154 |
-
<div class="notice-error notice"><?php
|
155 |
<?php } ?>
|
156 |
|
157 |
<div id="autoptimize_main">
|
@@ -210,11 +218,11 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
210 |
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv">
|
211 |
<th scope="row"><?php _e('Force JavaScript in <head>?','autoptimize'); ?></th>
|
212 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_js_forcehead" <?php echo get_option('autoptimize_js_forcehead')?'checked="checked" ':''; ?>/>
|
213 |
-
<?php _e('Load JavaScript early,
|
214 |
</tr>
|
215 |
<?php if (get_option('autoptimize_js_justhead')) { ?>
|
216 |
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv">
|
217 |
-
<th scope="row"><?php _e('Look for scripts only in <head>?','autoptimize');
|
218 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_js_justhead" <?php echo get_option('autoptimize_js_justhead')?'checked="checked" ':''; ?>/>
|
219 |
<?php _e('Mostly useful in combination with previous option when using jQuery-based templates, but might help keeping cache size under control.','autoptimize'); ?></label></td>
|
220 |
</tr>
|
@@ -222,7 +230,7 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
222 |
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv">
|
223 |
<th scope="row"><?php _e('Also aggregate inline JS?','autoptimize'); ?></th>
|
224 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_js_include_inline" <?php echo get_option('autoptimize_js_include_inline')?'checked="checked" ':''; ?>/>
|
225 |
-
<?php _e('
|
226 |
</tr>
|
227 |
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv">
|
228 |
<th scope="row"><?php _e('Exclude scripts from Autoptimize:','autoptimize'); ?></th>
|
@@ -256,7 +264,7 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
256 |
</tr>
|
257 |
<?php if (get_option('autoptimize_css_justhead')) { ?>
|
258 |
<tr valign="top" class="<?php echo $hiddenClass;?>css_sub ao_adv">
|
259 |
-
<th scope="row"><?php _e('Look for styles only in <head>?','autoptimize');
|
260 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_css_justhead" <?php echo get_option('autoptimize_css_justhead')?'checked="checked" ':''; ?>/>
|
261 |
<?php _e('Don\'t autoptimize CSS outside the head-section. If the cache gets big, you might want to enable this.','autoptimize'); ?></label></td>
|
262 |
</tr>
|
@@ -294,7 +302,7 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
294 |
<tr valign="top">
|
295 |
<th scope="row"><?php _e('CDN Base URL','autoptimize'); ?></th>
|
296 |
<td><label><input id="cdn_url" type="text" name="autoptimize_cdn_url" pattern="^(https?:)?\/\/([\da-z\.-]+)\.([\da-z\.]{2,6})([\/\w \.-]*)*(:\d{2,5})?\/?$" style="width:100%" value="<?php echo esc_url(get_option('autoptimize_cdn_url',''),array("http","https")); ?>" /><br />
|
297 |
-
<?php _e('Enter your CDN root URL to enable CDN for Autoptimized files. The URL can be http, https or protocol-relative (e.g. <code>//cdn.example.com/</code>).','autoptimize'); ?></label></td>
|
298 |
</tr>
|
299 |
</table>
|
300 |
</li>
|
@@ -315,14 +323,39 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
315 |
<td><?php
|
316 |
$AOstatArr=autoptimizeCache::stats();
|
317 |
$AOcacheSize=round($AOstatArr[1]/1024);
|
318 |
-
|
319 |
?></td>
|
320 |
</tr>
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
<?php
|
325 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
326 |
</table>
|
327 |
</li>
|
328 |
|
@@ -355,7 +388,7 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
355 |
echo $AO_banner;
|
356 |
}
|
357 |
?>
|
358 |
-
<li><?php _e("Need help? <a href='https://wordpress.org/plugins/autoptimize/faq/'>Check out the FAQ
|
359 |
<li><?php _e("Happy with Autoptimize?","autoptimize"); ?><br /><a href="<?php echo network_admin_url(); ?>plugin-install.php?tab=search&type=author&s=optimizingmatters"><?php _e("Try my other plugins!","autoptimize"); ?></a></li>
|
360 |
</ul>
|
361 |
</div>
|
@@ -380,7 +413,7 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
380 |
</div>
|
381 |
</div>
|
382 |
</div>
|
383 |
-
<div style="float:right;margin:50px 15px;"><a href="http://blog.futtta.be/2013/10/21/do-not-donate-to-me/" target="_blank"><img width="100px" height="85px" src="<?php echo plugins_url().'/'.plugin_basename(dirname(__FILE__)).'/external/do_not_donate_smallest.png'; ?>" title="<?php _e("Do not donate for this plugin!"); ?>"></a></div>
|
384 |
</div>
|
385 |
|
386 |
<script type="text/javascript">
|
@@ -556,6 +589,8 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
556 |
register_setting('autoptimize','autoptimize_cache_clean');
|
557 |
register_setting('autoptimize','autoptimize_cache_nogzip');
|
558 |
register_setting('autoptimize','autoptimize_show_adv');
|
|
|
|
|
559 |
}
|
560 |
|
561 |
public function setmeta($links,$file=null) {
|
@@ -603,7 +638,9 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
603 |
'autoptimize_css_nogooglefont' => 0,
|
604 |
'autoptimize_cdn_url' => "",
|
605 |
'autoptimize_cache_nogzip' => 1,
|
606 |
-
'autoptimize_show_adv' => 0
|
|
|
|
|
607 |
);
|
608 |
|
609 |
//Override with user settings
|
70 |
content: "\f108 \f140";
|
71 |
}
|
72 |
|
73 |
+
/* animate "show adv" button */
|
74 |
+
#ao_show_adv { animation: watchmenow 3s linear 5s 10; }
|
75 |
+
#ao_show_adv:hover { animation: none; }
|
76 |
+
@keyframes watchmenow {
|
77 |
+
0% { box-shadow: unset; }
|
78 |
+
100% { box-shadow: 0px 0px 20px yellow; }
|
79 |
+
}
|
80 |
+
|
81 |
/* form */
|
82 |
.itemDetail {
|
83 |
background: #fff;
|
159 |
<div class="wrap">
|
160 |
|
161 |
<?php if (version_compare(PHP_VERSION, '5.3.0') < 0) { ?>
|
162 |
+
<div class="notice-error notice"><?php echo '<p>' . sprintf( __('<strong>You are using a very old version of PHP</strong> (5.2.x or older) which has <a href=%s>serious security and performance issues</a>. Support for PHP 5.5 and below will be removed in one of the next AO released, please ask your hoster to provide you with an upgrade path to 7.x.','autoptimize'), '"http://blog.futtta.be/2016/03/15/why-would-you-still-be-on-php-5-2/" target="_blank"') . '</p>'; ?></div>
|
163 |
<?php } ?>
|
164 |
|
165 |
<div id="autoptimize_main">
|
218 |
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv">
|
219 |
<th scope="row"><?php _e('Force JavaScript in <head>?','autoptimize'); ?></th>
|
220 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_js_forcehead" <?php echo get_option('autoptimize_js_forcehead')?'checked="checked" ':''; ?>/>
|
221 |
+
<?php _e('Load JavaScript early, this can potentially fix some JS-errors, but makes the JS render blocking.','autoptimize'); ?></label></td>
|
222 |
</tr>
|
223 |
<?php if (get_option('autoptimize_js_justhead')) { ?>
|
224 |
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv">
|
225 |
+
<th scope="row"><?php _e('Look for scripts only in <head>?','autoptimize'); echo ' <i>'. __('(deprecated)','autoptimize') . '</i>'; ?></th>
|
226 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_js_justhead" <?php echo get_option('autoptimize_js_justhead')?'checked="checked" ':''; ?>/>
|
227 |
<?php _e('Mostly useful in combination with previous option when using jQuery-based templates, but might help keeping cache size under control.','autoptimize'); ?></label></td>
|
228 |
</tr>
|
230 |
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv">
|
231 |
<th scope="row"><?php _e('Also aggregate inline JS?','autoptimize'); ?></th>
|
232 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_js_include_inline" <?php echo get_option('autoptimize_js_include_inline')?'checked="checked" ':''; ?>/>
|
233 |
+
<?php _e('Let Autoptimize also extract JS from the HTML. <strong>Warning</strong>: this can make Autoptimize\'s cache size grow quickly, so only enable this if you know what you\'re doing.','autoptimize'); ?></label></td>
|
234 |
</tr>
|
235 |
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv">
|
236 |
<th scope="row"><?php _e('Exclude scripts from Autoptimize:','autoptimize'); ?></th>
|
264 |
</tr>
|
265 |
<?php if (get_option('autoptimize_css_justhead')) { ?>
|
266 |
<tr valign="top" class="<?php echo $hiddenClass;?>css_sub ao_adv">
|
267 |
+
<th scope="row"><?php _e('Look for styles only in <head>?','autoptimize'); echo ' <i>'. __('(deprecated)','autoptimize') . '</i>'; ?></th>
|
268 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_css_justhead" <?php echo get_option('autoptimize_css_justhead')?'checked="checked" ':''; ?>/>
|
269 |
<?php _e('Don\'t autoptimize CSS outside the head-section. If the cache gets big, you might want to enable this.','autoptimize'); ?></label></td>
|
270 |
</tr>
|
302 |
<tr valign="top">
|
303 |
<th scope="row"><?php _e('CDN Base URL','autoptimize'); ?></th>
|
304 |
<td><label><input id="cdn_url" type="text" name="autoptimize_cdn_url" pattern="^(https?:)?\/\/([\da-z\.-]+)\.([\da-z\.]{2,6})([\/\w \.-]*)*(:\d{2,5})?\/?$" style="width:100%" value="<?php echo esc_url(get_option('autoptimize_cdn_url',''),array("http","https")); ?>" /><br />
|
305 |
+
<?php _e('Enter your CDN root URL to enable CDN for Autoptimized files. The URL can be http, https or protocol-relative (e.g. <code>//cdn.example.com/</code>). This is not needed for Cloudflare.','autoptimize'); ?></label></td>
|
306 |
</tr>
|
307 |
</table>
|
308 |
</li>
|
323 |
<td><?php
|
324 |
$AOstatArr=autoptimizeCache::stats();
|
325 |
$AOcacheSize=round($AOstatArr[1]/1024);
|
326 |
+
printf( __( '%1$s files, totalling %2$s Kbytes (calculated at %3$s)', 'autoptimize'), $AOstatArr[0], $AOcacheSize, date("H:i e", $AOstatArr[2]) );
|
327 |
?></td>
|
328 |
</tr>
|
329 |
+
</table>
|
330 |
+
</li>
|
331 |
+
|
332 |
+
<li class="<?php echo $hiddenClass;?>itemDetail ao_adv">
|
333 |
+
<h2 class="itemTitle"><?php _e('Misc Options','autoptimize'); ?></h2>
|
334 |
+
<table class="form-table">
|
335 |
+
<tr valign="top" class="<?php echo $hiddenClass;?>ao_adv">
|
336 |
+
<th scope="row"><?php _e('Save aggregated script/css as static files?','autoptimize'); ?></th>
|
337 |
+
<td><label class="cb_label"><input type="checkbox" name="autoptimize_cache_nogzip" <?php echo get_option('autoptimize_cache_nogzip','1')?'checked="checked" ':''; ?>/>
|
338 |
+
<?php _e('By default files saved are static css/js, uncheck this option if your webserver doesn\'t properly handle the compression and expiry.','autoptimize'); ?></label>
|
339 |
+
</td>
|
340 |
+
</tr>
|
341 |
+
<tr valign="top" class="<?php echo $hiddenClass;?>ao_adv">
|
342 |
+
<th scope="row"><?php _e('Also optimize for logged in users?','autoptimize'); ?></th>
|
343 |
+
<td><label class="cb_label"><input type="checkbox" name="autoptimize_optimize_logged" <?php echo get_option('autoptimize_optimize_logged','1')?'checked="checked" ':''; ?>/>
|
344 |
+
<?php _e('By default Autoptimize is also active for logged on users, uncheck not to optimize when logged in e.g. to use a pagebuilder.','autoptimize'); ?></label>
|
345 |
+
</td>
|
346 |
+
</tr>
|
347 |
+
<?php
|
348 |
+
if ( function_exists("is_checkout") || function_exists("is_cart") || function_exists("edd_is_checkout") || function_exists("wpsc_is_cart") || function_exists("wpsc_is_checkout") ) {
|
349 |
+
?>
|
350 |
+
<tr valign="top" class="<?php echo $hiddenClass;?>ao_adv">
|
351 |
+
<th scope="row"><?php _e('Also optimize shop cart/ checkout?','autoptimize'); ?></th>
|
352 |
+
<td><label class="cb_label"><input type="checkbox" name="autoptimize_optimize_checkout" <?php echo get_option('autoptimize_optimize_checkout','1')?'checked="checked" ':''; ?>/>
|
353 |
+
<?php _e('By default Autoptimize is also active on your shop\'s cart/ checkout, uncheck not to optimize those.','autoptimize'); ?></label>
|
354 |
+
</td>
|
355 |
+
</tr>
|
356 |
+
<?php
|
357 |
+
}
|
358 |
+
?>
|
359 |
</table>
|
360 |
</li>
|
361 |
|
388 |
echo $AO_banner;
|
389 |
}
|
390 |
?>
|
391 |
+
<li><?php _e("Need help? <a href='https://wordpress.org/plugins/autoptimize/faq/'>Check out the FAQ here</a>.","autoptimize"); ?></li>
|
392 |
<li><?php _e("Happy with Autoptimize?","autoptimize"); ?><br /><a href="<?php echo network_admin_url(); ?>plugin-install.php?tab=search&type=author&s=optimizingmatters"><?php _e("Try my other plugins!","autoptimize"); ?></a></li>
|
393 |
</ul>
|
394 |
</div>
|
413 |
</div>
|
414 |
</div>
|
415 |
</div>
|
416 |
+
<div style="float:right;margin:50px 15px;"><a href="http://blog.futtta.be/2013/10/21/do-not-donate-to-me/" target="_blank"><img width="100px" height="85px" src="<?php echo plugins_url().'/'.plugin_basename(dirname(__FILE__)).'/external/do_not_donate_smallest.png'; ?>" title="<?php _e("Do not donate for this plugin!","autoptimize"); ?>"></a></div>
|
417 |
</div>
|
418 |
|
419 |
<script type="text/javascript">
|
589 |
register_setting('autoptimize','autoptimize_cache_clean');
|
590 |
register_setting('autoptimize','autoptimize_cache_nogzip');
|
591 |
register_setting('autoptimize','autoptimize_show_adv');
|
592 |
+
register_setting('autoptimize','autoptimize_optimize_logged');
|
593 |
+
register_setting('autoptimize','autoptimize_optimize_checkout');
|
594 |
}
|
595 |
|
596 |
public function setmeta($links,$file=null) {
|
638 |
'autoptimize_css_nogooglefont' => 0,
|
639 |
'autoptimize_cdn_url' => "",
|
640 |
'autoptimize_cache_nogzip' => 1,
|
641 |
+
'autoptimize_show_adv' => 0,
|
642 |
+
'autoptimize_optimize_logged' => 1,
|
643 |
+
'autoptimize_optimize_checkout' => 1
|
644 |
);
|
645 |
|
646 |
//Override with user settings
|
classes/autoptimizeHTML.php
CHANGED
@@ -66,6 +66,12 @@ class autoptimizeHTML extends autoptimizeBase {
|
|
66 |
}
|
67 |
}
|
68 |
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
return true;
|
70 |
}
|
71 |
|
66 |
}
|
67 |
}
|
68 |
|
69 |
+
// revslider data attribs somehow suffer from HTML optimization, this fixes that
|
70 |
+
if ( class_exists('RevSlider') || apply_filters('autoptimize_filter_html_dataattrib_cleanup', false) ) {
|
71 |
+
$this->content = preg_replace('#\n(data-.*$)\n#Um',' $1 ', $this->content);
|
72 |
+
$this->content = preg_replace('#(=\"[^"]*\")(\w)#','$1 $2', $this->content);
|
73 |
+
}
|
74 |
+
|
75 |
return true;
|
76 |
}
|
77 |
|
classes/autoptimizeScripts.php
CHANGED
@@ -25,26 +25,26 @@ class autoptimizeScripts extends autoptimizeBase {
|
|
25 |
if ($noptimizeJS) return false;
|
26 |
|
27 |
// only optimize known good JS?
|
28 |
-
$whitelistJS = apply_filters( 'autoptimize_filter_js_whitelist',
|
29 |
if (!empty($whitelistJS)) {
|
30 |
$this->whitelist = array_filter(array_map('trim',explode(",",$whitelistJS)));
|
31 |
}
|
32 |
|
33 |
// is there JS we should simply remove
|
34 |
-
$removableJS = apply_filters( 'autoptimize_filter_js_removables', '');
|
35 |
if (!empty($removableJS)) {
|
36 |
$this->jsremovables = array_filter(array_map('trim',explode(",",$removableJS)));
|
37 |
}
|
38 |
|
39 |
// only header?
|
40 |
-
if( apply_filters('autoptimize_filter_js_justhead'
|
41 |
$content = explode('</head>',$this->content,2);
|
42 |
$this->content = $content[0].'</head>';
|
43 |
$this->restofcontent = $content[1];
|
44 |
}
|
45 |
|
46 |
// include inline?
|
47 |
-
if( apply_filters('autoptimize_js_include_inline'
|
48 |
$this->include_inline = true;
|
49 |
}
|
50 |
|
@@ -58,9 +58,19 @@ class autoptimizeScripts extends autoptimizeBase {
|
|
58 |
|
59 |
// get extra exclusions settings or filter
|
60 |
$excludeJS = $options['js_exclude'];
|
61 |
-
$excludeJS = apply_filters( 'autoptimize_filter_js_exclude', $excludeJS );
|
62 |
if ($excludeJS!=="") {
|
63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
$this->dontmove = array_merge($exclJSArr,$this->dontmove);
|
65 |
}
|
66 |
|
@@ -88,53 +98,71 @@ class autoptimizeScripts extends autoptimizeBase {
|
|
88 |
// comments
|
89 |
$this->content = $this->hide_comments($this->content);
|
90 |
|
91 |
-
//Get script files
|
92 |
-
if(preg_match_all('#<script.*</script>#Usmi',$this->content,$matches)) {
|
93 |
foreach($matches[0] as $tag) {
|
94 |
-
// only consider aggregation whitelisted in should_aggregate-function
|
95 |
if( !$this->should_aggregate($tag) ) {
|
96 |
$tag='';
|
97 |
continue;
|
98 |
}
|
99 |
-
|
|
|
|
|
100 |
if ($this->isremovable($tag,$this->jsremovables)) {
|
101 |
$this->content = str_replace($tag,'',$this->content);
|
102 |
continue;
|
103 |
}
|
104 |
-
|
105 |
-
|
106 |
-
$url = current(explode('?',$source[2],2));
|
107 |
$path = $this->getpath($url);
|
108 |
-
if($path !== false && preg_match('#\.js$#',$path)) {
|
109 |
-
//
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
}
|
122 |
-
} else {
|
123 |
-
//We shouldn't touch this
|
124 |
-
$tag = '';
|
125 |
}
|
126 |
}
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
} else {
|
134 |
-
$this->move['first'][] = $
|
135 |
}
|
136 |
} else {
|
137 |
-
//
|
|
|
|
|
|
|
|
|
|
|
138 |
$tag = '';
|
139 |
}
|
140 |
}
|
@@ -154,8 +182,9 @@ class autoptimizeScripts extends autoptimizeBase {
|
|
154 |
$this->scripts[] = 'INLINE;'.$code;
|
155 |
} else {
|
156 |
// Can we move this?
|
157 |
-
|
158 |
-
|
|
|
159 |
$this->move['last'][] = $tag;
|
160 |
} else {
|
161 |
$this->move['first'][] = $tag;
|
@@ -191,7 +220,7 @@ class autoptimizeScripts extends autoptimizeBase {
|
|
191 |
if($this->trycatch) {
|
192 |
$script = 'try{'.$script.'}catch(e){}';
|
193 |
}
|
194 |
-
$tmpscript = apply_filters( 'autoptimize_js_individual_script', $script,
|
195 |
if ( has_filter('autoptimize_js_individual_script') && !empty($tmpscript) ) {
|
196 |
$script=$tmpscript;
|
197 |
$this->alreadyminified=true;
|
@@ -201,8 +230,10 @@ class autoptimizeScripts extends autoptimizeBase {
|
|
201 |
//External script
|
202 |
if($script !== false && file_exists($script) && is_readable($script)) {
|
203 |
$scriptsrc = file_get_contents($script);
|
|
|
204 |
$scriptsrc = preg_replace('/\x{EF}\x{BB}\x{BF}/','',$scriptsrc);
|
205 |
$scriptsrc = rtrim($scriptsrc,";\n\t\r").';';
|
|
|
206 |
//Add try-catch?
|
207 |
if($this->trycatch) {
|
208 |
$scriptsrc = 'try{'.$scriptsrc.'}catch(e){}';
|
@@ -211,8 +242,8 @@ class autoptimizeScripts extends autoptimizeBase {
|
|
211 |
if ( has_filter('autoptimize_js_individual_script') && !empty($tmpscriptsrc) ) {
|
212 |
$scriptsrc=$tmpscriptsrc;
|
213 |
$this->alreadyminified=true;
|
214 |
-
} else if (
|
215 |
-
$scriptsrc="
|
216 |
}
|
217 |
$this->jscode .= "\n".$scriptsrc;
|
218 |
}/*else{
|
@@ -248,9 +279,10 @@ class autoptimizeScripts extends autoptimizeBase {
|
|
248 |
}
|
249 |
} else {
|
250 |
$this->jscode = $this->inject_minified($this->jscode);
|
251 |
-
|
252 |
}
|
253 |
}
|
|
|
254 |
return true;
|
255 |
}
|
256 |
|
@@ -311,7 +343,9 @@ class autoptimizeScripts extends autoptimizeBase {
|
|
311 |
|
312 |
// Checks against the white- and blacklists
|
313 |
private function ismergeable($tag) {
|
314 |
-
|
|
|
|
|
315 |
foreach ($this->whitelist as $match) {
|
316 |
if(strpos($tag,$match)!==false) {
|
317 |
return true;
|
@@ -408,4 +442,28 @@ class autoptimizeScripts extends autoptimizeBase {
|
|
408 |
return false;
|
409 |
}
|
410 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
411 |
}
|
25 |
if ($noptimizeJS) return false;
|
26 |
|
27 |
// only optimize known good JS?
|
28 |
+
$whitelistJS = apply_filters( 'autoptimize_filter_js_whitelist', '', $this->content );
|
29 |
if (!empty($whitelistJS)) {
|
30 |
$this->whitelist = array_filter(array_map('trim',explode(",",$whitelistJS)));
|
31 |
}
|
32 |
|
33 |
// is there JS we should simply remove
|
34 |
+
$removableJS = apply_filters( 'autoptimize_filter_js_removables', '', $this->content );
|
35 |
if (!empty($removableJS)) {
|
36 |
$this->jsremovables = array_filter(array_map('trim',explode(",",$removableJS)));
|
37 |
}
|
38 |
|
39 |
// only header?
|
40 |
+
if( apply_filters('autoptimize_filter_js_justhead', $options['justhead']) == true ) {
|
41 |
$content = explode('</head>',$this->content,2);
|
42 |
$this->content = $content[0].'</head>';
|
43 |
$this->restofcontent = $content[1];
|
44 |
}
|
45 |
|
46 |
// include inline?
|
47 |
+
if( apply_filters('autoptimize_js_include_inline', $options['include_inline']) == true ) {
|
48 |
$this->include_inline = true;
|
49 |
}
|
50 |
|
58 |
|
59 |
// get extra exclusions settings or filter
|
60 |
$excludeJS = $options['js_exclude'];
|
61 |
+
$excludeJS = apply_filters( 'autoptimize_filter_js_exclude', $excludeJS, $this->content );
|
62 |
if ($excludeJS!=="") {
|
63 |
+
if (is_array($excludeJS)) {
|
64 |
+
if(($removeKeys = array_keys($excludeJS,"remove")) !== false) {
|
65 |
+
foreach ($removeKeys as $removeKey) {
|
66 |
+
unset($excludeJS[$removeKey]);
|
67 |
+
$this->jsremovables[]=$removeKey;
|
68 |
+
}
|
69 |
+
}
|
70 |
+
$exclJSArr = array_keys($excludeJS);
|
71 |
+
} else {
|
72 |
+
$exclJSArr = array_filter(array_map('trim',explode(",",$excludeJS)));
|
73 |
+
}
|
74 |
$this->dontmove = array_merge($exclJSArr,$this->dontmove);
|
75 |
}
|
76 |
|
98 |
// comments
|
99 |
$this->content = $this->hide_comments($this->content);
|
100 |
|
101 |
+
// Get script files
|
102 |
+
if (preg_match_all('#<script.*</script>#Usmi',$this->content,$matches)) {
|
103 |
foreach($matches[0] as $tag) {
|
104 |
+
// only consider script aggregation for types whitelisted in should_aggregate-function
|
105 |
if( !$this->should_aggregate($tag) ) {
|
106 |
$tag='';
|
107 |
continue;
|
108 |
}
|
109 |
+
|
110 |
+
if (preg_match('#<script[^>]*src=("|\')([^>]*)("|\')#Usmi',$tag,$source)) {
|
111 |
+
// non-inline script
|
112 |
if ($this->isremovable($tag,$this->jsremovables)) {
|
113 |
$this->content = str_replace($tag,'',$this->content);
|
114 |
continue;
|
115 |
}
|
116 |
+
$explUrl = explode('?',$source[2],2);
|
117 |
+
$url = $explUrl[0];
|
|
|
118 |
$path = $this->getpath($url);
|
119 |
+
if($path !== false && preg_match('#\.js$#',$path) && $this->ismergeable($tag)) {
|
120 |
+
// ok to optimize, add to array
|
121 |
+
$this->scripts[] = $path;
|
122 |
+
} else {
|
123 |
+
$origTag = $tag;
|
124 |
+
$newTag = $tag;
|
125 |
+
|
126 |
+
// non-mergeable script (excluded or dynamic or external)
|
127 |
+
if (is_array($excludeJS)) {
|
128 |
+
// should we add flags?
|
129 |
+
foreach ($excludeJS as $exclTag => $exclFlags) {
|
130 |
+
if ( strpos($origTag,$exclTag)!==false && in_array($exclFlags,array("async","defer")) ) {
|
131 |
+
$newTag = str_replace('<script ','<script '.$exclFlags.' ',$newTag);
|
132 |
}
|
|
|
|
|
|
|
133 |
}
|
134 |
}
|
135 |
+
|
136 |
+
// should we minify the non-aggregated script?
|
137 |
+
if ($path && apply_filters('autoptimize_filter_js_minify_excluded',false)) {
|
138 |
+
$_CachedMinifiedUrl = $this->minify_single($path);
|
139 |
+
|
140 |
+
// replace orig URL with minified URL from cache if so
|
141 |
+
if (!empty($_CachedMinifiedUrl)) {
|
142 |
+
$newTag = str_replace($url, $_CachedMinifiedUrl, $newTag);
|
143 |
+
}
|
144 |
+
|
145 |
+
// remove querystring from URL in newTag
|
146 |
+
if ( !empty($explUrl[1]) ) {
|
147 |
+
$newTag = str_replace("?".$explUrl[1],"",$newTag);
|
148 |
+
}
|
149 |
+
}
|
150 |
+
|
151 |
+
// should we move the non-aggregated script?
|
152 |
+
if( $this->ismovable($newTag) ) {
|
153 |
+
// can be moved, flags and all
|
154 |
+
if( $this->movetolast($newTag) ) {
|
155 |
+
$this->move['last'][] = $newTag;
|
156 |
} else {
|
157 |
+
$this->move['first'][] = $newTag;
|
158 |
}
|
159 |
} else {
|
160 |
+
// cannot be moved, so if flag was added re-inject altered tag immediately
|
161 |
+
if ( $origTag !== $newTag ) {
|
162 |
+
$this->content = str_replace($origTag,$newTag,$this->content);
|
163 |
+
$origTag = '';
|
164 |
+
}
|
165 |
+
// and forget about the $tag (not to be touched any more)
|
166 |
$tag = '';
|
167 |
}
|
168 |
}
|
182 |
$this->scripts[] = 'INLINE;'.$code;
|
183 |
} else {
|
184 |
// Can we move this?
|
185 |
+
$autoptimize_js_moveable = apply_filters( 'autoptimize_js_moveable', '', $tag );
|
186 |
+
if( $this->ismovable($tag) || $autoptimize_js_moveable !== '' ) {
|
187 |
+
if( $this->movetolast($tag) || $autoptimize_js_moveable === 'last' ) {
|
188 |
$this->move['last'][] = $tag;
|
189 |
} else {
|
190 |
$this->move['first'][] = $tag;
|
220 |
if($this->trycatch) {
|
221 |
$script = 'try{'.$script.'}catch(e){}';
|
222 |
}
|
223 |
+
$tmpscript = apply_filters( 'autoptimize_js_individual_script', $script, '' );
|
224 |
if ( has_filter('autoptimize_js_individual_script') && !empty($tmpscript) ) {
|
225 |
$script=$tmpscript;
|
226 |
$this->alreadyminified=true;
|
230 |
//External script
|
231 |
if($script !== false && file_exists($script) && is_readable($script)) {
|
232 |
$scriptsrc = file_get_contents($script);
|
233 |
+
$scripthash = md5($scriptsrc);
|
234 |
$scriptsrc = preg_replace('/\x{EF}\x{BB}\x{BF}/','',$scriptsrc);
|
235 |
$scriptsrc = rtrim($scriptsrc,";\n\t\r").';';
|
236 |
+
|
237 |
//Add try-catch?
|
238 |
if($this->trycatch) {
|
239 |
$scriptsrc = 'try{'.$scriptsrc.'}catch(e){}';
|
242 |
if ( has_filter('autoptimize_js_individual_script') && !empty($tmpscriptsrc) ) {
|
243 |
$scriptsrc=$tmpscriptsrc;
|
244 |
$this->alreadyminified=true;
|
245 |
+
} else if ($this->can_inject_late($script)) {
|
246 |
+
$scriptsrc="/*!%%INJECTLATER".AUTOPTIMIZE_HASH."%%".base64_encode($script)."|".$scripthash."%%INJECTLATER%%*/";
|
247 |
}
|
248 |
$this->jscode .= "\n".$scriptsrc;
|
249 |
}/*else{
|
279 |
}
|
280 |
} else {
|
281 |
$this->jscode = $this->inject_minified($this->jscode);
|
282 |
+
return false;
|
283 |
}
|
284 |
}
|
285 |
+
$this->jscode = apply_filters( 'autoptimize_js_after_minify', $this->jscode );
|
286 |
return true;
|
287 |
}
|
288 |
|
343 |
|
344 |
// Checks against the white- and blacklists
|
345 |
private function ismergeable($tag) {
|
346 |
+
if (apply_filters('autoptimize_filter_js_dontaggregate',false)) {
|
347 |
+
return false;
|
348 |
+
} else if (!empty($this->whitelist)) {
|
349 |
foreach ($this->whitelist as $match) {
|
350 |
if(strpos($tag,$match)!==false) {
|
351 |
return true;
|
442 |
return false;
|
443 |
}
|
444 |
}
|
445 |
+
|
446 |
+
/**
|
447 |
+
* Determines wheter a <script> $tag can be excluded from minification (as already minified) based on:
|
448 |
+
* - inject_min_late being active
|
449 |
+
* - filename ending in `min.js`
|
450 |
+
* - filename matching `js/jquery/jquery.js` (wordpress core jquery, is minified)
|
451 |
+
* - filename matching one passed in the consider minified filter
|
452 |
+
*
|
453 |
+
* @param string $jsPath
|
454 |
+
* @return bool
|
455 |
+
*/
|
456 |
+
private function can_inject_late($jsPath) {
|
457 |
+
$consider_minified_array = apply_filters('autoptimize_filter_js_consider_minified',false);
|
458 |
+
if ( $this->inject_min_late !== true ) {
|
459 |
+
// late-inject turned off
|
460 |
+
return false;
|
461 |
+
} else if ( (strpos($jsPath,"min.js") === false) && ( strpos($jsPath,"wp-includes/js/jquery/jquery.js") === false ) && ( str_replace($consider_minified_array, '', $jsPath) === $jsPath ) ) {
|
462 |
+
// file not minified based on filename & filter
|
463 |
+
return false;
|
464 |
+
} else {
|
465 |
+
// phew, all is safe, we can late-inject
|
466 |
+
return true;
|
467 |
+
}
|
468 |
+
}
|
469 |
}
|
classes/autoptimizeStyles.php
CHANGED
@@ -2,11 +2,13 @@
|
|
2 |
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
3 |
|
4 |
class autoptimizeStyles extends autoptimizeBase {
|
|
|
|
|
|
|
5 |
private $css = array();
|
6 |
private $csscode = array();
|
7 |
private $url = array();
|
8 |
private $restofcontent = '';
|
9 |
-
private $mhtml = '';
|
10 |
private $datauris = false;
|
11 |
private $hashmap = array();
|
12 |
private $alreadyminified = false;
|
@@ -24,7 +26,7 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
24 |
$noptimizeCSS = apply_filters( 'autoptimize_filter_css_noptimize', false, $this->content );
|
25 |
if ($noptimizeCSS) return false;
|
26 |
|
27 |
-
$whitelistCSS = apply_filters( 'autoptimize_filter_css_whitelist', '' );
|
28 |
if (!empty($whitelistCSS)) {
|
29 |
$this->whitelist = array_filter(array_map('trim',explode(",",$whitelistCSS)));
|
30 |
}
|
@@ -58,27 +60,30 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
58 |
|
59 |
// what CSS shouldn't be autoptimized
|
60 |
$excludeCSS = $options['css_exclude'];
|
61 |
-
$excludeCSS = apply_filters( 'autoptimize_filter_css_exclude', $excludeCSS );
|
62 |
if ($excludeCSS!=="") {
|
63 |
$this->dontmove = array_filter(array_map('trim',explode(",",$excludeCSS)));
|
64 |
} else {
|
65 |
-
$this->dontmove =
|
66 |
}
|
|
|
|
|
|
|
67 |
|
68 |
// should we defer css?
|
69 |
// value: true/ false
|
70 |
$this->defer = $options['defer'];
|
71 |
-
$this->defer = apply_filters( 'autoptimize_filter_css_defer', $this->defer );
|
72 |
|
73 |
// should we inline while deferring?
|
74 |
// value: inlined CSS
|
75 |
$this->defer_inline = $options['defer_inline'];
|
76 |
-
$this->defer_inline = apply_filters( 'autoptimize_filter_css_defer_inline', $this->defer_inline );
|
77 |
|
78 |
// should we inline?
|
79 |
// value: true/ false
|
80 |
$this->inline = $options['inline'];
|
81 |
-
$this->inline = apply_filters( 'autoptimize_filter_css_inline', $this->inline );
|
82 |
|
83 |
// get cdn url
|
84 |
$this->cdn_url = $options['cdn_url'];
|
@@ -130,7 +135,8 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
130 |
|
131 |
if(preg_match('#<link.*href=("|\')(.*)("|\')#Usmi',$tag,$source)) {
|
132 |
// <link>
|
133 |
-
$
|
|
|
134 |
$path = $this->getpath($url);
|
135 |
|
136 |
if($path!==false && preg_match('#\.css$#',$path)) {
|
@@ -158,7 +164,33 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
158 |
|
159 |
// Remove the original style tag
|
160 |
$this->content = str_replace($tag,'',$this->content);
|
161 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
}
|
163 |
return true;
|
164 |
}
|
@@ -183,14 +215,16 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
183 |
//<link>
|
184 |
if($css !== false && file_exists($css) && is_readable($css)) {
|
185 |
$cssPath = $css;
|
186 |
-
$
|
|
|
|
|
187 |
$css = preg_replace('/\x{EF}\x{BB}\x{BF}/','',$css);
|
188 |
$tmpstyle = apply_filters( 'autoptimize_css_individual_style', $css, $cssPath );
|
189 |
if (has_filter('autoptimize_css_individual_style') && !empty($tmpstyle)) {
|
190 |
$css=$tmpstyle;
|
191 |
$this->alreadyminified=true;
|
192 |
} else if ($this->can_inject_late($cssPath,$css)) {
|
193 |
-
$css="
|
194 |
}
|
195 |
} else {
|
196 |
// Couldn't read CSS. Maybe getpath isn't working?
|
@@ -233,7 +267,8 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
233 |
$external_imports = "";
|
234 |
|
235 |
// remove comments to avoid importing commented-out imports
|
236 |
-
$thiscss_nocomments=preg_replace('#/\*.*\*/#
|
|
|
237 |
while(preg_match_all('#@import.*(?:;|$)#Um',$thiscss_nocomments,$matches)) {
|
238 |
foreach($matches[0] as $import) {
|
239 |
if ($this->isremovable($import,$this->cssremovables)) {
|
@@ -251,7 +286,7 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
251 |
$code=$tmpstyle;
|
252 |
$this->alreadyminified=true;
|
253 |
} else if ($this->can_inject_late($path,$code)) {
|
254 |
-
$code="
|
255 |
}
|
256 |
|
257 |
if(!empty($code)) {
|
@@ -277,7 +312,7 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
277 |
$thiscss = preg_replace('#/\*FILESTART2\*/#','/*FILESTART*/',$thiscss);
|
278 |
|
279 |
// and update $thiscss_nocomments before going into next iteration in while loop
|
280 |
-
$thiscss_nocomments=preg_replace('#/\*.*\*/#
|
281 |
}
|
282 |
unset($thiscss_nocomments);
|
283 |
|
@@ -289,7 +324,6 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
289 |
unset($thiscss);
|
290 |
|
291 |
// $this->csscode has all the uncompressed code now.
|
292 |
-
$mhtmlcount = 0;
|
293 |
foreach($this->csscode as &$code) {
|
294 |
// Check for already-minified code
|
295 |
$hash = md5($code);
|
@@ -303,10 +337,10 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
303 |
|
304 |
// Do the imaging!
|
305 |
$imgreplace = array();
|
306 |
-
preg_match_all(
|
307 |
-
|
308 |
-
if(($this->datauris == true) && (function_exists('base64_encode')) && (is_array($matches)))
|
309 |
-
foreach($matches[
|
310 |
$iurl = trim($quotedurl," \t\n\r\0\x0B\"'");
|
311 |
|
312 |
// if querystring, remove it from url
|
@@ -370,26 +404,18 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
370 |
unset($icheck);
|
371 |
|
372 |
// Add it to the list for replacement
|
373 |
-
$imgreplace[$matches[
|
374 |
-
|
375 |
-
// Store image on the mhtml document
|
376 |
-
$this->mhtml .= "--_\r\nContent-Location:{$mhtmlcount}\r\nContent-Transfer-Encoding:base64\r\n\r\n{$base64data}\r\n";
|
377 |
-
$mhtmlcount++;
|
378 |
} else {
|
379 |
// just cdn the URL if applicable
|
380 |
if (!empty($this->cdn_url)) {
|
381 |
-
$
|
382 |
-
|
383 |
-
$imgreplace[$matches[1][$count]] = str_replace($quotedurl,$cdn_url,$matches[1][$count]);
|
384 |
-
}
|
385 |
}
|
386 |
}
|
387 |
} else if ((is_array($matches)) && (!empty($this->cdn_url))) {
|
388 |
-
// change
|
389 |
-
foreach($matches[
|
390 |
-
$
|
391 |
-
$cdn_url=$this->url_replace_cdn($url);
|
392 |
-
$imgreplace[$matches[1][$count]] = str_replace($quotedurl,$cdn_url,$matches[1][$count]);
|
393 |
}
|
394 |
}
|
395 |
|
@@ -397,24 +423,6 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
397 |
$code = str_replace(array_keys($imgreplace),array_values($imgreplace),$code);
|
398 |
}
|
399 |
|
400 |
-
// CDN the fonts!
|
401 |
-
if ( (!empty($this->cdn_url)) && (apply_filters('autoptimize_filter_css_fonts_cdn',false)) && (version_compare(PHP_VERSION, '5.3.0') >= 0) ) {
|
402 |
-
$fontreplace = array();
|
403 |
-
include_once(AUTOPTIMIZE_PLUGIN_DIR.'classlesses/autoptimizeFontRegex.php');
|
404 |
-
|
405 |
-
preg_match_all($fonturl_regex,$code,$matches);
|
406 |
-
if (is_array($matches)) {
|
407 |
-
foreach($matches[8] as $count => $quotedurl) {
|
408 |
-
$url = trim($quotedurl," \t\n\r\0\x0B\"'");
|
409 |
-
$cdn_url=$this->url_replace_cdn($url);
|
410 |
-
$fontreplace[$matches[8][$count]] = str_replace($quotedurl,$cdn_url,$matches[8][$count]);
|
411 |
-
}
|
412 |
-
if(!empty($fontreplace)) {
|
413 |
-
$code = str_replace(array_keys($fontreplace),array_values($fontreplace),$code);
|
414 |
-
}
|
415 |
-
}
|
416 |
-
}
|
417 |
-
|
418 |
// Minify
|
419 |
if (($this->alreadyminified!==true) && (apply_filters( "autoptimize_css_do_minify", true))) {
|
420 |
if (class_exists('Minify_CSS_Compressor')) {
|
@@ -435,7 +443,7 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
435 |
|
436 |
$code = $this->inject_minified($code);
|
437 |
|
438 |
-
$tmp_code = apply_filters( 'autoptimize_css_after_minify'
|
439 |
if (!empty($tmp_code)) {
|
440 |
$code = $tmp_code;
|
441 |
unset($tmp_code);
|
@@ -449,26 +457,9 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
449 |
|
450 |
//Caches the CSS in uncompressed, deflated and gzipped form.
|
451 |
public function cache() {
|
452 |
-
if($this->datauris) {
|
453 |
-
// MHTML Preparation
|
454 |
-
$this->mhtml = "/*\r\nContent-Type: multipart/related; boundary=\"_\"\r\n\r\n".$this->mhtml."*/\r\n";
|
455 |
-
$md5 = md5($this->mhtml);
|
456 |
-
$cache = new autoptimizeCache($md5,'txt');
|
457 |
-
if(!$cache->check()) {
|
458 |
-
// Cache our images for IE
|
459 |
-
$cache->cache($this->mhtml,'text/plain');
|
460 |
-
}
|
461 |
-
$mhtml = AUTOPTIMIZE_CACHE_URL.$cache->getname();
|
462 |
-
}
|
463 |
-
|
464 |
// CSS cache
|
465 |
foreach($this->csscode as $media => $code) {
|
466 |
$md5 = $this->hashmap[md5($code)];
|
467 |
-
|
468 |
-
if($this->datauris) {
|
469 |
-
// Images for ie! Get the right url
|
470 |
-
$code = str_replace('%%MHTML%%',$mhtml,$code);
|
471 |
-
}
|
472 |
|
473 |
$cache = new autoptimizeCache($md5,'css');
|
474 |
if(!$cache->check()) {
|
@@ -510,7 +501,7 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
510 |
|
511 |
// Inject the new stylesheets
|
512 |
$replaceTag = array("<title","before");
|
513 |
-
$replaceTag = apply_filters( 'autoptimize_filter_css_replacetag', $replaceTag );
|
514 |
|
515 |
if ($this->inline == true) {
|
516 |
foreach($this->csscode as $media => $code) {
|
@@ -518,12 +509,12 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
518 |
}
|
519 |
} else {
|
520 |
if ($this->defer == true) {
|
521 |
-
$
|
522 |
$noScriptCssBlock = "<noscript id=\"aonoscrcss\">";
|
523 |
$defer_inline_code=$this->defer_inline;
|
524 |
if(!empty($defer_inline_code)){
|
525 |
-
if ( apply_filters( 'autoptimize_filter_css_critcss_minify',true ) ) {
|
526 |
-
$iCssHash=md5($defer_inline_code);
|
527 |
$iCssCache = new autoptimizeCache($iCssHash,'css');
|
528 |
if($iCssCache->check()) {
|
529 |
// we have the optimized inline CSS in cache
|
@@ -552,7 +543,7 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
552 |
|
553 |
//Add the stylesheet either deferred (import at bottom) or normal links in head
|
554 |
if($this->defer == true) {
|
555 |
-
$
|
556 |
$noScriptCssBlock .= '<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" />';
|
557 |
} else {
|
558 |
if (strlen($this->csscode[$media]) > $this->cssinlinesize) {
|
@@ -564,10 +555,13 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
564 |
}
|
565 |
|
566 |
if($this->defer == true) {
|
567 |
-
$
|
|
|
|
|
|
|
568 |
$noScriptCssBlock .= "</noscript>";
|
569 |
-
$this->inject_in_html($noScriptCssBlock,$replaceTag);
|
570 |
-
$this->inject_in_html($
|
571 |
}
|
572 |
}
|
573 |
|
@@ -575,50 +569,74 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
575 |
return $this->content;
|
576 |
}
|
577 |
|
578 |
-
static function fixurls($file
|
579 |
-
|
580 |
-
$
|
581 |
|
582 |
-
|
583 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
584 |
|
585 |
-
if(preg_match_all('#url\((?!data)(?!\#)(?!"\#)(.*)\)#Usi',$code,$matches)) {
|
586 |
$replace = array();
|
587 |
-
foreach($matches[1] as $k => $url) {
|
588 |
// Remove quotes
|
589 |
-
$url
|
590 |
-
$noQurl = trim($url,"\"'");
|
591 |
-
if ($url
|
592 |
-
$removedQuotes=true;
|
593 |
} else {
|
594 |
-
$removedQuotes=false;
|
|
|
|
|
|
|
|
|
595 |
}
|
596 |
-
|
597 |
-
|
598 |
-
|
|
|
599 |
continue;
|
600 |
} else {
|
601 |
-
//
|
602 |
-
$newurl = preg_replace('/https?:/','',str_replace(
|
603 |
|
604 |
-
|
605 |
-
|
|
|
|
|
|
|
606 |
|
607 |
-
if (
|
608 |
-
$replace[$hash] =
|
609 |
} else {
|
610 |
-
$replace[$hash] = 'url('
|
611 |
}
|
612 |
}
|
613 |
-
}
|
614 |
-
|
615 |
-
|
616 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
617 |
return $code;
|
618 |
}
|
619 |
|
620 |
private function ismovable($tag) {
|
621 |
-
|
|
|
|
|
622 |
foreach ($this->whitelist as $match) {
|
623 |
if(strpos($tag,$match)!==false) {
|
624 |
return true;
|
@@ -642,10 +660,14 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
642 |
}
|
643 |
|
644 |
private function can_inject_late($cssPath,$css) {
|
645 |
-
|
646 |
-
|
|
|
647 |
return false;
|
648 |
-
} else if (strpos($
|
|
|
|
|
|
|
649 |
// can't late-inject files with imports as those need to be aggregated
|
650 |
return false;
|
651 |
} else if ( (strpos($css,"@font-face")!==false ) && ( apply_filters("autoptimize_filter_css_fonts_cdn",false)===true) && (!empty($this->cdn_url)) ) {
|
@@ -659,4 +681,18 @@ class autoptimizeStyles extends autoptimizeBase {
|
|
659 |
return true;
|
660 |
}
|
661 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
662 |
}
|
2 |
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
3 |
|
4 |
class autoptimizeStyles extends autoptimizeBase {
|
5 |
+
|
6 |
+
const ASSETS_REGEX = '/url\s*\(\s*(?!["\']?data:)(?![\'|\"]?[\#|\%|])([^)]+)\s*\)([^;},\s]*)/i';
|
7 |
+
|
8 |
private $css = array();
|
9 |
private $csscode = array();
|
10 |
private $url = array();
|
11 |
private $restofcontent = '';
|
|
|
12 |
private $datauris = false;
|
13 |
private $hashmap = array();
|
14 |
private $alreadyminified = false;
|
26 |
$noptimizeCSS = apply_filters( 'autoptimize_filter_css_noptimize', false, $this->content );
|
27 |
if ($noptimizeCSS) return false;
|
28 |
|
29 |
+
$whitelistCSS = apply_filters( 'autoptimize_filter_css_whitelist', '', $this->content );
|
30 |
if (!empty($whitelistCSS)) {
|
31 |
$this->whitelist = array_filter(array_map('trim',explode(",",$whitelistCSS)));
|
32 |
}
|
60 |
|
61 |
// what CSS shouldn't be autoptimized
|
62 |
$excludeCSS = $options['css_exclude'];
|
63 |
+
$excludeCSS = apply_filters( 'autoptimize_filter_css_exclude', $excludeCSS, $this->content );
|
64 |
if ($excludeCSS!=="") {
|
65 |
$this->dontmove = array_filter(array_map('trim',explode(",",$excludeCSS)));
|
66 |
} else {
|
67 |
+
$this->dontmove = array();
|
68 |
}
|
69 |
+
|
70 |
+
// forcefully exclude CSS with data-noptimize attrib
|
71 |
+
$this->dontmove[]="data-noptimize";
|
72 |
|
73 |
// should we defer css?
|
74 |
// value: true/ false
|
75 |
$this->defer = $options['defer'];
|
76 |
+
$this->defer = apply_filters( 'autoptimize_filter_css_defer', $this->defer, $this->content );
|
77 |
|
78 |
// should we inline while deferring?
|
79 |
// value: inlined CSS
|
80 |
$this->defer_inline = $options['defer_inline'];
|
81 |
+
$this->defer_inline = apply_filters( 'autoptimize_filter_css_defer_inline', $this->defer_inline, $this->content );
|
82 |
|
83 |
// should we inline?
|
84 |
// value: true/ false
|
85 |
$this->inline = $options['inline'];
|
86 |
+
$this->inline = apply_filters( 'autoptimize_filter_css_inline', $this->inline, $this->content );
|
87 |
|
88 |
// get cdn url
|
89 |
$this->cdn_url = $options['cdn_url'];
|
135 |
|
136 |
if(preg_match('#<link.*href=("|\')(.*)("|\')#Usmi',$tag,$source)) {
|
137 |
// <link>
|
138 |
+
$explUrl = explode('?',$source[2],2);
|
139 |
+
$url = $explUrl[0];
|
140 |
$path = $this->getpath($url);
|
141 |
|
142 |
if($path!==false && preg_match('#\.css$#',$path)) {
|
164 |
|
165 |
// Remove the original style tag
|
166 |
$this->content = str_replace($tag,'',$this->content);
|
167 |
+
} else {
|
168 |
+
// excluded CSS, minify if getpath
|
169 |
+
if (preg_match('#<link.*href=("|\')(.*)("|\')#Usmi',$tag,$source)) {
|
170 |
+
$explUrl = explode('?',$source[2],2);
|
171 |
+
$url = $explUrl[0];
|
172 |
+
$path = $this->getpath($url);
|
173 |
+
|
174 |
+
if ($path && apply_filters('autoptimize_filter_css_minify_excluded',false)) {
|
175 |
+
$_CachedMinifiedUrl = $this->minify_single($path);
|
176 |
+
|
177 |
+
if (!empty($_CachedMinifiedUrl)) {
|
178 |
+
// replace orig URL with URL to cache
|
179 |
+
$newTag = str_replace($url, $_CachedMinifiedUrl, $tag);
|
180 |
+
} else {
|
181 |
+
$newTag = $tag;
|
182 |
+
}
|
183 |
+
|
184 |
+
// remove querystring from URL
|
185 |
+
if ( !empty($explUrl[1]) ) {
|
186 |
+
$newTag = str_replace("?".$explUrl[1],"",$newTag);
|
187 |
+
}
|
188 |
+
|
189 |
+
// and replace
|
190 |
+
$this->content = str_replace($tag,$newTag,$this->content);
|
191 |
+
}
|
192 |
+
}
|
193 |
+
}
|
194 |
}
|
195 |
return true;
|
196 |
}
|
215 |
//<link>
|
216 |
if($css !== false && file_exists($css) && is_readable($css)) {
|
217 |
$cssPath = $css;
|
218 |
+
$cssContents = file_get_contents($cssPath);
|
219 |
+
$cssHash = md5($cssContents);
|
220 |
+
$css = $this->fixurls($cssPath,$cssContents);
|
221 |
$css = preg_replace('/\x{EF}\x{BB}\x{BF}/','',$css);
|
222 |
$tmpstyle = apply_filters( 'autoptimize_css_individual_style', $css, $cssPath );
|
223 |
if (has_filter('autoptimize_css_individual_style') && !empty($tmpstyle)) {
|
224 |
$css=$tmpstyle;
|
225 |
$this->alreadyminified=true;
|
226 |
} else if ($this->can_inject_late($cssPath,$css)) {
|
227 |
+
$css="/*!%%INJECTLATER%%".base64_encode($cssPath)."|".$cssHash."%%INJECTLATER%%*/";
|
228 |
}
|
229 |
} else {
|
230 |
// Couldn't read CSS. Maybe getpath isn't working?
|
267 |
$external_imports = "";
|
268 |
|
269 |
// remove comments to avoid importing commented-out imports
|
270 |
+
$thiscss_nocomments = preg_replace('#/\*.*\*/#Us','',$thiscss);
|
271 |
+
|
272 |
while(preg_match_all('#@import.*(?:;|$)#Um',$thiscss_nocomments,$matches)) {
|
273 |
foreach($matches[0] as $import) {
|
274 |
if ($this->isremovable($import,$this->cssremovables)) {
|
286 |
$code=$tmpstyle;
|
287 |
$this->alreadyminified=true;
|
288 |
} else if ($this->can_inject_late($path,$code)) {
|
289 |
+
$code="/*!%%INJECTLATER".AUTOPTIMIZE_HASH."%%".base64_encode($path)."|".md5($code)."%%INJECTLATER%%*/";
|
290 |
}
|
291 |
|
292 |
if(!empty($code)) {
|
312 |
$thiscss = preg_replace('#/\*FILESTART2\*/#','/*FILESTART*/',$thiscss);
|
313 |
|
314 |
// and update $thiscss_nocomments before going into next iteration in while loop
|
315 |
+
$thiscss_nocomments=preg_replace('#/\*.*\*/#Us','',$thiscss);
|
316 |
}
|
317 |
unset($thiscss_nocomments);
|
318 |
|
324 |
unset($thiscss);
|
325 |
|
326 |
// $this->csscode has all the uncompressed code now.
|
|
|
327 |
foreach($this->csscode as &$code) {
|
328 |
// Check for already-minified code
|
329 |
$hash = md5($code);
|
337 |
|
338 |
// Do the imaging!
|
339 |
$imgreplace = array();
|
340 |
+
preg_match_all( self::ASSETS_REGEX, $code, $matches );
|
341 |
+
|
342 |
+
if ( ($this->datauris == true) && (function_exists('base64_encode')) && (is_array($matches)) ) {
|
343 |
+
foreach($matches[1] as $count => $quotedurl) {
|
344 |
$iurl = trim($quotedurl," \t\n\r\0\x0B\"'");
|
345 |
|
346 |
// if querystring, remove it from url
|
404 |
unset($icheck);
|
405 |
|
406 |
// Add it to the list for replacement
|
407 |
+
$imgreplace[$matches[0][$count]] = str_replace($quotedurl,$headAndData,$matches[0][$count]);
|
|
|
|
|
|
|
|
|
408 |
} else {
|
409 |
// just cdn the URL if applicable
|
410 |
if (!empty($this->cdn_url)) {
|
411 |
+
$imgreplace[$matches[0][$count]] = str_replace($quotedurl,$this->maybe_cdn_urls($quotedurl),$matches[0][$count]);
|
412 |
+
}
|
|
|
|
|
413 |
}
|
414 |
}
|
415 |
} else if ((is_array($matches)) && (!empty($this->cdn_url))) {
|
416 |
+
// change urls to cdn-url
|
417 |
+
foreach($matches[1] as $count => $quotedurl) {
|
418 |
+
$imgreplace[$matches[0][$count]] = str_replace($quotedurl,$this->maybe_cdn_urls($quotedurl),$matches[0][$count]);
|
|
|
|
|
419 |
}
|
420 |
}
|
421 |
|
423 |
$code = str_replace(array_keys($imgreplace),array_values($imgreplace),$code);
|
424 |
}
|
425 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
426 |
// Minify
|
427 |
if (($this->alreadyminified!==true) && (apply_filters( "autoptimize_css_do_minify", true))) {
|
428 |
if (class_exists('Minify_CSS_Compressor')) {
|
443 |
|
444 |
$code = $this->inject_minified($code);
|
445 |
|
446 |
+
$tmp_code = apply_filters( 'autoptimize_css_after_minify', $code );
|
447 |
if (!empty($tmp_code)) {
|
448 |
$code = $tmp_code;
|
449 |
unset($tmp_code);
|
457 |
|
458 |
//Caches the CSS in uncompressed, deflated and gzipped form.
|
459 |
public function cache() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
460 |
// CSS cache
|
461 |
foreach($this->csscode as $media => $code) {
|
462 |
$md5 = $this->hashmap[md5($code)];
|
|
|
|
|
|
|
|
|
|
|
463 |
|
464 |
$cache = new autoptimizeCache($md5,'css');
|
465 |
if(!$cache->check()) {
|
501 |
|
502 |
// Inject the new stylesheets
|
503 |
$replaceTag = array("<title","before");
|
504 |
+
$replaceTag = apply_filters( 'autoptimize_filter_css_replacetag', $replaceTag, $this->content );
|
505 |
|
506 |
if ($this->inline == true) {
|
507 |
foreach($this->csscode as $media => $code) {
|
509 |
}
|
510 |
} else {
|
511 |
if ($this->defer == true) {
|
512 |
+
$preloadCssBlock = "";
|
513 |
$noScriptCssBlock = "<noscript id=\"aonoscrcss\">";
|
514 |
$defer_inline_code=$this->defer_inline;
|
515 |
if(!empty($defer_inline_code)){
|
516 |
+
if ( apply_filters( 'autoptimize_filter_css_critcss_minify', true ) ) {
|
517 |
+
$iCssHash = md5($defer_inline_code);
|
518 |
$iCssCache = new autoptimizeCache($iCssHash,'css');
|
519 |
if($iCssCache->check()) {
|
520 |
// we have the optimized inline CSS in cache
|
543 |
|
544 |
//Add the stylesheet either deferred (import at bottom) or normal links in head
|
545 |
if($this->defer == true) {
|
546 |
+
$preloadCssBlock .= '<link rel="preload" as="style" media="'.$media.'" href="'.$url.'" onload="this.rel=\'stylesheet\'" />';
|
547 |
$noScriptCssBlock .= '<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" />';
|
548 |
} else {
|
549 |
if (strlen($this->csscode[$media]) > $this->cssinlinesize) {
|
555 |
}
|
556 |
|
557 |
if($this->defer == true) {
|
558 |
+
$preloadPolyfill = '<script data-cfasync=\'false\'>/*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
|
559 |
+
!function(a){"use strict";var b=function(b,c,d){function e(a){return h.body?a():void setTimeout(function(){e(a)})}function f(){i.addEventListener&&i.removeEventListener("load",f),i.media=d||"all"}var g,h=a.document,i=h.createElement("link");if(c)g=c;else{var j=(h.body||h.getElementsByTagName("head")[0]).childNodes;g=j[j.length-1]}var k=h.styleSheets;i.rel="stylesheet",i.href=b,i.media="only x",e(function(){g.parentNode.insertBefore(i,c?g:g.nextSibling)});var l=function(a){for(var b=i.href,c=k.length;c--;)if(k[c].href===b)return a();setTimeout(function(){l(a)})};return i.addEventListener&&i.addEventListener("load",f),i.onloadcssdefined=l,l(f),i};"undefined"!=typeof exports?exports.loadCSS=b:a.loadCSS=b}("undefined"!=typeof global?global:this);
|
560 |
+
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */
|
561 |
+
!function(a){if(a.loadCSS){var b=loadCSS.relpreload={};if(b.support=function(){try{return a.document.createElement("link").relList.supports("preload")}catch(b){return!1}},b.poly=function(){for(var b=a.document.getElementsByTagName("link"),c=0;c<b.length;c++){var d=b[c];"preload"===d.rel&&"style"===d.getAttribute("as")&&(a.loadCSS(d.href,d,d.getAttribute("media")),d.rel=null)}},!b.support()){b.poly();var c=a.setInterval(b.poly,300);a.addEventListener&&a.addEventListener("load",function(){b.poly(),a.clearInterval(c)}),a.attachEvent&&a.attachEvent("onload",function(){a.clearInterval(c)})}}}(this);</script>';
|
562 |
$noScriptCssBlock .= "</noscript>";
|
563 |
+
$this->inject_in_html($preloadCssBlock.$noScriptCssBlock,$replaceTag);
|
564 |
+
$this->inject_in_html($preloadPolyfill,array('</body>','before'));
|
565 |
}
|
566 |
}
|
567 |
|
569 |
return $this->content;
|
570 |
}
|
571 |
|
572 |
+
static function fixurls($file, $code) {
|
573 |
+
// Switch all imports to the url() syntax
|
574 |
+
$code = preg_replace( '#@import ("|\')(.+?)\.css.*("|\')#', '@import url("${2}.css")', $code );
|
575 |
|
576 |
+
if ( preg_match_all( self::ASSETS_REGEX, $code, $matches ) ) {
|
577 |
+
$file = str_replace( WP_ROOT_DIR, '/', $file );
|
578 |
+
$dir = dirname( $file ); // Like /themes/expound/css
|
579 |
+
|
580 |
+
// $dir should not contain backslashes, since it's used to replace
|
581 |
+
// urls, but it can contain them when running on Windows because
|
582 |
+
// fixurls() is sometimes called with `ABSPATH . 'index.php'`
|
583 |
+
$dir = str_replace( '\\', '/', $dir );
|
584 |
+
unset( $file ); // not used below at all
|
585 |
|
|
|
586 |
$replace = array();
|
587 |
+
foreach ( $matches[1] as $k => $url ) {
|
588 |
// Remove quotes
|
589 |
+
$url = trim( $url," \t\n\r\0\x0B\"'" );
|
590 |
+
$noQurl = trim( $url, "\"'" );
|
591 |
+
if ( $url !== $noQurl ) {
|
592 |
+
$removedQuotes = true;
|
593 |
} else {
|
594 |
+
$removedQuotes = false;
|
595 |
+
}
|
596 |
+
|
597 |
+
if ( '' === $noQurl ) {
|
598 |
+
continue;
|
599 |
}
|
600 |
+
|
601 |
+
$url = $noQurl;
|
602 |
+
if ( '/' === $url{0} || preg_match( '#^(https?://|ftp://|data:)#i', $url ) ) {
|
603 |
+
// URL is protocol-relative, host-relative or something we don't touch
|
604 |
continue;
|
605 |
} else {
|
606 |
+
// Relative URL
|
607 |
+
$newurl = preg_replace( '/https?:/', '', str_replace( ' ', '%20', AUTOPTIMIZE_WP_ROOT_URL . str_replace( '//', '/', $dir . '/' . $url ) ) );
|
608 |
|
609 |
+
// Hash the url + whatever was behind potentially for replacement
|
610 |
+
// We must do this, or different css classes referencing the same bg image (but
|
611 |
+
// different parts of it, say, in sprites and such) loose their stuff...
|
612 |
+
$hash = md5( $url . $matches[2][$k] );
|
613 |
+
$code = str_replace( $matches[0][$k], $hash, $code );
|
614 |
|
615 |
+
if ( $removedQuotes ) {
|
616 |
+
$replace[$hash] = "url('" . $newurl . "')" . $matches[2][$k];
|
617 |
} else {
|
618 |
+
$replace[$hash] = 'url(' . $newurl . ')' . $matches[2][$k];
|
619 |
}
|
620 |
}
|
621 |
+
}
|
622 |
+
|
623 |
+
if ( ! empty( $replace ) ) {
|
624 |
+
// Sort the replacements array by key length in desc order (so that the longest strings are replaced first)
|
625 |
+
$keys = array_map( 'strlen', array_keys( $replace ) );
|
626 |
+
array_multisort( $keys, SORT_DESC, $replace );
|
627 |
+
|
628 |
+
// Replace URLs found within $code
|
629 |
+
$code = str_replace( array_keys( $replace ), array_values( $replace ), $code );
|
630 |
+
}
|
631 |
+
}
|
632 |
+
|
633 |
return $code;
|
634 |
}
|
635 |
|
636 |
private function ismovable($tag) {
|
637 |
+
if ( apply_filters('autoptimize_filter_css_dontaggregate', false) ) {
|
638 |
+
return false;
|
639 |
+
} else if (!empty($this->whitelist)) {
|
640 |
foreach ($this->whitelist as $match) {
|
641 |
if(strpos($tag,$match)!==false) {
|
642 |
return true;
|
660 |
}
|
661 |
|
662 |
private function can_inject_late($cssPath,$css) {
|
663 |
+
$consider_minified_array = apply_filters('autoptimize_filter_css_consider_minified', false, $cssPath);
|
664 |
+
if ( $this->inject_min_late !== true ) {
|
665 |
+
// late-inject turned off
|
666 |
return false;
|
667 |
+
} else if ( (strpos($cssPath,"min.css") === false) && ( str_replace($consider_minified_array, '', $cssPath) === $cssPath ) ) {
|
668 |
+
// file not minified based on filename & filter
|
669 |
+
return false;
|
670 |
+
} else if ( strpos($css,"@import") !== false ) {
|
671 |
// can't late-inject files with imports as those need to be aggregated
|
672 |
return false;
|
673 |
} else if ( (strpos($css,"@font-face")!==false ) && ( apply_filters("autoptimize_filter_css_fonts_cdn",false)===true) && (!empty($this->cdn_url)) ) {
|
681 |
return true;
|
682 |
}
|
683 |
}
|
684 |
+
|
685 |
+
private function maybe_cdn_urls($inUrl) {
|
686 |
+
$url = trim($inUrl," \t\n\r\0\x0B\"'");
|
687 |
+
$urlPath = parse_url($url,PHP_URL_PATH);
|
688 |
+
|
689 |
+
// exclude fonts from CDN except if filter returns true
|
690 |
+
if ( !preg_match('#\.(woff2?|eot|ttf|otf)$#i',$urlPath) || apply_filters('autoptimize_filter_css_fonts_cdn',false) ) {
|
691 |
+
$cdn_url = $this->url_replace_cdn($url);
|
692 |
+
} else {
|
693 |
+
$cdn_url = $url;
|
694 |
+
}
|
695 |
+
|
696 |
+
return $cdn_url;
|
697 |
+
}
|
698 |
}
|
classes/autoptimizeToolbar.php
CHANGED
@@ -1,36 +1,36 @@
|
|
1 |
<?php
|
2 |
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
public function __construct()
|
7 |
{
|
8 |
// If Cache is not available we don't add the Autoptimize Toolbar
|
9 |
-
if( !autoptimizeCache::cacheavail() )
|
10 |
-
|
|
|
11 |
// Load admin toolbar feature once WordPress, all plugins, and the theme are fully loaded and instantiated.
|
12 |
add_action( 'wp_loaded', array( $this, 'load_toolbar' ) );
|
13 |
}
|
14 |
|
15 |
public function load_toolbar()
|
16 |
{
|
17 |
-
//
|
18 |
-
if( current_user_can( 'manage_options' ) && apply_filters( 'autoptimize_filter_toolbar_show', true ) )
|
19 |
-
{
|
20 |
-
// Load custom styles and scripts
|
21 |
-
if( is_admin() ) {
|
22 |
-
// in the case of back-end
|
23 |
-
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
|
24 |
-
} else {
|
25 |
-
// in the case of front-end
|
26 |
-
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
|
27 |
-
}
|
28 |
-
|
29 |
// Create a handler for the AJAX toolbar requests
|
30 |
add_action( 'wp_ajax_autoptimize_delete_cache', array( $this, 'delete_cache' ) );
|
31 |
|
32 |
-
//
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
}
|
35 |
}
|
36 |
|
@@ -42,7 +42,7 @@ class autoptimizeToolbar {
|
|
42 |
$stats = autoptimizeCache::stats();
|
43 |
|
44 |
// Set the Max Size recommended for cache files
|
45 |
-
$max_size = apply_filters('autoptimize_filter_cachecheck_maxsize', 512 * 1024 * 1024);
|
46 |
|
47 |
// Retrieve the current Total Files in cache
|
48 |
$files = $stats[0];
|
@@ -53,10 +53,11 @@ class autoptimizeToolbar {
|
|
53 |
|
54 |
// We calculated the percentage of cache used
|
55 |
$percentage = ceil( $bytes / $max_size * 100 );
|
56 |
-
if( $percentage > 100 )
|
57 |
-
|
|
|
58 |
// We define the type of color indicator for the current state of cache size.
|
59 |
-
// "green" if the size is less than 80% of the total recommended
|
60 |
// "orange" if over 80%
|
61 |
// "red" if over 100%
|
62 |
$color = ( $percentage == 100 ) ? 'red' : ( ( $percentage > 80 ) ? 'orange' : 'green' );
|
@@ -65,15 +66,15 @@ class autoptimizeToolbar {
|
|
65 |
// Main Autoptimize node
|
66 |
$wp_admin_bar->add_node( array(
|
67 |
'id' => 'autoptimize',
|
68 |
-
'title' => '<span class="ab-icon"></span><span class="ab-label">' . __("Autoptimize",'autoptimize') . '</span>',
|
69 |
'href' => admin_url( 'options-general.php?page=autoptimize' ),
|
70 |
'meta' => array( 'class' => 'bullet-' . $color )
|
71 |
));
|
72 |
|
73 |
// Cache Info node
|
74 |
$wp_admin_bar->add_node( array(
|
75 |
-
'id'
|
76 |
-
'title'
|
77 |
'<div class="autoptimize-radial-bar" percentage="' . $percentage . '">' .
|
78 |
'<div class="circle">'.
|
79 |
'<div class="mask full"><div class="fill bg-' . $color . '"></div></div>'.
|
@@ -86,42 +87,39 @@ class autoptimizeToolbar {
|
|
86 |
'<tr><td>' . __( "Size", 'autoptimize' ) . ':</td><td class="size ' . $color . '">' . $size . '</td></tr>' .
|
87 |
'<tr><td>' . __( "Files", 'autoptimize' ) . ':</td><td class="files white">' . $files . '</td></tr>' .
|
88 |
'</table>',
|
89 |
-
'parent'=> 'autoptimize'
|
90 |
));
|
91 |
-
|
92 |
// Delete Cache node
|
93 |
$wp_admin_bar->add_node( array(
|
94 |
-
'id'
|
95 |
-
'title'
|
96 |
-
'parent'=> 'autoptimize'
|
97 |
));
|
98 |
}
|
99 |
|
100 |
public function delete_cache()
|
101 |
{
|
102 |
check_ajax_referer( 'ao_delcache_nonce', 'nonce' );
|
103 |
-
|
|
|
104 |
{
|
105 |
// We call the function for cleaning the Autoptimize cache
|
106 |
-
autoptimizeCache::clearall();
|
107 |
}
|
108 |
-
|
109 |
-
wp_die();
|
110 |
-
// NOTE: Remember that any return values of this function must be in JSON format
|
111 |
}
|
112 |
|
113 |
public function enqueue_scripts()
|
114 |
{
|
115 |
// Autoptimize Toolbar Styles
|
116 |
-
wp_enqueue_style( 'autoptimize-toolbar', plugins_url('/static/toolbar.css', __FILE__ ), array(), time(),
|
117 |
-
|
118 |
// Autoptimize Toolbar Javascript
|
119 |
-
wp_enqueue_script( 'autoptimize-toolbar', plugins_url( '/static/toolbar.js', __FILE__ ), array('jquery'), time(), true );
|
120 |
-
|
121 |
// Localizes a registered script with data for a JavaScript variable. (We need this for the AJAX work properly in the front-end mode)
|
122 |
wp_localize_script( 'autoptimize-toolbar', 'autoptimize_ajax_object', array(
|
123 |
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
124 |
-
'error_msg' => __( 'Your Autoptimize cache might not have been purged successfully, please check on the <a href
|
125 |
'dismiss_msg' => __( 'Dismiss this notice.' ),
|
126 |
'nonce' => wp_create_nonce( 'ao_delcache_nonce' )
|
127 |
) );
|
1 |
<?php
|
2 |
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
3 |
+
class autoptimizeToolbar
|
4 |
+
{
|
|
|
5 |
public function __construct()
|
6 |
{
|
7 |
// If Cache is not available we don't add the Autoptimize Toolbar
|
8 |
+
if( ! autoptimizeCache::cacheavail() ) {
|
9 |
+
return;
|
10 |
+
}
|
11 |
// Load admin toolbar feature once WordPress, all plugins, and the theme are fully loaded and instantiated.
|
12 |
add_action( 'wp_loaded', array( $this, 'load_toolbar' ) );
|
13 |
}
|
14 |
|
15 |
public function load_toolbar()
|
16 |
{
|
17 |
+
// Check permissions and that toolbar is not hidden via filter
|
18 |
+
if ( current_user_can( 'manage_options' ) && apply_filters( 'autoptimize_filter_toolbar_show', true ) ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
// Create a handler for the AJAX toolbar requests
|
20 |
add_action( 'wp_ajax_autoptimize_delete_cache', array( $this, 'delete_cache' ) );
|
21 |
|
22 |
+
// Load custom styles, scripts and menu only when needed
|
23 |
+
if ( is_admin_bar_showing() ) {
|
24 |
+
if ( is_admin() ) {
|
25 |
+
// in the case of back-end
|
26 |
+
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
|
27 |
+
} else {
|
28 |
+
// in the case of front-end
|
29 |
+
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
|
30 |
+
}
|
31 |
+
// Add the Autoptimize Toolbar to the Admin bar
|
32 |
+
add_action( 'admin_bar_menu', array( $this, 'add_toolbar' ), 100 );
|
33 |
+
}
|
34 |
}
|
35 |
}
|
36 |
|
42 |
$stats = autoptimizeCache::stats();
|
43 |
|
44 |
// Set the Max Size recommended for cache files
|
45 |
+
$max_size = apply_filters( 'autoptimize_filter_cachecheck_maxsize', 512 * 1024 * 1024 );
|
46 |
|
47 |
// Retrieve the current Total Files in cache
|
48 |
$files = $stats[0];
|
53 |
|
54 |
// We calculated the percentage of cache used
|
55 |
$percentage = ceil( $bytes / $max_size * 100 );
|
56 |
+
if ( $percentage > 100 ) {
|
57 |
+
$percentage = 100;
|
58 |
+
}
|
59 |
// We define the type of color indicator for the current state of cache size.
|
60 |
+
// "green" if the size is less than 80% of the total recommended
|
61 |
// "orange" if over 80%
|
62 |
// "red" if over 100%
|
63 |
$color = ( $percentage == 100 ) ? 'red' : ( ( $percentage > 80 ) ? 'orange' : 'green' );
|
66 |
// Main Autoptimize node
|
67 |
$wp_admin_bar->add_node( array(
|
68 |
'id' => 'autoptimize',
|
69 |
+
'title' => '<span class="ab-icon"></span><span class="ab-label">' . __( "Autoptimize", 'autoptimize' ) . '</span>',
|
70 |
'href' => admin_url( 'options-general.php?page=autoptimize' ),
|
71 |
'meta' => array( 'class' => 'bullet-' . $color )
|
72 |
));
|
73 |
|
74 |
// Cache Info node
|
75 |
$wp_admin_bar->add_node( array(
|
76 |
+
'id' => 'autoptimize-cache-info',
|
77 |
+
'title' => '<p>' . __( "Cache Info", 'autoptimize' ) . '</p>' .
|
78 |
'<div class="autoptimize-radial-bar" percentage="' . $percentage . '">' .
|
79 |
'<div class="circle">'.
|
80 |
'<div class="mask full"><div class="fill bg-' . $color . '"></div></div>'.
|
87 |
'<tr><td>' . __( "Size", 'autoptimize' ) . ':</td><td class="size ' . $color . '">' . $size . '</td></tr>' .
|
88 |
'<tr><td>' . __( "Files", 'autoptimize' ) . ':</td><td class="files white">' . $files . '</td></tr>' .
|
89 |
'</table>',
|
90 |
+
'parent' => 'autoptimize'
|
91 |
));
|
92 |
+
|
93 |
// Delete Cache node
|
94 |
$wp_admin_bar->add_node( array(
|
95 |
+
'id' => 'autoptimize-delete-cache',
|
96 |
+
'title' => __( "Delete Cache", 'autoptimize' ),
|
97 |
+
'parent' => 'autoptimize'
|
98 |
));
|
99 |
}
|
100 |
|
101 |
public function delete_cache()
|
102 |
{
|
103 |
check_ajax_referer( 'ao_delcache_nonce', 'nonce' );
|
104 |
+
$result = false;
|
105 |
+
if ( current_user_can( 'manage_options' ) )
|
106 |
{
|
107 |
// We call the function for cleaning the Autoptimize cache
|
108 |
+
$result = autoptimizeCache::clearall();
|
109 |
}
|
110 |
+
wp_send_json( $result );
|
|
|
|
|
111 |
}
|
112 |
|
113 |
public function enqueue_scripts()
|
114 |
{
|
115 |
// Autoptimize Toolbar Styles
|
116 |
+
wp_enqueue_style( 'autoptimize-toolbar', plugins_url( '/static/toolbar.css', __FILE__ ), array(), time(), 'all' );
|
|
|
117 |
// Autoptimize Toolbar Javascript
|
118 |
+
wp_enqueue_script( 'autoptimize-toolbar', plugins_url( '/static/toolbar.js', __FILE__ ), array( 'jquery' ), time(), true );
|
|
|
119 |
// Localizes a registered script with data for a JavaScript variable. (We need this for the AJAX work properly in the front-end mode)
|
120 |
wp_localize_script( 'autoptimize-toolbar', 'autoptimize_ajax_object', array(
|
121 |
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
122 |
+
'error_msg' => sprintf( __( 'Your Autoptimize cache might not have been purged successfully, please check on the <a href=%s>Autoptimize settings page</a>.', 'autoptimize' ), admin_url( 'options-general.php?page=autoptimize' ) . ' style="white-space:nowrap;"' ),
|
123 |
'dismiss_msg' => __( 'Dismiss this notice.' ),
|
124 |
'nonce' => wp_create_nonce( 'ao_delcache_nonce' )
|
125 |
) );
|
classes/external/php/minify-html.php
CHANGED
@@ -257,7 +257,7 @@ class Minify_HTML {
|
|
257 |
protected function _removeCdata($str)
|
258 |
{
|
259 |
return (false !== strpos($str, '<![CDATA['))
|
260 |
-
? str_replace(array('/*<![CDATA[*/','/*]]>*/','<![CDATA[', ']]>'), '', $str)
|
261 |
: $str;
|
262 |
}
|
263 |
|
257 |
protected function _removeCdata($str)
|
258 |
{
|
259 |
return (false !== strpos($str, '<![CDATA['))
|
260 |
+
? str_replace(array('/* <![CDATA[ */','/* ]]> */','/*<![CDATA[*/','/*]]>*/','<![CDATA[', ']]>'), '', $str)
|
261 |
: $str;
|
262 |
}
|
263 |
|
classes/external/php/yui-php-cssmin-2.4.8-4.php
DELETED
@@ -1,777 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*!
|
4 |
-
* cssmin.php v2.4.8-4
|
5 |
-
* Author: Tubal Martin - http://tubalmartin.me/
|
6 |
-
* Repo: https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port
|
7 |
-
*
|
8 |
-
* This is a PHP port of the CSS minification tool distributed with YUICompressor,
|
9 |
-
* itself a port of the cssmin utility by Isaac Schlueter - http://foohack.com/
|
10 |
-
* Permission is hereby granted to use the PHP version under the same
|
11 |
-
* conditions as the YUICompressor.
|
12 |
-
*/
|
13 |
-
|
14 |
-
/*!
|
15 |
-
* YUI Compressor
|
16 |
-
* http://developer.yahoo.com/yui/compressor/
|
17 |
-
* Author: Julien Lecomte - http://www.julienlecomte.net/
|
18 |
-
* Copyright (c) 2013 Yahoo! Inc. All rights reserved.
|
19 |
-
* The copyrights embodied in the content of this file are licensed
|
20 |
-
* by Yahoo! Inc. under the BSD (revised) open source license.
|
21 |
-
*/
|
22 |
-
|
23 |
-
class CSSmin
|
24 |
-
{
|
25 |
-
const NL = '___YUICSSMIN_PRESERVED_NL___';
|
26 |
-
const TOKEN = '___YUICSSMIN_PRESERVED_TOKEN_';
|
27 |
-
const COMMENT = '___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_';
|
28 |
-
const CLASSCOLON = '___YUICSSMIN_PSEUDOCLASSCOLON___';
|
29 |
-
const QUERY_FRACTION = '___YUICSSMIN_QUERY_FRACTION___';
|
30 |
-
|
31 |
-
private $comments;
|
32 |
-
private $preserved_tokens;
|
33 |
-
private $memory_limit;
|
34 |
-
private $max_execution_time;
|
35 |
-
private $pcre_backtrack_limit;
|
36 |
-
private $pcre_recursion_limit;
|
37 |
-
private $raise_php_limits;
|
38 |
-
|
39 |
-
/**
|
40 |
-
* @param bool|int $raise_php_limits
|
41 |
-
* If true, PHP settings will be raised if needed
|
42 |
-
*/
|
43 |
-
public function __construct($raise_php_limits = TRUE)
|
44 |
-
{
|
45 |
-
// Set suggested PHP limits
|
46 |
-
$this->memory_limit = 128 * 1048576; // 128MB in bytes
|
47 |
-
$this->max_execution_time = 60; // 1 min
|
48 |
-
$this->pcre_backtrack_limit = 1000 * 1000;
|
49 |
-
$this->pcre_recursion_limit = 500 * 1000;
|
50 |
-
|
51 |
-
$this->raise_php_limits = (bool) $raise_php_limits;
|
52 |
-
}
|
53 |
-
|
54 |
-
/**
|
55 |
-
* Minify a string of CSS
|
56 |
-
* @param string $css
|
57 |
-
* @param int|bool $linebreak_pos
|
58 |
-
* @return string
|
59 |
-
*/
|
60 |
-
public function run($css = '', $linebreak_pos = FALSE)
|
61 |
-
{
|
62 |
-
if (empty($css)) {
|
63 |
-
return '';
|
64 |
-
}
|
65 |
-
|
66 |
-
if ($this->raise_php_limits) {
|
67 |
-
$this->do_raise_php_limits();
|
68 |
-
}
|
69 |
-
|
70 |
-
$this->comments = array();
|
71 |
-
$this->preserved_tokens = array();
|
72 |
-
|
73 |
-
$start_index = 0;
|
74 |
-
$length = strlen($css);
|
75 |
-
|
76 |
-
$css = $this->extract_data_urls($css);
|
77 |
-
|
78 |
-
// collect all comment blocks...
|
79 |
-
while (($start_index = $this->index_of($css, '/*', $start_index)) >= 0) {
|
80 |
-
$end_index = $this->index_of($css, '*/', $start_index + 2);
|
81 |
-
if ($end_index < 0) {
|
82 |
-
$end_index = $length;
|
83 |
-
}
|
84 |
-
$comment_found = $this->str_slice($css, $start_index + 2, $end_index);
|
85 |
-
$this->comments[] = $comment_found;
|
86 |
-
$comment_preserve_string = self::COMMENT . (count($this->comments) - 1) . '___';
|
87 |
-
$css = $this->str_slice($css, 0, $start_index + 2) . $comment_preserve_string . $this->str_slice($css, $end_index);
|
88 |
-
// Set correct start_index: Fixes issue #2528130
|
89 |
-
$start_index = $end_index + 2 + strlen($comment_preserve_string) - strlen($comment_found);
|
90 |
-
}
|
91 |
-
|
92 |
-
// preserve strings so their content doesn't get accidentally minified
|
93 |
-
$css = preg_replace_callback('/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S", array($this, 'replace_string'), $css);
|
94 |
-
|
95 |
-
// Let's divide css code in chunks of 5.000 chars aprox.
|
96 |
-
// Reason: PHP's PCRE functions like preg_replace have a "backtrack limit"
|
97 |
-
// of 100.000 chars by default (php < 5.3.7) so if we're dealing with really
|
98 |
-
// long strings and a (sub)pattern matches a number of chars greater than
|
99 |
-
// the backtrack limit number (i.e. /(.*)/s) PCRE functions may fail silently
|
100 |
-
// returning NULL and $css would be empty.
|
101 |
-
$charset = '';
|
102 |
-
$charset_regexp = '/(@charset)( [^;]+;)/i';
|
103 |
-
$css_chunks = array();
|
104 |
-
$css_chunk_length = 5000; // aprox size, not exact
|
105 |
-
$start_index = 0;
|
106 |
-
$i = $css_chunk_length; // save initial iterations
|
107 |
-
$l = strlen($css);
|
108 |
-
|
109 |
-
|
110 |
-
// if the number of characters is 5000 or less, do not chunk
|
111 |
-
if ($l <= $css_chunk_length) {
|
112 |
-
$css_chunks[] = $css;
|
113 |
-
} else {
|
114 |
-
// chunk css code securely
|
115 |
-
while ($i < $l) {
|
116 |
-
$i += 50; // save iterations
|
117 |
-
if ($l - $start_index <= $css_chunk_length || $i >= $l) {
|
118 |
-
$css_chunks[] = $this->str_slice($css, $start_index);
|
119 |
-
break;
|
120 |
-
}
|
121 |
-
if ($css[$i - 1] === '}' && $i - $start_index > $css_chunk_length) {
|
122 |
-
// If there are two ending curly braces }} separated or not by spaces,
|
123 |
-
// join them in the same chunk (i.e. @media blocks)
|
124 |
-
$next_chunk = substr($css, $i);
|
125 |
-
if (preg_match('/^\s*\}/', $next_chunk)) {
|
126 |
-
$i = $i + $this->index_of($next_chunk, '}') + 1;
|
127 |
-
}
|
128 |
-
|
129 |
-
$css_chunks[] = $this->str_slice($css, $start_index, $i);
|
130 |
-
$start_index = $i;
|
131 |
-
}
|
132 |
-
}
|
133 |
-
}
|
134 |
-
|
135 |
-
// Minify each chunk
|
136 |
-
for ($i = 0, $n = count($css_chunks); $i < $n; $i++) {
|
137 |
-
$css_chunks[$i] = $this->minify($css_chunks[$i], $linebreak_pos);
|
138 |
-
// Keep the first @charset at-rule found
|
139 |
-
if (empty($charset) && preg_match($charset_regexp, $css_chunks[$i], $matches)) {
|
140 |
-
$charset = strtolower($matches[1]) . $matches[2];
|
141 |
-
}
|
142 |
-
// Delete all @charset at-rules
|
143 |
-
$css_chunks[$i] = preg_replace($charset_regexp, '', $css_chunks[$i]);
|
144 |
-
}
|
145 |
-
|
146 |
-
// Update the first chunk and push the charset to the top of the file.
|
147 |
-
$css_chunks[0] = $charset . $css_chunks[0];
|
148 |
-
|
149 |
-
return implode('', $css_chunks);
|
150 |
-
}
|
151 |
-
|
152 |
-
/**
|
153 |
-
* Sets the memory limit for this script
|
154 |
-
* @param int|string $limit
|
155 |
-
*/
|
156 |
-
public function set_memory_limit($limit)
|
157 |
-
{
|
158 |
-
$this->memory_limit = $this->normalize_int($limit);
|
159 |
-
}
|
160 |
-
|
161 |
-
/**
|
162 |
-
* Sets the maximum execution time for this script
|
163 |
-
* @param int|string $seconds
|
164 |
-
*/
|
165 |
-
public function set_max_execution_time($seconds)
|
166 |
-
{
|
167 |
-
$this->max_execution_time = (int) $seconds;
|
168 |
-
}
|
169 |
-
|
170 |
-
/**
|
171 |
-
* Sets the PCRE backtrack limit for this script
|
172 |
-
* @param int $limit
|
173 |
-
*/
|
174 |
-
public function set_pcre_backtrack_limit($limit)
|
175 |
-
{
|
176 |
-
$this->pcre_backtrack_limit = (int) $limit;
|
177 |
-
}
|
178 |
-
|
179 |
-
/**
|
180 |
-
* Sets the PCRE recursion limit for this script
|
181 |
-
* @param int $limit
|
182 |
-
*/
|
183 |
-
public function set_pcre_recursion_limit($limit)
|
184 |
-
{
|
185 |
-
$this->pcre_recursion_limit = (int) $limit;
|
186 |
-
}
|
187 |
-
|
188 |
-
/**
|
189 |
-
* Try to configure PHP to use at least the suggested minimum settings
|
190 |
-
*/
|
191 |
-
private function do_raise_php_limits()
|
192 |
-
{
|
193 |
-
$php_limits = array(
|
194 |
-
'memory_limit' => $this->memory_limit,
|
195 |
-
'max_execution_time' => $this->max_execution_time,
|
196 |
-
'pcre.backtrack_limit' => $this->pcre_backtrack_limit,
|
197 |
-
'pcre.recursion_limit' => $this->pcre_recursion_limit
|
198 |
-
);
|
199 |
-
|
200 |
-
// If current settings are higher respect them.
|
201 |
-
foreach ($php_limits as $name => $suggested) {
|
202 |
-
$current = $this->normalize_int(ini_get($name));
|
203 |
-
// memory_limit exception: allow -1 for "no memory limit".
|
204 |
-
if ($current > -1 && ($suggested == -1 || $current < $suggested)) {
|
205 |
-
ini_set($name, $suggested);
|
206 |
-
}
|
207 |
-
}
|
208 |
-
}
|
209 |
-
|
210 |
-
/**
|
211 |
-
* Does bulk of the minification
|
212 |
-
* @param string $css
|
213 |
-
* @param int|bool $linebreak_pos
|
214 |
-
* @return string
|
215 |
-
*/
|
216 |
-
private function minify($css, $linebreak_pos)
|
217 |
-
{
|
218 |
-
// strings are safe, now wrestle the comments
|
219 |
-
for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
|
220 |
-
|
221 |
-
$token = $this->comments[$i];
|
222 |
-
$placeholder = '/' . self::COMMENT . $i . '___/';
|
223 |
-
|
224 |
-
// ! in the first position of the comment means preserve
|
225 |
-
// so push to the preserved tokens keeping the !
|
226 |
-
if (substr($token, 0, 1) === '!') {
|
227 |
-
$this->preserved_tokens[] = $token;
|
228 |
-
$token_tring = self::TOKEN . (count($this->preserved_tokens) - 1) . '___';
|
229 |
-
$css = preg_replace($placeholder, $token_tring, $css, 1);
|
230 |
-
// Preserve new lines for /*! important comments
|
231 |
-
$css = preg_replace('/\s*[\n\r\f]+\s*(\/\*'. $token_tring .')/S', self::NL.'$1', $css);
|
232 |
-
$css = preg_replace('/('. $token_tring .'\*\/)\s*[\n\r\f]+\s*/', '$1'.self::NL, $css);
|
233 |
-
continue;
|
234 |
-
}
|
235 |
-
|
236 |
-
// \ in the last position looks like hack for Mac/IE5
|
237 |
-
// shorten that to /*\*/ and the next one to /**/
|
238 |
-
if (substr($token, (strlen($token) - 1), 1) === '\\') {
|
239 |
-
$this->preserved_tokens[] = '\\';
|
240 |
-
$css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
|
241 |
-
$i = $i + 1; // attn: advancing the loop
|
242 |
-
$this->preserved_tokens[] = '';
|
243 |
-
$css = preg_replace('/' . self::COMMENT . $i . '___/', self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
|
244 |
-
continue;
|
245 |
-
}
|
246 |
-
|
247 |
-
// keep empty comments after child selectors (IE7 hack)
|
248 |
-
// e.g. html >/**/ body
|
249 |
-
if (strlen($token) === 0) {
|
250 |
-
$start_index = $this->index_of($css, $this->str_slice($placeholder, 1, -1));
|
251 |
-
if ($start_index > 2) {
|
252 |
-
if (substr($css, $start_index - 3, 1) === '>') {
|
253 |
-
$this->preserved_tokens[] = '';
|
254 |
-
$css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
|
255 |
-
}
|
256 |
-
}
|
257 |
-
}
|
258 |
-
|
259 |
-
// in all other cases kill the comment
|
260 |
-
$css = preg_replace('/\/\*' . $this->str_slice($placeholder, 1, -1) . '\*\//', '', $css, 1);
|
261 |
-
}
|
262 |
-
|
263 |
-
|
264 |
-
// Normalize all whitespace strings to single spaces. Easier to work with that way.
|
265 |
-
$css = preg_replace('/\s+/', ' ', $css);
|
266 |
-
|
267 |
-
// Fix IE7 issue on matrix filters which browser accept whitespaces between Matrix parameters
|
268 |
-
$css = preg_replace_callback('/\s*filter\:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^\)]+)\)/', array($this, 'preserve_old_IE_specific_matrix_definition'), $css);
|
269 |
-
|
270 |
-
// Shorten & preserve calculations calc(...) since spaces are important
|
271 |
-
$css = preg_replace_callback('/calc(\(((?:[^\(\)]+|(?1))*)\))/i', array($this, 'replace_calc'), $css);
|
272 |
-
|
273 |
-
// Replace positive sign from numbers preceded by : or a white-space before the leading space is removed
|
274 |
-
// +1.2em to 1.2em, +.8px to .8px, +2% to 2%
|
275 |
-
$css = preg_replace('/((?<!\\\\)\:|\s)\+(\.?\d+)/S', '$1$2', $css);
|
276 |
-
|
277 |
-
// Remove leading zeros from integer and float numbers preceded by : or a white-space
|
278 |
-
// 000.6 to .6, -0.8 to -.8, 0050 to 50, -01.05 to -1.05
|
279 |
-
$css = preg_replace('/((?<!\\\\)\:|\s)(\-?)0+(\.?\d+)/S', '$1$2$3', $css);
|
280 |
-
|
281 |
-
// Remove trailing zeros from float numbers preceded by : or a white-space
|
282 |
-
// -6.0100em to -6.01em, .0100 to .01, 1.200px to 1.2px
|
283 |
-
$css = preg_replace('/((?<!\\\\)\:|\s)(\-?)(\d?\.\d+?)0+([^\d])/S', '$1$2$3$4', $css);
|
284 |
-
|
285 |
-
// Remove trailing .0 -> -9.0 to -9
|
286 |
-
$css = preg_replace('/((?<!\\\\)\:|\s)(\-?\d+)\.0([^\d])/S', '$1$2$3', $css);
|
287 |
-
|
288 |
-
// Replace 0 length numbers with 0
|
289 |
-
$css = preg_replace('/((?<!\\\\)\:|\s)\-?\.?0+([^\d])/S', '${1}0$2', $css);
|
290 |
-
|
291 |
-
// Remove the spaces before the things that should not have spaces before them.
|
292 |
-
// But, be careful not to turn "p :link {...}" into "p:link{...}"
|
293 |
-
// Swap out any pseudo-class colons with the token, and then swap back.
|
294 |
-
$css = preg_replace_callback('/(?:^|\})[^\{]*\s+\:/', array($this, 'replace_colon'), $css);
|
295 |
-
|
296 |
-
// Remove spaces before the things that should not have spaces before them.
|
297 |
-
$css = preg_replace('/\s+([\!\{\}\;\:\>\+\(\)\]\~\=,])/', '$1', $css);
|
298 |
-
|
299 |
-
// Restore spaces for !important
|
300 |
-
$css = preg_replace('/\!important/i', ' !important', $css);
|
301 |
-
|
302 |
-
// bring back the colon
|
303 |
-
$css = preg_replace('/' . self::CLASSCOLON . '/', ':', $css);
|
304 |
-
|
305 |
-
// retain space for special IE6 cases
|
306 |
-
$css = preg_replace_callback('/\:first\-(line|letter)(\{|,)/i', array($this, 'lowercase_pseudo_first'), $css);
|
307 |
-
|
308 |
-
// no space after the end of a preserved comment
|
309 |
-
$css = preg_replace('/\*\/ /', '*/', $css);
|
310 |
-
|
311 |
-
// lowercase some popular @directives
|
312 |
-
$css = preg_replace_callback('/@(font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframe|media|page|namespace)/i', array($this, 'lowercase_directives'), $css);
|
313 |
-
|
314 |
-
// lowercase some more common pseudo-elements
|
315 |
-
$css = preg_replace_callback('/:(active|after|before|checked|disabled|empty|enabled|first-(?:child|of-type)|focus|hover|last-(?:child|of-type)|link|only-(?:child|of-type)|root|:selection|target|visited)/i', array($this, 'lowercase_pseudo_elements'), $css);
|
316 |
-
|
317 |
-
// lowercase some more common functions
|
318 |
-
$css = preg_replace_callback('/:(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\(/i', array($this, 'lowercase_common_functions'), $css);
|
319 |
-
|
320 |
-
// lower case some common function that can be values
|
321 |
-
// NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us
|
322 |
-
$css = preg_replace_callback('/([:,\( ]\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)/iS', array($this, 'lowercase_common_functions_values'), $css);
|
323 |
-
|
324 |
-
// Put the space back in some cases, to support stuff like
|
325 |
-
// @media screen and (-webkit-min-device-pixel-ratio:0){
|
326 |
-
$css = preg_replace('/\band\(/i', 'and (', $css);
|
327 |
-
|
328 |
-
// Remove the spaces after the things that should not have spaces after them.
|
329 |
-
$css = preg_replace('/([\!\{\}\:;\>\+\(\[\~\=,])\s+/S', '$1', $css);
|
330 |
-
|
331 |
-
// remove unnecessary semicolons
|
332 |
-
$css = preg_replace('/;+\}/', '}', $css);
|
333 |
-
|
334 |
-
// Fix for issue: #2528146
|
335 |
-
// Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack)
|
336 |
-
// to avoid issues on Symbian S60 3.x browsers.
|
337 |
-
$css = preg_replace('/(\*[a-z0-9\-]+\s*\:[^;\}]+)(\})/', '$1;$2', $css);
|
338 |
-
|
339 |
-
// Replace 0 <length> and 0 <percentage> values with 0.
|
340 |
-
// <length> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/length
|
341 |
-
// <percentage> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/percentage
|
342 |
-
$css = preg_replace('/([^\\\\]\:|\s)0(?:em|ex|ch|rem|vw|vh|vm|vmin|cm|mm|in|px|pt|pc|%)/iS', '${1}0', $css);
|
343 |
-
|
344 |
-
// 0% step in a keyframe? restore the % unit
|
345 |
-
$css = preg_replace_callback('/(@[a-z\-]*?keyframes[^\{]+\{)(.*?)(\}\})/iS', array($this, 'replace_keyframe_zero'), $css);
|
346 |
-
|
347 |
-
// Replace 0 0; or 0 0 0; or 0 0 0 0; with 0.
|
348 |
-
$css = preg_replace('/\:0(?: 0){1,3}(;|\}| \!)/', ':0$1', $css);
|
349 |
-
|
350 |
-
// Fix for issue: #2528142
|
351 |
-
// Replace text-shadow:0; with text-shadow:0 0 0;
|
352 |
-
$css = preg_replace('/(text-shadow\:0)(;|\}| \!)/i', '$1 0 0$2', $css);
|
353 |
-
|
354 |
-
// Replace background-position:0; with background-position:0 0;
|
355 |
-
// same for transform-origin
|
356 |
-
// Changing -webkit-mask-position: 0 0 to just a single 0 will result in the second parameter defaulting to 50% (center)
|
357 |
-
$css = preg_replace('/(background\-position|webkit-mask-position|(?:webkit|moz|o|ms|)\-?transform\-origin)\:0(;|\}| \!)/iS', '$1:0 0$2', $css);
|
358 |
-
|
359 |
-
// Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space)
|
360 |
-
// Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space)
|
361 |
-
// This makes it more likely that it'll get further compressed in the next step.
|
362 |
-
$css = preg_replace_callback('/rgb\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'rgb_to_hex'), $css);
|
363 |
-
$css = preg_replace_callback('/hsl\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'hsl_to_hex'), $css);
|
364 |
-
|
365 |
-
// Shorten colors from #AABBCC to #ABC or short color name.
|
366 |
-
$css = $this->compress_hex_colors($css);
|
367 |
-
|
368 |
-
// border: none to border:0, outline: none to outline:0
|
369 |
-
$css = preg_replace('/(border\-?(?:top|right|bottom|left|)|outline)\:none(;|\}| \!)/iS', '$1:0$2', $css);
|
370 |
-
|
371 |
-
// shorter opacity IE filter
|
372 |
-
$css = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $css);
|
373 |
-
|
374 |
-
// Find a fraction that is used for Opera's -o-device-pixel-ratio query
|
375 |
-
// Add token to add the "\" back in later
|
376 |
-
$css = preg_replace('/\(([a-z\-]+):([0-9]+)\/([0-9]+)\)/i', '($1:$2'. self::QUERY_FRACTION .'$3)', $css);
|
377 |
-
|
378 |
-
// Remove empty rules.
|
379 |
-
$css = preg_replace('/[^\};\{\/]+\{\}/S', '', $css);
|
380 |
-
|
381 |
-
// Add "/" back to fix Opera -o-device-pixel-ratio query
|
382 |
-
$css = preg_replace('/'. self::QUERY_FRACTION .'/', '/', $css);
|
383 |
-
|
384 |
-
// Replace multiple semi-colons in a row by a single one
|
385 |
-
// See SF bug #1980989
|
386 |
-
$css = preg_replace('/;;+/', ';', $css);
|
387 |
-
|
388 |
-
// Restore new lines for /*! important comments
|
389 |
-
$css = preg_replace('/'. self::NL .'/', "\n", $css);
|
390 |
-
|
391 |
-
// Lowercase all uppercase properties
|
392 |
-
$css = preg_replace_callback('/(\{|\;)([A-Z\-]+)(\:)/', array($this, 'lowercase_properties'), $css);
|
393 |
-
|
394 |
-
// Some source control tools don't like it when files containing lines longer
|
395 |
-
// than, say 8000 characters, are checked in. The linebreak option is used in
|
396 |
-
// that case to split long lines after a specific column.
|
397 |
-
if ($linebreak_pos !== FALSE && (int) $linebreak_pos >= 0) {
|
398 |
-
$linebreak_pos = (int) $linebreak_pos;
|
399 |
-
$start_index = $i = 0;
|
400 |
-
while ($i < strlen($css)) {
|
401 |
-
$i++;
|
402 |
-
if ($css[$i - 1] === '}' && $i - $start_index > $linebreak_pos) {
|
403 |
-
$css = $this->str_slice($css, 0, $i) . "\n" . $this->str_slice($css, $i);
|
404 |
-
$start_index = $i;
|
405 |
-
}
|
406 |
-
}
|
407 |
-
}
|
408 |
-
|
409 |
-
// restore preserved comments and strings in reverse order
|
410 |
-
for ($i = count($this->preserved_tokens) - 1; $i >= 0; $i--) {
|
411 |
-
$css = preg_replace('/' . self::TOKEN . $i . '___/', $this->preserved_tokens[$i], $css, 1);
|
412 |
-
}
|
413 |
-
|
414 |
-
// Trim the final string (for any leading or trailing white spaces)
|
415 |
-
return trim($css);
|
416 |
-
}
|
417 |
-
|
418 |
-
/**
|
419 |
-
* Utility method to replace all data urls with tokens before we start
|
420 |
-
* compressing, to avoid performance issues running some of the subsequent
|
421 |
-
* regexes against large strings chunks.
|
422 |
-
*
|
423 |
-
* @param string $css
|
424 |
-
* @return string
|
425 |
-
*/
|
426 |
-
private function extract_data_urls($css)
|
427 |
-
{
|
428 |
-
// Leave data urls alone to increase parse performance.
|
429 |
-
$max_index = strlen($css) - 1;
|
430 |
-
$append_index = $index = $last_index = $offset = 0;
|
431 |
-
$sb = array();
|
432 |
-
$pattern = '/url\(\s*(["\']?)data\:/i';
|
433 |
-
|
434 |
-
// Since we need to account for non-base64 data urls, we need to handle
|
435 |
-
// ' and ) being part of the data string. Hence switching to indexOf,
|
436 |
-
// to determine whether or not we have matching string terminators and
|
437 |
-
// handling sb appends directly, instead of using matcher.append* methods.
|
438 |
-
|
439 |
-
while (preg_match($pattern, $css, $m, 0, $offset)) {
|
440 |
-
$index = $this->index_of($css, $m[0], $offset);
|
441 |
-
$last_index = $index + strlen($m[0]);
|
442 |
-
$start_index = $index + 4; // "url(".length()
|
443 |
-
$end_index = $last_index - 1;
|
444 |
-
$terminator = $m[1]; // ', " or empty (not quoted)
|
445 |
-
$found_terminator = FALSE;
|
446 |
-
|
447 |
-
if (strlen($terminator) === 0) {
|
448 |
-
$terminator = ')';
|
449 |
-
}
|
450 |
-
|
451 |
-
while ($found_terminator === FALSE && $end_index+1 <= $max_index) {
|
452 |
-
$end_index = $this->index_of($css, $terminator, $end_index + 1);
|
453 |
-
|
454 |
-
// endIndex == 0 doesn't really apply here
|
455 |
-
if ($end_index > 0 && substr($css, $end_index - 1, 1) !== '\\') {
|
456 |
-
$found_terminator = TRUE;
|
457 |
-
if (')' != $terminator) {
|
458 |
-
$end_index = $this->index_of($css, ')', $end_index);
|
459 |
-
}
|
460 |
-
}
|
461 |
-
}
|
462 |
-
|
463 |
-
// Enough searching, start moving stuff over to the buffer
|
464 |
-
$sb[] = $this->str_slice($css, $append_index, $index);
|
465 |
-
|
466 |
-
if ($found_terminator) {
|
467 |
-
$token = $this->str_slice($css, $start_index, $end_index);
|
468 |
-
$token = preg_replace('/\s+/', '', $token);
|
469 |
-
$this->preserved_tokens[] = $token;
|
470 |
-
|
471 |
-
$preserver = 'url(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___)';
|
472 |
-
$sb[] = $preserver;
|
473 |
-
|
474 |
-
$append_index = $end_index + 1;
|
475 |
-
} else {
|
476 |
-
// No end terminator found, re-add the whole match. Should we throw/warn here?
|
477 |
-
$sb[] = $this->str_slice($css, $index, $last_index);
|
478 |
-
$append_index = $last_index;
|
479 |
-
}
|
480 |
-
|
481 |
-
$offset = $last_index;
|
482 |
-
}
|
483 |
-
|
484 |
-
$sb[] = $this->str_slice($css, $append_index);
|
485 |
-
|
486 |
-
return implode('', $sb);
|
487 |
-
}
|
488 |
-
|
489 |
-
/**
|
490 |
-
* Utility method to compress hex color values of the form #AABBCC to #ABC or short color name.
|
491 |
-
*
|
492 |
-
* DOES NOT compress CSS ID selectors which match the above pattern (which would break things).
|
493 |
-
* e.g. #AddressForm { ... }
|
494 |
-
*
|
495 |
-
* DOES NOT compress IE filters, which have hex color values (which would break things).
|
496 |
-
* e.g. filter: chroma(color="#FFFFFF");
|
497 |
-
*
|
498 |
-
* DOES NOT compress invalid hex values.
|
499 |
-
* e.g. background-color: #aabbccdd
|
500 |
-
*
|
501 |
-
* @param string $css
|
502 |
-
* @return string
|
503 |
-
*/
|
504 |
-
private function compress_hex_colors($css)
|
505 |
-
{
|
506 |
-
// Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters)
|
507 |
-
$pattern = '/(\=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS';
|
508 |
-
$_index = $index = $last_index = $offset = 0;
|
509 |
-
$sb = array();
|
510 |
-
// See: http://ajaxmin.codeplex.com/wikipage?title=CSS%20Colors
|
511 |
-
$short_safe = array(
|
512 |
-
'#808080' => 'gray',
|
513 |
-
'#008000' => 'green',
|
514 |
-
'#800000' => 'maroon',
|
515 |
-
'#000080' => 'navy',
|
516 |
-
'#808000' => 'olive',
|
517 |
-
'#ffa500' => 'orange',
|
518 |
-
'#800080' => 'purple',
|
519 |
-
'#c0c0c0' => 'silver',
|
520 |
-
'#008080' => 'teal',
|
521 |
-
'#f00' => 'red'
|
522 |
-
);
|
523 |
-
|
524 |
-
while (preg_match($pattern, $css, $m, 0, $offset)) {
|
525 |
-
$index = $this->index_of($css, $m[0], $offset);
|
526 |
-
$last_index = $index + strlen($m[0]);
|
527 |
-
$is_filter = $m[1] !== null && $m[1] !== '';
|
528 |
-
|
529 |
-
$sb[] = $this->str_slice($css, $_index, $index);
|
530 |
-
|
531 |
-
if ($is_filter) {
|
532 |
-
// Restore, maintain case, otherwise filter will break
|
533 |
-
$sb[] = $m[1] . '#' . $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7];
|
534 |
-
} else {
|
535 |
-
if (strtolower($m[2]) == strtolower($m[3]) &&
|
536 |
-
strtolower($m[4]) == strtolower($m[5]) &&
|
537 |
-
strtolower($m[6]) == strtolower($m[7])) {
|
538 |
-
// Compress.
|
539 |
-
$hex = '#' . strtolower($m[3] . $m[5] . $m[7]);
|
540 |
-
} else {
|
541 |
-
// Non compressible color, restore but lower case.
|
542 |
-
$hex = '#' . strtolower($m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]);
|
543 |
-
}
|
544 |
-
// replace Hex colors to short safe color names
|
545 |
-
$sb[] = array_key_exists($hex, $short_safe) ? $short_safe[$hex] : $hex;
|
546 |
-
}
|
547 |
-
|
548 |
-
$_index = $offset = $last_index - strlen($m[8]);
|
549 |
-
}
|
550 |
-
|
551 |
-
$sb[] = $this->str_slice($css, $_index);
|
552 |
-
|
553 |
-
return implode('', $sb);
|
554 |
-
}
|
555 |
-
|
556 |
-
/* CALLBACKS
|
557 |
-
* ---------------------------------------------------------------------------------------------
|
558 |
-
*/
|
559 |
-
|
560 |
-
private function replace_string($matches)
|
561 |
-
{
|
562 |
-
$match = $matches[0];
|
563 |
-
$quote = substr($match, 0, 1);
|
564 |
-
// Must use addcslashes in PHP to avoid parsing of backslashes
|
565 |
-
$match = addcslashes($this->str_slice($match, 1, -1), '\\');
|
566 |
-
|
567 |
-
// maybe the string contains a comment-like substring?
|
568 |
-
// one, maybe more? put'em back then
|
569 |
-
if (($pos = $this->index_of($match, self::COMMENT)) >= 0) {
|
570 |
-
for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
|
571 |
-
$match = preg_replace('/' . self::COMMENT . $i . '___/', $this->comments[$i], $match, 1);
|
572 |
-
}
|
573 |
-
}
|
574 |
-
|
575 |
-
// minify alpha opacity in filter strings
|
576 |
-
$match = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $match);
|
577 |
-
|
578 |
-
$this->preserved_tokens[] = $match;
|
579 |
-
return $quote . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . $quote;
|
580 |
-
}
|
581 |
-
|
582 |
-
private function replace_colon($matches)
|
583 |
-
{
|
584 |
-
return preg_replace('/\:/', self::CLASSCOLON, $matches[0]);
|
585 |
-
}
|
586 |
-
|
587 |
-
private function replace_calc($matches)
|
588 |
-
{
|
589 |
-
$this->preserved_tokens[] = trim(preg_replace('/\s*([\*\/\(\),])\s*/', '$1', $matches[2]));
|
590 |
-
return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
|
591 |
-
}
|
592 |
-
|
593 |
-
private function preserve_old_IE_specific_matrix_definition($matches)
|
594 |
-
{
|
595 |
-
$this->preserved_tokens[] = $matches[1];
|
596 |
-
return 'filter:progid:DXImageTransform.Microsoft.Matrix(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
|
597 |
-
}
|
598 |
-
|
599 |
-
private function replace_keyframe_zero($matches)
|
600 |
-
{
|
601 |
-
return $matches[1] . preg_replace('/0(\{|,[^\)\{]+\{)/', '0%$1', $matches[2]) . $matches[3];
|
602 |
-
}
|
603 |
-
|
604 |
-
private function rgb_to_hex($matches)
|
605 |
-
{
|
606 |
-
// Support for percentage values rgb(100%, 0%, 45%);
|
607 |
-
if ($this->index_of($matches[1], '%') >= 0){
|
608 |
-
$rgbcolors = explode(',', str_replace('%', '', $matches[1]));
|
609 |
-
for ($i = 0; $i < count($rgbcolors); $i++) {
|
610 |
-
$rgbcolors[$i] = $this->round_number(floatval($rgbcolors[$i]) * 2.55);
|
611 |
-
}
|
612 |
-
} else {
|
613 |
-
$rgbcolors = explode(',', $matches[1]);
|
614 |
-
}
|
615 |
-
|
616 |
-
// Values outside the sRGB color space should be clipped (0-255)
|
617 |
-
for ($i = 0; $i < count($rgbcolors); $i++) {
|
618 |
-
$rgbcolors[$i] = $this->clamp_number(intval($rgbcolors[$i], 10), 0, 255);
|
619 |
-
$rgbcolors[$i] = sprintf("%02x", $rgbcolors[$i]);
|
620 |
-
}
|
621 |
-
|
622 |
-
// Fix for issue #2528093
|
623 |
-
if (!preg_match('/[\s\,\);\}]/', $matches[2])){
|
624 |
-
$matches[2] = ' ' . $matches[2];
|
625 |
-
}
|
626 |
-
|
627 |
-
return '#' . implode('', $rgbcolors) . $matches[2];
|
628 |
-
}
|
629 |
-
|
630 |
-
private function hsl_to_hex($matches)
|
631 |
-
{
|
632 |
-
$values = explode(',', str_replace('%', '', $matches[1]));
|
633 |
-
$h = floatval($values[0]);
|
634 |
-
$s = floatval($values[1]);
|
635 |
-
$l = floatval($values[2]);
|
636 |
-
|
637 |
-
// Wrap and clamp, then fraction!
|
638 |
-
$h = ((($h % 360) + 360) % 360) / 360;
|
639 |
-
$s = $this->clamp_number($s, 0, 100) / 100;
|
640 |
-
$l = $this->clamp_number($l, 0, 100) / 100;
|
641 |
-
|
642 |
-
if ($s == 0) {
|
643 |
-
$r = $g = $b = $this->round_number(255 * $l);
|
644 |
-
} else {
|
645 |
-
$v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l);
|
646 |
-
$v1 = (2 * $l) - $v2;
|
647 |
-
$r = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h + (1/3)));
|
648 |
-
$g = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h));
|
649 |
-
$b = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h - (1/3)));
|
650 |
-
}
|
651 |
-
|
652 |
-
return $this->rgb_to_hex(array('', $r.','.$g.','.$b, $matches[2]));
|
653 |
-
}
|
654 |
-
|
655 |
-
private function lowercase_pseudo_first($matches)
|
656 |
-
{
|
657 |
-
return ':first-'. strtolower($matches[1]) .' '. $matches[2];
|
658 |
-
}
|
659 |
-
|
660 |
-
private function lowercase_directives($matches)
|
661 |
-
{
|
662 |
-
return '@'. strtolower($matches[1]);
|
663 |
-
}
|
664 |
-
|
665 |
-
private function lowercase_pseudo_elements($matches)
|
666 |
-
{
|
667 |
-
return ':'. strtolower($matches[1]);
|
668 |
-
}
|
669 |
-
|
670 |
-
private function lowercase_common_functions($matches)
|
671 |
-
{
|
672 |
-
return ':'. strtolower($matches[1]) .'(';
|
673 |
-
}
|
674 |
-
|
675 |
-
private function lowercase_common_functions_values($matches)
|
676 |
-
{
|
677 |
-
return $matches[1] . strtolower($matches[2]);
|
678 |
-
}
|
679 |
-
|
680 |
-
private function lowercase_properties($matches)
|
681 |
-
{
|
682 |
-
return $matches[1].strtolower($matches[2]).$matches[3];
|
683 |
-
}
|
684 |
-
|
685 |
-
/* HELPERS
|
686 |
-
* ---------------------------------------------------------------------------------------------
|
687 |
-
*/
|
688 |
-
|
689 |
-
private function hue_to_rgb($v1, $v2, $vh)
|
690 |
-
{
|
691 |
-
$vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh);
|
692 |
-
if ($vh * 6 < 1) return $v1 + ($v2 - $v1) * 6 * $vh;
|
693 |
-
if ($vh * 2 < 1) return $v2;
|
694 |
-
if ($vh * 3 < 2) return $v1 + ($v2 - $v1) * ((2/3) - $vh) * 6;
|
695 |
-
return $v1;
|
696 |
-
}
|
697 |
-
|
698 |
-
private function round_number($n)
|
699 |
-
{
|
700 |
-
return intval(floor(floatval($n) + 0.5), 10);
|
701 |
-
}
|
702 |
-
|
703 |
-
private function clamp_number($n, $min, $max)
|
704 |
-
{
|
705 |
-
return min(max($n, $min), $max);
|
706 |
-
}
|
707 |
-
|
708 |
-
/**
|
709 |
-
* PHP port of Javascript's "indexOf" function for strings only
|
710 |
-
* Author: Tubal Martin http://blog.margenn.com
|
711 |
-
*
|
712 |
-
* @param string $haystack
|
713 |
-
* @param string $needle
|
714 |
-
* @param int $offset index (optional)
|
715 |
-
* @return int
|
716 |
-
*/
|
717 |
-
private function index_of($haystack, $needle, $offset = 0)
|
718 |
-
{
|
719 |
-
$index = strpos($haystack, $needle, $offset);
|
720 |
-
|
721 |
-
return ($index !== FALSE) ? $index : -1;
|
722 |
-
}
|
723 |
-
|
724 |
-
/**
|
725 |
-
* PHP port of Javascript's "slice" function for strings only
|
726 |
-
* Author: Tubal Martin http://blog.margenn.com
|
727 |
-
* Tests: http://margenn.com/tubal/str_slice/
|
728 |
-
*
|
729 |
-
* @param string $str
|
730 |
-
* @param int $start index
|
731 |
-
* @param int|bool $end index (optional)
|
732 |
-
* @return string
|
733 |
-
*/
|
734 |
-
private function str_slice($str, $start = 0, $end = FALSE)
|
735 |
-
{
|
736 |
-
if ($end !== FALSE && ($start < 0 || $end <= 0)) {
|
737 |
-
$max = strlen($str);
|
738 |
-
|
739 |
-
if ($start < 0) {
|
740 |
-
if (($start = $max + $start) < 0) {
|
741 |
-
return '';
|
742 |
-
}
|
743 |
-
}
|
744 |
-
|
745 |
-
if ($end < 0) {
|
746 |
-
if (($end = $max + $end) < 0) {
|
747 |
-
return '';
|
748 |
-
}
|
749 |
-
}
|
750 |
-
|
751 |
-
if ($end <= $start) {
|
752 |
-
return '';
|
753 |
-
}
|
754 |
-
}
|
755 |
-
|
756 |
-
$slice = ($end === FALSE) ? substr($str, $start) : substr($str, $start, $end - $start);
|
757 |
-
return ($slice === FALSE) ? '' : $slice;
|
758 |
-
}
|
759 |
-
|
760 |
-
/**
|
761 |
-
* Convert strings like "64M" or "30" to int values
|
762 |
-
* @param mixed $size
|
763 |
-
* @return int
|
764 |
-
*/
|
765 |
-
private function normalize_int($size)
|
766 |
-
{
|
767 |
-
if (is_string($size)) {
|
768 |
-
switch (substr($size, -1)) {
|
769 |
-
case 'M': case 'm': return $size * 1048576;
|
770 |
-
case 'K': case 'k': return $size * 1024;
|
771 |
-
case 'G': case 'g': return $size * 1073741824;
|
772 |
-
}
|
773 |
-
}
|
774 |
-
|
775 |
-
return (int) $size;
|
776 |
-
}
|
777 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
classes/external/php/yui-php-cssmin-2.4.8-4_fgo.php
CHANGED
@@ -592,7 +592,7 @@ class CSSmin
|
|
592 |
|
593 |
private function replace_calc($matches)
|
594 |
{
|
595 |
-
$this->preserved_tokens[] = preg_replace('/([\+\-]{1})\(/','$1 (',trim(preg_replace('/\s*([\*\/\(\),])\s*/', '$1', $matches[2])));
|
596 |
return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
|
597 |
}
|
598 |
|
@@ -778,9 +778,9 @@ class CSSmin
|
|
778 |
{
|
779 |
if (is_string($size)) {
|
780 |
switch (substr($size, -1)) {
|
781 |
-
case 'M': case 'm': return $size * 1048576;
|
782 |
-
case 'K': case 'k': return $size * 1024;
|
783 |
-
case 'G': case 'g': return $size * 1073741824;
|
784 |
}
|
785 |
}
|
786 |
|
592 |
|
593 |
private function replace_calc($matches)
|
594 |
{
|
595 |
+
$this->preserved_tokens[] = preg_replace('/\)([\+\-]{1})/',') $1',preg_replace('/([\+\-]{1})\(/','$1 (',trim(preg_replace('/\s*([\*\/\(\),])\s*/', '$1', $matches[2]))));
|
596 |
return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
|
597 |
}
|
598 |
|
778 |
{
|
779 |
if (is_string($size)) {
|
780 |
switch (substr($size, -1)) {
|
781 |
+
case 'M': case 'm': return (int) $size * 1048576;
|
782 |
+
case 'K': case 'k': return (int) $size * 1024;
|
783 |
+
case 'G': case 'g': return (int) $size * 1073741824;
|
784 |
}
|
785 |
}
|
786 |
|
classes/external/php/yui-php-cssmin-2.4.8-p10/cssmin.php
ADDED
@@ -0,0 +1,1112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*!
|
4 |
+
* cssmin.php
|
5 |
+
* Author: Tubal Martin - http://tubalmartin.me/
|
6 |
+
* Repo: https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port
|
7 |
+
*
|
8 |
+
* This is a PHP port of the CSS minification tool distributed with YUICompressor,
|
9 |
+
* itself a port of the cssmin utility by Isaac Schlueter - http://foohack.com/
|
10 |
+
* Permission is hereby granted to use the PHP version under the same
|
11 |
+
* conditions as the YUICompressor.
|
12 |
+
*/
|
13 |
+
|
14 |
+
/*!
|
15 |
+
* YUI Compressor
|
16 |
+
* http://developer.yahoo.com/yui/compressor/
|
17 |
+
* Author: Julien Lecomte - http://www.julienlecomte.net/
|
18 |
+
* Copyright (c) 2013 Yahoo! Inc. All rights reserved.
|
19 |
+
* The copyrights embodied in the content of this file are licensed
|
20 |
+
* by Yahoo! Inc. under the BSD (revised) open source license.
|
21 |
+
*/
|
22 |
+
|
23 |
+
class CSSmin
|
24 |
+
{
|
25 |
+
const NL = '___YUICSSMIN_PRESERVED_NL___';
|
26 |
+
const CLASSCOLON = '___YUICSSMIN_PSEUDOCLASSCOLON___';
|
27 |
+
const QUERY_FRACTION = '___YUICSSMIN_QUERY_FRACTION___';
|
28 |
+
|
29 |
+
const TOKEN = '___YUICSSMIN_PRESERVED_TOKEN_';
|
30 |
+
const COMMENT = '___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_';
|
31 |
+
const AT_RULE_BLOCK = '___YUICSSMIN_PRESERVE_AT_RULE_BLOCK_';
|
32 |
+
|
33 |
+
private $comments;
|
34 |
+
private $atRuleBlocks;
|
35 |
+
private $preservedTokens;
|
36 |
+
private $chunkLength = 5000;
|
37 |
+
private $minChunkLength = 100;
|
38 |
+
private $memoryLimit;
|
39 |
+
private $maxExecutionTime = 60; // 1 min
|
40 |
+
private $pcreBacktrackLimit;
|
41 |
+
private $pcreRecursionLimit;
|
42 |
+
private $raisePhpLimits;
|
43 |
+
|
44 |
+
private $unitsGroupRegex = '(?:ch|cm|em|ex|gd|in|mm|px|pt|pc|q|rem|vh|vmax|vmin|vw|%)';
|
45 |
+
private $numRegex;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* @param bool|int $raisePhpLimits If true, PHP settings will be raised if needed
|
49 |
+
*/
|
50 |
+
public function __construct($raisePhpLimits = true)
|
51 |
+
{
|
52 |
+
$this->memoryLimit = 128 * 1048576; // 128MB in bytes
|
53 |
+
$this->pcreBacktrackLimit = 1000 * 1000;
|
54 |
+
$this->pcreRecursionLimit = 500 * 1000;
|
55 |
+
|
56 |
+
$this->raisePhpLimits = (bool) $raisePhpLimits;
|
57 |
+
|
58 |
+
$this->numRegex = '(?:\+|-)?\d*\.?\d+' . $this->unitsGroupRegex .'?';
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Minifies a string of CSS
|
63 |
+
* @param string $css
|
64 |
+
* @param int|bool $linebreakPos
|
65 |
+
* @return string
|
66 |
+
*/
|
67 |
+
public function run($css = '', $linebreakPos = false)
|
68 |
+
{
|
69 |
+
if (empty($css)) {
|
70 |
+
return '';
|
71 |
+
}
|
72 |
+
|
73 |
+
if ($this->raisePhpLimits) {
|
74 |
+
$this->doRaisePhpLimits();
|
75 |
+
}
|
76 |
+
|
77 |
+
$this->comments = array();
|
78 |
+
$this->atRuleBlocks = array();
|
79 |
+
$this->preservedTokens = array();
|
80 |
+
|
81 |
+
// process data urls
|
82 |
+
$css = $this->processDataUrls($css);
|
83 |
+
|
84 |
+
// process comments
|
85 |
+
$css = preg_replace_callback('/(?<!\\\\)\/\*(.*?)\*(?<!\\\\)\//Ss', array($this, 'processComments'), $css);
|
86 |
+
|
87 |
+
// process strings so their content doesn't get accidentally minified
|
88 |
+
$css = preg_replace_callback(
|
89 |
+
'/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S",
|
90 |
+
array($this, 'processStrings'),
|
91 |
+
$css
|
92 |
+
);
|
93 |
+
|
94 |
+
// Safe chunking: process at rule blocks so after chunking nothing gets stripped out
|
95 |
+
$css = preg_replace_callback(
|
96 |
+
'/@(?:document|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframes|media|supports).+?\}\s*\}/si',
|
97 |
+
array($this, 'processAtRuleBlocks'),
|
98 |
+
$css
|
99 |
+
);
|
100 |
+
|
101 |
+
// Let's divide css code in chunks of {$this->chunkLength} chars aprox.
|
102 |
+
// Reason: PHP's PCRE functions like preg_replace have a "backtrack limit"
|
103 |
+
// of 100.000 chars by default (php < 5.3.7) so if we're dealing with really
|
104 |
+
// long strings and a (sub)pattern matches a number of chars greater than
|
105 |
+
// the backtrack limit number (i.e. /(.*)/s) PCRE functions may fail silently
|
106 |
+
// returning NULL and $css would be empty.
|
107 |
+
$charset = '';
|
108 |
+
$charsetRegexp = '/(@charset)( [^;]+;)/i';
|
109 |
+
$cssChunks = array();
|
110 |
+
$l = strlen($css);
|
111 |
+
|
112 |
+
// if the number of characters is <= {$this->chunkLength}, do not chunk
|
113 |
+
if ($l <= $this->chunkLength) {
|
114 |
+
$cssChunks[] = $css;
|
115 |
+
} else {
|
116 |
+
// chunk css code securely
|
117 |
+
for ($startIndex = 0, $i = $this->chunkLength; $i < $l; $i++) {
|
118 |
+
if ($css[$i - 1] === '}' && $i - $startIndex >= $this->chunkLength) {
|
119 |
+
$cssChunks[] = $this->strSlice($css, $startIndex, $i);
|
120 |
+
$startIndex = $i;
|
121 |
+
// Move forward saving iterations when possible!
|
122 |
+
if ($startIndex + $this->chunkLength < $l) {
|
123 |
+
$i += $this->chunkLength;
|
124 |
+
}
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
// Final chunk
|
129 |
+
$cssChunks[] = $this->strSlice($css, $startIndex);
|
130 |
+
}
|
131 |
+
|
132 |
+
// Minify each chunk
|
133 |
+
for ($i = 0, $n = count($cssChunks); $i < $n; $i++) {
|
134 |
+
$cssChunks[$i] = $this->minify($cssChunks[$i], $linebreakPos);
|
135 |
+
// Keep the first @charset at-rule found
|
136 |
+
if (empty($charset) && preg_match($charsetRegexp, $cssChunks[$i], $matches)) {
|
137 |
+
$charset = strtolower($matches[1]) . $matches[2];
|
138 |
+
}
|
139 |
+
// Delete all @charset at-rules
|
140 |
+
$cssChunks[$i] = preg_replace($charsetRegexp, '', $cssChunks[$i]);
|
141 |
+
}
|
142 |
+
|
143 |
+
// Update the first chunk and push the charset to the top of the file.
|
144 |
+
$cssChunks[0] = $charset . $cssChunks[0];
|
145 |
+
|
146 |
+
return trim(implode('', $cssChunks));
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Sets the approximate number of characters to use when splitting a string in chunks.
|
151 |
+
* @param int $length
|
152 |
+
*/
|
153 |
+
public function set_chunk_length($length)
|
154 |
+
{
|
155 |
+
$length = (int) $length;
|
156 |
+
$this->chunkLength = $length < $this->minChunkLength ? $this->minChunkLength : $length;
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Sets the memory limit for this script
|
161 |
+
* @param int|string $limit
|
162 |
+
*/
|
163 |
+
public function set_memory_limit($limit)
|
164 |
+
{
|
165 |
+
$this->memoryLimit = $this->normalizeInt($limit);
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Sets the maximum execution time for this script
|
170 |
+
* @param int|string $seconds
|
171 |
+
*/
|
172 |
+
public function set_max_execution_time($seconds)
|
173 |
+
{
|
174 |
+
$this->maxExecutionTime = (int) $seconds;
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Sets the PCRE backtrack limit for this script
|
179 |
+
* @param int $limit
|
180 |
+
*/
|
181 |
+
public function set_pcre_backtrack_limit($limit)
|
182 |
+
{
|
183 |
+
$this->pcreBacktrackLimit = (int) $limit;
|
184 |
+
}
|
185 |
+
|
186 |
+
/**
|
187 |
+
* Sets the PCRE recursion limit for this script
|
188 |
+
* @param int $limit
|
189 |
+
*/
|
190 |
+
public function set_pcre_recursion_limit($limit)
|
191 |
+
{
|
192 |
+
$this->pcreRecursionLimit = (int) $limit;
|
193 |
+
}
|
194 |
+
|
195 |
+
/**
|
196 |
+
* Tries to configure PHP to use at least the suggested minimum settings
|
197 |
+
* @return void
|
198 |
+
*/
|
199 |
+
private function doRaisePhpLimits()
|
200 |
+
{
|
201 |
+
$phpLimits = array(
|
202 |
+
'memory_limit' => $this->memoryLimit,
|
203 |
+
'max_execution_time' => $this->maxExecutionTime,
|
204 |
+
'pcre.backtrack_limit' => $this->pcreBacktrackLimit,
|
205 |
+
'pcre.recursion_limit' => $this->pcreRecursionLimit
|
206 |
+
);
|
207 |
+
|
208 |
+
// If current settings are higher respect them.
|
209 |
+
foreach ($phpLimits as $name => $suggested) {
|
210 |
+
$current = $this->normalizeInt(ini_get($name));
|
211 |
+
|
212 |
+
if ($current > $suggested) {
|
213 |
+
continue;
|
214 |
+
}
|
215 |
+
|
216 |
+
// memoryLimit exception: allow -1 for "no memory limit".
|
217 |
+
if ($name === 'memory_limit' && $current === -1) {
|
218 |
+
continue;
|
219 |
+
}
|
220 |
+
|
221 |
+
// maxExecutionTime exception: allow 0 for "no memory limit".
|
222 |
+
if ($name === 'max_execution_time' && $current === 0) {
|
223 |
+
continue;
|
224 |
+
}
|
225 |
+
|
226 |
+
ini_set($name, $suggested);
|
227 |
+
}
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Registers a preserved token
|
232 |
+
* @param $token
|
233 |
+
* @return string The token ID string
|
234 |
+
*/
|
235 |
+
private function registerPreservedToken($token)
|
236 |
+
{
|
237 |
+
$this->preservedTokens[] = $token;
|
238 |
+
return self::TOKEN . (count($this->preservedTokens) - 1) .'___';
|
239 |
+
}
|
240 |
+
|
241 |
+
/**
|
242 |
+
* Gets the regular expression to match the specified token ID string
|
243 |
+
* @param $id
|
244 |
+
* @return string
|
245 |
+
*/
|
246 |
+
private function getPreservedTokenPlaceholderRegexById($id)
|
247 |
+
{
|
248 |
+
return '/'. self::TOKEN . $id .'___/';
|
249 |
+
}
|
250 |
+
|
251 |
+
/**
|
252 |
+
* Registers a candidate comment token
|
253 |
+
* @param $comment
|
254 |
+
* @return string The comment token ID string
|
255 |
+
*/
|
256 |
+
private function registerComment($comment)
|
257 |
+
{
|
258 |
+
$this->comments[] = $comment;
|
259 |
+
return '/*'. self::COMMENT . (count($this->comments) - 1) .'___*/';
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Gets the candidate comment token ID string for the specified comment token ID
|
264 |
+
* @param $id
|
265 |
+
* @return string
|
266 |
+
*/
|
267 |
+
private function getCommentPlaceholderById($id)
|
268 |
+
{
|
269 |
+
return self::COMMENT . $id .'___';
|
270 |
+
}
|
271 |
+
|
272 |
+
/**
|
273 |
+
* Gets the regular expression to match the specified comment token ID string
|
274 |
+
* @param $id
|
275 |
+
* @return string
|
276 |
+
*/
|
277 |
+
private function getCommentPlaceholderRegexById($id)
|
278 |
+
{
|
279 |
+
return '/'. $this->getCommentPlaceholderById($id) .'/';
|
280 |
+
}
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Registers an at rule block token
|
284 |
+
* @param $block
|
285 |
+
* @return string The comment token ID string
|
286 |
+
*/
|
287 |
+
private function registerAtRuleBlock($block)
|
288 |
+
{
|
289 |
+
$this->atRuleBlocks[] = $block;
|
290 |
+
return self::AT_RULE_BLOCK . (count($this->atRuleBlocks) - 1) .'___';
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Gets the regular expression to match the specified at rule block token ID string
|
295 |
+
* @param $id
|
296 |
+
* @return string
|
297 |
+
*/
|
298 |
+
private function getAtRuleBlockPlaceholderRegexById($id)
|
299 |
+
{
|
300 |
+
return '/'. self::AT_RULE_BLOCK . $id .'___/';
|
301 |
+
}
|
302 |
+
|
303 |
+
/**
|
304 |
+
* Minifies the given input CSS string
|
305 |
+
* @param string $css
|
306 |
+
* @param int|bool $linebreakPos
|
307 |
+
* @return string
|
308 |
+
*/
|
309 |
+
private function minify($css, $linebreakPos)
|
310 |
+
{
|
311 |
+
// Restore preserved at rule blocks
|
312 |
+
for ($i = 0, $max = count($this->atRuleBlocks); $i < $max; $i++) {
|
313 |
+
$css = preg_replace(
|
314 |
+
$this->getAtRuleBlockPlaceholderRegexById($i),
|
315 |
+
$this->escapeReplacementString($this->atRuleBlocks[$i]),
|
316 |
+
$css,
|
317 |
+
1
|
318 |
+
);
|
319 |
+
}
|
320 |
+
|
321 |
+
// strings are safe, now wrestle the comments
|
322 |
+
for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
|
323 |
+
$comment = $this->comments[$i];
|
324 |
+
$commentPlaceholder = $this->getCommentPlaceholderById($i);
|
325 |
+
$commentPlaceholderRegex = $this->getCommentPlaceholderRegexById($i);
|
326 |
+
|
327 |
+
// ! in the first position of the comment means preserve
|
328 |
+
// so push to the preserved tokens keeping the !
|
329 |
+
if (preg_match('/^!/', $comment)) {
|
330 |
+
$preservedTokenPlaceholder = $this->registerPreservedToken($comment);
|
331 |
+
$css = preg_replace($commentPlaceholderRegex, $preservedTokenPlaceholder, $css, 1);
|
332 |
+
// Preserve new lines for /*! important comments
|
333 |
+
$css = preg_replace('/\R+\s*(\/\*'. $preservedTokenPlaceholder .')/', self::NL.'$1', $css);
|
334 |
+
$css = preg_replace('/('. $preservedTokenPlaceholder .'\*\/)\s*\R+/', '$1'.self::NL, $css);
|
335 |
+
continue;
|
336 |
+
}
|
337 |
+
|
338 |
+
// \ in the last position looks like hack for Mac/IE5
|
339 |
+
// shorten that to /*\*/ and the next one to /**/
|
340 |
+
if (preg_match('/\\\\$/', $comment)) {
|
341 |
+
$preservedTokenPlaceholder = $this->registerPreservedToken('\\');
|
342 |
+
$css = preg_replace($commentPlaceholderRegex, $preservedTokenPlaceholder, $css, 1);
|
343 |
+
$i = $i + 1; // attn: advancing the loop
|
344 |
+
$preservedTokenPlaceholder = $this->registerPreservedToken('');
|
345 |
+
$css = preg_replace($this->getCommentPlaceholderRegexById($i), $preservedTokenPlaceholder, $css, 1);
|
346 |
+
continue;
|
347 |
+
}
|
348 |
+
|
349 |
+
// keep empty comments after child selectors (IE7 hack)
|
350 |
+
// e.g. html >/**/ body
|
351 |
+
if (strlen($comment) === 0) {
|
352 |
+
$startIndex = $this->indexOf($css, $commentPlaceholder);
|
353 |
+
if ($startIndex > 2) {
|
354 |
+
if (substr($css, $startIndex - 3, 1) === '>') {
|
355 |
+
$preservedTokenPlaceholder = $this->registerPreservedToken('');
|
356 |
+
$css = preg_replace($commentPlaceholderRegex, $preservedTokenPlaceholder, $css, 1);
|
357 |
+
continue;
|
358 |
+
}
|
359 |
+
}
|
360 |
+
}
|
361 |
+
|
362 |
+
// in all other cases kill the comment
|
363 |
+
$css = preg_replace('/\/\*' . $commentPlaceholder . '\*\//', '', $css, 1);
|
364 |
+
}
|
365 |
+
|
366 |
+
// Normalize all whitespace strings to single spaces. Easier to work with that way.
|
367 |
+
$css = preg_replace('/\s+/', ' ', $css);
|
368 |
+
|
369 |
+
// Remove spaces before & after newlines
|
370 |
+
$css = preg_replace('/\s*'. self::NL .'\s*/', self::NL, $css);
|
371 |
+
|
372 |
+
// Fix IE7 issue on matrix filters which browser accept whitespaces between Matrix parameters
|
373 |
+
$css = preg_replace_callback(
|
374 |
+
'/\s*filter:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^)]+)\)/',
|
375 |
+
array($this, 'processOldIeSpecificMatrixDefinition'),
|
376 |
+
$css
|
377 |
+
);
|
378 |
+
|
379 |
+
// Shorten & preserve calculations calc(...) since spaces are important
|
380 |
+
$css = preg_replace_callback('/calc(\(((?:[^()]+|(?1))*)\))/i', array($this, 'processCalc'), $css);
|
381 |
+
|
382 |
+
// Replace positive sign from numbers preceded by : or a white-space before the leading space is removed
|
383 |
+
// +1.2em to 1.2em, +.8px to .8px, +2% to 2%
|
384 |
+
$css = preg_replace('/((?<!\\\\):|\s)\+(\.?\d+)/S', '$1$2', $css);
|
385 |
+
|
386 |
+
// Remove leading zeros from integer and float numbers preceded by : or a white-space
|
387 |
+
// 000.6 to .6, -0.8 to -.8, 0050 to 50, -01.05 to -1.05
|
388 |
+
$css = preg_replace('/((?<!\\\\):|\s)(-?)0+(\.?\d+)/S', '$1$2$3', $css);
|
389 |
+
|
390 |
+
// Remove trailing zeros from float numbers preceded by : or a white-space
|
391 |
+
// -6.0100em to -6.01em, .0100 to .01, 1.200px to 1.2px
|
392 |
+
$css = preg_replace('/((?<!\\\\):|\s)(-?)(\d?\.\d+?)0+([^\d])/S', '$1$2$3$4', $css);
|
393 |
+
|
394 |
+
// Remove trailing .0 -> -9.0 to -9
|
395 |
+
$css = preg_replace('/((?<!\\\\):|\s)(-?\d+)\.0([^\d])/S', '$1$2$3', $css);
|
396 |
+
|
397 |
+
// Replace 0 length numbers with 0
|
398 |
+
$css = preg_replace('/((?<!\\\\):|\s)-?\.?0+([^\d])/S', '${1}0$2', $css);
|
399 |
+
|
400 |
+
// Remove the spaces before the things that should not have spaces before them.
|
401 |
+
// But, be careful not to turn "p :link {...}" into "p:link{...}"
|
402 |
+
// Swap out any pseudo-class colons with the token, and then swap back.
|
403 |
+
$css = preg_replace_callback('/(?:^|\})[^{]*\s+:/', array($this, 'processColon'), $css);
|
404 |
+
|
405 |
+
// Remove spaces before the things that should not have spaces before them.
|
406 |
+
$css = preg_replace('/\s+([!{};:>+()\]~=,])/', '$1', $css);
|
407 |
+
|
408 |
+
// Restore spaces for !important
|
409 |
+
$css = preg_replace('/!important/i', ' !important', $css);
|
410 |
+
|
411 |
+
// bring back the colon
|
412 |
+
$css = preg_replace('/'. self::CLASSCOLON .'/', ':', $css);
|
413 |
+
|
414 |
+
// retain space for special IE6 cases
|
415 |
+
$css = preg_replace_callback('/:first-(line|letter)(\{|,)/i', array($this, 'lowercasePseudoFirst'), $css);
|
416 |
+
|
417 |
+
// no space after the end of a preserved comment
|
418 |
+
$css = preg_replace('/\*\/ /', '*/', $css);
|
419 |
+
|
420 |
+
// lowercase some popular @directives
|
421 |
+
$css = preg_replace_callback(
|
422 |
+
'/@(document|font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframes|media|namespace|page|' .
|
423 |
+
'supports|viewport)/i',
|
424 |
+
array($this, 'lowercaseDirectives'),
|
425 |
+
$css
|
426 |
+
);
|
427 |
+
|
428 |
+
// lowercase some more common pseudo-elements
|
429 |
+
$css = preg_replace_callback(
|
430 |
+
'/:(active|after|before|checked|disabled|empty|enabled|first-(?:child|of-type)|focus|hover|' .
|
431 |
+
'last-(?:child|of-type)|link|only-(?:child|of-type)|root|:selection|target|visited)/i',
|
432 |
+
array($this, 'lowercasePseudoElements'),
|
433 |
+
$css
|
434 |
+
);
|
435 |
+
|
436 |
+
// lowercase some more common functions
|
437 |
+
$css = preg_replace_callback(
|
438 |
+
'/:(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\(/i',
|
439 |
+
array($this, 'lowercaseCommonFunctions'),
|
440 |
+
$css
|
441 |
+
);
|
442 |
+
|
443 |
+
// lower case some common function that can be values
|
444 |
+
// NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us
|
445 |
+
$css = preg_replace_callback(
|
446 |
+
'/([:,( ]\s*)(attr|color-stop|from|rgba|to|url|-webkit-gradient|' .
|
447 |
+
'(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient))/iS',
|
448 |
+
array($this, 'lowercaseCommonFunctionsValues'),
|
449 |
+
$css
|
450 |
+
);
|
451 |
+
|
452 |
+
// Put the space back in some cases, to support stuff like
|
453 |
+
// @media screen and (-webkit-min-device-pixel-ratio:0){
|
454 |
+
$css = preg_replace_callback('/(\s|\)\s)(and|not|or)\(/i', array($this, 'processAtRulesOperators'), $css);
|
455 |
+
|
456 |
+
// Remove the spaces after the things that should not have spaces after them.
|
457 |
+
$css = preg_replace('/([!{}:;>+(\[~=,])\s+/S', '$1', $css);
|
458 |
+
|
459 |
+
// remove unnecessary semicolons
|
460 |
+
$css = preg_replace('/;+\}/', '}', $css);
|
461 |
+
|
462 |
+
// Fix for issue: #2528146
|
463 |
+
// Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack)
|
464 |
+
// to avoid issues on Symbian S60 3.x browsers.
|
465 |
+
$css = preg_replace('/(\*[a-z0-9\-]+\s*:[^;}]+)(\})/', '$1;$2', $css);
|
466 |
+
|
467 |
+
// Shorten zero values for safe properties only
|
468 |
+
$css = $this->shortenZeroValues($css);
|
469 |
+
|
470 |
+
// Shorten font-weight values
|
471 |
+
$css = preg_replace('/(font-weight:)bold\b/i', '${1}700', $css);
|
472 |
+
$css = preg_replace('/(font-weight:)normal\b/i', '${1}400', $css);
|
473 |
+
|
474 |
+
// Shorten suitable shorthand properties with repeated non-zero values
|
475 |
+
$css = preg_replace(
|
476 |
+
'/(margin|padding):('.$this->numRegex.') ('.$this->numRegex.') (?:\2) (?:\3)(;|\}| !)/i',
|
477 |
+
'$1:$2 $3$4',
|
478 |
+
$css
|
479 |
+
);
|
480 |
+
$css = preg_replace(
|
481 |
+
'/(margin|padding):('.$this->numRegex.') ('.$this->numRegex.') ('.$this->numRegex.') (?:\3)(;|\}| !)/i',
|
482 |
+
'$1:$2 $3 $4$5',
|
483 |
+
$css
|
484 |
+
);
|
485 |
+
|
486 |
+
// Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space)
|
487 |
+
// Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space)
|
488 |
+
// This makes it more likely that it'll get further compressed in the next step.
|
489 |
+
$css = preg_replace_callback('/rgb\s*\(\s*([0-9,\s\-.%]+)\s*\)(.{1})/i', array($this, 'rgbToHex'), $css);
|
490 |
+
$css = preg_replace_callback('/hsl\s*\(\s*([0-9,\s\-.%]+)\s*\)(.{1})/i', array($this, 'hslToHex'), $css);
|
491 |
+
|
492 |
+
// Shorten colors from #AABBCC to #ABC or shorter color name.
|
493 |
+
$css = $this->shortenHexColors($css);
|
494 |
+
|
495 |
+
// Shorten long named colors: white -> #fff.
|
496 |
+
$css = $this->shortenNamedColors($css);
|
497 |
+
|
498 |
+
// shorter opacity IE filter
|
499 |
+
$css = preg_replace('/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/i', 'alpha(opacity=', $css);
|
500 |
+
|
501 |
+
// Find a fraction that is used for Opera's -o-device-pixel-ratio query
|
502 |
+
// Add token to add the "\" back in later
|
503 |
+
$css = preg_replace('/\(([a-z\-]+):([0-9]+)\/([0-9]+)\)/i', '($1:$2'. self::QUERY_FRACTION .'$3)', $css);
|
504 |
+
|
505 |
+
// Patch new lines to avoid being removed when followed by empty rules cases
|
506 |
+
$css = preg_replace('/'. self::NL .'/', self::NL .'}', $css);
|
507 |
+
|
508 |
+
// Remove empty rules.
|
509 |
+
$css = preg_replace('/[^{};\/]+\{\}/S', '', $css);
|
510 |
+
|
511 |
+
// Restore new lines for /*! important comments
|
512 |
+
$css = preg_replace('/'. self::NL .'}/', "\n", $css);
|
513 |
+
|
514 |
+
// Add "/" back to fix Opera -o-device-pixel-ratio query
|
515 |
+
$css = preg_replace('/'. self::QUERY_FRACTION .'/', '/', $css);
|
516 |
+
|
517 |
+
// Replace multiple semi-colons in a row by a single one
|
518 |
+
// See SF bug #1980989
|
519 |
+
$css = preg_replace('/;;+/', ';', $css);
|
520 |
+
|
521 |
+
// Lowercase all uppercase properties
|
522 |
+
$css = preg_replace_callback('/(\{|;)([A-Z\-]+)(:)/', array($this, 'lowercaseProperties'), $css);
|
523 |
+
|
524 |
+
// Some source control tools don't like it when files containing lines longer
|
525 |
+
// than, say 8000 characters, are checked in. The linebreak option is used in
|
526 |
+
// that case to split long lines after a specific column.
|
527 |
+
if ($linebreakPos !== false && (int) $linebreakPos >= 0) {
|
528 |
+
$linebreakPos = (int) $linebreakPos;
|
529 |
+
for ($startIndex = $i = 1, $l = strlen($css); $i < $l; $i++) {
|
530 |
+
if ($css[$i - 1] === '}' && $i - $startIndex > $linebreakPos) {
|
531 |
+
$css = $this->strSlice($css, 0, $i) . "\n" . $this->strSlice($css, $i);
|
532 |
+
$l = strlen($css);
|
533 |
+
$startIndex = $i;
|
534 |
+
}
|
535 |
+
}
|
536 |
+
}
|
537 |
+
|
538 |
+
// restore preserved comments and strings in reverse order
|
539 |
+
for ($i = count($this->preservedTokens) - 1; $i >= 0; $i--) {
|
540 |
+
$css = preg_replace(
|
541 |
+
$this->getPreservedTokenPlaceholderRegexById($i),
|
542 |
+
$this->escapeReplacementString($this->preservedTokens[$i]),
|
543 |
+
$css,
|
544 |
+
1
|
545 |
+
);
|
546 |
+
}
|
547 |
+
|
548 |
+
// Trim the final string for any leading or trailing white space but respect newlines!
|
549 |
+
$css = preg_replace('/(^ | $)/', '', $css);
|
550 |
+
|
551 |
+
return $css;
|
552 |
+
}
|
553 |
+
|
554 |
+
/**
|
555 |
+
* Searches & replaces all data urls with tokens before we start compressing,
|
556 |
+
* to avoid performance issues running some of the subsequent regexes against large string chunks.
|
557 |
+
* @param string $css
|
558 |
+
* @return string
|
559 |
+
*/
|
560 |
+
private function processDataUrls($css)
|
561 |
+
{
|
562 |
+
// Leave data urls alone to increase parse performance.
|
563 |
+
$maxIndex = strlen($css) - 1;
|
564 |
+
$appenIndex = $index = $lastIndex = $offset = 0;
|
565 |
+
$sb = array();
|
566 |
+
$pattern = '/url\(\s*(["\']?)data:/i';
|
567 |
+
|
568 |
+
// Since we need to account for non-base64 data urls, we need to handle
|
569 |
+
// ' and ) being part of the data string. Hence switching to indexOf,
|
570 |
+
// to determine whether or not we have matching string terminators and
|
571 |
+
// handling sb appends directly, instead of using matcher.append* methods.
|
572 |
+
while (preg_match($pattern, $css, $m, 0, $offset)) {
|
573 |
+
$index = $this->indexOf($css, $m[0], $offset);
|
574 |
+
$lastIndex = $index + strlen($m[0]);
|
575 |
+
$startIndex = $index + 4; // "url(".length()
|
576 |
+
$endIndex = $lastIndex - 1;
|
577 |
+
$terminator = $m[1]; // ', " or empty (not quoted)
|
578 |
+
$terminatorFound = false;
|
579 |
+
|
580 |
+
if (strlen($terminator) === 0) {
|
581 |
+
$terminator = ')';
|
582 |
+
}
|
583 |
+
|
584 |
+
while ($terminatorFound === false && $endIndex+1 <= $maxIndex) {
|
585 |
+
$endIndex = $this->indexOf($css, $terminator, $endIndex + 1);
|
586 |
+
// endIndex == 0 doesn't really apply here
|
587 |
+
if ($endIndex > 0 && substr($css, $endIndex - 1, 1) !== '\\') {
|
588 |
+
$terminatorFound = true;
|
589 |
+
if (')' !== $terminator) {
|
590 |
+
$endIndex = $this->indexOf($css, ')', $endIndex);
|
591 |
+
}
|
592 |
+
}
|
593 |
+
}
|
594 |
+
|
595 |
+
// Enough searching, start moving stuff over to the buffer
|
596 |
+
$sb[] = $this->strSlice($css, $appenIndex, $index);
|
597 |
+
|
598 |
+
if ($terminatorFound) {
|
599 |
+
$token = $this->strSlice($css, $startIndex, $endIndex);
|
600 |
+
// Remove all spaces only for base64 encoded URLs.
|
601 |
+
$token = preg_replace_callback(
|
602 |
+
'/.+base64,.+/s',
|
603 |
+
array($this, 'removeSpacesFromDataUrls'),
|
604 |
+
trim($token)
|
605 |
+
);
|
606 |
+
$preservedTokenPlaceholder = $this->registerPreservedToken($token);
|
607 |
+
$sb[] = 'url('. $preservedTokenPlaceholder .')';
|
608 |
+
$appenIndex = $endIndex + 1;
|
609 |
+
} else {
|
610 |
+
// No end terminator found, re-add the whole match. Should we throw/warn here?
|
611 |
+
$sb[] = $this->strSlice($css, $index, $lastIndex);
|
612 |
+
$appenIndex = $lastIndex;
|
613 |
+
}
|
614 |
+
|
615 |
+
$offset = $lastIndex;
|
616 |
+
}
|
617 |
+
|
618 |
+
$sb[] = $this->strSlice($css, $appenIndex);
|
619 |
+
|
620 |
+
return implode('', $sb);
|
621 |
+
}
|
622 |
+
|
623 |
+
/**
|
624 |
+
* Shortens all zero values for a set of safe properties
|
625 |
+
* e.g. padding: 0px 1px; -> padding:0 1px
|
626 |
+
* e.g. padding: 0px 0rem 0em 0.0pc; -> padding:0
|
627 |
+
* @param string $css
|
628 |
+
* @return string
|
629 |
+
*/
|
630 |
+
private function shortenZeroValues($css)
|
631 |
+
{
|
632 |
+
$unitsGroupReg = $this->unitsGroupRegex;
|
633 |
+
$numOrPosReg = '('. $this->numRegex .'|top|left|bottom|right|center)';
|
634 |
+
$oneZeroSafeProperties = array(
|
635 |
+
'(?:line-)?height',
|
636 |
+
'(?:(?:min|max)-)?width',
|
637 |
+
'top',
|
638 |
+
'left',
|
639 |
+
'background-position',
|
640 |
+
'bottom',
|
641 |
+
'right',
|
642 |
+
'border(?:-(?:top|left|bottom|right))?(?:-width)?',
|
643 |
+
'border-(?:(?:top|bottom)-(?:left|right)-)?radius',
|
644 |
+
'column-(?:gap|width)',
|
645 |
+
'margin(?:-(?:top|left|bottom|right))?',
|
646 |
+
'outline-width',
|
647 |
+
'padding(?:-(?:top|left|bottom|right))?'
|
648 |
+
);
|
649 |
+
$nZeroSafeProperties = array(
|
650 |
+
'margin',
|
651 |
+
'padding',
|
652 |
+
'background-position'
|
653 |
+
);
|
654 |
+
|
655 |
+
$regStart = '/(;|\{)';
|
656 |
+
$regEnd = '/i';
|
657 |
+
|
658 |
+
// First zero regex start
|
659 |
+
$oneZeroRegStart = $regStart .'('. implode('|', $oneZeroSafeProperties) .'):';
|
660 |
+
|
661 |
+
// Multiple zeros regex start
|
662 |
+
$nZerosRegStart = $regStart .'('. implode('|', $nZeroSafeProperties) .'):';
|
663 |
+
|
664 |
+
$css = preg_replace(
|
665 |
+
array(
|
666 |
+
$oneZeroRegStart .'0'. $unitsGroupReg . $regEnd,
|
667 |
+
$nZerosRegStart . $numOrPosReg .' 0'. $unitsGroupReg . $regEnd,
|
668 |
+
$nZerosRegStart . $numOrPosReg .' '. $numOrPosReg .' 0'. $unitsGroupReg . $regEnd,
|
669 |
+
$nZerosRegStart . $numOrPosReg .' '. $numOrPosReg .' '. $numOrPosReg .' 0'. $unitsGroupReg . $regEnd
|
670 |
+
),
|
671 |
+
array(
|
672 |
+
'$1$2:0',
|
673 |
+
'$1$2:$3 0',
|
674 |
+
'$1$2:$3 $4 0',
|
675 |
+
'$1$2:$3 $4 $5 0'
|
676 |
+
),
|
677 |
+
$css
|
678 |
+
);
|
679 |
+
|
680 |
+
// Remove background-position
|
681 |
+
array_pop($nZeroSafeProperties);
|
682 |
+
|
683 |
+
// Replace 0 0; or 0 0 0; or 0 0 0 0; with 0 for safe properties only.
|
684 |
+
$css = preg_replace(
|
685 |
+
'/('. implode('|', $nZeroSafeProperties) .'):0(?: 0){1,3}(;|\}| !)'. $regEnd,
|
686 |
+
'$1:0$2',
|
687 |
+
$css
|
688 |
+
);
|
689 |
+
|
690 |
+
// Replace 0 0 0; or 0 0 0 0; with 0 0 for background-position property.
|
691 |
+
$css = preg_replace('/(background-position):0(?: 0){2,3}(;|\}| !)'. $regEnd, '$1:0 0$2', $css);
|
692 |
+
|
693 |
+
return $css;
|
694 |
+
}
|
695 |
+
|
696 |
+
/**
|
697 |
+
* Shortens all named colors with a shorter HEX counterpart for a set of safe properties
|
698 |
+
* e.g. white -> #fff
|
699 |
+
* @param string $css
|
700 |
+
* @return string
|
701 |
+
*/
|
702 |
+
private function shortenNamedColors($css)
|
703 |
+
{
|
704 |
+
$patterns = array();
|
705 |
+
$replacements = array();
|
706 |
+
$longNamedColors = include 'data/named-to-hex-color-map.php';
|
707 |
+
$propertiesWithColors = array(
|
708 |
+
'color',
|
709 |
+
'background(?:-color)?',
|
710 |
+
'border(?:-(?:top|right|bottom|left|color)(?:-color)?)?',
|
711 |
+
'outline(?:-color)?',
|
712 |
+
'(?:text|box)-shadow'
|
713 |
+
);
|
714 |
+
|
715 |
+
$regStart = '/(;|\{)('. implode('|', $propertiesWithColors) .'):([^;}]*)\b';
|
716 |
+
$regEnd = '\b/iS';
|
717 |
+
|
718 |
+
foreach ($longNamedColors as $colorName => $colorCode) {
|
719 |
+
$patterns[] = $regStart . $colorName . $regEnd;
|
720 |
+
$replacements[] = '$1$2:$3'. $colorCode;
|
721 |
+
}
|
722 |
+
|
723 |
+
// Run at least 4 times to cover most cases (same color used several times for the same property)
|
724 |
+
for ($i = 0; $i < 4; $i++) {
|
725 |
+
$css = preg_replace($patterns, $replacements, $css);
|
726 |
+
}
|
727 |
+
|
728 |
+
return $css;
|
729 |
+
}
|
730 |
+
|
731 |
+
/**
|
732 |
+
* Compresses HEX color values of the form #AABBCC to #ABC or short color name.
|
733 |
+
*
|
734 |
+
* DOES NOT compress CSS ID selectors which match the above pattern (which would break things).
|
735 |
+
* e.g. #AddressForm { ... }
|
736 |
+
*
|
737 |
+
* DOES NOT compress IE filters, which have hex color values (which would break things).
|
738 |
+
* e.g. filter: chroma(color="#FFFFFF");
|
739 |
+
*
|
740 |
+
* DOES NOT compress invalid hex values.
|
741 |
+
* e.g. background-color: #aabbccdd
|
742 |
+
*
|
743 |
+
* @param string $css
|
744 |
+
* @return string
|
745 |
+
*/
|
746 |
+
private function shortenHexColors($css)
|
747 |
+
{
|
748 |
+
// Look for hex colors inside { ... } (to avoid IDs) and
|
749 |
+
// which don't have a =, or a " in front of them (to avoid filters)
|
750 |
+
$pattern =
|
751 |
+
'/(=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS';
|
752 |
+
$_index = $index = $lastIndex = $offset = 0;
|
753 |
+
$longHexColors = include 'data/hex-to-named-color-map.php';
|
754 |
+
$sb = array();
|
755 |
+
|
756 |
+
while (preg_match($pattern, $css, $m, 0, $offset)) {
|
757 |
+
$index = $this->indexOf($css, $m[0], $offset);
|
758 |
+
$lastIndex = $index + strlen($m[0]);
|
759 |
+
$isFilter = $m[1] !== null && $m[1] !== '';
|
760 |
+
|
761 |
+
$sb[] = $this->strSlice($css, $_index, $index);
|
762 |
+
|
763 |
+
if ($isFilter) {
|
764 |
+
// Restore, maintain case, otherwise filter will break
|
765 |
+
$sb[] = $m[1] .'#'. $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7];
|
766 |
+
} else {
|
767 |
+
if (strtolower($m[2]) == strtolower($m[3]) &&
|
768 |
+
strtolower($m[4]) == strtolower($m[5]) &&
|
769 |
+
strtolower($m[6]) == strtolower($m[7])) {
|
770 |
+
// Compress.
|
771 |
+
$hex = '#'. strtolower($m[3] . $m[5] . $m[7]);
|
772 |
+
} else {
|
773 |
+
// Non compressible color, restore but lower case.
|
774 |
+
$hex = '#'. strtolower($m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]);
|
775 |
+
}
|
776 |
+
// replace Hex colors with shorter color names
|
777 |
+
$sb[] = array_key_exists($hex, $longHexColors) ? $longHexColors[$hex] : $hex;
|
778 |
+
}
|
779 |
+
|
780 |
+
$_index = $offset = $lastIndex - strlen($m[8]);
|
781 |
+
}
|
782 |
+
|
783 |
+
$sb[] = $this->strSlice($css, $_index);
|
784 |
+
|
785 |
+
return implode('', $sb);
|
786 |
+
}
|
787 |
+
|
788 |
+
// ---------------------------------------------------------------------------------------------
|
789 |
+
// CALLBACKS
|
790 |
+
// ---------------------------------------------------------------------------------------------
|
791 |
+
|
792 |
+
private function processComments($matches)
|
793 |
+
{
|
794 |
+
$match = !empty($matches[1]) ? $matches[1] : '';
|
795 |
+
return $this->registerComment($match);
|
796 |
+
}
|
797 |
+
|
798 |
+
private function processStrings($matches)
|
799 |
+
{
|
800 |
+
$match = $matches[0];
|
801 |
+
$quote = substr($match, 0, 1);
|
802 |
+
$match = $this->strSlice($match, 1, -1);
|
803 |
+
|
804 |
+
// maybe the string contains a comment-like substring?
|
805 |
+
// one, maybe more? put'em back then
|
806 |
+
if (($pos = strpos($match, self::COMMENT)) !== false) {
|
807 |
+
for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
|
808 |
+
$match = preg_replace(
|
809 |
+
$this->getCommentPlaceholderRegexById($i),
|
810 |
+
$this->escapeReplacementString($this->comments[$i]),
|
811 |
+
$match,
|
812 |
+
1
|
813 |
+
);
|
814 |
+
}
|
815 |
+
}
|
816 |
+
|
817 |
+
// minify alpha opacity in filter strings
|
818 |
+
$match = preg_replace('/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/i', 'alpha(opacity=', $match);
|
819 |
+
|
820 |
+
$preservedTokenPlaceholder = $this->registerPreservedToken($match);
|
821 |
+
return $quote . $preservedTokenPlaceholder . $quote;
|
822 |
+
}
|
823 |
+
|
824 |
+
private function processAtRuleBlocks($matches)
|
825 |
+
{
|
826 |
+
return $this->registerAtRuleBlock($matches[0]);
|
827 |
+
}
|
828 |
+
|
829 |
+
private function processCalc($matches)
|
830 |
+
{
|
831 |
+
$token = preg_replace(
|
832 |
+
'/\)([+\-]{1})/',
|
833 |
+
') $1',
|
834 |
+
preg_replace(
|
835 |
+
'/([+\-]{1})\(/',
|
836 |
+
'$1 (',
|
837 |
+
trim(preg_replace('/\s*([*\/(),])\s*/', '$1', $matches[2]))
|
838 |
+
)
|
839 |
+
);
|
840 |
+
$preservedTokenPlaceholder = $this->registerPreservedToken($token);
|
841 |
+
return 'calc('. $preservedTokenPlaceholder .')';
|
842 |
+
}
|
843 |
+
|
844 |
+
private function processOldIeSpecificMatrixDefinition($matches)
|
845 |
+
{
|
846 |
+
$preservedTokenPlaceholder = $this->registerPreservedToken($matches[1]);
|
847 |
+
return 'filter:progid:DXImageTransform.Microsoft.Matrix('. $preservedTokenPlaceholder .')';
|
848 |
+
}
|
849 |
+
|
850 |
+
private function processColon($matches)
|
851 |
+
{
|
852 |
+
return preg_replace('/\:/', self::CLASSCOLON, $matches[0]);
|
853 |
+
}
|
854 |
+
|
855 |
+
private function removeSpacesFromDataUrls($matches)
|
856 |
+
{
|
857 |
+
return preg_replace('/\s+/', '', $matches[0]);
|
858 |
+
}
|
859 |
+
|
860 |
+
private function rgbToHex($matches)
|
861 |
+
{
|
862 |
+
$hexColors = array();
|
863 |
+
$rgbColors = explode(',', $matches[1]);
|
864 |
+
|
865 |
+
// Values outside the sRGB color space should be clipped (0-255)
|
866 |
+
for ($i = 0, $l = count($rgbColors); $i < $l; $i++) {
|
867 |
+
$hexColors[$i] = sprintf("%02x", $this->clampNumberSrgb($this->rgbPercentageToRgbInteger($rgbColors[$i])));
|
868 |
+
}
|
869 |
+
|
870 |
+
// Fix for issue #2528093
|
871 |
+
if (!preg_match('/[\s,);}]/', $matches[2])) {
|
872 |
+
$matches[2] = ' '. $matches[2];
|
873 |
+
}
|
874 |
+
|
875 |
+
return '#'. implode('', $hexColors) . $matches[2];
|
876 |
+
}
|
877 |
+
|
878 |
+
private function hslToHex($matches)
|
879 |
+
{
|
880 |
+
$hslValues = explode(',', $matches[1]);
|
881 |
+
|
882 |
+
$rgbColors = $this->hslToRgb($hslValues);
|
883 |
+
|
884 |
+
return $this->rgbToHex(array('', implode(',', $rgbColors), $matches[2]));
|
885 |
+
}
|
886 |
+
|
887 |
+
private function processAtRulesOperators($matches)
|
888 |
+
{
|
889 |
+
return $matches[1] . strtolower($matches[2]) .' (';
|
890 |
+
}
|
891 |
+
|
892 |
+
private function lowercasePseudoFirst($matches)
|
893 |
+
{
|
894 |
+
return ':first-'. strtolower($matches[1]) .' '. $matches[2];
|
895 |
+
}
|
896 |
+
|
897 |
+
private function lowercaseDirectives($matches)
|
898 |
+
{
|
899 |
+
return '@'. strtolower($matches[1]);
|
900 |
+
}
|
901 |
+
|
902 |
+
private function lowercasePseudoElements($matches)
|
903 |
+
{
|
904 |
+
return ':'. strtolower($matches[1]);
|
905 |
+
}
|
906 |
+
|
907 |
+
private function lowercaseCommonFunctions($matches)
|
908 |
+
{
|
909 |
+
return ':'. strtolower($matches[1]) .'(';
|
910 |
+
}
|
911 |
+
|
912 |
+
private function lowercaseCommonFunctionsValues($matches)
|
913 |
+
{
|
914 |
+
return $matches[1] . strtolower($matches[2]);
|
915 |
+
}
|
916 |
+
|
917 |
+
private function lowercaseProperties($matches)
|
918 |
+
{
|
919 |
+
return $matches[1] . strtolower($matches[2]) . $matches[3];
|
920 |
+
}
|
921 |
+
|
922 |
+
// ---------------------------------------------------------------------------------------------
|
923 |
+
// HELPERS
|
924 |
+
// ---------------------------------------------------------------------------------------------
|
925 |
+
|
926 |
+
/**
|
927 |
+
* Clamps a number between a minimum and a maximum value.
|
928 |
+
* @param int|float $n the number to clamp
|
929 |
+
* @param int|float $min the lower end number allowed
|
930 |
+
* @param int|float $max the higher end number allowed
|
931 |
+
* @return int|float
|
932 |
+
*/
|
933 |
+
private function clampNumber($n, $min, $max)
|
934 |
+
{
|
935 |
+
return min(max($n, $min), $max);
|
936 |
+
}
|
937 |
+
|
938 |
+
/**
|
939 |
+
* Clamps a RGB color number outside the sRGB color space
|
940 |
+
* @param int|float $n the number to clamp
|
941 |
+
* @return int|float
|
942 |
+
*/
|
943 |
+
private function clampNumberSrgb($n)
|
944 |
+
{
|
945 |
+
return $this->clampNumber($n, 0, 255);
|
946 |
+
}
|
947 |
+
|
948 |
+
/**
|
949 |
+
* Escapes backreferences such as \1 and $1 in a regular expression replacement string
|
950 |
+
* @param $string
|
951 |
+
* @return string
|
952 |
+
*/
|
953 |
+
private function escapeReplacementString($string)
|
954 |
+
{
|
955 |
+
return addcslashes($string, '\\$');
|
956 |
+
}
|
957 |
+
|
958 |
+
/**
|
959 |
+
* Converts a HSL color into a RGB color
|
960 |
+
* @param array $hslValues
|
961 |
+
* @return array
|
962 |
+
*/
|
963 |
+
private function hslToRgb($hslValues)
|
964 |
+
{
|
965 |
+
$h = floatval($hslValues[0]);
|
966 |
+
$s = floatval(str_replace('%', '', $hslValues[1]));
|
967 |
+
$l = floatval(str_replace('%', '', $hslValues[2]));
|
968 |
+
|
969 |
+
// Wrap and clamp, then fraction!
|
970 |
+
$h = ((($h % 360) + 360) % 360) / 360;
|
971 |
+
$s = $this->clampNumber($s, 0, 100) / 100;
|
972 |
+
$l = $this->clampNumber($l, 0, 100) / 100;
|
973 |
+
|
974 |
+
if ($s == 0) {
|
975 |
+
$r = $g = $b = $this->roundNumber(255 * $l);
|
976 |
+
} else {
|
977 |
+
$v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l);
|
978 |
+
$v1 = (2 * $l) - $v2;
|
979 |
+
$r = $this->roundNumber(255 * $this->hueToRgb($v1, $v2, $h + (1/3)));
|
980 |
+
$g = $this->roundNumber(255 * $this->hueToRgb($v1, $v2, $h));
|
981 |
+
$b = $this->roundNumber(255 * $this->hueToRgb($v1, $v2, $h - (1/3)));
|
982 |
+
}
|
983 |
+
|
984 |
+
return array($r, $g, $b);
|
985 |
+
}
|
986 |
+
|
987 |
+
/**
|
988 |
+
* Tests and selects the correct formula for each RGB color channel
|
989 |
+
* @param $v1
|
990 |
+
* @param $v2
|
991 |
+
* @param $vh
|
992 |
+
* @return mixed
|
993 |
+
*/
|
994 |
+
private function hueToRgb($v1, $v2, $vh)
|
995 |
+
{
|
996 |
+
$vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh);
|
997 |
+
|
998 |
+
if ($vh * 6 < 1) {
|
999 |
+
return $v1 + ($v2 - $v1) * 6 * $vh;
|
1000 |
+
}
|
1001 |
+
|
1002 |
+
if ($vh * 2 < 1) {
|
1003 |
+
return $v2;
|
1004 |
+
}
|
1005 |
+
|
1006 |
+
if ($vh * 3 < 2) {
|
1007 |
+
return $v1 + ($v2 - $v1) * ((2 / 3) - $vh) * 6;
|
1008 |
+
}
|
1009 |
+
|
1010 |
+
return $v1;
|
1011 |
+
}
|
1012 |
+
|
1013 |
+
/**
|
1014 |
+
* PHP port of Javascript's "indexOf" function for strings only
|
1015 |
+
* Author: Tubal Martin
|
1016 |
+
*
|
1017 |
+
* @param string $haystack
|
1018 |
+
* @param string $needle
|
1019 |
+
* @param int $offset index (optional)
|
1020 |
+
* @return int
|
1021 |
+
*/
|
1022 |
+
private function indexOf($haystack, $needle, $offset = 0)
|
1023 |
+
{
|
1024 |
+
$index = strpos($haystack, $needle, $offset);
|
1025 |
+
|
1026 |
+
return ($index !== false) ? $index : -1;
|
1027 |
+
}
|
1028 |
+
|
1029 |
+
/**
|
1030 |
+
* Convert strings like "64M" or "30" to int values
|
1031 |
+
* @param mixed $size
|
1032 |
+
* @return int
|
1033 |
+
*/
|
1034 |
+
private function normalizeInt($size)
|
1035 |
+
{
|
1036 |
+
if (is_string($size)) {
|
1037 |
+
$letter = substr($size, -1);
|
1038 |
+
$size = intval($size);
|
1039 |
+
switch ($letter) {
|
1040 |
+
case 'M':
|
1041 |
+
case 'm':
|
1042 |
+
return (int) $size * 1048576;
|
1043 |
+
case 'K':
|
1044 |
+
case 'k':
|
1045 |
+
return (int) $size * 1024;
|
1046 |
+
case 'G':
|
1047 |
+
case 'g':
|
1048 |
+
return (int) $size * 1073741824;
|
1049 |
+
}
|
1050 |
+
}
|
1051 |
+
return (int) $size;
|
1052 |
+
}
|
1053 |
+
|
1054 |
+
/**
|
1055 |
+
* Converts a string containing and RGB percentage value into a RGB integer value i.e. '90%' -> 229.5
|
1056 |
+
* @param $rgbPercentage
|
1057 |
+
* @return int
|
1058 |
+
*/
|
1059 |
+
private function rgbPercentageToRgbInteger($rgbPercentage)
|
1060 |
+
{
|
1061 |
+
if (strpos($rgbPercentage, '%') !== false) {
|
1062 |
+
$rgbPercentage = $this->roundNumber(floatval(str_replace('%', '', $rgbPercentage)) * 2.55);
|
1063 |
+
}
|
1064 |
+
|
1065 |
+
return intval($rgbPercentage, 10);
|
1066 |
+
}
|
1067 |
+
|
1068 |
+
/**
|
1069 |
+
* Rounds a number to its closest integer
|
1070 |
+
* @param $n
|
1071 |
+
* @return int
|
1072 |
+
*/
|
1073 |
+
private function roundNumber($n)
|
1074 |
+
{
|
1075 |
+
return intval(round(floatval($n)), 10);
|
1076 |
+
}
|
1077 |
+
|
1078 |
+
/**
|
1079 |
+
* PHP port of Javascript's "slice" function for strings only
|
1080 |
+
* Author: Tubal Martin
|
1081 |
+
*
|
1082 |
+
* @param string $str
|
1083 |
+
* @param int $start index
|
1084 |
+
* @param int|bool $end index (optional)
|
1085 |
+
* @return string
|
1086 |
+
*/
|
1087 |
+
private function strSlice($str, $start = 0, $end = false)
|
1088 |
+
{
|
1089 |
+
if ($end !== false && ($start < 0 || $end <= 0)) {
|
1090 |
+
$max = strlen($str);
|
1091 |
+
|
1092 |
+
if ($start < 0) {
|
1093 |
+
if (($start = $max + $start) < 0) {
|
1094 |
+
return '';
|
1095 |
+
}
|
1096 |
+
}
|
1097 |
+
|
1098 |
+
if ($end < 0) {
|
1099 |
+
if (($end = $max + $end) < 0) {
|
1100 |
+
return '';
|
1101 |
+
}
|
1102 |
+
}
|
1103 |
+
|
1104 |
+
if ($end <= $start) {
|
1105 |
+
return '';
|
1106 |
+
}
|
1107 |
+
}
|
1108 |
+
|
1109 |
+
$slice = ($end === false) ? substr($str, $start) : substr($str, $start, $end - $start);
|
1110 |
+
return ($slice === false) ? '' : $slice;
|
1111 |
+
}
|
1112 |
+
}
|
classes/external/php/yui-php-cssmin-2.4.8-p10/data/hex-to-named-color-map.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// Hex colors longer than named counterpart
|
4 |
+
return array(
|
5 |
+
'#f0ffff' => 'azure',
|
6 |
+
'#f5f5dc' => 'beige',
|
7 |
+
'#ffe4c4' => 'bisque',
|
8 |
+
'#a52a2a' => 'brown',
|
9 |
+
'#ff7f50' => 'coral',
|
10 |
+
'#ffd700' => 'gold',
|
11 |
+
'#808080' => 'gray',
|
12 |
+
'#008000' => 'green',
|
13 |
+
'#4b0082' => 'indigo',
|
14 |
+
'#fffff0' => 'ivory',
|
15 |
+
'#f0e68c' => 'khaki',
|
16 |
+
'#faf0e6' => 'linen',
|
17 |
+
'#800000' => 'maroon',
|
18 |
+
'#000080' => 'navy',
|
19 |
+
'#fdf5e6' => 'oldlace',
|
20 |
+
'#808000' => 'olive',
|
21 |
+
'#ffa500' => 'orange',
|
22 |
+
'#da70d6' => 'orchid',
|
23 |
+
'#cd853f' => 'peru',
|
24 |
+
'#ffc0cb' => 'pink',
|
25 |
+
'#dda0dd' => 'plum',
|
26 |
+
'#800080' => 'purple',
|
27 |
+
'#f00' => 'red',
|
28 |
+
'#fa8072' => 'salmon',
|
29 |
+
'#a0522d' => 'sienna',
|
30 |
+
'#c0c0c0' => 'silver',
|
31 |
+
'#fffafa' => 'snow',
|
32 |
+
'#d2b48c' => 'tan',
|
33 |
+
'#008080' => 'teal',
|
34 |
+
'#ff6347' => 'tomato',
|
35 |
+
'#ee82ee' => 'violet',
|
36 |
+
'#f5deb3' => 'wheat'
|
37 |
+
);
|
classes/external/php/yui-php-cssmin-2.4.8-p10/data/named-to-hex-color-map.php
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// Named colors longer than hex counterpart
|
4 |
+
return array(
|
5 |
+
'aliceblue' => '#f0f8ff',
|
6 |
+
'antiquewhite' => '#faebd7',
|
7 |
+
'aquamarine' => '#7fffd4',
|
8 |
+
'black' => '#000',
|
9 |
+
'blanchedalmond' => '#ffebcd',
|
10 |
+
'blueviolet' => '#8a2be2',
|
11 |
+
'burlywood' => '#deb887',
|
12 |
+
'cadetblue' => '#5f9ea0',
|
13 |
+
'chartreuse' => '#7fff00',
|
14 |
+
'chocolate' => '#d2691e',
|
15 |
+
'cornflowerblue' => '#6495ed',
|
16 |
+
'cornsilk' => '#fff8dc',
|
17 |
+
'darkblue' => '#00008b',
|
18 |
+
'darkcyan' => '#008b8b',
|
19 |
+
'darkgoldenrod' => '#b8860b',
|
20 |
+
'darkgray' => '#a9a9a9',
|
21 |
+
'darkgreen' => '#006400',
|
22 |
+
'darkgrey' => '#a9a9a9',
|
23 |
+
'darkkhaki' => '#bdb76b',
|
24 |
+
'darkmagenta' => '#8b008b',
|
25 |
+
'darkolivegreen' => '#556b2f',
|
26 |
+
'darkorange' => '#ff8c00',
|
27 |
+
'darkorchid' => '#9932cc',
|
28 |
+
'darksalmon' => '#e9967a',
|
29 |
+
'darkseagreen' => '#8fbc8f',
|
30 |
+
'darkslateblue' => '#483d8b',
|
31 |
+
'darkslategray' => '#2f4f4f',
|
32 |
+
'darkslategrey' => '#2f4f4f',
|
33 |
+
'darkturquoise' => '#00ced1',
|
34 |
+
'darkviolet' => '#9400d3',
|
35 |
+
'deeppink' => '#ff1493',
|
36 |
+
'deepskyblue' => '#00bfff',
|
37 |
+
'dodgerblue' => '#1e90ff',
|
38 |
+
'firebrick' => '#b22222',
|
39 |
+
'floralwhite' => '#fffaf0',
|
40 |
+
'forestgreen' => '#228b22',
|
41 |
+
'fuchsia' => '#f0f',
|
42 |
+
'gainsboro' => '#dcdcdc',
|
43 |
+
'ghostwhite' => '#f8f8ff',
|
44 |
+
'goldenrod' => '#daa520',
|
45 |
+
'greenyellow' => '#adff2f',
|
46 |
+
'honeydew' => '#f0fff0',
|
47 |
+
'indianred' => '#cd5c5c',
|
48 |
+
'lavender' => '#e6e6fa',
|
49 |
+
'lavenderblush' => '#fff0f5',
|
50 |
+
'lawngreen' => '#7cfc00',
|
51 |
+
'lemonchiffon' => '#fffacd',
|
52 |
+
'lightblue' => '#add8e6',
|
53 |
+
'lightcoral' => '#f08080',
|
54 |
+
'lightcyan' => '#e0ffff',
|
55 |
+
'lightgoldenrodyellow' => '#fafad2',
|
56 |
+
'lightgray' => '#d3d3d3',
|
57 |
+
'lightgreen' => '#90ee90',
|
58 |
+
'lightgrey' => '#d3d3d3',
|
59 |
+
'lightpink' => '#ffb6c1',
|
60 |
+
'lightsalmon' => '#ffa07a',
|
61 |
+
'lightseagreen' => '#20b2aa',
|
62 |
+
'lightskyblue' => '#87cefa',
|
63 |
+
'lightslategray' => '#778899',
|
64 |
+
'lightslategrey' => '#778899',
|
65 |
+
'lightsteelblue' => '#b0c4de',
|
66 |
+
'lightyellow' => '#ffffe0',
|
67 |
+
'limegreen' => '#32cd32',
|
68 |
+
'mediumaquamarine' => '#66cdaa',
|
69 |
+
'mediumblue' => '#0000cd',
|
70 |
+
'mediumorchid' => '#ba55d3',
|
71 |
+
'mediumpurple' => '#9370db',
|
72 |
+
'mediumseagreen' => '#3cb371',
|
73 |
+
'mediumslateblue' => '#7b68ee',
|
74 |
+
'mediumspringgreen' => '#00fa9a',
|
75 |
+
'mediumturquoise' => '#48d1cc',
|
76 |
+
'mediumvioletred' => '#c71585',
|
77 |
+
'midnightblue' => '#191970',
|
78 |
+
'mintcream' => '#f5fffa',
|
79 |
+
'mistyrose' => '#ffe4e1',
|
80 |
+
'moccasin' => '#ffe4b5',
|
81 |
+
'navajowhite' => '#ffdead',
|
82 |
+
'olivedrab' => '#6b8e23',
|
83 |
+
'orangered' => '#ff4500',
|
84 |
+
'palegoldenrod' => '#eee8aa',
|
85 |
+
'palegreen' => '#98fb98',
|
86 |
+
'paleturquoise' => '#afeeee',
|
87 |
+
'palevioletred' => '#db7093',
|
88 |
+
'papayawhip' => '#ffefd5',
|
89 |
+
'peachpuff' => '#ffdab9',
|
90 |
+
'powderblue' => '#b0e0e6',
|
91 |
+
'rebeccapurple' => '#663399',
|
92 |
+
'rosybrown' => '#bc8f8f',
|
93 |
+
'royalblue' => '#4169e1',
|
94 |
+
'saddlebrown' => '#8b4513',
|
95 |
+
'sandybrown' => '#f4a460',
|
96 |
+
'seagreen' => '#2e8b57',
|
97 |
+
'seashell' => '#fff5ee',
|
98 |
+
'slateblue' => '#6a5acd',
|
99 |
+
'slategray' => '#708090',
|
100 |
+
'slategrey' => '#708090',
|
101 |
+
'springgreen' => '#00ff7f',
|
102 |
+
'steelblue' => '#4682b4',
|
103 |
+
'turquoise' => '#40e0d0',
|
104 |
+
'white' => '#fff',
|
105 |
+
'whitesmoke' => '#f5f5f5',
|
106 |
+
'yellow' => '#ff0',
|
107 |
+
'yellowgreen' => '#9acd32'
|
108 |
+
);
|
classes/static/toolbar.js
CHANGED
@@ -1,13 +1,12 @@
|
|
1 |
jQuery( document ).ready(function()
|
2 |
{
|
3 |
-
|
4 |
var percentage = jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar' ).attr('percentage');
|
5 |
var rotate = percentage * 1.8;
|
6 |
|
7 |
jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .mask.full, #wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill' ).css({
|
8 |
-
'-webkit-transform'
|
9 |
-
'-ms-transform'
|
10 |
-
'transform'
|
11 |
});
|
12 |
|
13 |
// Fix Background color of circle percentage & delete cache to fit with the current color theme
|
@@ -30,34 +29,45 @@ jQuery( document ).ready(function()
|
|
30 |
|
31 |
// Create and Show the Autoptimize Loading Modal
|
32 |
var modal_loading = jQuery( '<div class="autoptimize-loading"></div>' ).appendTo( 'body' ).show();
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
jQuery.ajax({
|
35 |
-
type
|
36 |
-
url
|
37 |
-
data
|
38 |
-
dataType: 'json',
|
39 |
-
cache
|
40 |
-
timeout
|
41 |
-
success
|
42 |
{
|
43 |
// Remove the Autoptimize Loading Modal
|
44 |
modal_loading.remove();
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill' ).attr( 'class', 'fill bg-green' );
|
51 |
-
|
52 |
-
// Reset the class names of bullet icon
|
53 |
-
jQuery( '#wp-admin-bar-autoptimize' ).attr( 'class', 'menupop bullet-green' );
|
54 |
-
|
55 |
-
// Reset the Radial Bar progress
|
56 |
-
jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .mask.full, #wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill' ).css({
|
57 |
-
'-webkit-transform' : 'rotate(0deg)',
|
58 |
-
'-ms-transform' : 'rotate(0deg)',
|
59 |
-
'transform' : 'rotate(0deg)'
|
60 |
-
});
|
61 |
},
|
62 |
error: function( jqXHR, textStatus )
|
63 |
{
|
@@ -65,8 +75,7 @@ jQuery( document ).ready(function()
|
|
65 |
modal_loading.remove();
|
66 |
|
67 |
// WordPress Admin Notice
|
68 |
-
|
69 |
-
|
70 |
}
|
71 |
});
|
72 |
});
|
1 |
jQuery( document ).ready(function()
|
2 |
{
|
|
|
3 |
var percentage = jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar' ).attr('percentage');
|
4 |
var rotate = percentage * 1.8;
|
5 |
|
6 |
jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .mask.full, #wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill' ).css({
|
7 |
+
'-webkit-transform' : 'rotate(' + rotate + 'deg)',
|
8 |
+
'-ms-transform' : 'rotate(' + rotate + 'deg)',
|
9 |
+
'transform' : 'rotate(' + rotate + 'deg)'
|
10 |
});
|
11 |
|
12 |
// Fix Background color of circle percentage & delete cache to fit with the current color theme
|
29 |
|
30 |
// Create and Show the Autoptimize Loading Modal
|
31 |
var modal_loading = jQuery( '<div class="autoptimize-loading"></div>' ).appendTo( 'body' ).show();
|
32 |
+
|
33 |
+
var success = function() {
|
34 |
+
// Reset output values & class names of cache info
|
35 |
+
jQuery( '#wp-admin-bar-autoptimize-cache-info .size' ).attr( 'class', 'size green' ).html( '0.00 B' );
|
36 |
+
jQuery( '#wp-admin-bar-autoptimize-cache-info .files' ).html( '0' );
|
37 |
+
jQuery( '#wp-admin-bar-autoptimize-cache-info .percentage .numbers' ).attr( 'class', 'numbers green' ).html( '0%' );
|
38 |
+
jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill' ).attr( 'class', 'fill bg-green' );
|
39 |
+
|
40 |
+
// Reset the class names of bullet icon
|
41 |
+
jQuery( '#wp-admin-bar-autoptimize' ).attr( 'class', 'menupop bullet-green' );
|
42 |
+
|
43 |
+
// Reset the Radial Bar progress
|
44 |
+
jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .mask.full, #wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill' ).css({
|
45 |
+
'-webkit-transform' : 'rotate(0deg)',
|
46 |
+
'-ms-transform' : 'rotate(0deg)',
|
47 |
+
'transform' : 'rotate(0deg)'
|
48 |
+
});
|
49 |
+
};
|
50 |
+
|
51 |
+
var notice = function() {
|
52 |
+
jQuery( '<div id="ao-delete-cache-timeout" class="notice notice-error is-dismissible"><p><strong><span style="display:block;clear:both;">' + autoptimize_ajax_object.error_msg + '</span></strong></p><button type="button" class="notice-dismiss"><span class="screen-reader-text">' + autoptimize_ajax_object.dismiss_msg + '</span></button></div><br>' ).insertAfter( '#wpbody .wrap h1:first-of-type' ).show();
|
53 |
+
};
|
54 |
+
|
55 |
jQuery.ajax({
|
56 |
+
type : 'GET',
|
57 |
+
url : autoptimize_ajax_object.ajaxurl,
|
58 |
+
data : {'action':action, 'nonce':autoptimize_ajax_object.nonce},
|
59 |
+
dataType : 'json',
|
60 |
+
cache : false,
|
61 |
+
timeout : 5000,
|
62 |
+
success : function( cleared )
|
63 |
{
|
64 |
// Remove the Autoptimize Loading Modal
|
65 |
modal_loading.remove();
|
66 |
+
if ( cleared ) {
|
67 |
+
success();
|
68 |
+
} else {
|
69 |
+
notice();
|
70 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
},
|
72 |
error: function( jqXHR, textStatus )
|
73 |
{
|
75 |
modal_loading.remove();
|
76 |
|
77 |
// WordPress Admin Notice
|
78 |
+
notice();
|
|
|
79 |
}
|
80 |
});
|
81 |
});
|
classlesses/autoptimizeCacheChecker.php
CHANGED
@@ -39,10 +39,11 @@ function ao_cachechecker_cronjob() {
|
|
39 |
if (($cacheSize>$maxSize) && ($doCacheCheck)) {
|
40 |
update_option("autoptimize_cachesize_notice",true);
|
41 |
if (apply_filters('autoptimize_filter_cachecheck_sendmail',true)) {
|
|
|
42 |
$ao_mailto=apply_filters('autoptimize_filter_cachecheck_mailto',get_option('admin_email',''));
|
43 |
-
$ao_mailsubject=__('Autoptimize cache size warning','autoptimize');
|
44 |
-
$ao_mailbody=__('Autoptimize\'s cache size is getting big, consider purging the cache. Have a look at https://wordpress.org/plugins/autoptimize/faq/ to see how you can keep the cache size under control.', 'autoptimize');
|
45 |
-
|
46 |
if (!empty($ao_mailto)) {
|
47 |
$ao_mailresult=wp_mail($ao_mailto,$ao_mailsubject,$ao_mailbody);
|
48 |
if (!$ao_mailresult) {
|
39 |
if (($cacheSize>$maxSize) && ($doCacheCheck)) {
|
40 |
update_option("autoptimize_cachesize_notice",true);
|
41 |
if (apply_filters('autoptimize_filter_cachecheck_sendmail',true)) {
|
42 |
+
$saniSiteUrl=esc_url(site_url());
|
43 |
$ao_mailto=apply_filters('autoptimize_filter_cachecheck_mailto',get_option('admin_email',''));
|
44 |
+
$ao_mailsubject=__('Autoptimize cache size warning','autoptimize')." (".$saniSiteUrl.")";
|
45 |
+
$ao_mailbody=__('Autoptimize\'s cache size is getting big, consider purging the cache. Have a look at https://wordpress.org/plugins/autoptimize/faq/ to see how you can keep the cache size under control.', 'autoptimize')." (site: ".$saniSiteUrl.")";
|
46 |
+
|
47 |
if (!empty($ao_mailto)) {
|
48 |
$ao_mailresult=wp_mail($ao_mailto,$ao_mailsubject,$ao_mailbody);
|
49 |
if (!$ao_mailresult) {
|
classlesses/autoptimizeFontRegex.php
DELETED
@@ -1,7 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
// regex to find fonts, externalised to avoid nasty errors for php<5.3
|
3 |
-
|
4 |
-
$fonturl_regex = <<<'LOD'
|
5 |
-
~(?(DEFINE)(?<quoted_content>(["']) (?>[^"'\\]++ | \\{2} | \\. | (?!\g{-1})["'] )*+ \g{-1})(?<comment> /\* .*? \*/ ) (?<url_skip>(?: data: ) [^"'\s)}]*+ ) (?<other_content>(?> [^u}/"']++ | \g<quoted_content> | \g<comment> | \Bu | u(?!rl\s*+\() | /(?!\*) | \g<url_start> \g<url_skip> ["']?+ )++ ) (?<anchor> \G(?<!^) ["']?+ | @font-face \s*+ { ) (?<url_start> url\( \s*+ ["']?+ ) ) \g<comment> (*SKIP)(*FAIL) | \g<anchor> \g<other_content>?+ \g<url_start> \K ((?:(?:https?:)?(?://[[:alnum:]\-\.]+)(?::[0-9]+)?)?\/[^"'\s)}]*+) ~xs
|
6 |
-
LOD;
|
7 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
classlesses/autoptimizePageCacheFlush.php
CHANGED
@@ -2,6 +2,8 @@
|
|
2 |
// flush as many page cache plugin's caches as possible
|
3 |
// hyper cache and gator cache hook into AO, so we don't need to :-)
|
4 |
|
|
|
|
|
5 |
function autoptimize_flush_pagecache() {
|
6 |
if(function_exists('wp_cache_clear_cache')) {
|
7 |
if (is_multisite()) {
|
@@ -37,6 +39,8 @@ function autoptimize_flush_pagecache() {
|
|
37 |
if ( method_exists( "WpeCommon", "purge_varnish_cache" ) ) {
|
38 |
WpeCommon::purge_varnish_cache();
|
39 |
}
|
|
|
|
|
40 |
} else if(file_exists(WP_CONTENT_DIR.'/wp-cache-config.php') && function_exists('prune_super_cache')){
|
41 |
// fallback for WP-Super-Cache
|
42 |
global $cache_path;
|
2 |
// flush as many page cache plugin's caches as possible
|
3 |
// hyper cache and gator cache hook into AO, so we don't need to :-)
|
4 |
|
5 |
+
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
6 |
+
|
7 |
function autoptimize_flush_pagecache() {
|
8 |
if(function_exists('wp_cache_clear_cache')) {
|
9 |
if (is_multisite()) {
|
39 |
if ( method_exists( "WpeCommon", "purge_varnish_cache" ) ) {
|
40 |
WpeCommon::purge_varnish_cache();
|
41 |
}
|
42 |
+
} else if ( function_exists('sg_cachepress_purge_cache') ) {
|
43 |
+
sg_cachepress_purge_cache();
|
44 |
} else if(file_exists(WP_CONTENT_DIR.'/wp-cache-config.php') && function_exists('prune_super_cache')){
|
45 |
// fallback for WP-Super-Cache
|
46 |
global $cache_path;
|
classlesses/autoptimizePartners.php
CHANGED
@@ -3,6 +3,8 @@
|
|
3 |
Classlessly add a "more tools" tab to promote (future) AO addons and/ or affiliate services
|
4 |
*/
|
5 |
|
|
|
|
|
6 |
add_action('admin_init', 'ao_partner_tabs_preinit');
|
7 |
function ao_partner_tabs_preinit() {
|
8 |
if (apply_filters('autoptimize_filter_show_partner_tabs',true)) {
|
@@ -29,7 +31,7 @@ function ao_partners() {
|
|
29 |
.itemDetail {
|
30 |
background: #fff;
|
31 |
width: 250px;
|
32 |
-
min-height:
|
33 |
border: 1px solid #ccc;
|
34 |
float: left;
|
35 |
padding: 15px;
|
@@ -72,7 +74,7 @@ function ao_partners() {
|
|
72 |
<h1><?php _e('Autoptimize Settings','autoptimize'); ?></h1>
|
73 |
<?php echo autoptimizeConfig::ao_admin_tabs(); ?>
|
74 |
<?php
|
75 |
-
|
76 |
?>
|
77 |
<div>
|
78 |
<?php getAOPartnerFeed(); ?>
|
@@ -117,4 +119,4 @@ function getAOPartnerFeed() {
|
|
117 |
} else {
|
118 |
echo $noFeedText;
|
119 |
}
|
120 |
-
}
|
3 |
Classlessly add a "more tools" tab to promote (future) AO addons and/ or affiliate services
|
4 |
*/
|
5 |
|
6 |
+
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
7 |
+
|
8 |
add_action('admin_init', 'ao_partner_tabs_preinit');
|
9 |
function ao_partner_tabs_preinit() {
|
10 |
if (apply_filters('autoptimize_filter_show_partner_tabs',true)) {
|
31 |
.itemDetail {
|
32 |
background: #fff;
|
33 |
width: 250px;
|
34 |
+
min-height: 290px;
|
35 |
border: 1px solid #ccc;
|
36 |
float: left;
|
37 |
padding: 15px;
|
74 |
<h1><?php _e('Autoptimize Settings','autoptimize'); ?></h1>
|
75 |
<?php echo autoptimizeConfig::ao_admin_tabs(); ?>
|
76 |
<?php
|
77 |
+
echo '<h2>'. __("These Autoptimize power-ups and related services will improve your site's performance even more!",'autoptimize') . '</h2>';
|
78 |
?>
|
79 |
<div>
|
80 |
<?php getAOPartnerFeed(); ?>
|
119 |
} else {
|
120 |
echo $noFeedText;
|
121 |
}
|
122 |
+
}
|
classlesses/autoptimizeSpeedupper.php
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
* Autoptimize SpeedUp; minify & cache each JS/ CSS separately
|
4 |
+
* new in Autoptimize 2.2
|
5 |
+
*/
|
6 |
+
|
7 |
+
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
8 |
+
|
9 |
+
function ao_js_snippetcache($jsin,$jsfilename) {
|
10 |
+
$md5hash = "snippet_".md5($jsin);
|
11 |
+
$ccheck = new autoptimizeCache($md5hash,'js');
|
12 |
+
if($ccheck->check()) {
|
13 |
+
$scriptsrc = $ccheck->retrieve();
|
14 |
+
} else {
|
15 |
+
if ( (strpos($jsfilename,"min.js") === false) && ( strpos($jsfilename,"js/jquery/jquery.js") === false ) && ( str_replace(apply_filters('autoptimize_filter_js_consider_minified',false), '', $jsfilename) === $jsfilename ) ) {
|
16 |
+
if(class_exists('JSMin')) {
|
17 |
+
$tmp_jscode = trim(JSMin::minify($jsin));
|
18 |
+
if (!empty($tmp_jscode)) {
|
19 |
+
$scriptsrc = $tmp_jscode;
|
20 |
+
unset($tmp_jscode);
|
21 |
+
} else {
|
22 |
+
$scriptsrc=$jsin;
|
23 |
+
}
|
24 |
+
} else {
|
25 |
+
$scriptsrc=$jsin;
|
26 |
+
}
|
27 |
+
} else {
|
28 |
+
// do some housekeeping here to remove comments & linebreaks and stuff
|
29 |
+
$scriptsrc=preg_replace("#^\s*\/\/.*$#Um","",$jsin);
|
30 |
+
$scriptsrc=preg_replace("#^\s*\/\*[^!].*\*\/\s?#Us","",$scriptsrc);
|
31 |
+
$scriptsrc=preg_replace("#(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+#", "\n", $scriptsrc);
|
32 |
+
|
33 |
+
if ((substr($scriptsrc,-1,1)!==";")&&(substr($scriptsrc,-1,1)!=="}")) {
|
34 |
+
$scriptsrc.=";";
|
35 |
+
}
|
36 |
+
}
|
37 |
+
if ( !empty($jsfilename) && str_replace( apply_filters('autoptimize_filter_js_speedup_cache',false), '', $jsfilename ) === $jsfilename ) {
|
38 |
+
// don't cache inline CSS or if filter says no
|
39 |
+
$ccheck->cache($scriptsrc,'text/javascript');
|
40 |
+
}
|
41 |
+
}
|
42 |
+
unset($ccheck);
|
43 |
+
|
44 |
+
if (get_option("autoptimize_js_trycatch")==="on") {
|
45 |
+
$scriptsrc="try{".$scriptsrc."}catch(e){}";
|
46 |
+
}
|
47 |
+
|
48 |
+
return $scriptsrc;
|
49 |
+
}
|
50 |
+
|
51 |
+
function ao_css_snippetcache($cssin,$cssfilename) {
|
52 |
+
$md5hash = "snippet_".md5($cssin);
|
53 |
+
$ccheck = new autoptimizeCache($md5hash,'css');
|
54 |
+
if($ccheck->check()) {
|
55 |
+
$stylesrc = $ccheck->retrieve();
|
56 |
+
} else {
|
57 |
+
if ( ( strpos($cssfilename,"min.css") === false ) && ( str_replace( apply_filters('autoptimize_filter_css_consider_minified',false), '', $cssfilename ) === $cssfilename ) ) {
|
58 |
+
if (class_exists('Minify_CSS_Compressor')) {
|
59 |
+
$tmp_code = trim(Minify_CSS_Compressor::process($cssin));
|
60 |
+
} else if(class_exists('CSSmin')) {
|
61 |
+
$cssmin = new CSSmin();
|
62 |
+
if (method_exists($cssmin,"run")) {
|
63 |
+
$tmp_code = trim($cssmin->run($cssin));
|
64 |
+
} elseif (@is_callable(array($cssmin,"minify"))) {
|
65 |
+
$tmp_code = trim(CssMin::minify($cssin));
|
66 |
+
}
|
67 |
+
}
|
68 |
+
|
69 |
+
if (!empty($tmp_code)) {
|
70 |
+
$stylesrc = $tmp_code;
|
71 |
+
unset($tmp_code);
|
72 |
+
} else {
|
73 |
+
$stylesrc = $cssin;
|
74 |
+
}
|
75 |
+
} else {
|
76 |
+
// .min.css -> no heavy-lifting, just some cleanup
|
77 |
+
$stylesrc=preg_replace("#^\s*\/\*[^!].*\*\/\s?#Us","",$cssin);
|
78 |
+
$stylesrc=preg_replace("#(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+#", "\n", $stylesrc);
|
79 |
+
$stylesrc=autoptimizeStyles::fixurls($cssfilename,$stylesrc);
|
80 |
+
}
|
81 |
+
if ( !empty($cssfilename) && ( str_replace( apply_filters('autoptimize_filter_css_speedup_cache',false), '', $cssfilename ) === $cssfilename ) ) {
|
82 |
+
// only cache CSS if not inline and allowed by filter
|
83 |
+
$ccheck->cache($stylesrc,'text/css');
|
84 |
+
}
|
85 |
+
}
|
86 |
+
unset($ccheck);
|
87 |
+
return $stylesrc;
|
88 |
+
}
|
89 |
+
|
90 |
+
function ao_css_speedup_cleanup($cssin) {
|
91 |
+
// speedupper results in aggregated CSS not being minified, so the filestart-marker AO adds when aggregating need to be removed
|
92 |
+
return trim(str_replace(array('/*FILESTART*/','/*FILESTART2*/'),'',$cssin));
|
93 |
+
}
|
94 |
+
|
95 |
+
function ao_js_speedup_cleanup($jsin) {
|
96 |
+
// cleanup
|
97 |
+
return trim($jsin);
|
98 |
+
}
|
99 |
+
|
100 |
+
add_filter('autoptimize_css_individual_style','ao_css_snippetcache',10,2);
|
101 |
+
add_filter('autoptimize_js_individual_script','ao_js_snippetcache',10,2);
|
102 |
+
add_filter('autoptimize_css_after_minify','ao_css_speedup_cleanup',10,1);
|
103 |
+
add_filter('autoptimize_js_after_minify','ao_js_speedup_cleanup',10,1);
|
classlesses/autoptimizeUpdateCode.php
CHANGED
@@ -3,6 +3,8 @@
|
|
3 |
* below code handles updates and is only included by autoptimize.php if/ when needed
|
4 |
*/
|
5 |
|
|
|
|
|
6 |
$majorUp = false;
|
7 |
$autoptimize_major_version=substr($autoptimize_db_version,0,3);
|
8 |
|
3 |
* below code handles updates and is only included by autoptimize.php if/ when needed
|
4 |
*/
|
5 |
|
6 |
+
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
7 |
+
|
8 |
$majorUp = false;
|
9 |
$autoptimize_major_version=substr($autoptimize_db_version,0,3);
|
10 |
|
config/default.php
CHANGED
@@ -54,7 +54,7 @@ if (($modTimeMatch)||($eTagMatch)) {
|
|
54 |
header('Vary: Accept-Encoding');
|
55 |
header('Content-Length: '.strlen($contents));
|
56 |
header('Content-type: %%CONTENT%%; charset=utf-8');
|
57 |
-
header('Cache-Control: max-age='.$expireTime.', public,
|
58 |
header('Expires: '.gmdate('D, d M Y H:i:s', time() + $expireTime).' GMT'); //10 years
|
59 |
header('ETag: ' . $eTag);
|
60 |
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $modTime).' GMT');
|
54 |
header('Vary: Accept-Encoding');
|
55 |
header('Content-Length: '.strlen($contents));
|
56 |
header('Content-type: %%CONTENT%%; charset=utf-8');
|
57 |
+
header('Cache-Control: max-age='.$expireTime.', public, immutable');
|
58 |
header('Expires: '.gmdate('D, d M Y H:i:s', time() + $expireTime).' GMT'); //10 years
|
59 |
header('ETag: ' . $eTag);
|
60 |
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $modTime).' GMT');
|
config/delayed.php
CHANGED
@@ -62,7 +62,7 @@ if (($modTimeMatch)||($eTagMatch)) {
|
|
62 |
header('Vary: Accept-Encoding');
|
63 |
header('Content-Length: '.strlen($contents));
|
64 |
header('Content-type: %%CONTENT%%; charset=utf-8');
|
65 |
-
header('Cache-Control: max-age='.$expireTime.', public,
|
66 |
header('Expires: '.gmdate('D, d M Y H:i:s', time() + $expireTime).' GMT');
|
67 |
header('ETag: ' . $eTag);
|
68 |
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $modTime).' GMT');
|
62 |
header('Vary: Accept-Encoding');
|
63 |
header('Content-Length: '.strlen($contents));
|
64 |
header('Content-type: %%CONTENT%%; charset=utf-8');
|
65 |
+
header('Cache-Control: max-age='.$expireTime.', public, immutable');
|
66 |
header('Expires: '.gmdate('D, d M Y H:i:s', time() + $expireTime).' GMT');
|
67 |
header('ETag: ' . $eTag);
|
68 |
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $modTime).' GMT');
|
readme.txt
CHANGED
@@ -1,18 +1,21 @@
|
|
1 |
=== Autoptimize ===
|
2 |
-
Contributors: futtta,
|
3 |
-
Tags:
|
4 |
Donate link: http://blog.futtta.be/2013/10/21/do-not-donate-to-me/
|
5 |
Requires at least: 4.0
|
6 |
Tested up to: 4.8
|
7 |
-
Stable tag: 2.2.
|
8 |
|
9 |
Autoptimize speeds up your website and helps you save bandwidth by aggregating and minimizing JS, CSS and HTML.
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
-
Autoptimize makes optimizing your site really easy. It
|
14 |
|
15 |
-
If you consider performance important, you really should use one of the many caching plugins to do page caching. Some good candidates to complement Autoptimize that way are e.g. [WP Super Cache](http://wordpress.org/
|
|
|
|
|
|
|
16 |
|
17 |
(Speed-surfing image under creative commons [by LL Twistiti](https://www.flickr.com/photos/twistiti/818552808/))
|
18 |
|
@@ -20,7 +23,7 @@ If you consider performance important, you really should use one of the many cac
|
|
20 |
|
21 |
Just install from your WordPress "Plugins > Add New" screen and all will be well. Manual installation is very straightforward as well:
|
22 |
|
23 |
-
1. Upload the zip file and unzip it in the `/wp-content/plugins/` directory
|
24 |
1. Activate the plugin through the 'Plugins' menu in WordPress
|
25 |
1. Go to `Settings > Autoptimize` and enable the options you want. Generally this means "Optimize HTML/ CSS/ JavaScript".
|
26 |
|
@@ -30,10 +33,18 @@ Just install from your WordPress "Plugins > Add New" screen and all will be well
|
|
30 |
|
31 |
It concatenates all scripts and styles, minifies and compresses them, adds expires headers, caches them, and moves styles to the page head, and scripts (optionally) to the footer. It also minifies the HTML code itself, making your page really lightweight.
|
32 |
|
|
|
|
|
|
|
|
|
33 |
= Will this work with my blog? =
|
34 |
|
35 |
Although Autoptimize comes without any warranties, it will in general work flawlessly if you configure it correctly. See "Troubleshooting" below for info on how to configure in case of problems.
|
36 |
|
|
|
|
|
|
|
|
|
37 |
= What is the use of "inline and defer CSS"? =
|
38 |
|
39 |
CSS in general should go in the head of the document. Recently a.o. Google started promoting deferring non-essential CSS, while inlining those styles needed to build the page above the fold. This is especially important to render pages as quickly as possible on mobile devices. As from Autoptimize 1.9.0 this is easy; select "inline and defer CSS", paste the block of "above the fold CSS" in the input field (text area) and you're good to go!
|
@@ -44,7 +55,7 @@ There's no easy solution for that as "above the fold" depends on where the fold
|
|
44 |
|
45 |
= Or should you inline all CSS? =
|
46 |
|
47 |
-
The short answer: probably not
|
48 |
|
49 |
Back in the days CSS optimization was easy; put all CSS in your head, aggregating everything in one CSS-file per media-type and you were good to go. But ever since Google included mobile in PageSpeed Insights and started complaining about render blocking CSS, things got messy (see "deferring CSS" elsewhere in this FAQ). One of the solutions is inlining all your CSS, which as of Autoptimize 1.8.0 is supported.
|
50 |
|
@@ -56,20 +67,18 @@ You can find more information on this topic [in this blog post](http://blog.futt
|
|
56 |
|
57 |
= My cache is getting huge, doesn't Autoptimize purge the cache? =
|
58 |
|
59 |
-
Autoptimize does not have its proper cache purging mechanism, as this could remove optimized CSS/JS which is still referred to in other caches, which would break your site.
|
60 |
|
61 |
-
|
62 |
|
63 |
* disactivating the "aggregate inline JS" and/ or "aggregate inline CSS" options
|
64 |
* excluding JS-variables (or sometimes CSS-selectors) that change on a per page (or per pageload) basis. You can read how you can do that [in this blogpost](http://blog.futtta.be/2014/03/19/how-to-keep-autoptimizes-cache-size-under-control-and-improve-visitor-experience/).
|
65 |
|
66 |
-
|
67 |
-
|
68 |
-
While "look only in head" still works, it is now (since Autoptimize 2.0.0) no longer visible on the settings-page if it is not active. As long as the option is active (for JS or CSS), it will however remain visible until you deactivate it. If you're comfortable with PHP, there still are filters available to keep on using "look only in head".
|
69 |
|
70 |
= So should I aggregate inline CSS/ JS? =
|
71 |
|
72 |
-
Before Autoptimize 2.0.0, inline code was always optimized with all CSS pushed in the head-section and all JS at the end with a defer-flag. This often caused 2 problems; the priority of inline CSS got lost and inline JS could contain page- or request-specific code which broke Autoptimize's caching mechanism leading to too many cached files and the minification running over and over. This is why as from 2.0
|
73 |
|
74 |
= What can I do with the API? =
|
75 |
|
@@ -95,6 +104,10 @@ Autoptimize supports this, but it is not enabled by default because [non-local f
|
|
95 |
|
96 |
`add_filter('autoptimize_filter_css_fonts_cdn',__return_true);`
|
97 |
|
|
|
|
|
|
|
|
|
98 |
= How can I force the aggregated files to be static CSS or JS instead of PHP? =
|
99 |
|
100 |
If your webserver is properly configured to handle compression (gzip or deflate) and cache expiry (expires and cache-control with sufficient cacheability), you don't need Autoptimize to handle that for you. In that case you can check the "Save aggregated script/css as static files?"-option, which will force Autoptimize to save the aggregated files as .css and .js-files (meaning no PHP is needed to serve these files). This setting is default as of Autoptimize 1.8.
|
@@ -137,6 +150,7 @@ If you are running Apache, the htaccess file written by Autoptimize can in some
|
|
137 |
= I get no error, but my pages are not optimized at all? =
|
138 |
|
139 |
Autoptimize does a number of checks before actually optimizing. When one of the following is true, your pages won't be optimized:
|
|
|
140 |
* when in the customizer
|
141 |
* if there is no opening `<html` tag
|
142 |
* if there is `<xsl:stylesheet` in the response (indicating the output is not HTML but XML)
|
@@ -149,47 +163,36 @@ Autoptimize does a number of checks before actually optimizing. When one of the
|
|
149 |
|
150 |
= Visual Composer, Beaver Builder and similar page builder solutions are broken!! =
|
151 |
|
152 |
-
|
153 |
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
if (is_user_logged_in()) {
|
158 |
-
return true;
|
159 |
-
} else {
|
160 |
-
return false;
|
161 |
-
}
|
162 |
-
}
|
163 |
-
`
|
164 |
|
165 |
= Revolution Slider is broken! =
|
166 |
|
167 |
-
|
168 |
|
169 |
= I'm getting "jQuery is not defined" errors =
|
170 |
|
171 |
-
In that case you have un-aggregated JavaScript that requires jQuery to be loaded, so you'll have to
|
172 |
|
173 |
-
= My Autoptimized CSS/ JS is broken after upgrading from 1
|
174 |
|
175 |
-
One of the bigger changes in Autoptimize 2.
|
176 |
|
177 |
`
|
178 |
-
add_filter('
|
179 |
-
add_filter('autoptimize_filter_css_inject_min_late',__return_false);
|
180 |
`
|
181 |
|
182 |
-
Obviously you can choose to do this for only CSS, JS or both (as in example).
|
183 |
-
|
184 |
= I use NextGen Galleries and a lot of JS is not aggregated/ minified? =
|
185 |
|
186 |
-
NextGen Galleries does some nifty stuff to add JavaScript. In order for Autoptimize to be able to aggregate that, you'
|
187 |
-
`define("AUTOPTIMIZE_INIT_EARLIER","true");`
|
188 |
|
189 |
= What is noptimize? =
|
190 |
|
191 |
Starting with version 1.6.6 Autoptimize excludes everything inside noptimize tags, e.g.:
|
192 |
-
|
193 |
|
194 |
You can do this in your page/ post content, in widgets and in your theme files (consider creating [a child theme](http://codex.wordpress.org/Child_Themes) to avoid your work being overwritten by theme updates).
|
195 |
|
@@ -205,17 +208,9 @@ define('AUTOPTIMIZE_CACHEFILE_PREFIX','aggregated_');
|
|
205 |
|
206 |
Yes, but this is off by default. You can enable this by passing ´true´ to ´autoptimize_filter_cache_create_static_gzip´. You'll obviously still have to configure your webserver to use these files instead of the non-gzipped ones to avoid the overhead of on-the-fly compression.
|
207 |
|
208 |
-
= Where can I
|
209 |
-
|
210 |
-
You can report problems on the [wordpress.org support forum](http://wordpress.org/support/plugin/autoptimize). If you are 100% sure this your problem cannot be solved using Autoptimize configuration and that you in fact discovered a bug in the code, you can [create an issue on GitHub](https://github.com/futtta/autoptimize/issues).
|
211 |
|
212 |
-
|
213 |
-
|
214 |
-
* A description of the problem, including screenshots and information from your browser's Error/ debug console
|
215 |
-
* URL of your blog (you can turn Autoptimize off, but should be willing to turn it briefly on to have the error visible)
|
216 |
-
* your Autoptimize settings (including a description of changes you made to the configuration to try to troubleshoot yourself)
|
217 |
-
* the Theme used (including the Theme's download link)
|
218 |
-
* optionally plugins used (if you suspect one or more plugins are raising havoc)
|
219 |
|
220 |
= I want out, how should I remove Autoptimize? =
|
221 |
|
@@ -229,9 +224,29 @@ Just [fork Autoptimize on Github](https://github.com/futtta/autoptimize) and cod
|
|
229 |
|
230 |
== Changelog ==
|
231 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
232 |
= 2.1.1 =
|
233 |
-
*
|
234 |
-
* confirmed working with WordPress 4.8
|
235 |
|
236 |
= 2.1.0 =
|
237 |
* new: Autoptimize now appears in admin-toolbar with an easy view on cache size and the possibility to purge the cache (pass `false` to `autoptimize_filter_toolbar_show` filter to disable), a big thanks to [Pablo Custo](https://github.com/pablocusto) for his hard work on this nice feature!
|
1 |
=== Autoptimize ===
|
2 |
+
Contributors: futtta, optimizingmatters, turl
|
3 |
+
Tags: css, html, javascript, js, optimize, speed, cache, aggregate, minimize, minification, performance, pagespeed
|
4 |
Donate link: http://blog.futtta.be/2013/10/21/do-not-donate-to-me/
|
5 |
Requires at least: 4.0
|
6 |
Tested up to: 4.8
|
7 |
+
Stable tag: 2.2.1
|
8 |
|
9 |
Autoptimize speeds up your website and helps you save bandwidth by aggregating and minimizing JS, CSS and HTML.
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
+
Autoptimize makes optimizing your site really easy. It can aggregate, minify and cache scripts and styles, injects CSS in the page head by default and can move and defer scripts to the footer. It also minifies the HTML code itself, making your page really lightweight. There are advanced options and an extensive API available to enable you to tailor Autoptimize to each and every site's specific needs. And it can even improve your site's performance when on HTTP/2!
|
14 |
|
15 |
+
If you consider performance important, you really should use one of the many caching plugins to do page caching. Some good candidates to complement Autoptimize that way are e.g. [WP Super Cache](http://wordpress.org/plugins/wp-super-cache/), [HyperCache](http://wordpress.org/plugins/hyper-cache/), [Comet Cache](https://wordpress.org/plugins/comet-cache/) or [KeyCDN's Cache Enabler](https://wordpress.org/plugins/cache-enabler).
|
16 |
+
|
17 |
+
> <strong>Premium Support</strong><br>
|
18 |
+
> We provide great [Autoptimize Pro Support and Web Performance Optimization services](http://autoptimize.com/), check out our offering on (http://autoptimize.com/)!
|
19 |
|
20 |
(Speed-surfing image under creative commons [by LL Twistiti](https://www.flickr.com/photos/twistiti/818552808/))
|
21 |
|
23 |
|
24 |
Just install from your WordPress "Plugins > Add New" screen and all will be well. Manual installation is very straightforward as well:
|
25 |
|
26 |
+
1. Upload the zip file and unzip it in the `/wp-content/plugins/` directory
|
27 |
1. Activate the plugin through the 'Plugins' menu in WordPress
|
28 |
1. Go to `Settings > Autoptimize` and enable the options you want. Generally this means "Optimize HTML/ CSS/ JavaScript".
|
29 |
|
33 |
|
34 |
It concatenates all scripts and styles, minifies and compresses them, adds expires headers, caches them, and moves styles to the page head, and scripts (optionally) to the footer. It also minifies the HTML code itself, making your page really lightweight.
|
35 |
|
36 |
+
= But I'm on HTTP/2, so I don't need Autoptimize? =
|
37 |
+
|
38 |
+
HTTP/2 is a great step forward for sure, reducing the impact of multiple requests from the same server significantly by using the same connection to perform several concurrent requests. That being said, [concatenation of CSS/ JS can still make a lot of sense](http://engineering.khanacademy.org/posts/js-packaging-http2.htm), as described in [this css-tricks.com article](https://css-tricks.com/http2-real-world-performance-test-analysis/) and this [blogpost from one of the Ebay engineers](http://calendar.perfplanet.com/2015/packaging-for-performance/). The conclusion; configure, test, reconfigure, retest, tweak and look what works best in your context. Maybe it's just HTTP/2, maybe it's HTTP/2 + aggregation and minification, maybe it's HTTP/2 + minification (which AO can do as well).
|
39 |
+
|
40 |
= Will this work with my blog? =
|
41 |
|
42 |
Although Autoptimize comes without any warranties, it will in general work flawlessly if you configure it correctly. See "Troubleshooting" below for info on how to configure in case of problems.
|
43 |
|
44 |
+
= Why are jquery.js and the autoptimized CSS still called out as render blocking? =
|
45 |
+
|
46 |
+
With the default Autoptimize configuration jquery.js is excluded from optimization and the CSS is linked in the head, which are safe defaults but have Google PageSpeed Insights complaining. You can try removing `js/jquery/jquery.js` from the JS optimization exclusions and check if your site still works. For the render blocking CSS you can look into "inline all CSS" (easy) or "inline and defer CSS" (better) which are explained in this FAQ as well.
|
47 |
+
|
48 |
= What is the use of "inline and defer CSS"? =
|
49 |
|
50 |
CSS in general should go in the head of the document. Recently a.o. Google started promoting deferring non-essential CSS, while inlining those styles needed to build the page above the fold. This is especially important to render pages as quickly as possible on mobile devices. As from Autoptimize 1.9.0 this is easy; select "inline and defer CSS", paste the block of "above the fold CSS" in the input field (text area) and you're good to go!
|
55 |
|
56 |
= Or should you inline all CSS? =
|
57 |
|
58 |
+
The short answer: probably not.
|
59 |
|
60 |
Back in the days CSS optimization was easy; put all CSS in your head, aggregating everything in one CSS-file per media-type and you were good to go. But ever since Google included mobile in PageSpeed Insights and started complaining about render blocking CSS, things got messy (see "deferring CSS" elsewhere in this FAQ). One of the solutions is inlining all your CSS, which as of Autoptimize 1.8.0 is supported.
|
61 |
|
67 |
|
68 |
= My cache is getting huge, doesn't Autoptimize purge the cache? =
|
69 |
|
70 |
+
Autoptimize does not have its proper cache purging mechanism, as this could remove optimized CSS/JS which is still referred to in other caches, which would break your site. Moreover a fast growing cache is an indication of [other problems you should avoid](http://blog.futtta.be/2016/09/15/autoptimize-cache-size-the-canary-in-the-coal-mine/).
|
71 |
|
72 |
+
Instead you can keep the cache size at an acceptable level by either:
|
73 |
|
74 |
* disactivating the "aggregate inline JS" and/ or "aggregate inline CSS" options
|
75 |
* excluding JS-variables (or sometimes CSS-selectors) that change on a per page (or per pageload) basis. You can read how you can do that [in this blogpost](http://blog.futtta.be/2014/03/19/how-to-keep-autoptimizes-cache-size-under-control-and-improve-visitor-experience/).
|
76 |
|
77 |
+
Despite above objections, there are 3rd party solutions to automatically purge the AO cache, e.g. using [this code](https://wordpress.org/support/topic/contribution-autoptimize-cache-size-under-control-by-schedule-auto-cache-purge/) or [this plugin](https://wordpress.org/plugins/bi-clean-cache/), but for reasons above these are to be used only if you really know what you're doing.
|
|
|
|
|
78 |
|
79 |
= So should I aggregate inline CSS/ JS? =
|
80 |
|
81 |
+
Before Autoptimize 2.0.0, inline code was always optimized with all CSS pushed in the head-section and all JS at the end with a defer-flag. This often caused 2 problems; the priority of inline CSS got lost and inline JS could contain page- or request-specific code which broke Autoptimize's caching mechanism leading to too many cached files and the minification running over and over. This is why as from AQ 2.0 by default inline code is not optimized (except for those upgrading from previous versions). Additionally, to avoid inline JS breaking because jquery is not available, `js/jquery/jquery.js` is excluded by default.
|
82 |
|
83 |
= What can I do with the API? =
|
84 |
|
104 |
|
105 |
`add_filter('autoptimize_filter_css_fonts_cdn',__return_true);`
|
106 |
|
107 |
+
= I'm using Cloudflare, what should I enter as CDN root directory =
|
108 |
+
|
109 |
+
Nothing, when on Cloudflare your autoptimized CSS/ JS is on the Cloudflare's CDN automatically.
|
110 |
+
|
111 |
= How can I force the aggregated files to be static CSS or JS instead of PHP? =
|
112 |
|
113 |
If your webserver is properly configured to handle compression (gzip or deflate) and cache expiry (expires and cache-control with sufficient cacheability), you don't need Autoptimize to handle that for you. In that case you can check the "Save aggregated script/css as static files?"-option, which will force Autoptimize to save the aggregated files as .css and .js-files (meaning no PHP is needed to serve these files). This setting is default as of Autoptimize 1.8.
|
150 |
= I get no error, but my pages are not optimized at all? =
|
151 |
|
152 |
Autoptimize does a number of checks before actually optimizing. When one of the following is true, your pages won't be optimized:
|
153 |
+
|
154 |
* when in the customizer
|
155 |
* if there is no opening `<html` tag
|
156 |
* if there is `<xsl:stylesheet` in the response (indicating the output is not HTML but XML)
|
163 |
|
164 |
= Visual Composer, Beaver Builder and similar page builder solutions are broken!! =
|
165 |
|
166 |
+
Disable the option to have Autoptimize active for logged on users and go crazy dragging and dropping ;-)
|
167 |
|
168 |
+
= Help, my shop checkout/ payment don't work!! =
|
169 |
+
|
170 |
+
Disable the option to optimize cart/ checkout pages (works for WooCommerce, Easy Digital Downloads and WP eCommerce).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
|
172 |
= Revolution Slider is broken! =
|
173 |
|
174 |
+
Make sure `js/jquery/jquery.js` is in the comma-separated list of JS optimization exclusions (this is excluded in the default configuration).
|
175 |
|
176 |
= I'm getting "jQuery is not defined" errors =
|
177 |
|
178 |
+
In that case you have un-aggregated JavaScript that requires jQuery to be loaded, so you'll have to add `js/jquery/jquery.js` to the comma-separated list of JS optimization exclusions.
|
179 |
|
180 |
+
= My Autoptimized CSS/ JS is broken after upgrading from 2.1 to 2.2! =
|
181 |
|
182 |
+
One of the bigger changes in Autoptimize 2.2 it that it minifies first and aggregates second, which has important performance-benefits. Although this has been tested rather thoroughly, it is possible that this approach does not always work. You can turn this behavior off by hooking into Autoptimize's API, like this;
|
183 |
|
184 |
`
|
185 |
+
add_filter('autoptimize_filter_speedupper','__return_false');
|
|
|
186 |
`
|
187 |
|
|
|
|
|
188 |
= I use NextGen Galleries and a lot of JS is not aggregated/ minified? =
|
189 |
|
190 |
+
NextGen Galleries does some nifty stuff to add JavaScript. In order for Autoptimize to be able to aggregate that, you can either disable Nextgen Gallery's resourced manage with this code snippet `add_filter( 'run_ngg_resource_manager', '__return_false' );` or you can tell Autoptimize to initialize earlier, by adding this to your wp-config.php: `define("AUTOPTIMIZE_INIT_EARLIER","true");`
|
|
|
191 |
|
192 |
= What is noptimize? =
|
193 |
|
194 |
Starting with version 1.6.6 Autoptimize excludes everything inside noptimize tags, e.g.:
|
195 |
+
`<!--noptimize--><script>alert('this will not get autoptimized');</script><!--/noptimize-->`
|
196 |
|
197 |
You can do this in your page/ post content, in widgets and in your theme files (consider creating [a child theme](http://codex.wordpress.org/Child_Themes) to avoid your work being overwritten by theme updates).
|
198 |
|
208 |
|
209 |
Yes, but this is off by default. You can enable this by passing ´true´ to ´autoptimize_filter_cache_create_static_gzip´. You'll obviously still have to configure your webserver to use these files instead of the non-gzipped ones to avoid the overhead of on-the-fly compression.
|
210 |
|
211 |
+
= Where can I get help? =
|
|
|
|
|
212 |
|
213 |
+
You can get help on the [wordpress.org support forum](http://wordpress.org/support/plugin/autoptimize). If you are 100% sure this your problem cannot be solved using Autoptimize configuration and that you in fact discovered a bug in the code, you can [create an issue on GitHub](https://github.com/futtta/autoptimize/issues). If you're looking for premium support, check out our [Autoptimize Pro Support and Web Performance Optimization services](http://autoptimize.com/).
|
|
|
|
|
|
|
|
|
|
|
|
|
214 |
|
215 |
= I want out, how should I remove Autoptimize? =
|
216 |
|
224 |
|
225 |
== Changelog ==
|
226 |
|
227 |
+
= 2.2.1 =
|
228 |
+
* fix for images in CSS not all being translated to correct path, leading to 404’s as reported by Jeff Inho
|
229 |
+
* fix for "[] operator not supported for strings" error in PHP7.1 as reported by falk-wussow.de
|
230 |
+
* fix for security hash busting AO's cache in some cases (esp. in 2.1.1)
|
231 |
+
|
232 |
+
= 2.2.0 =
|
233 |
+
* new: Autoptimize minifies first (caching the individual snippets) and aggregrates the minified snippets, resulting in huge performance improvements for uncached JS/ CSS.
|
234 |
+
* new: option to enable/ disable AO for logged in users (on by default)
|
235 |
+
* new: option to enable/ disable AO on WooCommerce, Easy Digital Downloads or WP eCommerce cart/ checkout page (on by default)
|
236 |
+
* improvement: switched to [rel=preload + Filamentgroup’s loadCSS for CSS deferring](http://blog.futtta.be/2017/02/24/autoptimize-css-defer-switching-to-loadcss-soon/)
|
237 |
+
* improvement: switched to YUI CSS minifier PHP-port 2.8.4-p10 (so not to the 3.x branch yet)
|
238 |
+
* improvements to the logic of which JS/ CSS can be optimized (getPath function) increasing reliability of the aggregation process
|
239 |
+
* security: made placeholder replacement less naive to protect against XSS and LFI vulnerability as reported by Matthew Barry and fixed with great help from Matthew and Tomas Trkulja. Thanks guys!!
|
240 |
+
* API: Lots of extra filters, making AO (even) more flexible.
|
241 |
+
* Lots of bugfixes and smaller improvements (see [GitHub commit log](https://github.com/futtta/autoptimize/commits/master))
|
242 |
+
* tested and confirmed working in WordPress 4.8
|
243 |
+
|
244 |
+
= 2.1.2 =
|
245 |
+
* fix for security hash busting AO's cache badly
|
246 |
+
* identical to 2.1.0 except for the security fix backported from 2.2.0
|
247 |
+
|
248 |
= 2.1.1 =
|
249 |
+
* identical to 2.1.0 except for the security fix backported from 2.2.0
|
|
|
250 |
|
251 |
= 2.1.0 =
|
252 |
* new: Autoptimize now appears in admin-toolbar with an easy view on cache size and the possibility to purge the cache (pass `false` to `autoptimize_filter_toolbar_show` filter to disable), a big thanks to [Pablo Custo](https://github.com/pablocusto) for his hard work on this nice feature!
|