Version Description
[2017.08.13] = * fixed some debug notices * fixed the alternative html minification option
Download this release
Release Info
Developer | Alignak |
Plugin | Fast Velocity Minify |
Version | 2.2.0 |
Comparing to | |
See all releases |
Version 2.2.0
- fvm.css +30 -0
- fvm.js +122 -0
- fvm.php +1771 -0
- inc/functions-admin.php +74 -0
- inc/functions-serverinfo.php +362 -0
- inc/functions.php +862 -0
- libs/index.html +0 -0
- libs/jar/index.html +0 -0
- libs/jar/yuicompressor-2.4.8.jar +0 -0
- libs/matthiasmullie/index.html +0 -0
- libs/matthiasmullie/minify/bin/index.html +0 -0
- libs/matthiasmullie/minify/bin/minifycss +45 -0
- libs/matthiasmullie/minify/bin/minifyjs +45 -0
- libs/matthiasmullie/minify/data/index.html +0 -0
- libs/matthiasmullie/minify/data/js/index.html +0 -0
- libs/matthiasmullie/minify/data/js/keywords_after.txt +7 -0
- libs/matthiasmullie/minify/data/js/keywords_before.txt +26 -0
- libs/matthiasmullie/minify/data/js/keywords_reserved.txt +63 -0
- libs/matthiasmullie/minify/data/js/operators.txt +46 -0
- libs/matthiasmullie/minify/data/js/operators_after.txt +44 -0
- libs/matthiasmullie/minify/data/js/operators_before.txt +43 -0
- libs/matthiasmullie/minify/index.html +0 -0
- libs/matthiasmullie/minify/src/CSS.php +690 -0
- libs/matthiasmullie/minify/src/Exception.php +12 -0
- libs/matthiasmullie/minify/src/Exceptions/BasicException.php +12 -0
- libs/matthiasmullie/minify/src/Exceptions/FileImportException.php +10 -0
- libs/matthiasmullie/minify/src/Exceptions/IOException.php +10 -0
- libs/matthiasmullie/minify/src/Exceptions/index.html +0 -0
- libs/matthiasmullie/minify/src/JS.php +529 -0
- libs/matthiasmullie/minify/src/Minify.php +434 -0
- libs/matthiasmullie/minify/src/index.html +0 -0
- libs/matthiasmullie/path-converter/index.html +0 -0
- libs/matthiasmullie/path-converter/src/Converter.php +195 -0
- libs/matthiasmullie/path-converter/src/ConverterInterface.php +24 -0
- libs/matthiasmullie/path-converter/src/NoConverter.php +23 -0
- libs/matthiasmullie/path-converter/src/index.html +0 -0
- libs/mrclay/HTML.php +241 -0
- libs/mrclay/index.html +0 -0
- readme.txt +365 -0
fvm.css
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#fastvelocity-min{margin-top:10px;}
|
2 |
+
#fastvelocity-min .processed{ min-height: 20px; margin: -4px 0 -2px 0; border: none !important; }
|
3 |
+
#fastvelocity-min .processed li{margin:0; padding:10px 0; border: none !important; }
|
4 |
+
#fastvelocity-min .processed > li:last-of-type { border: 0; }
|
5 |
+
#fastvelocity-min .processed li .filename{width: 50%;float:left;font-family:monospace;display:block;word-wrap:break-word;line-height:30px;}
|
6 |
+
#fastvelocity-min .processed li .accessed{display:block;}
|
7 |
+
#fastvelocity-min .processed li .error{color:red}
|
8 |
+
#fastvelocity-min .processed li .actions{display:block; padding:0; margin:0; text-align: right;}
|
9 |
+
#fastvelocity-min .processed li a{margin-left:10px}
|
10 |
+
#fastvelocity-min .processed pre{background:#EEE;max-height:300px;overflow:auto;display:none;margin-top:18px;margin-bottom:7px;padding:5px}
|
11 |
+
#fastvelocity-min .clear { clear:both; }
|
12 |
+
#fastvelocity-min #purgeall-row { padding-bottom: 2px; }
|
13 |
+
.fvm-settings label { font-size: 14px; color: #222; padding-top: 1px; }
|
14 |
+
.fvm-settings span.note-info { font-size: 14px; margin-left: 8px; color: #666; font-style: italic; }
|
15 |
+
.fvm-settings p.description { font-size: 14px; color: #666; font-style: italic; font-size: 14px; }
|
16 |
+
#tab-info h4{font-size: 14px; margin-bottom:-10px; }
|
17 |
+
h3.hndle { background: #F7F7F7; color: #000;}
|
18 |
+
.fvm-hide { max-height: 1px; overflow: none; position: absolute; top: -9999px; left: -9999px; visibility: hidden; }
|
19 |
+
.fvm-warning { font-weight: 600; color: #AA0000; }
|
20 |
+
.fvm-bold-green { font-weight: 600; color: #1196A3; }
|
21 |
+
.fvm-label-special { line-height: 38px; }
|
22 |
+
.fvm-label-pad { line-height: 21px; }
|
23 |
+
|
24 |
+
@media screen and (max-width:520px) {
|
25 |
+
#fastvelocity-min .processed li .filename{width: 100%;float:none;}
|
26 |
+
#fastvelocity-min .processed li .actions{text-align: left;margin-top: 4px}
|
27 |
+
#fastvelocity-min .processed li a{margin-left:0;margin-right:10px}
|
28 |
+
#fastvelocity-min .processed pre{margin-top:12px;margin-bottom:5px;}
|
29 |
+
.fvm-label-special { line-height: inherit; }
|
30 |
+
}
|
fvm.js
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(function($){
|
2 |
+
|
3 |
+
$(function(){
|
4 |
+
|
5 |
+
// disable some checkboxes when some other is on or off
|
6 |
+
$('#fastvelocity_min_enable_defer_js').bind('click init', function() {
|
7 |
+
if( $(this).is(':checked')) {
|
8 |
+
$("#fastvelocity_min_exclude_defer_jquery, #fastvelocity_min_exclude_defer_login").prop("disabled", false);
|
9 |
+
} else {
|
10 |
+
$("#fastvelocity_min_exclude_defer_jquery, #fastvelocity_min_exclude_defer_login").prop("disabled", true);
|
11 |
+
}
|
12 |
+
}).trigger('init');
|
13 |
+
|
14 |
+
// disable some checkboxes when some other is on or off
|
15 |
+
$('#fastvelocity_min_skip_html_minification').bind('click init', function() {
|
16 |
+
if( $(this).is(':checked')) {
|
17 |
+
$("#fastvelocity_min_strip_htmlcomments").prop("disabled", true).prop('checked', false);
|
18 |
+
} else {
|
19 |
+
$("#fastvelocity_min_strip_htmlcomments").prop("disabled", false);
|
20 |
+
}
|
21 |
+
}).trigger('init');
|
22 |
+
|
23 |
+
// disable some checkboxes when some other is on or off
|
24 |
+
$('#fastvelocity_min_disable_css_merge').bind('click init', function() {
|
25 |
+
if( $(this).is(':checked')) {
|
26 |
+
$("#fastvelocity_min_disable_css_minification, #fastvelocity_min_force_inline_css").prop("disabled", true);
|
27 |
+
$("#fastvelocity_min_force_inline_css_footer").prop("disabled", true);
|
28 |
+
$("#fastvelocity_min_skip_cssorder, #fastvelocity_min_remove_print_mediatypes").prop("disabled", true);
|
29 |
+
} else {
|
30 |
+
$("#fastvelocity_min_disable_css_minification, #fastvelocity_min_force_inline_css").prop("disabled", false);
|
31 |
+
$("#fastvelocity_min_force_inline_css_footer").prop("disabled", false);
|
32 |
+
$("#fastvelocity_min_skip_cssorder, #fastvelocity_min_remove_print_mediatypes").prop("disabled", false);
|
33 |
+
}
|
34 |
+
}).trigger('init');
|
35 |
+
|
36 |
+
// disable some checkboxes when some other is on or off
|
37 |
+
$('#fastvelocity_min_disable_js_merge').bind('click init', function() {
|
38 |
+
if( $(this).is(':checked')) {
|
39 |
+
$("#fastvelocity_min_use_yui, #fastvelocity_min_disable_js_minification").prop("disabled", true);
|
40 |
+
$("#fastvelocity_min_enable_defer_js, #fastvelocity_min_defer_for_pagespeed").prop("disabled", true);
|
41 |
+
$("#fastvelocity_min_exclude_defer_jquery, #fastvelocity_min_exclude_defer_login").prop("disabled", true);
|
42 |
+
} else {
|
43 |
+
$("#fastvelocity_min_use_yui, #fastvelocity_min_disable_js_minification").prop("disabled", false);
|
44 |
+
$("#fastvelocity_min_enable_defer_js, #fastvelocity_min_defer_for_pagespeed").prop("disabled", false);
|
45 |
+
$("#fastvelocity_min_exclude_defer_jquery, #fastvelocity_min_exclude_defer_login").prop("disabled", false);
|
46 |
+
}
|
47 |
+
}).trigger('init');
|
48 |
+
|
49 |
+
|
50 |
+
|
51 |
+
// disable collapse
|
52 |
+
$('.postbox h3, .postbox .handlediv').unbind('click.postboxes');
|
53 |
+
|
54 |
+
// variables
|
55 |
+
var $fastvelocity_min_processed = $('#fastvelocity_min_processed'),
|
56 |
+
$fastvelocity_min_jsprocessed = $('#fastvelocity_min_jsprocessed',$fastvelocity_min_processed),
|
57 |
+
$fastvelocity_min_jsprocessed_ul = $('ul',$fastvelocity_min_jsprocessed),
|
58 |
+
$fastvelocity_min_cssprocessed = $('#fastvelocity_min_cssprocessed',$fastvelocity_min_processed),
|
59 |
+
$fastvelocity_min_cssprocessed_ul = $('ul',$fastvelocity_min_cssprocessed),
|
60 |
+
$fastvelocity_min_noprocessed = $('#fastvelocity_min_noprocessed'),
|
61 |
+
timeout = null,
|
62 |
+
stamp = null;
|
63 |
+
|
64 |
+
$($fastvelocity_min_processed).on('click','.log',function(e){
|
65 |
+
e.preventDefault();
|
66 |
+
$(this).parent().nextAll('pre').slideToggle();
|
67 |
+
});
|
68 |
+
|
69 |
+
function getFiles(extra) {
|
70 |
+
stamp = new Date().getTime();
|
71 |
+
var data = {
|
72 |
+
'action': 'fastvelocity_min_files',
|
73 |
+
'stamp': stamp
|
74 |
+
};
|
75 |
+
if(extra) {
|
76 |
+
for (var attrname in extra) { data[attrname] = extra[attrname]; }
|
77 |
+
}
|
78 |
+
|
79 |
+
|
80 |
+
$.post(ajaxurl, data, function(response) {
|
81 |
+
|
82 |
+
if(stamp == response.stamp) {
|
83 |
+
if(response.js.length > 0) {
|
84 |
+
$fastvelocity_min_jsprocessed.show();
|
85 |
+
|
86 |
+
$(response.js).each(function(){
|
87 |
+
var $li = $fastvelocity_min_jsprocessed_ul.find('li.'+this.hash);
|
88 |
+
if($li.length > 0) {
|
89 |
+
if($li.find('pre').html() != this.log) {
|
90 |
+
$li.find('pre').html(this.log);
|
91 |
+
}
|
92 |
+
} else {
|
93 |
+
$fastvelocity_min_jsprocessed_ul.append('<li class="'+this.hash+'"><span class="filename">'+this.filename+'</span> <span class="actions"><a href="#" class="log button button-primary">View Log</a></span><pre>'+this.log+'</pre></li><div class="clear"></div>');
|
94 |
+
}
|
95 |
+
});
|
96 |
+
|
97 |
+
}
|
98 |
+
if(response.css.length > 0) {
|
99 |
+
|
100 |
+
$(response.css).each(function(){
|
101 |
+
var $li = $fastvelocity_min_cssprocessed_ul.find('li.'+this.hash);
|
102 |
+
if($li.length > 0) {
|
103 |
+
if($li.find('pre').html() != this.log) {
|
104 |
+
$li.find('pre').html(this.log);
|
105 |
+
}
|
106 |
+
} else {
|
107 |
+
$fastvelocity_min_cssprocessed_ul.append('<li class="'+this.hash+'"><span class="filename">'+this.filename+'</span> <span class="actions"><a href="#" class="log button button-primary">View Log</a></span><pre>'+this.log+'</pre></li><div class="clear"></div>');
|
108 |
+
}
|
109 |
+
});
|
110 |
+
}
|
111 |
+
|
112 |
+
// check for new files
|
113 |
+
timeout = setTimeout(getFiles, 2500);
|
114 |
+
}
|
115 |
+
});
|
116 |
+
}
|
117 |
+
|
118 |
+
getFiles();
|
119 |
+
|
120 |
+
});
|
121 |
+
|
122 |
+
})(jQuery);
|
fvm.php
ADDED
@@ -0,0 +1,1771 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: Fast Velocity Minify
|
4 |
+
Plugin URI: http://fastvelocity.com
|
5 |
+
Description: Improve your speed score on GTmetrix, Pingdom Tools and Google PageSpeed Insights by merging and minifying CSS and JavaScript files into groups, compressing HTML and other speed optimizations.
|
6 |
+
Author: Raul Peixoto
|
7 |
+
Author URI: http://fastvelocity.com
|
8 |
+
Version: 2.2.0
|
9 |
+
License: GPL2
|
10 |
+
|
11 |
+
------------------------------------------------------------------------
|
12 |
+
This program is free software; you can redistribute it and/or modify
|
13 |
+
it under the terms of the GNU General Public License as published by
|
14 |
+
the Free Software Foundation; either version 2 of the License, or
|
15 |
+
(at your option) any later version.
|
16 |
+
|
17 |
+
This program is distributed in the hope that it will be useful,
|
18 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
20 |
+
GNU General Public License for more details.
|
21 |
+
|
22 |
+
You should have received a copy of the GNU General Public License
|
23 |
+
along with this program; if not, write to the Free Software
|
24 |
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
25 |
+
*/
|
26 |
+
|
27 |
+
|
28 |
+
# check for minimum requirements and prevent activation or disable if not fully compatible
|
29 |
+
function fvm_compat_checker() {
|
30 |
+
global $wp_version;
|
31 |
+
|
32 |
+
# defaults
|
33 |
+
$error = '';
|
34 |
+
$nwpv = implode('.', array_slice(explode('.', $wp_version), 0, 2)); # get 2 p only
|
35 |
+
|
36 |
+
# php version requirements
|
37 |
+
if (version_compare( PHP_VERSION, '5.4', '<' )) {
|
38 |
+
$error = 'Fast Velocity Minify requires PHP 5.4 or higher. You’re still on '. PHP_VERSION;
|
39 |
+
}
|
40 |
+
|
41 |
+
# php extension requirements
|
42 |
+
if (!extension_loaded('mbstring')) {
|
43 |
+
$error = 'Fast Velocity Minify requires the PHP mbstring module to be installed on the server.';
|
44 |
+
}
|
45 |
+
|
46 |
+
# wp version requirements
|
47 |
+
if ( $nwpv < '4.5' ) {
|
48 |
+
$error = 'Fast Velocity Minify requires WP 4.5 or higher. You’re still on ' . $wp_version;
|
49 |
+
}
|
50 |
+
|
51 |
+
|
52 |
+
if ((is_plugin_active(plugin_basename( __FILE__ )) && !empty($error)) || !empty($error)) {
|
53 |
+
if (isset($_GET['activate'])) { unset($_GET['activate']); }
|
54 |
+
deactivate_plugins( plugin_basename( __FILE__ ));
|
55 |
+
add_action('admin_notices', function() use ($error){
|
56 |
+
echo '<div class="notice notice-error is-dismissible"><p><strong>'.$error.'</strong></p></div>';
|
57 |
+
});
|
58 |
+
}
|
59 |
+
}
|
60 |
+
add_action('admin_init', 'fvm_compat_checker');
|
61 |
+
|
62 |
+
|
63 |
+
# get the plugin directory and include functions
|
64 |
+
$plugindir = plugin_dir_path( __FILE__ ); # with trailing slash
|
65 |
+
include($plugindir.'inc/functions.php');
|
66 |
+
include($plugindir.'inc/functions-serverinfo.php');
|
67 |
+
|
68 |
+
# get cache directories and urls
|
69 |
+
$cachepath = fvm_cachepath();
|
70 |
+
$tmpdir = $cachepath['tmpdir'];
|
71 |
+
$cachedir = $cachepath['cachedir'];
|
72 |
+
$cachedirurl = $cachepath['cachedirurl'];
|
73 |
+
|
74 |
+
# get the current wordpress installation url and path
|
75 |
+
$wp_home = site_url(); # get the current wordpress installation url
|
76 |
+
$wp_domain = trim(str_ireplace(array('http://', 'https://'), '', trim($wp_home, '/')));
|
77 |
+
$wp_home_path = ABSPATH;
|
78 |
+
|
79 |
+
# cleanup, delete any minification files older than 45 days (most probably unused files)
|
80 |
+
if ($handle = opendir($cachedir.'/')) {
|
81 |
+
while (false !== ($file = readdir($handle))) { $file = $cachedir.'/'.$file; if (is_file($file) && time() - filemtime($file) >= 86400 * 45) { unlink($file); } }
|
82 |
+
closedir($handle);
|
83 |
+
}
|
84 |
+
|
85 |
+
# default globals
|
86 |
+
$fastvelocity_min_global_js_done = array();
|
87 |
+
|
88 |
+
|
89 |
+
###########################################
|
90 |
+
# build control panel pages ###############
|
91 |
+
###########################################
|
92 |
+
|
93 |
+
# default options
|
94 |
+
$ignore = array(); # urls to exclude for merging and minification
|
95 |
+
$default_protocol = 'dynamic'; # use dynamic "//" protocols by default
|
96 |
+
$disable_js_merge = false; # disable JS merging? Default: false (if true, minification is also disabled)
|
97 |
+
$disable_css_merge = false; # disable CSS merging? Default: false (if true, minification is also disabled)
|
98 |
+
$disable_js_minification = false; # disable JS minification? Default: false
|
99 |
+
$disable_css_minification = false; # disable CSS minification? Default: false
|
100 |
+
$use_yui = false; # Use the YUI processor instead of PHP Minify? Default false
|
101 |
+
$remove_print_mediatypes = false; # remove CSS files of "print" mediatype
|
102 |
+
$skip_html_minification = false; # skip HTML minification? Default: false
|
103 |
+
$use_alt_html_minification = false; # use alt HTML minification? Default: false
|
104 |
+
$strip_htmlcomments = false; # whether to remove html comments on html minification
|
105 |
+
$skip_cssorder = false; # skip reordering CSS files by mediatype
|
106 |
+
$skip_google_fonts = false; # skip google fonts optimization? Default: false
|
107 |
+
$skip_emoji_removal = false; # skip removing emoji support? Default: false
|
108 |
+
$enable_defer_js = false; # Defer parsing of JavaScript? Default false
|
109 |
+
$exclude_defer_jquery = false; # Disable defer for jquery on the home
|
110 |
+
$use_google_closure = false; # Use Google closure (slower) instead of YUI processor? Default false
|
111 |
+
$use_php_minify = false; # Use PHP Minify instead of YUI or Closure? Default false
|
112 |
+
$force_inline_css = false; # Don't inline all css by default
|
113 |
+
$force_inline_css_footer = false; # Don't inline all css by default
|
114 |
+
$force_inline_googlefonts = false; # Don't inline all google fonts by default
|
115 |
+
$defer_for_pagespeed = false; # force defer for when we are being tested by pagespeed insights
|
116 |
+
$exclude_defer_login = false; # Disable defer js on the login page
|
117 |
+
$preload = array(); # urls to preload before anything else
|
118 |
+
$preconnect = array(); # domains to preconnect to
|
119 |
+
$fvm_fix_editor = false; # enable production mode by default?
|
120 |
+
|
121 |
+
# extra
|
122 |
+
$send_css_to_footer = false; # force defer for css
|
123 |
+
$critical_path_css = false; # critical path for homepage
|
124 |
+
$critical_css_tester = false; # will remove all css, except the critical path code
|
125 |
+
$generate_gulp_files = false; # will generate gulp files for gulp-uncss (spider the site first to generate the fvm cache files)
|
126 |
+
$generate_gulp_path = false; # path to working directory where gulp-uncss is installed
|
127 |
+
$used_css_files = array();
|
128 |
+
|
129 |
+
# add admin page and rewrite defaults
|
130 |
+
if(is_admin()) {
|
131 |
+
add_action('admin_menu', 'fastvelocity_min_admin_menu');
|
132 |
+
add_action('admin_enqueue_scripts', 'fastvelocity_min_load_admin_jscss');
|
133 |
+
add_action('wp_ajax_fastvelocity_min_files', 'fastvelocity_min_files_callback');
|
134 |
+
add_action('admin_init', 'fastvelocity_min_register_settings');
|
135 |
+
register_deactivation_hook( __FILE__, 'fastvelocity_min_plugin_deactivate');
|
136 |
+
} else {
|
137 |
+
# overwrite options from the database, false if not set
|
138 |
+
$ignore = array_map('trim', explode("\n", get_option('fastvelocity_min_ignore', '')));
|
139 |
+
$default_protocol = get_option('fastvelocity_min_default_protocol', 'dynamic');
|
140 |
+
$disable_js_merge = get_option('fastvelocity_min_disable_js_merge');
|
141 |
+
$disable_css_merge = get_option('fastvelocity_min_disable_css_merge');
|
142 |
+
$disable_js_minification = get_option('fastvelocity_min_disable_js_minification');
|
143 |
+
$disable_css_minification = get_option('fastvelocity_min_disable_css_minification');
|
144 |
+
$use_yui = get_option('fastvelocity_min_use_yui');
|
145 |
+
$remove_print_mediatypes = get_option('fastvelocity_min_remove_print_mediatypes');
|
146 |
+
$skip_html_minification = get_option('fastvelocity_min_skip_html_minification');
|
147 |
+
$use_alt_html_minification = get_option('fastvelocity_min_use_alt_html_minification');
|
148 |
+
$strip_htmlcomments = get_option('fastvelocity_min_strip_htmlcomments');
|
149 |
+
$skip_cssorder = get_option('fastvelocity_min_skip_cssorder');
|
150 |
+
$skip_google_fonts = get_option('fastvelocity_min_skip_google_fonts');
|
151 |
+
$skip_emoji_removal = get_option('fastvelocity_min_skip_emoji_removal');
|
152 |
+
$enable_defer_js = get_option('fastvelocity_min_enable_defer_js');
|
153 |
+
$exclude_defer_jquery = get_option('fastvelocity_min_exclude_defer_jquery');
|
154 |
+
$force_inline_css = get_option('fastvelocity_min_force_inline_css');
|
155 |
+
$force_inline_css_footer = get_option('fastvelocity_min_force_inline_css_footer');
|
156 |
+
$force_inline_googlefonts = get_option('fastvelocity_min_force_inline_googlefonts');
|
157 |
+
$defer_for_pagespeed = get_option('fastvelocity_min_defer_for_pagespeed');
|
158 |
+
$exclude_defer_login = get_option('fastvelocity_min_exclude_defer_login');
|
159 |
+
$preload = array_map('trim', explode("\n", get_option('fastvelocity_min_preload')));
|
160 |
+
$preconnect = array_map('trim', explode("\n", get_option('fastvelocity_min_preconnect')));
|
161 |
+
$fvm_fix_editor = get_option('fastvelocity_min_fvm_fix_editor');
|
162 |
+
$send_css_to_footer = get_option('fastvelocity_min_send_css_to_footer');
|
163 |
+
$critical_css_tester = get_option('fastvelocity_min_critical_css_tester');
|
164 |
+
$critical_path_css = get_option('fastvelocity_min_critical_path_css');
|
165 |
+
$generate_gulp_files = get_option('fastvelocity_min_generate_gulp_files');
|
166 |
+
$generate_gulp_path = get_option('fastvelocity_min_generate_gulp_path');
|
167 |
+
|
168 |
+
|
169 |
+
# skip on certain post_types or if there are specific keys on the url or if editor or admin
|
170 |
+
if(!fastvelocity_exclude_contents()) {
|
171 |
+
|
172 |
+
# actions for frontend only
|
173 |
+
if(!$disable_js_merge) {
|
174 |
+
add_action( 'wp_print_scripts', 'fastvelocity_min_merge_header_scripts', PHP_INT_MAX );
|
175 |
+
add_action( 'wp_print_footer_scripts', 'fastvelocity_min_merge_footer_scripts', 9.999999 );
|
176 |
+
}
|
177 |
+
if(!$disable_css_merge) {
|
178 |
+
add_action('wp_head', 'fvm_buffer_placeholder_top', 0);
|
179 |
+
add_action('wp_print_styles', 'fastvelocity_min_merge_header_css', PHP_INT_MAX );
|
180 |
+
add_action('wp_print_footer_scripts', 'fastvelocity_min_merge_footer_css', 9.999999 );
|
181 |
+
}
|
182 |
+
if(!$skip_emoji_removal) {
|
183 |
+
add_action( 'init', 'fastvelocity_min_disable_wp_emojicons' );
|
184 |
+
}
|
185 |
+
|
186 |
+
}
|
187 |
+
}
|
188 |
+
|
189 |
+
|
190 |
+
|
191 |
+
# exclude processing for editors and administrators (fix editors)
|
192 |
+
add_action( 'plugins_loaded', 'fastvelocity_fix_editor' );
|
193 |
+
function fastvelocity_fix_editor() {
|
194 |
+
global $fvm_fix_editor, $disable_js_merge, $disable_css_merge, $skip_emoji_removal;
|
195 |
+
if($fvm_fix_editor == true && is_user_logged_in() && (current_user_can('editor') || current_user_can('administrator'))) {
|
196 |
+
if(!$disable_js_merge) {
|
197 |
+
remove_action( 'wp_print_scripts', 'fastvelocity_min_merge_header_scripts', PHP_INT_MAX );
|
198 |
+
remove_action( 'wp_print_footer_scripts', 'fastvelocity_min_merge_footer_scripts', 9.999999 );
|
199 |
+
}
|
200 |
+
if(!$disable_css_merge) {
|
201 |
+
remove_action('wp_head', 'fvm_buffer_placeholder_top', 0);
|
202 |
+
remove_action('wp_print_styles', 'fastvelocity_min_merge_header_css', PHP_INT_MAX );
|
203 |
+
remove_action('wp_print_footer_scripts', 'fastvelocity_min_merge_footer_css', 9.999999 );
|
204 |
+
}
|
205 |
+
if(!$skip_emoji_removal) {
|
206 |
+
remove_action( 'init', 'fastvelocity_min_disable_wp_emojicons' );
|
207 |
+
}
|
208 |
+
}
|
209 |
+
}
|
210 |
+
|
211 |
+
|
212 |
+
# delete the cache when we deactivate the plugin
|
213 |
+
function fastvelocity_min_plugin_deactivate() { fvm_purge_all(); }
|
214 |
+
|
215 |
+
|
216 |
+
# create admin menu
|
217 |
+
function fastvelocity_min_admin_menu() {
|
218 |
+
add_options_page('Fast Velocity Minify Settings', 'Fast Velocity Minify', 'manage_options', 'fastvelocity-min', 'fastvelocity_min_settings');
|
219 |
+
}
|
220 |
+
|
221 |
+
|
222 |
+
# function to list all cache files
|
223 |
+
function fastvelocity_min_files_callback() {
|
224 |
+
global $cachedir;
|
225 |
+
|
226 |
+
# default
|
227 |
+
$return = array('js' => array(), 'css' => array(), 'stamp' => $_POST['stamp']);
|
228 |
+
|
229 |
+
# inspect directory with opendir, since glob might not be available in some systems
|
230 |
+
if ($handle = opendir($cachedir.'/')) {
|
231 |
+
while (false !== ($file = readdir($handle))) {
|
232 |
+
$file = $cachedir.'/'.$file;
|
233 |
+
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
234 |
+
if (in_array($ext, array('js', 'css'))) {
|
235 |
+
$log = file_get_contents($file.'.txt');
|
236 |
+
$mincss = substr($file, 0, -4).'.min.css';
|
237 |
+
$minjs = substr($file, 0, -3).'.min.js';
|
238 |
+
$filename = basename($file);
|
239 |
+
if ($ext == 'css' && file_exists($mincss)) { $filename = basename($mincss); }
|
240 |
+
if ($ext == 'js' && file_exists($minjs)) { $filename = basename($minjs); }
|
241 |
+
|
242 |
+
# get location, hash, modified date
|
243 |
+
$info = explode('-', $filename);
|
244 |
+
$hash = $info['1'];
|
245 |
+
array_push($return[$ext], array('hash' => $hash, 'filename' => $filename, 'log' => $log));
|
246 |
+
}
|
247 |
+
}
|
248 |
+
closedir($handle);
|
249 |
+
}
|
250 |
+
|
251 |
+
header('Content-Type: application/json');
|
252 |
+
echo json_encode($return);
|
253 |
+
wp_die();
|
254 |
+
}
|
255 |
+
|
256 |
+
|
257 |
+
# load wp-admin css and js files
|
258 |
+
function fastvelocity_min_load_admin_jscss($hook) {
|
259 |
+
if ('settings_page_fastvelocity-min' != $hook) { return; }
|
260 |
+
wp_enqueue_script('postbox');
|
261 |
+
wp_enqueue_style('fastvelocity-min', plugins_url('fvm.css', __FILE__), array(), filemtime(plugin_dir_path( __FILE__).'fvm.css'));
|
262 |
+
wp_enqueue_script('fastvelocity-min', plugins_url('fvm.js', __FILE__), array('jquery'), filemtime(plugin_dir_path( __FILE__).'fvm.js'), true);
|
263 |
+
}
|
264 |
+
|
265 |
+
|
266 |
+
# register plugin settings
|
267 |
+
function fastvelocity_min_register_settings() {
|
268 |
+
register_setting('fvm-group', 'fastvelocity_min_ignore');
|
269 |
+
register_setting('fvm-group', 'fastvelocity_min_default_protocol');
|
270 |
+
register_setting('fvm-group', 'fastvelocity_min_disable_js_merge');
|
271 |
+
register_setting('fvm-group', 'fastvelocity_min_disable_css_merge');
|
272 |
+
register_setting('fvm-group', 'fastvelocity_min_disable_js_minification');
|
273 |
+
register_setting('fvm-group', 'fastvelocity_min_disable_css_minification');
|
274 |
+
register_setting('fvm-group', 'fastvelocity_min_use_yui');
|
275 |
+
register_setting('fvm-group', 'fastvelocity_min_remove_print_mediatypes');
|
276 |
+
register_setting('fvm-group', 'fastvelocity_min_skip_html_minification');
|
277 |
+
register_setting('fvm-group', 'fastvelocity_min_use_alt_html_minification');
|
278 |
+
register_setting('fvm-group', 'fastvelocity_min_strip_htmlcomments');
|
279 |
+
register_setting('fvm-group', 'fastvelocity_min_skip_cssorder');
|
280 |
+
register_setting('fvm-group', 'fastvelocity_min_skip_google_fonts');
|
281 |
+
register_setting('fvm-group', 'fastvelocity_min_skip_fontawesome_fonts');
|
282 |
+
register_setting('fvm-group', 'fastvelocity_min_skip_emoji_removal');
|
283 |
+
register_setting('fvm-group', 'fastvelocity_min_enable_defer_js');
|
284 |
+
register_setting('fvm-group', 'fastvelocity_min_exclude_defer_jquery');
|
285 |
+
register_setting('fvm-group', 'fastvelocity_min_force_inline_css');
|
286 |
+
register_setting('fvm-group', 'fastvelocity_min_force_inline_css_footer');
|
287 |
+
register_setting('fvm-group', 'fastvelocity_min_force_inline_googlefonts');
|
288 |
+
register_setting('fvm-group', 'fastvelocity_min_defer_for_pagespeed');
|
289 |
+
register_setting('fvm-group', 'fastvelocity_min_exclude_defer_login');
|
290 |
+
register_setting('fvm-group', 'fastvelocity_min_preload');
|
291 |
+
register_setting('fvm-group', 'fastvelocity_min_preconnect');
|
292 |
+
register_setting('fvm-group', 'fastvelocity_min_fvm_fix_editor');
|
293 |
+
register_setting('fvm-group', 'fastvelocity_min_fvm_enable_cdn');
|
294 |
+
register_setting('fvm-group', 'fastvelocity_min_fvm_cdn_url');
|
295 |
+
|
296 |
+
# pro version (for private usage... or if you know what you're doing)
|
297 |
+
register_setting('fvm-group-pro', 'fastvelocity_min_send_css_to_footer');
|
298 |
+
register_setting('fvm-group-pro', 'fastvelocity_min_critical_css_tester');
|
299 |
+
register_setting('fvm-group-pro', 'fastvelocity_min_critical_path_css');
|
300 |
+
register_setting('fvm-group-pro', 'fastvelocity_min_generate_gulp_files');
|
301 |
+
register_setting('fvm-group-pro', 'fastvelocity_min_generate_gulp_path');
|
302 |
+
register_setting('fvm-group-license', 'fastvelocity_min_license_code');
|
303 |
+
}
|
304 |
+
|
305 |
+
|
306 |
+
|
307 |
+
# add settings link on plugin page
|
308 |
+
function fastvelocity_min_settings_link($links) {
|
309 |
+
if (is_plugin_active(plugin_basename( __FILE__ ))) {
|
310 |
+
$settings_link = '<a href="options-general.php?page=fastvelocity-min">Settings</a>';
|
311 |
+
array_unshift($links, $settings_link);
|
312 |
+
}
|
313 |
+
return $links;
|
314 |
+
}
|
315 |
+
add_filter("plugin_action_links_".plugin_basename(__FILE__), 'fastvelocity_min_settings_link' );
|
316 |
+
|
317 |
+
|
318 |
+
|
319 |
+
# manage settings page
|
320 |
+
function fastvelocity_min_settings() {
|
321 |
+
if (!current_user_can('manage_options')) { wp_die( __('You do not have sufficient permissions to access this page.')); }
|
322 |
+
|
323 |
+
# tmp folder
|
324 |
+
global $tmpdir, $cachedir, $plugindir;
|
325 |
+
|
326 |
+
# get active tab, set default
|
327 |
+
$active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'status';
|
328 |
+
|
329 |
+
?>
|
330 |
+
<div class="wrap">
|
331 |
+
<h1>Fast Velocity Minify</h1>
|
332 |
+
|
333 |
+
<?php
|
334 |
+
|
335 |
+
# purge all caches
|
336 |
+
if(isset($_POST['purgeall']) && $_POST['purgeall'] == 1) {
|
337 |
+
fvm_purge_all(); # purge all
|
338 |
+
echo __('<div class="notice notice-success is-dismissible"><p>The <strong>CSS and JS</strong> files have been purged!</p></div>');
|
339 |
+
echo fastvelocity_purge_others(); # purge third party caches
|
340 |
+
}
|
341 |
+
?>
|
342 |
+
|
343 |
+
<h2 class="nav-tab-wrapper wp-clearfix">
|
344 |
+
<a href="?page=fastvelocity-min&tab=status" class="nav-tab <?php echo $active_tab == 'status' ? 'nav-tab-active' : ''; ?>">Status</a>
|
345 |
+
<a href="?page=fastvelocity-min&tab=settings" class="nav-tab <?php echo $active_tab == 'settings' ? 'nav-tab-active' : ''; ?>">Settings</a>
|
346 |
+
<?php
|
347 |
+
# this is still under development
|
348 |
+
$fvm_license = get_option('fastvelocity_min_license_code');
|
349 |
+
if($fvm_license != false && mb_strlen($fvm_license, 'UTF-8') == 32) {
|
350 |
+
?>
|
351 |
+
<a href="?page=fastvelocity-min&tab=pro" class="nav-tab <?php echo $active_tab == 'pro' ? 'nav-tab-active' : ''; ?>">Extra</a>
|
352 |
+
<?php
|
353 |
+
}
|
354 |
+
?>
|
355 |
+
<a href="?page=fastvelocity-min&tab=server" class="nav-tab <?php echo $active_tab == 'server' ? 'nav-tab-active' : ''; ?>">Server Info</a>
|
356 |
+
<a href="?page=fastvelocity-min&tab=help" class="nav-tab <?php echo $active_tab == 'help' ? 'nav-tab-active' : ''; ?>">Help</a>
|
357 |
+
</h2>
|
358 |
+
|
359 |
+
|
360 |
+
<?php if( $active_tab == 'status' ) { ?>
|
361 |
+
|
362 |
+
<div id="fastvelocity-min">
|
363 |
+
<div id="poststuff">
|
364 |
+
<div id="fastvelocity_min_processed" class="postbox-container">
|
365 |
+
<div class="meta-box">
|
366 |
+
|
367 |
+
<div class="postbox" id="tab-purge">
|
368 |
+
<h3 class="hndle"><span>Purge processed files</span></h3>
|
369 |
+
<div class="inside" id="fastvelocity_min_topbtns">
|
370 |
+
<ul class="processed">
|
371 |
+
<li id="purgeall-row">
|
372 |
+
<span class="filename">Purge processed CSS and JS files</span>
|
373 |
+
<span class="actions">
|
374 |
+
<form method="post" id="fastvelocity_min_clearall" action="<?php echo admin_url('options-general.php?page=fastvelocity-min&tab=status'); ?>">
|
375 |
+
<input type="hidden" name="purgeall" value="1" />
|
376 |
+
<?php submit_button('Delete', 'button-secondary', 'submit', false); ?>
|
377 |
+
</form>
|
378 |
+
</li>
|
379 |
+
</ul>
|
380 |
+
</div>
|
381 |
+
</div>
|
382 |
+
|
383 |
+
<div class="postbox" id="tab-js">
|
384 |
+
<h3 class="hndle"><span>List of processed JS files</span></h3>
|
385 |
+
<div class="inside" id="fastvelocity_min_jsprocessed">
|
386 |
+
<ul class="processed"></ul>
|
387 |
+
</div>
|
388 |
+
</div>
|
389 |
+
|
390 |
+
<div class="postbox" id="tab-css">
|
391 |
+
<h3 class="hndle"><span>List of processed CSS files</span></h3>
|
392 |
+
<div class="inside" id="fastvelocity_min_cssprocessed">
|
393 |
+
<ul class="processed"></ul>
|
394 |
+
</div>
|
395 |
+
</div>
|
396 |
+
|
397 |
+
</div>
|
398 |
+
</div>
|
399 |
+
</div>
|
400 |
+
</div>
|
401 |
+
<?php } ?>
|
402 |
+
|
403 |
+
<?php if( $active_tab == 'settings' ) { ?>
|
404 |
+
<form method="post" action="options.php">
|
405 |
+
<?php settings_fields('fvm-group'); do_settings_sections('fvm-group'); ?>
|
406 |
+
|
407 |
+
<div style="height: 20px;"></div>
|
408 |
+
<h2 class="title">Basic Options</h2>
|
409 |
+
<p class="fvm-bold-green">These options are generaly safe to edit as needed. If you use a cache plugin, kindly purge all your caches once you're done with the changes.</p>
|
410 |
+
|
411 |
+
<table class="form-table fvm-settings">
|
412 |
+
<tbody>
|
413 |
+
|
414 |
+
<tr>
|
415 |
+
<th scope="row">Troubleshooting</th>
|
416 |
+
<td><fieldset><legend class="screen-reader-text"><span>Troubleshooting</span></legend>
|
417 |
+
<label for="fastvelocity_min_fvm_fix_editor">
|
418 |
+
<input name="fastvelocity_min_fvm_fix_editor" type="checkbox" id="fastvelocity_min_fvm_fix_editor" value="1" <?php echo checked(1 == get_option('fastvelocity_min_fvm_fix_editor'), true, false); ?>>
|
419 |
+
Fix Page Editors <span class="note-info">[ If selected, logged in users with the "editor" role (and above) will bypass all optimizations ]</span></label>
|
420 |
+
</fieldset></td>
|
421 |
+
</tr>
|
422 |
+
|
423 |
+
|
424 |
+
<tr>
|
425 |
+
<th scope="row">URL Options</th>
|
426 |
+
<td>
|
427 |
+
<?php
|
428 |
+
# what to select
|
429 |
+
$sel = get_option('fastvelocity_min_default_protocol');
|
430 |
+
$a = ''; if($sel == 'dynamic' || empty($sel)) { $a = ' checked="checked"'; }
|
431 |
+
$b = ''; if($sel == 'http') { $b = ' checked="checked"'; }
|
432 |
+
$c = ''; if($sel == 'https') { $c = ' checked="checked"'; }
|
433 |
+
?>
|
434 |
+
<fieldset><legend class="screen-reader-text"><span>URL Options</span></legend>
|
435 |
+
<label><input type="radio" name="fastvelocity_min_default_protocol" value="dynamic" <?php echo $a; ?>> Use the default dynamic "//" protocol</label><br>
|
436 |
+
<label><input type="radio" name="fastvelocity_min_default_protocol" value="http"<?php echo $b; ?>> Force HTTP urls</label><br>
|
437 |
+
<label><input type="radio" name="fastvelocity_min_default_protocol" value="https"<?php echo $c; ?>> Force HTTPS urls</span></label><br>
|
438 |
+
</fieldset>
|
439 |
+
</td>
|
440 |
+
</tr>
|
441 |
+
|
442 |
+
<tr>
|
443 |
+
<th scope="row">HTML Options</th>
|
444 |
+
<td><fieldset><legend class="screen-reader-text"><span>HTML Options</span></legend>
|
445 |
+
<label for="fastvelocity_min_skip_html_minification">
|
446 |
+
<input name="fastvelocity_min_skip_html_minification" type="checkbox" id="fastvelocity_min_skip_html_minification" value="1" <?php echo checked(1 == get_option('fastvelocity_min_skip_html_minification'), true, false); ?>>
|
447 |
+
Disable minification on HTML <span class="note-info">[ Normally, it's safe to leave HTML minification enabled ]</span></label>
|
448 |
+
<br />
|
449 |
+
|
450 |
+
<label for="fastvelocity_min_use_alt_html_minification">
|
451 |
+
<input name="fastvelocity_min_use_alt_html_minification" type="checkbox" id="fastvelocity_min_use_alt_html_minification" value="1" <?php echo checked(1 == get_option('fastvelocity_min_use_alt_html_minification'), true, false); ?>>
|
452 |
+
Use the alternative HTML minification <span class="note-info">[ Select this, if you have some problem with some spaces disappearing ]</span></label>
|
453 |
+
<br />
|
454 |
+
|
455 |
+
<label for="fastvelocity_min_strip_htmlcomments">
|
456 |
+
<input name="fastvelocity_min_strip_htmlcomments" type="checkbox" id="fastvelocity_min_strip_htmlcomments" value="1" <?php echo checked(1 == get_option('fastvelocity_min_strip_htmlcomments'), true, false); ?>>
|
457 |
+
Strip HTML comments <span class="note-info">[ Some plugins need HTML comments to work properly ]</span></label>
|
458 |
+
<br />
|
459 |
+
|
460 |
+
</fieldset></td>
|
461 |
+
</tr>
|
462 |
+
|
463 |
+
|
464 |
+
<tr>
|
465 |
+
<th scope="row">Fonts Options</th>
|
466 |
+
<td><fieldset><legend class="screen-reader-text"><span>Fonts Options</span></legend>
|
467 |
+
<label for="fastvelocity_min_skip_emoji_removal">
|
468 |
+
<input name="fastvelocity_min_skip_emoji_removal" type="checkbox" id="fastvelocity_min_skip_emoji_removal" class="jsprocessor" value="1" <?php echo checked(1 == get_option('fastvelocity_min_skip_emoji_removal'), true, false); ?> >
|
469 |
+
Stop removing Emojis and smileys <span class="note-info">[ If selected, Emojis will be left alone and won't be removed from wordpress ]</span></label>
|
470 |
+
<br />
|
471 |
+
|
472 |
+
<label for="fastvelocity_min_skip_google_fonts">
|
473 |
+
<input name="fastvelocity_min_skip_google_fonts" type="checkbox" id="fastvelocity_min_skip_google_fonts" value="1" <?php echo checked(1 == get_option('fastvelocity_min_skip_google_fonts'), true, false); ?> >
|
474 |
+
Disable Google Fonts merging <span class="note-info">[ If selected, Google Fonts will no longer be merged into one request ]</span></label>
|
475 |
+
<br />
|
476 |
+
|
477 |
+
<label for="fastvelocity_min_force_inline_googlefonts">
|
478 |
+
<input name="fastvelocity_min_force_inline_googlefonts" type="checkbox" id="fastvelocity_min_force_inline_googlefonts" value="1" <?php echo checked(1 == get_option('fastvelocity_min_force_inline_googlefonts'), true, false); ?> >
|
479 |
+
Inline Google Fonts CSS <span class="note-info">[ If selected, Google Fonts CSS code will be inlined using "*.woof" format - NOTE: IE9+ and <a target="_blank" href="http://caniuse.com/#feat=woff">modern browsers</a> only]</span></label>
|
480 |
+
<br />
|
481 |
+
|
482 |
+
</fieldset></td>
|
483 |
+
</tr>
|
484 |
+
|
485 |
+
|
486 |
+
|
487 |
+
|
488 |
+
<tr>
|
489 |
+
<th scope="row">CSS Options</th>
|
490 |
+
<td><fieldset><legend class="screen-reader-text"><span>CSS Options</span></legend>
|
491 |
+
|
492 |
+
<label for="fastvelocity_min_disable_css_merge">
|
493 |
+
<input name="fastvelocity_min_disable_css_merge" type="checkbox" id="fastvelocity_min_disable_css_merge" value="1" <?php echo checked(1 == get_option('fastvelocity_min_disable_css_merge'), true, false); ?>>
|
494 |
+
Disable CSS processing<span class="note-info">[ If selected, this plugin will ignore CSS files completely ]</span></label>
|
495 |
+
<br />
|
496 |
+
<label for="fastvelocity_min_disable_css_minification">
|
497 |
+
<input name="fastvelocity_min_disable_css_minification" type="checkbox" id="fastvelocity_min_disable_css_minification" value="1" <?php echo checked(1 == get_option('fastvelocity_min_disable_css_minification'), true, false); ?>>
|
498 |
+
Disable minification on CSS files <span class="note-info">[ If selected, CSS files will be merged but not minified ]</span></label>
|
499 |
+
<br />
|
500 |
+
<label for="fastvelocity_min_skip_cssorder">
|
501 |
+
<input name="fastvelocity_min_skip_cssorder" type="checkbox" id="fastvelocity_min_skip_cssorder" value="1" <?php echo checked(1 == get_option('fastvelocity_min_skip_cssorder'), true, false); ?> >
|
502 |
+
Preserve the order of CSS files <span class="note-info">[ If selected, you will have better CSS compatibility but possibly more CSS files]</span></label>
|
503 |
+
<br />
|
504 |
+
<label for="fastvelocity_min_remove_print_mediatypes">
|
505 |
+
<input name="fastvelocity_min_remove_print_mediatypes" type="checkbox" id="fastvelocity_min_remove_print_mediatypes" value="1" <?php echo checked(1 == get_option('fastvelocity_min_remove_print_mediatypes'), true, false); ?> >
|
506 |
+
Remove the "Print" related stylesheets <span class="note-info">[ If selected, CSS files of mediatype "print" will be removed from the site ]</span></label>
|
507 |
+
<br />
|
508 |
+
<label for="fastvelocity_min_force_inline_css">
|
509 |
+
<input name="fastvelocity_min_force_inline_css" type="checkbox" id="fastvelocity_min_force_inline_css" value="1" <?php echo checked(1 == get_option('fastvelocity_min_force_inline_css'), true, false); ?>>
|
510 |
+
Inline all header CSS files <span class="note-info">[ If selected, the header CSS will be inlined to avoid the "render blocking" on pagespeed insights tests ]</span></label>
|
511 |
+
<br />
|
512 |
+
<label for="fastvelocity_min_force_inline_css_footer">
|
513 |
+
<input name="fastvelocity_min_force_inline_css_footer" type="checkbox" id="fastvelocity_min_force_inline_css_footer" value="1" <?php echo checked(1 == get_option('fastvelocity_min_force_inline_css_footer'), true, false); ?>>
|
514 |
+
Inline all footer CSS files <span class="note-info">[ If selected, the footer CSS will be inlined to avoid the "render blocking" on pagespeed insights tests ]</span></label>
|
515 |
+
<br />
|
516 |
+
</fieldset></td>
|
517 |
+
</tr>
|
518 |
+
|
519 |
+
|
520 |
+
<tr>
|
521 |
+
<th scope="row">JavaScript Options</th>
|
522 |
+
<td><fieldset><legend class="screen-reader-text"><span>JavaScript Options</span></legend>
|
523 |
+
<label for="fastvelocity_min_disable_js_merge">
|
524 |
+
<input name="fastvelocity_min_disable_js_merge" type="checkbox" id="fastvelocity_min_disable_js_merge" value="1" <?php echo checked(1 == get_option('fastvelocity_min_disable_js_merge'), true, false); ?> >
|
525 |
+
Disable JavaScript processing <span class="note-info">[ If selected, this plugin will ignore JS files completely ]</span></label>
|
526 |
+
<br />
|
527 |
+
|
528 |
+
<?php
|
529 |
+
# check for exec + a supported java version
|
530 |
+
if(function_exists('exec') && exec('command -v java >/dev/null && echo "yes" || echo "no"') == 'yes') {
|
531 |
+
?>
|
532 |
+
<label for="fastvelocity_min_use_yui">
|
533 |
+
<input name="fastvelocity_min_use_yui" type="checkbox" id="fastvelocity_min_use_yui" class="jsprocessor" value="1" <?php echo checked(1 == get_option('fastvelocity_min_use_yui'), true, false); ?> >
|
534 |
+
Minify with YUI Compressor <span class="note-info">[ If selected, it will try to use the YUI Compressor to minify JS files ]</span></label>
|
535 |
+
<br />
|
536 |
+
<?php } ?>
|
537 |
+
|
538 |
+
<label for="fastvelocity_min_disable_js_minification">
|
539 |
+
<input name="fastvelocity_min_disable_js_minification" type="checkbox" id="fastvelocity_min_disable_js_minification" value="1" <?php echo checked(1 == get_option('fastvelocity_min_disable_js_minification'), true, false); ?> >
|
540 |
+
Disable minification on JS files <span class="note-info">[ If selected, JS files will be merged but not minified ]</span></label>
|
541 |
+
<br />
|
542 |
+
</fieldset></td>
|
543 |
+
</tr>
|
544 |
+
</tbody></table>
|
545 |
+
|
546 |
+
|
547 |
+
<div style="height: 20px;"></div>
|
548 |
+
<h2 class="title">JS Advanced Options</h2>
|
549 |
+
<p class="fvm-bold-green">It's highly recommended that you only select the options below if you're an advanced user or developer and understand what these options mean.</p>
|
550 |
+
|
551 |
+
<table class="form-table fvm-settings">
|
552 |
+
<tbody>
|
553 |
+
<tr>
|
554 |
+
<th scope="row">Render-blocking JS</th>
|
555 |
+
<td><fieldset><legend class="screen-reader-text"><span>Render-blocking</span></legend>
|
556 |
+
<label for="fastvelocity_min_enable_defer_js">
|
557 |
+
<input name="fastvelocity_min_enable_defer_js" type="checkbox" id="fastvelocity_min_enable_defer_js" value="1" <?php echo checked(1 == get_option('fastvelocity_min_enable_defer_js'), true, false); ?>>
|
558 |
+
Enable defer parsing of JS files globally <span class="note-info">[ Not all browsers, themes or plugins support this. Beware of broken functionality and design ]</span></label>
|
559 |
+
<br />
|
560 |
+
<label for="fastvelocity_min_defer_for_pagespeed">
|
561 |
+
<input name="fastvelocity_min_defer_for_pagespeed" type="checkbox" id="fastvelocity_min_defer_for_pagespeed" value="1" <?php echo checked(1 == get_option('fastvelocity_min_defer_for_pagespeed'), true, false); ?>>
|
562 |
+
Enable defer of JS for Pagespeed Insights <span class="note-info">[ This will defer JS files for Pagespeed Insights only, <a target="_blank" href="https://www.chromestatus.com/feature/5718547946799104">except external scripts</a> loaded from other domains ]</span></label>
|
563 |
+
<br />
|
564 |
+
|
565 |
+
<label for="fastvelocity_min_exclude_defer_jquery">
|
566 |
+
<input name="fastvelocity_min_exclude_defer_jquery" type="checkbox" id="fastvelocity_min_exclude_defer_jquery" value="1" <?php echo checked(1 == get_option('fastvelocity_min_exclude_defer_jquery'), true, false); ?> >
|
567 |
+
Skip deferring the jQuery library <span class="note-info">[ Will fix "undefined jQuery" errors on the Google Chrome console log ]</span></label>
|
568 |
+
<br />
|
569 |
+
<label for="fastvelocity_min_exclude_defer_login">
|
570 |
+
<input name="fastvelocity_min_exclude_defer_login" type="checkbox" id="fastvelocity_min_exclude_defer_login" value="1" <?php echo checked(1 == get_option('fastvelocity_min_exclude_defer_login'), true, false); ?> >
|
571 |
+
Skip deferring completely on the login page <span class="note-info">[ If selected, will disable JS deferring on your login page ]</span></label>
|
572 |
+
<br />
|
573 |
+
|
574 |
+
|
575 |
+
</fieldset></td>
|
576 |
+
</tr>
|
577 |
+
</tbody></table>
|
578 |
+
|
579 |
+
|
580 |
+
|
581 |
+
<div style="height: 20px;"></div>
|
582 |
+
<h2 class="title">JS and CSS Exceptions</h2>
|
583 |
+
<p class="fvm-bold-green">You can use this section to exclude certain CSS or JS files from being processed in case of conflicts while merging.</p>
|
584 |
+
|
585 |
+
<table class="form-table fvm-settings">
|
586 |
+
<tbody>
|
587 |
+
<tr>
|
588 |
+
<th scope="row">Ignore List</th>
|
589 |
+
<td><fieldset><legend class="screen-reader-text"><span>Ignore List</span></legend>
|
590 |
+
<p><label for="blacklist_keys"><span class="fvm-label-pad">Ignore the following CSS and JS paths below:</span></label></p>
|
591 |
+
<p>
|
592 |
+
<textarea name="fastvelocity_min_ignore" rows="10" cols="50" id="fastvelocity_min_ignore" class="large-text code" placeholder="ex: /wp-includes/js/jquery/jquery.js"><?php echo get_option('fastvelocity_min_ignore'); ?></textarea>
|
593 |
+
</p>
|
594 |
+
<p class="description">[ Remove all query strings and use only relative or partial urls, ex: /wp-includes/js/jquery/jquery.js ]</p>
|
595 |
+
<br />
|
596 |
+
</fieldset></td>
|
597 |
+
</tr>
|
598 |
+
</tbody></table>
|
599 |
+
|
600 |
+
|
601 |
+
<div style="height: 20px;"></div>
|
602 |
+
<h2 class="title">CDN Options</h2>
|
603 |
+
<p class="fvm-bold-green">This rewrite our generated CSS and JS urls to use your cdn domain name.</p>
|
604 |
+
|
605 |
+
<table class="form-table fvm-settings">
|
606 |
+
<tbody>
|
607 |
+
<tr>
|
608 |
+
<th scope="row"><span class="fvm-label-special">CDN URL</span></th>
|
609 |
+
<td><fieldset><legend class="screen-reader-text"><span>CDN URL</span></legend>
|
610 |
+
<label for="fastvelocity_min_fvm_cdn_url">
|
611 |
+
<p><input type="text" name="fastvelocity_min_fvm_cdn_url" id="fastvelocity_min_fvm_cdn_url" value="<?php echo get_option('fastvelocity_min_fvm_cdn_url', ''); ?>" size="80" /></p>
|
612 |
+
<p class="description">[ Leave empty, or enter your CDN URL domain name here ]</p></label>
|
613 |
+
</fieldset></td>
|
614 |
+
</tr>
|
615 |
+
</tbody></table>
|
616 |
+
|
617 |
+
|
618 |
+
<div style="height: 20px;"></div>
|
619 |
+
<h2 class="title">Preconnect Optimization</h2>
|
620 |
+
<p class="fvm-bold-green">Please make sure you understand these options before using them.</p>
|
621 |
+
|
622 |
+
<table class="form-table fvm-settings">
|
623 |
+
<tbody>
|
624 |
+
<tr>
|
625 |
+
<th scope="row">Preconnect Headers</th>
|
626 |
+
<td><fieldset><legend class="screen-reader-text"><span>Preconnect</span></legend>
|
627 |
+
<label for="fastvelocity_min_preconnect"><span class="fvm-label-pad">Insert one domain name url per line:</span></label>
|
628 |
+
<p>
|
629 |
+
<textarea name="fastvelocity_min_preconnect" rows="10" cols="50" id="fastvelocity_min_preconnect" class="large-text code" placeholder="ex: //fonts.gstatic.com"><?php echo get_option('fastvelocity_min_preconnect'); ?></textarea>
|
630 |
+
</p>
|
631 |
+
<p class="description">[ Use only the necessary domain names, such as remote font domain names, ex: //fonts.gstatic.com ]</p>
|
632 |
+
</fieldset></td>
|
633 |
+
</tr>
|
634 |
+
|
635 |
+
</tbody></table>
|
636 |
+
|
637 |
+
|
638 |
+
<div style="height: 20px;"></div>
|
639 |
+
<h2 class="title">Homepage Optimization</h2>
|
640 |
+
<p class="fvm-bold-green">Prioritize visible content by preloading images with high priority, such as the first image on a slider that is shown above the folder.</p>
|
641 |
+
|
642 |
+
<table class="form-table fvm-settings">
|
643 |
+
<tbody>
|
644 |
+
<tr>
|
645 |
+
<th scope="row">Preload Images</th>
|
646 |
+
<td><fieldset><legend class="screen-reader-text"><span>Preload Images</span></legend>
|
647 |
+
<label for="fastvelocity_min_preload"><span class="fvm-label-pad">Insert one image url per line:</span></label>
|
648 |
+
<p>
|
649 |
+
<textarea name="fastvelocity_min_preload" rows="10" cols="50" id="fastvelocity_min_preload" class="large-text code" placeholder="ex: //yoursite.com/wp-content/plugins/some-slider/large.img"><?php echo get_option('fastvelocity_min_preload'); ?></textarea>
|
650 |
+
</p>
|
651 |
+
<p class="description">[ Use only for large images that first load above the fold. Read the Help section for more details. ]</p>
|
652 |
+
</fieldset></td>
|
653 |
+
</tr>
|
654 |
+
</tbody></table>
|
655 |
+
|
656 |
+
|
657 |
+
<p class="submit"><input type="submit" name="fastvelocity_min_save_options" id="fastvelocity_min_save_options" class="button button-primary" value="Save Changes"></p>
|
658 |
+
</form>
|
659 |
+
<?php } ?>
|
660 |
+
|
661 |
+
|
662 |
+
<?php if( $active_tab == 'pro' ) {
|
663 |
+
|
664 |
+
# this is still under development
|
665 |
+
$fvm_license = get_option('fastvelocity_min_license_code');
|
666 |
+
if($fvm_license != false && mb_strlen($fvm_license, 'UTF-8') == 32) {
|
667 |
+
?>
|
668 |
+
|
669 |
+
<form method="post" action="options.php">
|
670 |
+
<?php settings_fields('fvm-group-pro'); do_settings_sections('fvm-group-pro'); ?>
|
671 |
+
|
672 |
+
<div style="height: 20px;"></div>
|
673 |
+
<h2 class="title">Extra Optimization</h2>
|
674 |
+
<p class="fvm-bold-green">These options are available for the professional version only.<br />
|
675 |
+
When deferring all generated css files, you must enqueue any inline css code that was supposed to load after the generated files.</p>
|
676 |
+
|
677 |
+
|
678 |
+
<table class="form-table fvm-settings">
|
679 |
+
<tbody>
|
680 |
+
|
681 |
+
<tr>
|
682 |
+
<th scope="row">Extra CSS Options</th>
|
683 |
+
<td><fieldset><legend class="screen-reader-text"><span>Extra CSS Options</span></legend>
|
684 |
+
<label for="fastvelocity_min_send_css_to_footer">
|
685 |
+
<input name="fastvelocity_min_send_css_to_footer" type="checkbox" id="fastvelocity_min_send_css_to_footer" value="1" <?php echo checked(1 == get_option('fastvelocity_min_send_css_to_footer'), true, false); ?>>
|
686 |
+
Async CSS with LoadCSS<span class="note-info">[ If selected, you will need a Critical Path CSS to Optimize CSS Delivery ]</span></label>
|
687 |
+
<br />
|
688 |
+
<label for="fastvelocity_min_critical_css_tester">
|
689 |
+
<input name="fastvelocity_min_critical_css_tester" type="checkbox" id="fastvelocity_min_critical_css_tester" value="1" <?php echo checked(1 == get_option('fastvelocity_min_critical_css_tester'), true, false); ?>>
|
690 |
+
Critical Path Tester<span class="note-info">[ If selected, only the critical path code will be shown and no css files will be enqueued ]</span></label>
|
691 |
+
</fieldset>
|
692 |
+
</td>
|
693 |
+
</tr>
|
694 |
+
|
695 |
+
<tr>
|
696 |
+
<th scope="row">Global Critical CSS</th>
|
697 |
+
<td>
|
698 |
+
<p>
|
699 |
+
<textarea name="fastvelocity_min_critical_path_css" rows="20" cols="50" id="fastvelocity_min_critical_path_css" class="large-text code" placeholder="your css code here"><?php echo get_option('fastvelocity_min_critical_path_css'); ?></textarea>
|
700 |
+
</p>
|
701 |
+
<p class="description">[ Please minify your CSS code manually and insert your Global Critical CSS here ]</p>
|
702 |
+
</td>
|
703 |
+
</tr>
|
704 |
+
|
705 |
+
|
706 |
+
<tr>
|
707 |
+
<th scope="row">Gulp Options</th>
|
708 |
+
<td><fieldset>
|
709 |
+
<label for="fastvelocity_min_generate_gulp_files">
|
710 |
+
<input name="fastvelocity_min_generate_gulp_files" type="checkbox" id="fastvelocity_min_generate_gulp_files" value="1" <?php echo checked(1 == get_option('fastvelocity_min_generate_gulp_files'), true, false); ?>>
|
711 |
+
Generate gulp-uncss files<span class="note-info">[ If selected, it will try to generate one gulp-uncss per pageview ]</span></label>
|
712 |
+
</fieldset>
|
713 |
+
</td>
|
714 |
+
</tr>
|
715 |
+
|
716 |
+
<tr>
|
717 |
+
<th scope="row">Gulp Directory</th>
|
718 |
+
<td>
|
719 |
+
<label for="fastvelocity_min_generate_gulp_path">
|
720 |
+
<input name="fastvelocity_min_generate_gulp_path" type="text" id="fastvelocity_min_generate_gulp_path" value="<?php echo get_option('fastvelocity_min_generate_gulp_path'); ?>" class="regular-text code">
|
721 |
+
<p class="description">The absolute path to your local "Gulp" working directory</p>
|
722 |
+
</td>
|
723 |
+
</tr>
|
724 |
+
|
725 |
+
|
726 |
+
</tbody></table>
|
727 |
+
|
728 |
+
<p class="submit"><input type="submit" name="fastvelocity_min_save_options" id="fastvelocity_min_save_options" class="button button-primary" value="Save Changes"></p>
|
729 |
+
</form>
|
730 |
+
|
731 |
+
<?php
|
732 |
+
} else {
|
733 |
+
|
734 |
+
?>
|
735 |
+
|
736 |
+
<form method="post" action="options.php">
|
737 |
+
<?php settings_fields('fvm-group-license'); do_settings_sections('fvm-group-license'); ?>
|
738 |
+
|
739 |
+
<div style="height: 20px;"></div>
|
740 |
+
<h2 class="title">Extra Optimization</h2>
|
741 |
+
<p class="fvm-bold-green">These options are available for the professional version only.</p>
|
742 |
+
|
743 |
+
<table class="form-table fvm-settings">
|
744 |
+
<tbody>
|
745 |
+
|
746 |
+
<tr>
|
747 |
+
<th scope="row">License Code</th>
|
748 |
+
<td>
|
749 |
+
<input name="fastvelocity_min_license_code" type="text" id="fastvelocity_min_license_code" value="<?php echo get_option('fastvelocity_min_license_code'); ?>" class="regular-text">
|
750 |
+
<p class="description">Please insert the license code that has been provided.</p>
|
751 |
+
</td>
|
752 |
+
</tr>
|
753 |
+
|
754 |
+
</tbody></table>
|
755 |
+
|
756 |
+
<p class="submit"><input type="submit" name="fastvelocity_min_save_options" id="fastvelocity_min_save_options" class="button button-primary" value="Save Changes"></p>
|
757 |
+
</form>
|
758 |
+
|
759 |
+
<?php
|
760 |
+
}
|
761 |
+
}
|
762 |
+
?>
|
763 |
+
|
764 |
+
|
765 |
+
<?php
|
766 |
+
if( $active_tab == 'server' ) {
|
767 |
+
fvm_get_generalinfo();
|
768 |
+
}
|
769 |
+
?>
|
770 |
+
|
771 |
+
<?php if( $active_tab == 'help' ) { ?>
|
772 |
+
|
773 |
+
<div class="wrap" id="fastvelocity-min">
|
774 |
+
<div id="poststuff">
|
775 |
+
<div id="fastvelocity_min_processed" class="postbox-container">
|
776 |
+
<div class="meta-box-sortables ui-sortable">
|
777 |
+
|
778 |
+
|
779 |
+
|
780 |
+
|
781 |
+
<div class="postbox" id="tab-info">
|
782 |
+
<h3 class="hndle"><span>Frequently Asked Questions</span></h3>
|
783 |
+
<div class="inside"><? echo fastvelocity_min_readme($plugindir.'readme.txt'); ?></div>
|
784 |
+
</div>
|
785 |
+
|
786 |
+
</div>
|
787 |
+
</div>
|
788 |
+
</div>
|
789 |
+
</div>
|
790 |
+
<?php } ?>
|
791 |
+
|
792 |
+
|
793 |
+
|
794 |
+
</div>
|
795 |
+
|
796 |
+
<div class="clear"></div>
|
797 |
+
|
798 |
+
<?php
|
799 |
+
}
|
800 |
+
|
801 |
+
|
802 |
+
###########################################
|
803 |
+
# process header javascript ###############
|
804 |
+
###########################################
|
805 |
+
function fastvelocity_min_merge_header_scripts() {
|
806 |
+
global $wp_scripts, $wp_domain, $wp_home, $wp_home_path, $cachedir, $cachedirurl, $ignore, $disable_js_merge, $disable_js_minification, $enable_defer_js, $exclude_defer_jquery;
|
807 |
+
if(!is_object($wp_scripts)) { return false; }
|
808 |
+
$scripts = wp_clone($wp_scripts);
|
809 |
+
$scripts->all_deps($scripts->queue);
|
810 |
+
$ctime = get_option('fvm-last-cache-update', '0');
|
811 |
+
$header = array();
|
812 |
+
|
813 |
+
# mark as done (as we go)
|
814 |
+
$done = $scripts->done;
|
815 |
+
|
816 |
+
# add defaults to ignore list
|
817 |
+
$ignore = fastvelocity_default_ignore($ignore);
|
818 |
+
|
819 |
+
# get groups of handles
|
820 |
+
foreach( $scripts->to_do as $handle ) :
|
821 |
+
|
822 |
+
# is it a footer script?
|
823 |
+
$is_footer = 0; if (isset($wp_scripts->registered[$handle]->extra["group"]) || isset($wp_scripts->registered[$handle]->args)) { $is_footer = 1; }
|
824 |
+
|
825 |
+
# skip footer scripts for now
|
826 |
+
if($is_footer != 1) {
|
827 |
+
|
828 |
+
# get full url
|
829 |
+
$hurl = fastvelocity_min_get_hurl($wp_scripts->registered[$handle]->src, $wp_domain, $wp_home);
|
830 |
+
|
831 |
+
# IE only files don't increment things
|
832 |
+
$ieonly = fastvelocity_ie_blacklist($hurl);
|
833 |
+
if($ieonly == true) { continue; }
|
834 |
+
|
835 |
+
# skip ignore list, scripts with conditionals, external scripts
|
836 |
+
if ((!fastvelocity_min_in_arrayi($hurl, $ignore) && !isset($wp_scripts->registered[$handle]->extra["conditional"]) && fvm_internal_url($hurl, $wp_home)) || empty($hurl)) {
|
837 |
+
|
838 |
+
# process
|
839 |
+
if(isset($header[count($header)-1]['handle']) || count($header) == 0) {
|
840 |
+
array_push($header, array('handles'=>array()));
|
841 |
+
}
|
842 |
+
|
843 |
+
# push it to the array
|
844 |
+
array_push($header[count($header)-1]['handles'], $handle);
|
845 |
+
|
846 |
+
# external and ignored scripts
|
847 |
+
} else {
|
848 |
+
array_push($header, array('handle'=>$handle));
|
849 |
+
}
|
850 |
+
|
851 |
+
# make sure that the scripts skipped here, show up in the footer
|
852 |
+
} else {
|
853 |
+
$hurl = fastvelocity_min_get_hurl($wp_scripts->registered[$handle]->src, $wp_domain, $wp_home);
|
854 |
+
wp_enqueue_script($handle, $hurl, array(), null, true);
|
855 |
+
}
|
856 |
+
endforeach;
|
857 |
+
|
858 |
+
|
859 |
+
# loop through header scripts and merge
|
860 |
+
for($i=0,$l=count($header);$i<$l;$i++) {
|
861 |
+
if(!isset($header[$i]['handle'])) {
|
862 |
+
|
863 |
+
# static cache file info + done
|
864 |
+
$done = array_merge($done, $header[$i]['handles']);
|
865 |
+
$hash = 'header-'.hash('adler32',implode('',$header[$i]['handles']));
|
866 |
+
|
867 |
+
# create cache files and urls
|
868 |
+
$file = $cachedir.'/'.$hash.'-'.$ctime.'.min.js';
|
869 |
+
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'-'.$ctime.'.min.js');
|
870 |
+
|
871 |
+
# generate a new cache file
|
872 |
+
if (!file_exists($file)) {
|
873 |
+
|
874 |
+
# code and log initialization
|
875 |
+
$log = '';
|
876 |
+
$code = '';
|
877 |
+
|
878 |
+
# minify and write to file
|
879 |
+
foreach($header[$i]['handles'] as $handle) :
|
880 |
+
if(!empty($wp_scripts->registered[$handle]->src)) {
|
881 |
+
|
882 |
+
# get hurl per handle
|
883 |
+
$hurl = fastvelocity_min_get_hurl($wp_scripts->registered[$handle]->src, $wp_domain, $wp_home);
|
884 |
+
$printurl = str_ireplace(array(site_url(), home_url(), 'http:', 'https:'), '', $hurl);
|
885 |
+
|
886 |
+
# get css from hurl, if available and valid
|
887 |
+
$tkey = 'fvm-cache-'.$ctime.hash('adler32', $hurl);
|
888 |
+
$newcode = false; $newcode = get_transient($tkey);
|
889 |
+
if ( $newcode === false) {
|
890 |
+
$res = fvm_download_and_cache($hurl, $tkey, null, $disable_js_minification, 'js');
|
891 |
+
if(is_array($res)) {
|
892 |
+
$newcode = $res['code'];
|
893 |
+
$newlog = $res['log'];
|
894 |
+
}
|
895 |
+
} else {
|
896 |
+
$newlog = "$printurl --- Debug: Fetched from transients cache with key $tkey ---\n";
|
897 |
+
}
|
898 |
+
|
899 |
+
# append
|
900 |
+
if($newcode !== false) {
|
901 |
+
$code.= $newcode;
|
902 |
+
$log.= $newlog;
|
903 |
+
}
|
904 |
+
|
905 |
+
# consider dependencies on handles with an empty src
|
906 |
+
} else {
|
907 |
+
wp_dequeue_script($handle); wp_enqueue_script($handle);
|
908 |
+
}
|
909 |
+
endforeach;
|
910 |
+
|
911 |
+
# prepare log
|
912 |
+
$log = "PROCESSED on ".date('r')."\n".$log."PROCESSED from ".home_url(add_query_arg( NULL, NULL ))."\n";
|
913 |
+
|
914 |
+
# generate cache, write log
|
915 |
+
file_put_contents($file.'.txt', $log);
|
916 |
+
file_put_contents($file, $code);
|
917 |
+
file_put_contents($file.'.gz', gzencode(file_get_contents($file), 9));
|
918 |
+
}
|
919 |
+
|
920 |
+
# register minified file
|
921 |
+
wp_register_script("fvm-header-$i", $file_url, array(), null, false);
|
922 |
+
|
923 |
+
# add all extra data from wp_localize_script
|
924 |
+
$data = array();
|
925 |
+
foreach($header[$i]['handles'] as $handle) {
|
926 |
+
if(isset($wp_scripts->registered[$handle]->extra['data'])) { $data[] = $wp_scripts->registered[$handle]->extra['data']; }
|
927 |
+
}
|
928 |
+
if(count($data) > 0) { $wp_scripts->registered["fvm-header-$i"]->extra['data'] = implode("\n", $data); }
|
929 |
+
|
930 |
+
# enqueue file
|
931 |
+
wp_enqueue_script("fvm-header-$i");
|
932 |
+
|
933 |
+
# other scripts need to be requeued for the order of files to be kept
|
934 |
+
} else {
|
935 |
+
wp_dequeue_script($header[$i]['handle']); wp_enqueue_script($header[$i]['handle']);
|
936 |
+
}
|
937 |
+
}
|
938 |
+
|
939 |
+
# remove from queue
|
940 |
+
$wp_scripts->done = $done;
|
941 |
+
}
|
942 |
+
###########################################
|
943 |
+
|
944 |
+
|
945 |
+
|
946 |
+
###########################################
|
947 |
+
# process js in the footer ################
|
948 |
+
###########################################
|
949 |
+
function fastvelocity_min_merge_footer_scripts() {
|
950 |
+
global $wp_scripts, $wp_domain, $wp_home, $wp_home_path, $cachedir, $cachedirurl, $ignore, $disable_js_merge, $disable_js_minification, $enable_defer_js, $exclude_defer_jquery;
|
951 |
+
if(!is_object($wp_scripts)) { return false; }
|
952 |
+
$ctime = get_option('fvm-last-cache-update', '0');
|
953 |
+
$scripts = wp_clone($wp_scripts);
|
954 |
+
$scripts->all_deps($scripts->queue);
|
955 |
+
$footer = array();
|
956 |
+
|
957 |
+
# mark as done (as we go)
|
958 |
+
$done = $scripts->done;
|
959 |
+
|
960 |
+
# add defaults to ignore list
|
961 |
+
$ignore = fastvelocity_default_ignore($ignore);
|
962 |
+
|
963 |
+
|
964 |
+
# get groups of handles
|
965 |
+
foreach( $scripts->to_do as $handle ) :
|
966 |
+
|
967 |
+
# get full url
|
968 |
+
$hurl = fastvelocity_min_get_hurl($wp_scripts->registered[$handle]->src, $wp_domain, $wp_home);
|
969 |
+
|
970 |
+
# IE only files don't increment things
|
971 |
+
$ieonly = fastvelocity_ie_blacklist($hurl);
|
972 |
+
if($ieonly == true) { continue; }
|
973 |
+
|
974 |
+
# skip ignore list, scripts with conditionals, external scripts
|
975 |
+
if ((!fastvelocity_min_in_arrayi($hurl, $ignore) && !isset($wp_scripts->registered[$handle]->extra["conditional"]) && fvm_internal_url($hurl, $wp_home)) || empty($hurl)) {
|
976 |
+
|
977 |
+
# process
|
978 |
+
if(isset($footer[count($footer)-1]['handle']) || count($footer) == 0) {
|
979 |
+
array_push($footer, array('handles'=>array()));
|
980 |
+
}
|
981 |
+
|
982 |
+
# push it to the array
|
983 |
+
array_push($footer[count($footer)-1]['handles'], $handle);
|
984 |
+
|
985 |
+
# external and ignored scripts
|
986 |
+
} else {
|
987 |
+
array_push($footer, array('handle'=>$handle));
|
988 |
+
}
|
989 |
+
endforeach;
|
990 |
+
|
991 |
+
# loop through footer scripts and merge
|
992 |
+
for($i=0,$l=count($footer);$i<$l;$i++) {
|
993 |
+
if(!isset($footer[$i]['handle'])) {
|
994 |
+
|
995 |
+
# static cache file info + done
|
996 |
+
$done = array_merge($done, $footer[$i]['handles']);
|
997 |
+
$hash = 'footer-'.hash('adler32',implode('',$footer[$i]['handles']));
|
998 |
+
|
999 |
+
# create cache files and urls
|
1000 |
+
$file = $cachedir.'/'.$hash.'-'.$ctime.'.min.js';
|
1001 |
+
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'-'.$ctime.'.min.js');
|
1002 |
+
|
1003 |
+
# generate a new cache file
|
1004 |
+
if (!file_exists($file)) {
|
1005 |
+
|
1006 |
+
# code and log initialization
|
1007 |
+
$log = '';
|
1008 |
+
$code = '';
|
1009 |
+
|
1010 |
+
# minify and write to file
|
1011 |
+
foreach($footer[$i]['handles'] as $handle) :
|
1012 |
+
if(!empty($wp_scripts->registered[$handle]->src)) {
|
1013 |
+
|
1014 |
+
# get hurl per handle
|
1015 |
+
$hurl = fastvelocity_min_get_hurl($wp_scripts->registered[$handle]->src, $wp_domain, $wp_home);
|
1016 |
+
$printurl = str_ireplace(array(site_url(), home_url(), 'http:', 'https:'), '', $hurl);
|
1017 |
+
|
1018 |
+
# get css from hurl, if available and valid
|
1019 |
+
$tkey = 'fvm-cache-'.$ctime.hash('adler32', $hurl);
|
1020 |
+
$newcode = false; $newcode = get_transient($tkey);
|
1021 |
+
if ( $newcode === false) {
|
1022 |
+
$res = fvm_download_and_cache($hurl, $tkey, null, $disable_js_minification, 'js');
|
1023 |
+
if(is_array($res)) {
|
1024 |
+
$newcode = $res['code'];
|
1025 |
+
$newlog = $res['log'];
|
1026 |
+
}
|
1027 |
+
} else {
|
1028 |
+
$newlog = "$printurl --- Debug: Fetched from transients cache with key $tkey ---\n";
|
1029 |
+
}
|
1030 |
+
|
1031 |
+
# append
|
1032 |
+
if($newcode !== false) {
|
1033 |
+
$code.= $newcode;
|
1034 |
+
$log.= $newlog;
|
1035 |
+
}
|
1036 |
+
|
1037 |
+
# consider dependencies on handles with an empty src
|
1038 |
+
} else {
|
1039 |
+
wp_dequeue_script($handle); wp_enqueue_script($handle);
|
1040 |
+
}
|
1041 |
+
endforeach;
|
1042 |
+
|
1043 |
+
# prepare log
|
1044 |
+
$log = "PROCESSED on ".date('r')."\n".$log."PROCESSED from ".home_url(add_query_arg( NULL, NULL ))."\n";
|
1045 |
+
|
1046 |
+
# generate cache, write log
|
1047 |
+
file_put_contents($file.'.txt', $log);
|
1048 |
+
file_put_contents($file, $code);
|
1049 |
+
file_put_contents($file.'.gz', gzencode(file_get_contents($file), 9));
|
1050 |
+
}
|
1051 |
+
|
1052 |
+
# register minified file
|
1053 |
+
wp_register_script("fvm-footer-$i", $file_url, array(), null, false);
|
1054 |
+
|
1055 |
+
# add all extra data from wp_localize_script
|
1056 |
+
$data = array();
|
1057 |
+
foreach($footer[$i]['handles'] as $handle) {
|
1058 |
+
if(isset($wp_scripts->registered[$handle]->extra['data'])) { $data[] = $wp_scripts->registered[$handle]->extra['data']; }
|
1059 |
+
}
|
1060 |
+
if(count($data) > 0) { $wp_scripts->registered["fvm-footer-$i"]->extra['data'] = implode("\n", $data); }
|
1061 |
+
|
1062 |
+
# enqueue file
|
1063 |
+
wp_enqueue_script("fvm-footer-$i");
|
1064 |
+
|
1065 |
+
# other scripts need to be requeued for the order of files to be kept
|
1066 |
+
} else {
|
1067 |
+
wp_dequeue_script($footer[$i]['handle']); wp_enqueue_script($footer[$i]['handle']);
|
1068 |
+
}
|
1069 |
+
}
|
1070 |
+
|
1071 |
+
# remove from queue
|
1072 |
+
$wp_scripts->done = $done;
|
1073 |
+
}
|
1074 |
+
##############################
|
1075 |
+
|
1076 |
+
|
1077 |
+
|
1078 |
+
###########################################
|
1079 |
+
# enable defer for JavaScript (WP 4.1 and above) and remove query strings for ignored files
|
1080 |
+
###########################################
|
1081 |
+
function fastvelocity_min_defer_js($tag, $handle, $src) {
|
1082 |
+
global $ignore, $enable_defer_js, $defer_for_pagespeed, $wp_domain, $exclude_defer_login;
|
1083 |
+
|
1084 |
+
# no query strings
|
1085 |
+
if (stripos($src, '?ver') !== false) {
|
1086 |
+
$srcf = stristr($src, '?ver', true);
|
1087 |
+
$tag = str_ireplace($src, $srcf, $tag);
|
1088 |
+
$src = $srcf;
|
1089 |
+
}
|
1090 |
+
|
1091 |
+
# should we exclude defer on the login page?
|
1092 |
+
if($exclude_defer_login == true && stripos($_SERVER["SCRIPT_NAME"], strrchr(wp_login_url(), '/')) !== false){ return $tag; }
|
1093 |
+
|
1094 |
+
# reprocess the ignore list to remove the /fvm/cache/ from the list (else won't defer)
|
1095 |
+
if(is_array($ignore)) { $nignore = array(); foreach ($ignore as $i) { if($i != '/fvm/cache/') { $nignore[] = $i; } } }
|
1096 |
+
|
1097 |
+
# when to defer, order matters
|
1098 |
+
$defer = 0; if($enable_defer_js == true) { $defer = 1; }
|
1099 |
+
if (fastvelocity_min_in_arrayi($src, $nignore)) { $defer = 0; }
|
1100 |
+
|
1101 |
+
# get available nodes and add create with defer tag (if not async)
|
1102 |
+
$dom = new DOMDocument();
|
1103 |
+
libxml_use_internal_errors(true);
|
1104 |
+
@$dom->loadHTML($tag);
|
1105 |
+
$nodes = $dom->getElementsByTagName('script');
|
1106 |
+
$tagdefer = '';
|
1107 |
+
if ($nodes->length != 0) {
|
1108 |
+
$node = $dom->getElementsByTagName('script')->item(0);
|
1109 |
+
if (!$node->hasAttribute('async')) { $node->setAttribute('defer','defer'); };
|
1110 |
+
$tagdefer = $dom->saveHTML($node);
|
1111 |
+
}
|
1112 |
+
|
1113 |
+
# skip the nignore list by default, defer the rest
|
1114 |
+
if ($defer == 0) {
|
1115 |
+
|
1116 |
+
# no defer
|
1117 |
+
if ($defer_for_pagespeed != true) { return $tag; } else {
|
1118 |
+
|
1119 |
+
# return if external script url https://www.chromestatus.com/feature/5718547946799104
|
1120 |
+
if (stripos($src, $wp_domain) === false) { return $tag; }
|
1121 |
+
|
1122 |
+
# print code or return
|
1123 |
+
if(!empty($tagdefer)) {
|
1124 |
+
$deferinsights = '<script type="text/javascript">if(navigator.userAgent.match(/speed|gtmetrix|x11.*firefox\/53|x11.*chrome\/39/i)){document.write('.json_encode($tagdefer).');}else{document.write('.json_encode($tag).');}</script>';
|
1125 |
+
return preg_replace('#<script(.*?)>(.*?)</script>#is', $deferinsights, $tag);
|
1126 |
+
}
|
1127 |
+
|
1128 |
+
return $tag;
|
1129 |
+
}
|
1130 |
+
|
1131 |
+
# normal defer enabled
|
1132 |
+
} else { return $tagdefer; }
|
1133 |
+
}
|
1134 |
+
###########################################
|
1135 |
+
|
1136 |
+
|
1137 |
+
|
1138 |
+
|
1139 |
+
###########################################
|
1140 |
+
# process header css ######################
|
1141 |
+
###########################################
|
1142 |
+
function fastvelocity_min_merge_header_css() {
|
1143 |
+
global $wp_styles, $wp_domain, $wp_home, $wp_home_path, $cachedir, $cachedirurl, $ignore, $disable_css_merge, $disable_css_minification, $skip_google_fonts, $skip_cssorder, $remove_print_mediatypes, $force_inline_css, $force_inline_googlefonts, $send_css_to_footer, $critical_path_css, $critical_css_tester;
|
1144 |
+
if(!is_object($wp_styles)) { return false; }
|
1145 |
+
$ctime = get_option('fvm-last-cache-update', '0');
|
1146 |
+
$styles = wp_clone($wp_styles);
|
1147 |
+
$styles->all_deps($styles->queue);
|
1148 |
+
$done = $styles->done;
|
1149 |
+
$header = array();
|
1150 |
+
$google_fonts = array();
|
1151 |
+
$process = array();
|
1152 |
+
$inline_css = array();
|
1153 |
+
|
1154 |
+
# add defaults to ignore list
|
1155 |
+
$ignore = fastvelocity_default_ignore($ignore);
|
1156 |
+
|
1157 |
+
|
1158 |
+
# get list of handles to process, dequeue duplicate css urls and keep empty source handles (for dependencies)
|
1159 |
+
$uniq = array(); $gfonts = array();
|
1160 |
+
foreach( $styles->to_do as $handle):
|
1161 |
+
|
1162 |
+
# conditionals
|
1163 |
+
$conditional = NULL; if(isset($wp_styles->registered[$handle]->extra["conditional"])) {
|
1164 |
+
$conditional = $wp_styles->registered[$handle]->extra["conditional"]; # such as ie7, ie8, ie9, etc
|
1165 |
+
}
|
1166 |
+
|
1167 |
+
# mediatype
|
1168 |
+
$mediatype = isset($wp_styles->registered[$handle]->args) ? $wp_styles->registered[$handle]->args : 'all'; # such as all, print, mobile, etc
|
1169 |
+
if ($mediatype == 'screen' || $mediatype == 'screen, print') { $mediatype = 'all'; }
|
1170 |
+
|
1171 |
+
# full url or empty
|
1172 |
+
$hurl = fastvelocity_min_get_hurl($wp_styles->registered[$handle]->src, $wp_domain, $wp_home);
|
1173 |
+
|
1174 |
+
# mark duplicates as done and remove from the queue
|
1175 |
+
if(!empty($hurl)) {
|
1176 |
+
$key = hash('adler32', $hurl);
|
1177 |
+
if (isset($uniq[$key])) { $done = array_merge($done, array($handle)); continue; } else { $uniq[$key] = $handle; }
|
1178 |
+
}
|
1179 |
+
|
1180 |
+
# array of info to save
|
1181 |
+
$arr = array('handle'=>$handle, 'url'=>$hurl, 'conditional'=>$conditional, 'mediatype'=>$mediatype);
|
1182 |
+
|
1183 |
+
# google fonts to the top (collect and skip process array)
|
1184 |
+
if (stripos($hurl, 'fonts.googleapis.com') !== false) {
|
1185 |
+
if(!$skip_google_fonts) { $google_fonts[$handle] = $hurl; } else { wp_enqueue_style($handle); } # skip google fonts optimization?
|
1186 |
+
continue;
|
1187 |
+
}
|
1188 |
+
|
1189 |
+
# all else
|
1190 |
+
$process[$handle] = $arr;
|
1191 |
+
|
1192 |
+
endforeach;
|
1193 |
+
|
1194 |
+
|
1195 |
+
# concat google fonts, if enabled
|
1196 |
+
if(!$skip_google_fonts && count($google_fonts) > 0) {
|
1197 |
+
$concat_google_fonts = fastvelocity_min_concatenate_google_fonts($google_fonts);
|
1198 |
+
foreach ($google_fonts as $h=>$a) { $done = array_merge($done, array($h)); } # mark as done
|
1199 |
+
if($force_inline_googlefonts == false) {
|
1200 |
+
wp_enqueue_style('header-fvm-fonts', fvm_get_protocol($concat_google_fonts), array(), null, 'all');
|
1201 |
+
} else {
|
1202 |
+
|
1203 |
+
# google fonts download and inlining, ignore logs
|
1204 |
+
$tkey = 'fvm-cache-'.$ctime.hash('adler32', $concat_google_fonts);
|
1205 |
+
$newcode = false; $newcode = get_transient($tkey);
|
1206 |
+
if ( $newcode === false) {
|
1207 |
+
$res = fvm_download_and_cache($concat_google_fonts, $tkey, null, $disable_minification, 'css');
|
1208 |
+
if(is_array($res)) { $newcode = $res['code']; }
|
1209 |
+
}
|
1210 |
+
|
1211 |
+
# inline css or fail
|
1212 |
+
if($newcode !== false) {
|
1213 |
+
echo '<style type="text/css" media="all">'.$newcode.'</style>'."\n";
|
1214 |
+
} else {
|
1215 |
+
echo "<!-- GOOGLE FONTS REQUEST FAILED for $concat_google_fonts -->\n"; # log if failed
|
1216 |
+
}
|
1217 |
+
}
|
1218 |
+
}
|
1219 |
+
|
1220 |
+
|
1221 |
+
|
1222 |
+
|
1223 |
+
# get groups of handles
|
1224 |
+
foreach( $styles->to_do as $handle ) :
|
1225 |
+
|
1226 |
+
# skip already processed google fonts and empty dependencies
|
1227 |
+
if(isset($google_fonts[$handle])) { continue; } # skip google fonts
|
1228 |
+
if(empty($wp_styles->registered[$handle]->src)) { continue; } # skip empty src
|
1229 |
+
if (fastvelocity_min_in_arrayi($handle, $done)) { continue; } # skip if marked as done before
|
1230 |
+
if (!isset($process[$handle])) { continue; } # skip if not on our unique process list
|
1231 |
+
|
1232 |
+
# get full url
|
1233 |
+
$hurl = $process[$handle]['url'];
|
1234 |
+
$conditional = $process[$handle]['conditional'];
|
1235 |
+
$mediatype = $process[$handle]['mediatype'];
|
1236 |
+
|
1237 |
+
# IE only files don't increment things
|
1238 |
+
$ieonly = fastvelocity_ie_blacklist($hurl);
|
1239 |
+
if($ieonly == true) { continue; }
|
1240 |
+
|
1241 |
+
# skip ignore list, conditional css, external css
|
1242 |
+
if ((!fastvelocity_min_in_arrayi($hurl, $ignore) && !isset($conditional) && fvm_internal_url($hurl, $wp_home)) || empty($hurl)) {
|
1243 |
+
|
1244 |
+
# colect inline css for this handle
|
1245 |
+
if(isset($wp_styles->registered[$handle]->extra['after']) && is_array($wp_styles->registered[$handle]->extra['after'])) {
|
1246 |
+
$inline_css[$handle] = fastvelocity_min_minify_css_string(implode('', $wp_styles->registered[$handle]->extra['after'])); # save
|
1247 |
+
$wp_styles->registered[$handle]->extra['after'] = null; # dequeue
|
1248 |
+
}
|
1249 |
+
|
1250 |
+
# process
|
1251 |
+
if(isset($header[count($header)-1]['handle']) || count($header) == 0 || $header[count($header)-1]['media'] != $mediatype) {
|
1252 |
+
array_push($header, array('handles'=>array(), 'media'=>$mediatype));
|
1253 |
+
}
|
1254 |
+
|
1255 |
+
# push it to the array
|
1256 |
+
array_push($header[count($header)-1]['handles'], $handle);
|
1257 |
+
|
1258 |
+
# collect generated file urls, except print
|
1259 |
+
if ($mediatype != 'print') { $GLOBALS['used_css_files'][] = $hurl; }
|
1260 |
+
|
1261 |
+
# external and ignored css
|
1262 |
+
} else {
|
1263 |
+
|
1264 |
+
# collect generated file urls for gulp, except print and conditionals
|
1265 |
+
if ($mediatype != 'print' && !isset($conditional)) { $GLOBALS['used_css_files'][] = $hurl; }
|
1266 |
+
|
1267 |
+
# normal enqueuing
|
1268 |
+
array_push($header, array('handle'=>$handle));
|
1269 |
+
}
|
1270 |
+
endforeach;
|
1271 |
+
|
1272 |
+
|
1273 |
+
# reorder CSS by mediatypes
|
1274 |
+
if(!$skip_cssorder) {
|
1275 |
+
if(count($header) > 0) {
|
1276 |
+
|
1277 |
+
# get unique mediatypes
|
1278 |
+
$allmedia = array();
|
1279 |
+
foreach($header as $array) {
|
1280 |
+
if(isset($array['media'])) { $allmedia[$array['media']] = ''; }
|
1281 |
+
}
|
1282 |
+
|
1283 |
+
# extract handles by mediatype
|
1284 |
+
$grouphandles = array();
|
1285 |
+
foreach ($allmedia as $md=>$var) {
|
1286 |
+
foreach($header as $array) {
|
1287 |
+
if (isset($array['media']) && $array['media'] == $md) {
|
1288 |
+
foreach($array['handles'] as $h) { $grouphandles[$md][] = $h; }
|
1289 |
+
}
|
1290 |
+
}
|
1291 |
+
}
|
1292 |
+
|
1293 |
+
# reset and reorder header by mediatypes
|
1294 |
+
$newheader = array();
|
1295 |
+
foreach ($allmedia as $md=>$var) { $newheader[] = array('handles' => $grouphandles[$md], 'media'=>$md); }
|
1296 |
+
if(count($newheader) > 0) { $header = $newheader; }
|
1297 |
+
}
|
1298 |
+
}
|
1299 |
+
|
1300 |
+
|
1301 |
+
# critical path
|
1302 |
+
if(!empty($critical_path_css) && $critical_path_css != false) {
|
1303 |
+
if($send_css_to_footer != false) {
|
1304 |
+
echo '<style id="critical-path-global" type="text/css" media="all">'.$critical_path_css.'</style>'."\n";
|
1305 |
+
}
|
1306 |
+
}
|
1307 |
+
|
1308 |
+
|
1309 |
+
# loop through header css and merge
|
1310 |
+
for($i=0,$l=count($header);$i<$l;$i++) {
|
1311 |
+
if(!isset($header[$i]['handle'])) {
|
1312 |
+
|
1313 |
+
# get has for the inline css in this group
|
1314 |
+
$inline_css_group = array();
|
1315 |
+
foreach($header[$i]['handles'] as $h) { if(isset($inline_css[$h]) && !empty($inline_css[$h])) { $inline_css_group[] = $inline_css[$h]; } }
|
1316 |
+
$inline_css_hash = md5(implode('',$inline_css_group));
|
1317 |
+
|
1318 |
+
# static cache file info + done
|
1319 |
+
$done = array_merge($done, $header[$i]['handles']);
|
1320 |
+
$hash = 'header-'.hash('adler32',implode('',$header[$i]['handles']).$inline_css_hash);
|
1321 |
+
|
1322 |
+
# create cache files and urls
|
1323 |
+
$file = $cachedir.'/'.$hash.'-'.$ctime.'.min.css';
|
1324 |
+
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'-'.$ctime.'.min.css');
|
1325 |
+
|
1326 |
+
# generate a new cache file
|
1327 |
+
if (!file_exists($file)) {
|
1328 |
+
|
1329 |
+
# code and log initialization
|
1330 |
+
$log = '';
|
1331 |
+
$code = '';
|
1332 |
+
|
1333 |
+
# minify and write to file
|
1334 |
+
foreach($header[$i]['handles'] as $handle) :
|
1335 |
+
if(!empty($wp_styles->registered[$handle]->src)) {
|
1336 |
+
|
1337 |
+
# get hurl per handle
|
1338 |
+
$hurl = fastvelocity_min_get_hurl($wp_styles->registered[$handle]->src, $wp_domain, $wp_home);
|
1339 |
+
$printurl = str_ireplace(array(site_url(), home_url(), 'http:', 'https:'), '', $hurl);
|
1340 |
+
|
1341 |
+
# get css from hurl, if available and valid
|
1342 |
+
$tkey = 'fvm-cache-'.$ctime.hash('adler32', $hurl);
|
1343 |
+
$newcode = false; $newcode = get_transient($tkey);
|
1344 |
+
if ( $newcode === false) {
|
1345 |
+
$res = fvm_download_and_cache($hurl, $tkey, null, $disable_css_minification, 'css');
|
1346 |
+
if(is_array($res)) {
|
1347 |
+
$newcode = $res['code'];
|
1348 |
+
$newlog = $res['log'];
|
1349 |
+
}
|
1350 |
+
} else {
|
1351 |
+
$newlog = "$printurl --- Debug: Fetched from transients cache with key $tkey ---\n";
|
1352 |
+
}
|
1353 |
+
|
1354 |
+
# append
|
1355 |
+
if($newcode !== false) {
|
1356 |
+
$code.= $newcode;
|
1357 |
+
if(isset($inline_css[$handle]) && !empty($inline_css[$handle])) { $code.= $inline_css[$handle]; } # add inline css on the fly
|
1358 |
+
$log.= $newlog;
|
1359 |
+
}
|
1360 |
+
|
1361 |
+
# consider dependencies on handles with an empty src
|
1362 |
+
} else {
|
1363 |
+
wp_dequeue_script($handle); wp_enqueue_script($handle);
|
1364 |
+
}
|
1365 |
+
endforeach;
|
1366 |
+
|
1367 |
+
# prepare log
|
1368 |
+
$log = "PROCESSED on ".date('r')."\n".$log."PROCESSED from ".home_url(add_query_arg( NULL, NULL ))."\n";
|
1369 |
+
|
1370 |
+
# generate cache, write log
|
1371 |
+
file_put_contents($file.'.txt', $log);
|
1372 |
+
file_put_contents($file, $code);
|
1373 |
+
file_put_contents($file.'.gz', gzencode(file_get_contents($file), 9));
|
1374 |
+
|
1375 |
+
}
|
1376 |
+
|
1377 |
+
# register and enqueue minified file, consider excluding of mediatype "print" and inline css
|
1378 |
+
if ($remove_print_mediatypes != 1 || ($remove_print_mediatypes == 1 && $header[$i]['media'] != 'print')) {
|
1379 |
+
if($force_inline_css != false) {
|
1380 |
+
echo '<style type="text/css" media="'.$header[$i]['media'].'">'.file_get_contents($file).'</style>';
|
1381 |
+
} else {
|
1382 |
+
|
1383 |
+
# move CSS to footer ?
|
1384 |
+
if($send_css_to_footer != false) {
|
1385 |
+
if($critical_css_tester != true) {
|
1386 |
+
echo '<link rel="preload" href="'.$file_url.'" as="style" media="'.$header[$i]['media'].'" onload="this.rel=\'stylesheet\'">';
|
1387 |
+
echo '<noscript><link rel="stylesheet" type="text/css" media="'.$header[$i]['media'].'" href="'.$file_url.'"></noscript>';
|
1388 |
+
echo '<!--[if IE]><link rel="stylesheet" type="text/css" media="'.$header[$i]['media'].'" href="'.$file_url.'"><![endif]-->';
|
1389 |
+
}
|
1390 |
+
} else {
|
1391 |
+
|
1392 |
+
# default
|
1393 |
+
wp_register_style("fvm-header-$i", $file_url, array(), null, $header[$i]['media']);
|
1394 |
+
wp_enqueue_style("fvm-header-$i");
|
1395 |
+
|
1396 |
+
}
|
1397 |
+
}
|
1398 |
+
}
|
1399 |
+
|
1400 |
+
# other css need to be requeued for the order of files to be kept
|
1401 |
+
} else {
|
1402 |
+
wp_dequeue_style($header[$i]['handle']); wp_enqueue_style($header[$i]['handle']);
|
1403 |
+
}
|
1404 |
+
}
|
1405 |
+
|
1406 |
+
# remove from queue
|
1407 |
+
$wp_styles->done = $done;
|
1408 |
+
|
1409 |
+
}
|
1410 |
+
###########################################
|
1411 |
+
|
1412 |
+
|
1413 |
+
###########################################
|
1414 |
+
# process css in the footer ###############
|
1415 |
+
###########################################
|
1416 |
+
function fastvelocity_min_merge_footer_css() {
|
1417 |
+
global $wp_styles, $wp_domain, $wp_home, $wp_home_path, $cachedir, $cachedirurl, $ignore, $disable_css_merge, $disable_css_minification, $skip_google_fonts, $skip_cssorder, $remove_print_mediatypes, $force_inline_css_footer, $force_inline_googlefonts, $send_css_to_footer, $critical_css_tester;
|
1418 |
+
if(!is_object($wp_styles)) { return false; }
|
1419 |
+
$ctime = get_option('fvm-last-cache-update', '0');
|
1420 |
+
$styles = wp_clone($wp_styles);
|
1421 |
+
$styles->all_deps($styles->queue);
|
1422 |
+
$done = $styles->done;
|
1423 |
+
$footer = array();
|
1424 |
+
$google_fonts = array();
|
1425 |
+
$inline_css = array();
|
1426 |
+
|
1427 |
+
# add defaults to ignore list
|
1428 |
+
$ignore = fastvelocity_default_ignore($ignore);
|
1429 |
+
|
1430 |
+
|
1431 |
+
# google fonts to the top
|
1432 |
+
foreach( $styles->to_do as $handle ) :
|
1433 |
+
# dequeue and get a list of google fonts, or requeue external
|
1434 |
+
$hurl = fastvelocity_min_get_hurl($wp_styles->registered[$handle]->src, $wp_domain, $wp_home);
|
1435 |
+
if (stripos($hurl, 'fonts.googleapis.com') !== false) {
|
1436 |
+
wp_dequeue_style($handle);
|
1437 |
+
if(!$skip_google_fonts) { $google_fonts[$handle] = $hurl; } else { wp_enqueue_style($handle); } # skip google fonts optimization?
|
1438 |
+
} else {
|
1439 |
+
wp_dequeue_style($handle); wp_enqueue_style($handle); # failsafe
|
1440 |
+
}
|
1441 |
+
endforeach;
|
1442 |
+
|
1443 |
+
|
1444 |
+
# concat google fonts, if enabled
|
1445 |
+
if(!$skip_google_fonts && count($google_fonts) > 0) {
|
1446 |
+
$concat_google_fonts = fastvelocity_min_concatenate_google_fonts($google_fonts);
|
1447 |
+
foreach ($google_fonts as $h=>$a) { $done = array_merge($done, array($h)); } # mark as done
|
1448 |
+
if($force_inline_googlefonts == false) {
|
1449 |
+
wp_enqueue_style('footer-fvm-fonts', fvm_get_protocol($concat_google_fonts), array(), null, 'all');
|
1450 |
+
} else {
|
1451 |
+
|
1452 |
+
# google fonts download and inlining, ignore logs
|
1453 |
+
$tkey = 'fvm-cache-'.$ctime.hash('adler32', $concat_google_fonts);
|
1454 |
+
$newcode = false; $newcode = get_transient($tkey);
|
1455 |
+
if ( $newcode === false) {
|
1456 |
+
$res = fvm_download_and_cache($concat_google_fonts, $tkey, null, $disable_css_minification, 'css');
|
1457 |
+
if(is_array($res)) { $newcode = $res['code']; }
|
1458 |
+
}
|
1459 |
+
|
1460 |
+
# inline css or fail
|
1461 |
+
if($newcode !== false) {
|
1462 |
+
echo '<style type="text/css" media="all">'.$newcode.'</style>';
|
1463 |
+
} else {
|
1464 |
+
echo "<!-- GOOGLE FONTS REQUEST FAILED for $concat_google_fonts -->\n"; # log if failed
|
1465 |
+
}
|
1466 |
+
}
|
1467 |
+
}
|
1468 |
+
|
1469 |
+
|
1470 |
+
# get groups of handles
|
1471 |
+
foreach( $styles->to_do as $handle ) :
|
1472 |
+
|
1473 |
+
# skip already processed google fonts
|
1474 |
+
if(isset($google_fonts[$handle])) { continue; }
|
1475 |
+
|
1476 |
+
# get full url
|
1477 |
+
$hurl = fastvelocity_min_get_hurl($wp_styles->registered[$handle]->src, $wp_domain, $wp_home);
|
1478 |
+
|
1479 |
+
# media type
|
1480 |
+
$media = isset($wp_styles->registered[$handle]->args) ? $wp_styles->registered[$handle]->args : 'all';
|
1481 |
+
|
1482 |
+
# IE only files don't increment things
|
1483 |
+
$ieonly = fastvelocity_ie_blacklist($hurl);
|
1484 |
+
if($ieonly == true) { continue; }
|
1485 |
+
|
1486 |
+
# conditionals
|
1487 |
+
$conditional = NULL; if(isset($wp_styles->registered[$handle]->extra["conditional"])) {
|
1488 |
+
$conditional = $wp_styles->registered[$handle]->extra["conditional"]; # such as ie7, ie8, ie9, etc
|
1489 |
+
}
|
1490 |
+
|
1491 |
+
# skip ignore list, conditional css, external css
|
1492 |
+
if ((!fastvelocity_min_in_arrayi($hurl, $ignore) && !isset($conditional) && fvm_internal_url($hurl, $wp_home)) || empty($hurl)) {
|
1493 |
+
|
1494 |
+
# colect inline css for this handle
|
1495 |
+
if(isset($wp_styles->registered[$handle]->extra['after']) && is_array($wp_styles->registered[$handle]->extra['after'])) {
|
1496 |
+
$inline_css[$handle] = fastvelocity_min_minify_css_string(implode('', $wp_styles->registered[$handle]->extra['after'])); # save
|
1497 |
+
$wp_styles->registered[$handle]->extra['after'] = null; # dequeue
|
1498 |
+
}
|
1499 |
+
|
1500 |
+
# process
|
1501 |
+
if(isset($footer[count($footer)-1]['handle']) || count($footer) == 0 || $footer[count($footer)-1]['media'] != $wp_styles->registered[$handle]->args) {
|
1502 |
+
array_push($footer, array('handles'=>array(),'media'=>$media));
|
1503 |
+
}
|
1504 |
+
|
1505 |
+
# push it to the array get latest modified time
|
1506 |
+
array_push($footer[count($footer)-1]['handles'], $handle);
|
1507 |
+
|
1508 |
+
# collect generated file urls for gulp, except print
|
1509 |
+
if ($media != 'print') { $GLOBALS['used_css_files'][] = $hurl; }
|
1510 |
+
|
1511 |
+
# external and ignored css
|
1512 |
+
} else {
|
1513 |
+
|
1514 |
+
# collect generated file urls for gulp, except print and conditionals
|
1515 |
+
if ($media != 'print' && !isset($conditional)) { $GLOBALS['used_css_files'][] = $hurl; }
|
1516 |
+
|
1517 |
+
# normal enqueueing
|
1518 |
+
array_push($footer, array('handle'=>$handle));
|
1519 |
+
}
|
1520 |
+
endforeach;
|
1521 |
+
|
1522 |
+
|
1523 |
+
# reorder CSS by mediatypes
|
1524 |
+
if(!$skip_cssorder) {
|
1525 |
+
if(count($footer) > 0) {
|
1526 |
+
|
1527 |
+
# get unique mediatypes
|
1528 |
+
$allmedia = array();
|
1529 |
+
foreach($footer as $key=>$array) {
|
1530 |
+
if(isset($array['media'])) { $allmedia[$array['media']] = ''; }
|
1531 |
+
}
|
1532 |
+
|
1533 |
+
# extract handles by mediatype
|
1534 |
+
$grouphandles = array();
|
1535 |
+
foreach ($allmedia as $md=>$var) {
|
1536 |
+
foreach($footer as $array) {
|
1537 |
+
if (isset($array['media']) && $array['media'] == $md) {
|
1538 |
+
foreach($array['handles'] as $h) { $grouphandles[$md][] = $h; }
|
1539 |
+
}
|
1540 |
+
}
|
1541 |
+
}
|
1542 |
+
|
1543 |
+
# reset and reorder footer by mediatypes
|
1544 |
+
$newfooter = array();
|
1545 |
+
foreach ($allmedia as $md=>$var) { $newfooter[] = array('handles' => $grouphandles[$md], 'media'=>$md); }
|
1546 |
+
if(count($newfooter) > 0) { $footer = $newfooter; }
|
1547 |
+
}
|
1548 |
+
}
|
1549 |
+
|
1550 |
+
# loop through footer css and merge
|
1551 |
+
for($i=0,$l=count($footer);$i<$l;$i++) {
|
1552 |
+
if(!isset($footer[$i]['handle'])) {
|
1553 |
+
|
1554 |
+
# get has for the inline css in this group
|
1555 |
+
$inline_css_group = array();
|
1556 |
+
foreach($footer[$i]['handles'] as $h) { if(isset($inline_css[$h]) && !empty($inline_css[$h])) { $inline_css_group[] = $inline_css[$h]; } }
|
1557 |
+
$inline_css_hash = md5(implode('',$inline_css_group));
|
1558 |
+
|
1559 |
+
# static cache file info + done
|
1560 |
+
$done = array_merge($done, $footer[$i]['handles']);
|
1561 |
+
$hash = 'footer-'.hash('adler32',implode('',$footer[$i]['handles']).$inline_css_hash);
|
1562 |
+
|
1563 |
+
# create cache files and urls
|
1564 |
+
$file = $cachedir.'/'.$hash.'-'.$ctime.'.min.css';
|
1565 |
+
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'-'.$ctime.'.min.css');
|
1566 |
+
|
1567 |
+
# generate a new cache file
|
1568 |
+
if (!file_exists($file)) {
|
1569 |
+
|
1570 |
+
# code and log initialization
|
1571 |
+
$log = '';
|
1572 |
+
$code = '';
|
1573 |
+
|
1574 |
+
# minify and write to file
|
1575 |
+
foreach($footer[$i]['handles'] as $handle) :
|
1576 |
+
if(!empty($wp_styles->registered[$handle]->src)) {
|
1577 |
+
|
1578 |
+
# get hurl per handle
|
1579 |
+
$hurl = fastvelocity_min_get_hurl($wp_styles->registered[$handle]->src, $wp_domain, $wp_home);
|
1580 |
+
$printurl = str_ireplace(array(site_url(), home_url(), 'http:', 'https:'), '', $hurl);
|
1581 |
+
|
1582 |
+
# get css from hurl, if available and valid
|
1583 |
+
$tkey = 'fvm-cache-'.$ctime.hash('adler32', $hurl);
|
1584 |
+
$newcode = false; $newcode = get_transient($tkey);
|
1585 |
+
if ( $newcode === false) {
|
1586 |
+
$res = fvm_download_and_cache($hurl, $tkey, null, $disable_css_minification, 'css');
|
1587 |
+
if(is_array($res)) {
|
1588 |
+
$newcode = $res['code'];
|
1589 |
+
$newlog = $res['log'];
|
1590 |
+
}
|
1591 |
+
} else {
|
1592 |
+
$newlog = "$printurl --- Debug: Fetched from transients cache with key $tkey ---\n";
|
1593 |
+
}
|
1594 |
+
|
1595 |
+
# append
|
1596 |
+
if($newcode !== false) {
|
1597 |
+
$code.= $newcode;
|
1598 |
+
if(isset($inline_css[$handle]) && !empty($inline_css[$handle])) { $code.= $inline_css[$handle]; } # add inline css on the fly
|
1599 |
+
$log.= $newlog;
|
1600 |
+
}
|
1601 |
+
|
1602 |
+
# consider dependencies on handles with an empty src
|
1603 |
+
} else {
|
1604 |
+
wp_dequeue_script($handle); wp_enqueue_script($handle);
|
1605 |
+
}
|
1606 |
+
endforeach;
|
1607 |
+
|
1608 |
+
# prepare log
|
1609 |
+
$log = "PROCESSED on ".date('r')."\n".$log."PROCESSED from ".home_url(add_query_arg( NULL, NULL ))."\n";
|
1610 |
+
|
1611 |
+
# generate cache, add inline css, write log
|
1612 |
+
file_put_contents($file.'.txt', $log);
|
1613 |
+
file_put_contents($file, $code); # preserve style tags
|
1614 |
+
file_put_contents($file.'.gz', gzencode(file_get_contents($file), 9));
|
1615 |
+
|
1616 |
+
}
|
1617 |
+
|
1618 |
+
# register and enqueue minified file, consider excluding of mediatype "print" and inline css
|
1619 |
+
if ($remove_print_mediatypes != 1 || ($remove_print_mediatypes == 1 && $footer[$i]['media'] != 'print')) {
|
1620 |
+
if($force_inline_css_footer != false) {
|
1621 |
+
echo '<style type="text/css" media="'.$footer[$i]['media'].'">'.file_get_contents($file).'</style>';
|
1622 |
+
} else {
|
1623 |
+
|
1624 |
+
# move CSS to footer
|
1625 |
+
if($send_css_to_footer != false) {
|
1626 |
+
|
1627 |
+
if($critical_css_tester != true) {
|
1628 |
+
echo '<link rel="preload" href="'.$file_url.'" as="style" media="'.$footer[$i]['media'].'" onload="this.rel=\'stylesheet\'">';
|
1629 |
+
echo '<noscript><link rel="stylesheet" type="text/css" media="'.$footer[$i]['media'].'" href="'.$file_url.'"></noscript>';
|
1630 |
+
echo '<!--[if IE]><link rel="stylesheet" type="text/css" media="'.$footer[$i]['media'].'" href="'.$file_url.'"><![endif]-->';
|
1631 |
+
}
|
1632 |
+
|
1633 |
+
} else {
|
1634 |
+
|
1635 |
+
# default
|
1636 |
+
wp_register_style("fvm-footer-$i", $file_url, array(), null, $footer[$i]['media']);
|
1637 |
+
wp_enqueue_style("fvm-footer-$i");
|
1638 |
+
|
1639 |
+
}
|
1640 |
+
}
|
1641 |
+
}
|
1642 |
+
|
1643 |
+
# other css need to be requeued for the order of files to be kept
|
1644 |
+
} else {
|
1645 |
+
wp_dequeue_style($footer[$i]['handle']); wp_enqueue_style($footer[$i]['handle']);
|
1646 |
+
}
|
1647 |
+
}
|
1648 |
+
|
1649 |
+
# remove from queue
|
1650 |
+
$wp_styles->done = $done;
|
1651 |
+
}
|
1652 |
+
###########################################
|
1653 |
+
|
1654 |
+
|
1655 |
+
|
1656 |
+
|
1657 |
+
###########################################
|
1658 |
+
# defer CSS globally from the header (order matters)
|
1659 |
+
###########################################
|
1660 |
+
function fvm_movecss_to_footer_header() {
|
1661 |
+
global $send_css_to_footer;
|
1662 |
+
if($send_css_to_footer != false) {
|
1663 |
+
|
1664 |
+
# echo LoadCSS scripts
|
1665 |
+
echo '<script>
|
1666 |
+
/*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
|
1667 |
+
!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);
|
1668 |
+
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */
|
1669 |
+
!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);
|
1670 |
+
</script>';
|
1671 |
+
|
1672 |
+
} }
|
1673 |
+
|
1674 |
+
if (!is_admin()) { add_action('wp_head', 'fvm_movecss_to_footer_header', PHP_INT_MAX); }
|
1675 |
+
###########################################
|
1676 |
+
|
1677 |
+
|
1678 |
+
|
1679 |
+
###########################################
|
1680 |
+
# generate gulp-uncss files for this page (dev only)
|
1681 |
+
###########################################
|
1682 |
+
function fvm_generate_gulp_uncss() {
|
1683 |
+
global $wp, $generate_gulp_files, $generate_gulp_path;
|
1684 |
+
|
1685 |
+
if(isset($GLOBALS['used_css_files']) && $generate_gulp_files != false && !empty($generate_gulp_path)) {
|
1686 |
+
|
1687 |
+
# some paths and urls
|
1688 |
+
$currenturl = fvm_get_protocol($_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"]);
|
1689 |
+
$file = sanitize_title($currenturl);
|
1690 |
+
$save = get_stylesheet_directory().'/criticalcss/css/'.$file.'.css';
|
1691 |
+
$generate_gulp_path = rtrim(trim($generate_gulp_path), '/');
|
1692 |
+
$generate_gulp_path_out = $generate_gulp_path.'/out/';
|
1693 |
+
if(!is_dir($generate_gulp_path_out) && is_writable($generate_gulp_path_out)) { mkdir($generate_gulp_path_out); }
|
1694 |
+
$gulpfile = "$generate_gulp_path/$file.js";
|
1695 |
+
|
1696 |
+
# process
|
1697 |
+
if(!file_exists($save) && !file_exists($gulpfile) && is_dir($generate_gulp_path_out)) {
|
1698 |
+
|
1699 |
+
$cssfiles = json_encode($GLOBALS['used_css_files'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
1700 |
+
|
1701 |
+
# gulp tasks
|
1702 |
+
$gulptask = <<<EOF
|
1703 |
+
var gulp = require('gulp');
|
1704 |
+
var uncss = require('gulp-uncss');
|
1705 |
+
var concat = require('gulp-concat');
|
1706 |
+
var nano = require('gulp-cssnano');
|
1707 |
+
var remoteSrc = require('gulp-remote-src');
|
1708 |
+
gulp.task('uncss', function() {
|
1709 |
+
remoteSrc($cssfiles, { base: null })
|
1710 |
+
.pipe(concat('$file.css'))
|
1711 |
+
.pipe(uncss({ html: ['$currenturl'] }))
|
1712 |
+
.pipe(nano())
|
1713 |
+
.pipe(gulp.dest('$generate_gulp_path/out/'));
|
1714 |
+
});
|
1715 |
+
EOF;
|
1716 |
+
|
1717 |
+
# write gulp file
|
1718 |
+
file_put_contents($gulpfile, $gulptask);
|
1719 |
+
|
1720 |
+
}
|
1721 |
+
}
|
1722 |
+
}
|
1723 |
+
|
1724 |
+
if (!is_admin()) { add_action('wp_footer', 'fvm_generate_gulp_uncss', PHP_INT_MAX); }
|
1725 |
+
|
1726 |
+
|
1727 |
+
|
1728 |
+
###########################################
|
1729 |
+
# add preconnect and preload headers
|
1730 |
+
###########################################
|
1731 |
+
function fvm_buffer_placeholder_top() {
|
1732 |
+
global $preload, $preconnect;
|
1733 |
+
|
1734 |
+
# defaults
|
1735 |
+
$meta = array();
|
1736 |
+
|
1737 |
+
# preconnect resources
|
1738 |
+
# https://css-tricks.com/prefetching-preloading-prebrowsing/
|
1739 |
+
if(count($preconnect) > 0) {
|
1740 |
+
$a = array(); foreach ($preconnect as $b) {
|
1741 |
+
if(!empty($b)) { $a[] = '<link href="'.str_ireplace(array('http://', 'https://'), '//', $b).'" rel="preconnect">'; }
|
1742 |
+
}
|
1743 |
+
if(count($a) > 0) { $meta[] = implode('', $a); }
|
1744 |
+
}
|
1745 |
+
|
1746 |
+
# preload resources (beta: homepage only)
|
1747 |
+
# https://css-tricks.com/prefetching-preloading-prebrowsing/
|
1748 |
+
if((is_home() || is_front_page()) && count($preload) > 0) {
|
1749 |
+
$a = array();
|
1750 |
+
foreach ($preload as $b) {
|
1751 |
+
if(!empty($b)) {
|
1752 |
+
$meta[] = '<link rel="preload" as="image" href="'.str_ireplace(array('http://', 'https://'), '//', $b).'">';
|
1753 |
+
}
|
1754 |
+
}
|
1755 |
+
}
|
1756 |
+
|
1757 |
+
# output on top
|
1758 |
+
echo implode('', $meta);
|
1759 |
+
}
|
1760 |
+
|
1761 |
+
# remove query from static assets and process defering (if enabled)
|
1762 |
+
if (!is_admin()) {
|
1763 |
+
add_filter('script_loader_tag', 'fastvelocity_min_defer_js', 10, 3);
|
1764 |
+
add_filter('style_loader_src', 'fastvelocity_remove_cssjs_ver', 10, 2);
|
1765 |
+
}
|
1766 |
+
|
1767 |
+
# enable html minification
|
1768 |
+
if(!$skip_html_minification && !is_admin()) {
|
1769 |
+
add_action('get_header', 'fastvelocity_min_html_compression_start', PHP_INT_MAX);
|
1770 |
+
}
|
1771 |
+
|
inc/functions-admin.php
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
in development...
|
5 |
+
*/
|
6 |
+
|
7 |
+
# add admin toolbar
|
8 |
+
function fastvelocity_load_toolbar() {
|
9 |
+
if(current_user_can('manage_options')) { add_action( 'admin_bar_menu', 'fastvelocity_add_toolbar', 100 ); }
|
10 |
+
}
|
11 |
+
|
12 |
+
# admin toolbar processing
|
13 |
+
function fastvelocity_add_toolbar() {
|
14 |
+
global $wp_admin_bar;
|
15 |
+
|
16 |
+
# get cache size
|
17 |
+
$stats = fastvelocity_get_cachestats();
|
18 |
+
$count = $stats['count'];
|
19 |
+
$size = $stats['size'];
|
20 |
+
|
21 |
+
# Create or add new items into the Admin Toolbar.
|
22 |
+
$wp_admin_bar->add_node( array(
|
23 |
+
'id' => 'fvm',
|
24 |
+
'title' => '<span class="ab-icon"></span><span class="ab-label">' . __("Fast Velocity",'fvm') . '</span>',
|
25 |
+
'href' => admin_url( 'options-general.php?page=fastvelocity-min' ),
|
26 |
+
'meta' => array( 'class' => 'bullet-green')
|
27 |
+
));
|
28 |
+
|
29 |
+
# Cache Info node
|
30 |
+
$wp_admin_bar->add_node( array(
|
31 |
+
'id' => 'fvm-cache-info',
|
32 |
+
'title' => '<p class="bold">' . __( "Cache Info", 'fvm' ) . '</p>' .
|
33 |
+
'<table>' .
|
34 |
+
'<tr><td>' . __( "Size", 'fvm' ) . ':</td><td class="size green">' . $size . '</td></tr>' .
|
35 |
+
'<tr><td>' . __( "Files", 'fvm' ) . ':</td><td class="files white">' . $count . '</td></tr>' .
|
36 |
+
'</table>',
|
37 |
+
'parent'=> 'fvm'
|
38 |
+
));
|
39 |
+
|
40 |
+
# Delete Cache node
|
41 |
+
$wp_admin_bar->add_node( array(
|
42 |
+
'id' => 'fvm-delete-cache',
|
43 |
+
'title' => __("Purge Cache",'fvm'),
|
44 |
+
'parent'=> 'fvm'
|
45 |
+
));
|
46 |
+
|
47 |
+
}
|
48 |
+
|
49 |
+
|
50 |
+
|
51 |
+
# get cache size and count
|
52 |
+
function fastvelocity_get_cachestats() {
|
53 |
+
|
54 |
+
# info
|
55 |
+
$cachepath = fvm_cachepath();
|
56 |
+
$tmpdir = $cachepath['tmpdir'];
|
57 |
+
$cachedir = $cachepath['cachedir'];
|
58 |
+
$search = array($tmpdir, $cachedir);
|
59 |
+
$size = 0;
|
60 |
+
$count = 0;
|
61 |
+
|
62 |
+
foreach ($search as $dir) {
|
63 |
+
if(is_dir(rtrim($dir, '/'))) {
|
64 |
+
if ($handle = opendir($dir.'/')) {
|
65 |
+
while (false !== ($file = readdir($handle))) { $f = $dir.'/'.$file; $size = $size + filesize($f); $count++; }
|
66 |
+
closedir($handle);
|
67 |
+
}
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
return array('size'=>fastvelocity_format_filesize($size), 'count'=>$count);
|
72 |
+
}
|
73 |
+
|
74 |
+
|
inc/functions-serverinfo.php
ADDED
@@ -0,0 +1,362 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
|
5 |
+
### Get General Information
|
6 |
+
function fvm_get_generalinfo() {
|
7 |
+
global $is_IIS;
|
8 |
+
if( is_rtl() ) : ?>
|
9 |
+
<style type="text/css">
|
10 |
+
#GeneralOverview table,
|
11 |
+
#GeneralOverview th,
|
12 |
+
#GeneralOverview td {
|
13 |
+
direction: ltr;
|
14 |
+
text-align: left;
|
15 |
+
}
|
16 |
+
#GeneralOverview h2 {
|
17 |
+
padding: 0.5em 0 0;
|
18 |
+
}
|
19 |
+
</style>
|
20 |
+
<?php endif;
|
21 |
+
?>
|
22 |
+
<div class="wrap" id="GeneralOverview">
|
23 |
+
<h2><?php _e('Server Info','fvm-serverinfo'); ?></h2>
|
24 |
+
<br />
|
25 |
+
<table class="widefat">
|
26 |
+
<thead>
|
27 |
+
<tr>
|
28 |
+
<th><?php _e('Variable Name', 'fvm-serverinfo'); ?></th>
|
29 |
+
<th><?php _e('Value', 'fvm-serverinfo'); ?></th>
|
30 |
+
<th><?php _e('Variable Name', 'fvm-serverinfo'); ?></th>
|
31 |
+
<th><?php _e('Value', 'fvm-serverinfo'); ?></th>
|
32 |
+
</tr>
|
33 |
+
</thead>
|
34 |
+
<tbody>
|
35 |
+
<tr>
|
36 |
+
<td><?php _e('OS', 'fvm-serverinfo'); ?></td>
|
37 |
+
<td><?php echo PHP_OS; ?></td>
|
38 |
+
<td><?php _e('Database Data Disk Usage', 'fvm-serverinfo'); ?></td>
|
39 |
+
<td><?php echo fvm_format_filesize(fvm_get_mysql_data_usage()); ?></td>
|
40 |
+
</tr>
|
41 |
+
<tr class="alternate">
|
42 |
+
<td><?php _e('Server', 'fvm-serverinfo'); ?></td>
|
43 |
+
<td><?php echo $_SERVER["SERVER_SOFTWARE"]; ?></td>
|
44 |
+
<td><?php _e('Database Index Disk Usage', 'fvm-serverinfo'); ?></td>
|
45 |
+
<td><?php echo fvm_format_filesize(fvm_get_mysql_index_usage()); ?></td>
|
46 |
+
</tr>
|
47 |
+
<tr>
|
48 |
+
<td>PHP</td>
|
49 |
+
<td>v<?php echo PHP_VERSION; ?></td>
|
50 |
+
<td><?php _e('MYSQL Maximum Packet Size', 'fvm-serverinfo'); ?></td>
|
51 |
+
<td><?php echo fvm_format_filesize(fvm_get_mysql_max_allowed_packet()); ?></td>
|
52 |
+
</tr>
|
53 |
+
<tr class="alternate">
|
54 |
+
<td>MYSQL</td>
|
55 |
+
<td>v<?php echo fvm_get_mysql_version(); ?></td>
|
56 |
+
<td><?php _e('MYSQL Maximum No. Connection', 'fvm-serverinfo'); ?></td>
|
57 |
+
<td><?php echo number_format_i18n(fvm_get_mysql_max_allowed_connections()); ?></td>
|
58 |
+
</tr>
|
59 |
+
<tr>
|
60 |
+
<td><?php _e('Server Load', 'fvm-serverinfo'); ?></td>
|
61 |
+
<td><?php echo fvm_get_serverload(); ?></td>
|
62 |
+
<td><?php _e( 'MYSQL Query Cache Size', 'fvm-serverinfo' ); ?></td>
|
63 |
+
<td><?php echo fvm_format_filesize( fvm_get_mysql_query_cache_size() ); ?></td>
|
64 |
+
</tr>
|
65 |
+
<tr class="alternate">
|
66 |
+
<td><?php _e("Server CPU's", 'fvm-serverinfo'); ?></td>
|
67 |
+
<td><?php echo fvm_get_servercpu(); ?></td>
|
68 |
+
<td><?php _e('PHP Short Tag', 'fvm-serverinfo'); ?></td>
|
69 |
+
<td><?php echo fvm_get_php_short_tag(); ?></td>
|
70 |
+
</tr>
|
71 |
+
<tr>
|
72 |
+
<td><?php _e('Server Hostname', 'fvm-serverinfo'); ?></td>
|
73 |
+
<td><?php echo $_SERVER['SERVER_NAME']; ?></td>
|
74 |
+
<td><?php _e('PHP Magic Quotes GPC', 'fvm-serverinfo'); ?></td>
|
75 |
+
<td><?php echo fvm_get_php_magic_quotes_gpc(); ?></td>
|
76 |
+
</tr>
|
77 |
+
<tr class="alternate">
|
78 |
+
<td><?php _e('Server Document Root','fvm-serverinfo'); ?></td>
|
79 |
+
<td><?php echo $_SERVER['DOCUMENT_ROOT']; ?></td>
|
80 |
+
<td><?php _e('PHP Memory Limit', 'fvm-serverinfo'); ?></td>
|
81 |
+
<td><?php echo fvm_format_php_size(fvm_get_php_memory_limit()); ?></td>
|
82 |
+
</tr>
|
83 |
+
<tr>
|
84 |
+
<td><?php _e('Site Url', 'fvm-serverinfo'); ?></td>
|
85 |
+
<td><?php echo site_url(); ?></td>
|
86 |
+
<td><?php _e('PHP Max Upload Size', 'fvm-serverinfo'); ?></td>
|
87 |
+
<td><?php echo fvm_format_php_size(fvm_get_php_upload_max()); ?></td>
|
88 |
+
</tr>
|
89 |
+
<tr class="alternate">
|
90 |
+
<td><?php _e('Home Url', 'fvm-serverinfo'); ?></td>
|
91 |
+
<td><?php echo home_url(); ?></td>
|
92 |
+
<td><?php _e('PHP Max Post Size', 'fvm-serverinfo'); ?></td>
|
93 |
+
<td><?php echo fvm_format_php_size(fvm_get_php_post_max()); ?></td>
|
94 |
+
</tr>
|
95 |
+
<tr>
|
96 |
+
<td><?php _e('MySQL Date/Time', 'fvm-serverinfo'); ?></td>
|
97 |
+
<td><?php echo mysql2date(sprintf(__('%s @ %s', 'wp-postratings'), get_option('date_format'), get_option('time_format')), current_time('mysql', 1)). ' GMT'; ?></td>
|
98 |
+
<td><?php _e('PHP Max Script Execute Time', 'fvm-serverinfo'); ?></td>
|
99 |
+
<td><?php echo fvm_get_php_max_execution(); ?>s</td>
|
100 |
+
</tr>
|
101 |
+
</tbody>
|
102 |
+
</table>
|
103 |
+
</div>
|
104 |
+
<?php
|
105 |
+
}
|
106 |
+
|
107 |
+
|
108 |
+
### Function: Format Bytes Into TiB/GiB/MiB/KiB/Bytes
|
109 |
+
if(!function_exists('fvm_format_filesize')) {
|
110 |
+
function fvm_format_filesize($rawSize) {
|
111 |
+
if($rawSize / 1099511627776 > 1) {
|
112 |
+
return number_format_i18n($rawSize/1099511627776, 1).' '.__('TiB', 'fvm-serverinfo');
|
113 |
+
} elseif($rawSize / 1073741824 > 1) {
|
114 |
+
return number_format_i18n($rawSize/1073741824, 1).' '.__('GiB', 'fvm-serverinfo');
|
115 |
+
} elseif($rawSize / 1048576 > 1) {
|
116 |
+
return number_format_i18n($rawSize/1048576, 1).' '.__('MiB', 'fvm-serverinfo');
|
117 |
+
} elseif($rawSize / 1024 > 1) {
|
118 |
+
return number_format_i18n($rawSize/1024, 1).' '.__('KiB', 'fvm-serverinfo');
|
119 |
+
} elseif($rawSize > 1) {
|
120 |
+
return number_format_i18n($rawSize, 0).' '.__('bytes', 'fvm-serverinfo');
|
121 |
+
} else {
|
122 |
+
return __('unknown', 'fvm-serverinfo');
|
123 |
+
}
|
124 |
+
}
|
125 |
+
}
|
126 |
+
|
127 |
+
### Function: Convert PHP Size Format to Localized
|
128 |
+
function fvm_format_php_size($size) {
|
129 |
+
if (!is_numeric($size)) {
|
130 |
+
if (strpos($size, 'M') !== false) {
|
131 |
+
$size = intval($size)*1024*1024;
|
132 |
+
} elseif (strpos($size, 'K') !== false) {
|
133 |
+
$size = intval($size)*1024;
|
134 |
+
} elseif (strpos($size, 'G') !== false) {
|
135 |
+
$size = intval($size)*1024*1024*1024;
|
136 |
+
}
|
137 |
+
}
|
138 |
+
return is_numeric($size) ? fvm_format_filesize($size) : $size;
|
139 |
+
}
|
140 |
+
|
141 |
+
### Function: Get PHP Short Tag
|
142 |
+
if(!function_exists('fvm_get_php_short_tag')) {
|
143 |
+
function fvm_get_php_short_tag() {
|
144 |
+
if(ini_get('short_open_tag')) {
|
145 |
+
$short_tag = __('On', 'fvm-serverinfo');
|
146 |
+
} else {
|
147 |
+
$short_tag = __('Off', 'fvm-serverinfo');
|
148 |
+
}
|
149 |
+
return $short_tag;
|
150 |
+
}
|
151 |
+
}
|
152 |
+
|
153 |
+
|
154 |
+
### Function: Get PHP Magic Quotes GPC
|
155 |
+
if(!function_exists('fvm_get_php_magic_quotes_gpc')) {
|
156 |
+
function fvm_get_php_magic_quotes_gpc() {
|
157 |
+
if(get_magic_quotes_gpc()) {
|
158 |
+
$magic_quotes_gpc = __('On', 'fvm-serverinfo');
|
159 |
+
} else {
|
160 |
+
$magic_quotes_gpc = __('Off', 'fvm-serverinfo');
|
161 |
+
}
|
162 |
+
return $magic_quotes_gpc;
|
163 |
+
}
|
164 |
+
}
|
165 |
+
|
166 |
+
|
167 |
+
### Function: Get PHP Max Upload Size
|
168 |
+
if(!function_exists('fvm_get_php_upload_max')) {
|
169 |
+
function fvm_get_php_upload_max() {
|
170 |
+
if(ini_get('upload_max_filesize')) {
|
171 |
+
$upload_max = ini_get('upload_max_filesize');
|
172 |
+
} else {
|
173 |
+
$upload_max = __('N/A', 'fvm-serverinfo');
|
174 |
+
}
|
175 |
+
return $upload_max;
|
176 |
+
}
|
177 |
+
}
|
178 |
+
|
179 |
+
|
180 |
+
### Function: Get PHP Max Post Size
|
181 |
+
if(!function_exists('fvm_get_php_post_max')) {
|
182 |
+
function fvm_get_php_post_max() {
|
183 |
+
if(ini_get('post_max_size')) {
|
184 |
+
$post_max = ini_get('post_max_size');
|
185 |
+
} else {
|
186 |
+
$post_max = __('N/A', 'fvm-serverinfo');
|
187 |
+
}
|
188 |
+
return $post_max;
|
189 |
+
}
|
190 |
+
}
|
191 |
+
|
192 |
+
|
193 |
+
### Function: PHP Maximum Execution Time
|
194 |
+
if(!function_exists('fvm_get_php_max_execution')) {
|
195 |
+
function fvm_get_php_max_execution() {
|
196 |
+
if(ini_get('max_execution_time')) {
|
197 |
+
$max_execute = ini_get('max_execution_time');
|
198 |
+
} else {
|
199 |
+
$max_execute = __('N/A', 'fvm-serverinfo');
|
200 |
+
}
|
201 |
+
return $max_execute;
|
202 |
+
}
|
203 |
+
}
|
204 |
+
|
205 |
+
|
206 |
+
### Function: PHP Memory Limit
|
207 |
+
if(!function_exists('fvm_get_php_memory_limit')) {
|
208 |
+
function fvm_get_php_memory_limit() {
|
209 |
+
if(ini_get('memory_limit')) {
|
210 |
+
$memory_limit = ini_get('memory_limit');
|
211 |
+
} else {
|
212 |
+
$memory_limit = __('N/A', 'fvm-serverinfo');
|
213 |
+
}
|
214 |
+
return $memory_limit;
|
215 |
+
}
|
216 |
+
}
|
217 |
+
|
218 |
+
|
219 |
+
### Function: Get MYSQL Version
|
220 |
+
if(!function_exists('fvm_get_mysql_version')) {
|
221 |
+
function fvm_get_mysql_version() {
|
222 |
+
global $wpdb;
|
223 |
+
return $wpdb->get_var("SELECT VERSION() AS version");
|
224 |
+
}
|
225 |
+
}
|
226 |
+
|
227 |
+
|
228 |
+
### Function: Get MYSQL Data Usage
|
229 |
+
if(!function_exists('fvm_get_mysql_data_usage')) {
|
230 |
+
function fvm_get_mysql_data_usage() {
|
231 |
+
global $wpdb;
|
232 |
+
$data_usage = '';
|
233 |
+
$tablesstatus = $wpdb->get_results("SHOW TABLE STATUS");
|
234 |
+
foreach($tablesstatus as $tablestatus) {
|
235 |
+
$data_usage += $tablestatus->Data_length;
|
236 |
+
}
|
237 |
+
if (!$data_usage) {
|
238 |
+
$data_usage = __('N/A', 'fvm-serverinfo');
|
239 |
+
}
|
240 |
+
return $data_usage;
|
241 |
+
}
|
242 |
+
}
|
243 |
+
|
244 |
+
|
245 |
+
### Function: Get MYSQL Index Usage
|
246 |
+
if(!function_exists('fvm_get_mysql_index_usage')) {
|
247 |
+
function fvm_get_mysql_index_usage() {
|
248 |
+
global $wpdb;
|
249 |
+
$index_usage = '';
|
250 |
+
$tablesstatus = $wpdb->get_results("SHOW TABLE STATUS");
|
251 |
+
foreach($tablesstatus as $tablestatus) {
|
252 |
+
$index_usage += $tablestatus->Index_length;
|
253 |
+
}
|
254 |
+
if (!$index_usage){
|
255 |
+
$index_usage = __('N/A', 'fvm-serverinfo');
|
256 |
+
}
|
257 |
+
return $index_usage;
|
258 |
+
}
|
259 |
+
}
|
260 |
+
|
261 |
+
|
262 |
+
### Function: Get MYSQL Max Allowed Packet
|
263 |
+
if(!function_exists('fvm_get_mysql_max_allowed_packet')) {
|
264 |
+
function fvm_get_mysql_max_allowed_packet() {
|
265 |
+
global $wpdb;
|
266 |
+
$packet_max_query = $wpdb->get_row("SHOW VARIABLES LIKE 'max_allowed_packet'");
|
267 |
+
$packet_max = $packet_max_query->Value;
|
268 |
+
if(!$packet_max) {
|
269 |
+
$packet_max = __('N/A', 'fvm-serverinfo');
|
270 |
+
}
|
271 |
+
return $packet_max;
|
272 |
+
}
|
273 |
+
}
|
274 |
+
|
275 |
+
|
276 |
+
### Function:Get MYSQL Max Allowed Connections
|
277 |
+
if(!function_exists('fvm_get_mysql_max_allowed_connections')) {
|
278 |
+
function fvm_get_mysql_max_allowed_connections() {
|
279 |
+
global $wpdb;
|
280 |
+
$connection_max_query = $wpdb->get_row("SHOW VARIABLES LIKE 'max_connections'");
|
281 |
+
$connection_max = $connection_max_query->Value;
|
282 |
+
if(!$connection_max) {
|
283 |
+
$connection_max = __('N/A', 'fvm-serverinfo');
|
284 |
+
}
|
285 |
+
return $connection_max;
|
286 |
+
}
|
287 |
+
}
|
288 |
+
|
289 |
+
### Function:Get MYSQL Query Cache Size
|
290 |
+
if(!function_exists('fvm_get_mysql_query_cache_size')) {
|
291 |
+
function fvm_get_mysql_query_cache_size() {
|
292 |
+
global $wpdb;
|
293 |
+
$query_cache_size_query = $wpdb->get_row( "SHOW VARIABLES LIKE 'query_cache_size'" );
|
294 |
+
$query_cache_size = $query_cache_size_query->Value;
|
295 |
+
if ( empty( $query_cache_size ) ) {
|
296 |
+
$query_cache_size = __( 'N/A', 'fvm-serverinfo' );
|
297 |
+
}
|
298 |
+
return $query_cache_size;
|
299 |
+
}
|
300 |
+
}
|
301 |
+
|
302 |
+
|
303 |
+
### Function: Get The Server Load
|
304 |
+
if(!function_exists('fvm_get_serverload')) {
|
305 |
+
function fvm_get_serverload() {
|
306 |
+
$server_load = '';
|
307 |
+
$numCpus = 'N/A';
|
308 |
+
if(PHP_OS != 'WINNT' && PHP_OS != 'WIN32') {
|
309 |
+
if(@file_exists('/proc/loadavg') ) {
|
310 |
+
if ($fh = @fopen( '/proc/loadavg', 'r' )) {
|
311 |
+
$data = @fread( $fh, 6 );
|
312 |
+
@fclose( $fh );
|
313 |
+
$load_avg = explode( " ", $data );
|
314 |
+
$server_load = trim($load_avg[0]);
|
315 |
+
}
|
316 |
+
} else if ('WIN' == strtoupper(substr(PHP_OS, 0, 3))) {
|
317 |
+
$process = @popen('wmic cpu get NumberOfCores', 'rb');
|
318 |
+
if (false !== $process && null !== $process) {
|
319 |
+
fgets($process);
|
320 |
+
$numCpus = intval(fgets($process));
|
321 |
+
pclose($process);
|
322 |
+
}
|
323 |
+
} else {
|
324 |
+
$data = @system('uptime');
|
325 |
+
preg_match('/(.*):{1}(.*)/', $data, $matches);
|
326 |
+
$load_arr = explode(',', $matches[2]);
|
327 |
+
$server_load = trim($load_arr[0]);
|
328 |
+
}
|
329 |
+
}
|
330 |
+
if(empty($server_load)) {
|
331 |
+
$server_load = __('N/A', 'fvm-serverinfo');
|
332 |
+
}
|
333 |
+
return $server_load;
|
334 |
+
}
|
335 |
+
}
|
336 |
+
|
337 |
+
|
338 |
+
### Function: Get The Server CPU's
|
339 |
+
if(!function_exists('fvm_get_servercpu')) {
|
340 |
+
function fvm_get_servercpu() {
|
341 |
+
$numCpus = '';
|
342 |
+
if(PHP_OS != 'WINNT' && PHP_OS != 'WIN32') {
|
343 |
+
if (is_file('/proc/cpuinfo')) {
|
344 |
+
$cpuinfo = file_get_contents('/proc/cpuinfo');
|
345 |
+
preg_match_all('/^processor/m', $cpuinfo, $matches);
|
346 |
+
$numCpus = count($matches[0]);
|
347 |
+
} else {
|
348 |
+
$process = @popen('sysctl -a', 'rb');
|
349 |
+
if (false !== $process && null !== $process) {
|
350 |
+
$output = stream_get_contents($process);
|
351 |
+
preg_match('/hw.ncpu: (\d+)/', $output, $matches);
|
352 |
+
if ($matches) { $numCpus = intval($matches[1][0]); }
|
353 |
+
pclose($process);
|
354 |
+
}
|
355 |
+
}
|
356 |
+
}
|
357 |
+
if(empty($numCpus)) {
|
358 |
+
$numCpus = __('N/A', 'fvm-serverinfo');
|
359 |
+
}
|
360 |
+
return $numCpus;
|
361 |
+
}
|
362 |
+
}
|
inc/functions.php
ADDED
@@ -0,0 +1,862 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
# handle better utf-8 and unicode encoding
|
4 |
+
if(function_exists('mb_internal_encoding')) { mb_internal_encoding('UTF-8'); }
|
5 |
+
|
6 |
+
# Consider fallback to PHP Minify [2017.07.01] from https://github.com/matthiasmullie/minify (must be defined on the outer scope)
|
7 |
+
$path = $plugindir . 'libs/matthiasmullie';
|
8 |
+
require_once $path . '/minify/src/Minify.php';
|
9 |
+
require_once $path . '/minify/src/CSS.php';
|
10 |
+
require_once $path . '/minify/src/JS.php';
|
11 |
+
require_once $path . '/minify/src/Exception.php';
|
12 |
+
require_once $path . '/minify/src/Exceptions/BasicException.php';
|
13 |
+
require_once $path . '/minify/src/Exceptions/FileImportException.php';
|
14 |
+
require_once $path . '/minify/src/Exceptions/IOException.php';
|
15 |
+
require_once $path . '/path-converter/src/ConverterInterface.php';
|
16 |
+
require_once $path . '/path-converter/src/Converter.php';
|
17 |
+
use MatthiasMullie\Minify;
|
18 |
+
|
19 |
+
# use HTML minification
|
20 |
+
require_once ($plugindir . 'libs/mrclay/HTML.php');
|
21 |
+
|
22 |
+
# get cache directories and urls
|
23 |
+
function fvm_cachepath() {
|
24 |
+
|
25 |
+
# create
|
26 |
+
$upload = wp_upload_dir();
|
27 |
+
$cachebase = rtrim($upload['basedir'], '/').'/fvm';
|
28 |
+
$cachedir = rtrim($upload['basedir'], '/').'/fvm/cache';
|
29 |
+
$tmpdir = rtrim($upload['basedir'], '/').'/fvm/temp';
|
30 |
+
$cachedirurl = rtrim($upload['baseurl'], '/').'/fvm/cache';
|
31 |
+
if(!is_dir($cachebase)) { mkdir($cachebase); }
|
32 |
+
if(!is_dir($cachedir)) { mkdir($cachedir); }
|
33 |
+
if(!is_dir($tmpdir)) { mkdir($tmpdir); }
|
34 |
+
$return = array('tmpdir'=>$tmpdir, 'cachedir'=>$cachedir, 'cachedirurl'=>$cachedirurl);
|
35 |
+
|
36 |
+
# save or update
|
37 |
+
$save = get_option('fvm-cachepath', array());
|
38 |
+
if($save != $return) {
|
39 |
+
update_option('fvm-cachepath', $return);
|
40 |
+
}
|
41 |
+
|
42 |
+
return $return;
|
43 |
+
}
|
44 |
+
|
45 |
+
|
46 |
+
# functions, get hurl info
|
47 |
+
function fastvelocity_min_get_hurl($src, $wp_domain, $wp_home) {
|
48 |
+
|
49 |
+
# preserve empty source handles
|
50 |
+
$hurl = trim($src); if(empty($hurl)) { return $hurl; }
|
51 |
+
|
52 |
+
# some fixes
|
53 |
+
$hurl = str_ireplace(array('&', '&'), '&', $hurl);
|
54 |
+
|
55 |
+
# get current protocol scheme with cloudflare support
|
56 |
+
if (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { $protocol = 'https://'; } else { $protocol = 'http://'; }
|
57 |
+
|
58 |
+
#make sure wp_home doesn't have a forward slash
|
59 |
+
$wp_home = rtrim($wp_home, '/');
|
60 |
+
|
61 |
+
# apply some filters
|
62 |
+
if (substr($hurl, 0, 2) === "//") { $hurl = 'http://'.ltrim($hurl, "/"); } # protocol only
|
63 |
+
if (substr($hurl, 0, 4) === "http" && stripos($hurl, $wp_domain) === false) { return $hurl; } # return if external domain
|
64 |
+
if (substr($hurl, 0, 4) !== "http" && stripos($hurl, $wp_domain) !== false) { $hurl = $wp_home.'/'.ltrim($hurl, "/"); } # protocol + home
|
65 |
+
|
66 |
+
# prevent double forward slashes in the middle
|
67 |
+
$hurl = str_ireplace('###', '://', str_ireplace('//', '/', str_ireplace('://', '###', $hurl)));
|
68 |
+
|
69 |
+
# consider different wp-content directory
|
70 |
+
$proceed = 0; if(!empty($wp_home)) {
|
71 |
+
$alt_wp_content = basename($wp_home);
|
72 |
+
if(substr($hurl, 0, strlen($alt_wp_content)) === $alt_wp_content) { $proceed = 1; }
|
73 |
+
}
|
74 |
+
|
75 |
+
# protocol + home for relative paths
|
76 |
+
if (substr($hurl, 0, 12) === "/wp-includes" || substr($hurl, 0, 9) === "/wp-admin" || substr($hurl, 0, 11) === "/wp-content" || $proceed == 1) {
|
77 |
+
$hurl = $wp_home.'/'.ltrim($hurl, "/"); }
|
78 |
+
|
79 |
+
# make sure there is a protocol prefix as required
|
80 |
+
$hurl = $protocol.str_ireplace(array('http://', 'https://'), '', $hurl); # enforce protocol
|
81 |
+
|
82 |
+
# no query strings
|
83 |
+
if (stripos($hurl, '.js?v') !== false) { $hurl = stristr($hurl, '.js?v', true).'.js'; } # no query strings
|
84 |
+
if (stripos($hurl, '.css?v') !== false) { $hurl = stristr($hurl, '.css?v', true).'.css'; } # no query strings
|
85 |
+
|
86 |
+
return $hurl;
|
87 |
+
}
|
88 |
+
|
89 |
+
|
90 |
+
# check if it's an internal url or not
|
91 |
+
function fvm_internal_url($hurl, $wp_home) {
|
92 |
+
if (substr($hurl, 0, strlen($wp_home)) === $wp_home) { return true; }
|
93 |
+
if (stripos($hurl, $wp_home) !== false) { return true; }
|
94 |
+
if (isset($_SERVER['HTTP_HOST']) && stripos($hurl, preg_replace('/:\d+$/', '', $_SERVER['HTTP_HOST'])) !== false) { return true; }
|
95 |
+
if (isset($_SERVER['SERVER_NAME']) && stripos($hurl, preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME'])) !== false) { return true; }
|
96 |
+
if (isset($_SERVER['SERVER_ADDR']) && stripos($hurl, preg_replace('/:\d+$/', '', $_SERVER['SERVER_ADDR'])) !== false) { return true; }
|
97 |
+
return false;
|
98 |
+
}
|
99 |
+
|
100 |
+
|
101 |
+
# case-insensitive in_array() wrapper
|
102 |
+
function fastvelocity_min_in_arrayi($hurl, $ignore){
|
103 |
+
$hurl = str_ireplace(array('http://', 'https://'), '//', $hurl); # better compatibility
|
104 |
+
$hurl = strtok(urldecode(rawurldecode($hurl)), '?'); # no query string, decode entities
|
105 |
+
|
106 |
+
if (!empty($hurl) && is_array($ignore)) {
|
107 |
+
foreach ($ignore as $i) {
|
108 |
+
$i = str_ireplace(array('http://', 'https://'), '//', $i); # better compatibility
|
109 |
+
$i = strtok(urldecode(rawurldecode($i)), '?'); # no query string, decode entities
|
110 |
+
$i = trim(trim($i, '/'), '*'); # wildcard removal
|
111 |
+
if (stripos($hurl, $i) !== false) { return true; }
|
112 |
+
}
|
113 |
+
}
|
114 |
+
return false;
|
115 |
+
}
|
116 |
+
|
117 |
+
|
118 |
+
# better compatibility urls, fix bootstrap 4 svg images https://www.w3.org/TR/SVG/intro.html#NamespaceAndDTDIdentifiers
|
119 |
+
function fvm_compat_urls($code) {
|
120 |
+
$code = str_ireplace(array('http://', 'https://'), '//', $code);
|
121 |
+
$code = str_ireplace('//www.w3.org/2000/svg', 'http://www.w3.org/2000/svg', $code);
|
122 |
+
return $code;
|
123 |
+
}
|
124 |
+
|
125 |
+
|
126 |
+
# minify css string with PHP Minify
|
127 |
+
function fastvelocity_min_minify_css_string($css) {
|
128 |
+
$minifier = new Minify\CSS($css);
|
129 |
+
$minifier->setMaxImportSize(15); # [css only] embed assets up to 15 Kb (default 5Kb) - processes gif, png, jpg, jpeg, svg & woff
|
130 |
+
$min = $minifier->minify();
|
131 |
+
if($min !== false) { return fvm_compat_urls($min); }
|
132 |
+
return fvm_compat_urls($css);
|
133 |
+
}
|
134 |
+
|
135 |
+
|
136 |
+
# find if we are running windows
|
137 |
+
function fvm_server_is_windows() {
|
138 |
+
if(defined('PHP_OS_FAMILY') && strtolower(PHP_OS_FAMILY) == 'windows') { return true; } # PHP 7.2.0+
|
139 |
+
if (stripos(php_uname('s'), 'Windows') !== false) { return true; }# fallback
|
140 |
+
return false;
|
141 |
+
}
|
142 |
+
|
143 |
+
|
144 |
+
|
145 |
+
# minify js on demand (one file at one time, for compatibility)
|
146 |
+
function fastvelocity_min_get_js($url, $js, $disable_js_minification) {
|
147 |
+
|
148 |
+
# exclude minification on already minified files + jquery (because minification might break those)
|
149 |
+
$excl = array('jquery.js', '.min.js', '-min.js', '/uploads/fusion-scripts/');
|
150 |
+
foreach($excl as $e) { if (stripos(basename($url), $e) !== false) { $disable_js_minification = true; break; } }
|
151 |
+
|
152 |
+
# remove BOM
|
153 |
+
$js = fastvelocity_min_remove_utf8_bom($js);
|
154 |
+
|
155 |
+
# minify JS
|
156 |
+
if(!$disable_js_minification) {
|
157 |
+
$js = fastvelocity_min_minify_js_string($js);
|
158 |
+
} else {
|
159 |
+
$js = fvm_compat_urls($js);
|
160 |
+
}
|
161 |
+
|
162 |
+
# needed when merging js files
|
163 |
+
$js = $js."\r\n;";
|
164 |
+
|
165 |
+
# return html
|
166 |
+
return $js;
|
167 |
+
}
|
168 |
+
|
169 |
+
|
170 |
+
# minify JS string with PHP Minify or YUI Compressors
|
171 |
+
function fastvelocity_min_minify_js_string($js) {
|
172 |
+
global $tmpdir, $plugindir;
|
173 |
+
|
174 |
+
# check for exec + a supported java version
|
175 |
+
$use_yui = get_option('fastvelocity_min_use_yui');
|
176 |
+
if($use_yui == true && function_exists('exec') && exec('command -v java >/dev/null && echo "yes" || echo "no"') == 'yes') {
|
177 |
+
|
178 |
+
# create temp files
|
179 |
+
$tmpname = hash('adler32', $js);
|
180 |
+
$tmpin = $tmpdir.'/'.$tmpname.'.js';
|
181 |
+
file_put_contents($tmpin, $js);
|
182 |
+
$tmpout = $tmpdir.'/'.$tmpname.'.min.js';
|
183 |
+
|
184 |
+
# define jar path and command
|
185 |
+
$cmd = 'java -jar '.$plugindir.'libs/jar/yuicompressor-2.4.8.jar'.' --preserve-semi --nomunge '.$tmpin.' -o '.$tmpout;
|
186 |
+
|
187 |
+
# run local compiler
|
188 |
+
exec($cmd . ' 2>&1', $output);
|
189 |
+
if(count($output) == 0 && file_exists($tmpout)) {
|
190 |
+
$min = file_get_contents($tmpout);
|
191 |
+
if($min !== false) { return fvm_compat_urls($min); }
|
192 |
+
exit();
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
# PHP Minify [2016.08.01] from https://github.com/matthiasmullie/minify
|
197 |
+
$minifier = new Minify\JS($js);
|
198 |
+
$min = $minifier->minify();
|
199 |
+
if($min !== false && (strlen(trim($js)) == strlen(trim($min)) || strlen(trim($min)) > 0)) { return fvm_compat_urls($min); }
|
200 |
+
|
201 |
+
# if we are here, something went wrong and minification didn't work
|
202 |
+
$js = "\n/*! Fast Velocity Minify: Minification of the following section has failed, so it has been merged instead. */\n".$js;
|
203 |
+
return fvm_compat_urls($js);
|
204 |
+
}
|
205 |
+
|
206 |
+
# functions, minify html
|
207 |
+
function fastvelocity_min_minify_html($html) {
|
208 |
+
return trim(fastvelocity_min_Minify_HTML::minify($html));
|
209 |
+
}
|
210 |
+
|
211 |
+
# functions to minify HTML
|
212 |
+
function fastvelocity_min_html_compression_finish($html) { return fastvelocity_min_minify_html($html); }
|
213 |
+
function fastvelocity_min_html_compression_start() {
|
214 |
+
|
215 |
+
$use_alt_html_minification = get_option('fastvelocity_min_use_alt_html_minification', '0');
|
216 |
+
if($use_alt_html_minification == '1') { ob_start('fastvelocity_min_minify_alt_html'); }
|
217 |
+
else { ob_start('fastvelocity_min_html_compression_finish'); }
|
218 |
+
|
219 |
+
}
|
220 |
+
|
221 |
+
|
222 |
+
# alternative html minification, minimal
|
223 |
+
function fastvelocity_min_minify_alt_html($html) {
|
224 |
+
$html = trim(preg_replace('/\v(?:[\t\v\h]+)/', "\n", $html));
|
225 |
+
$html = trim(preg_replace('/\t(?:[\t\v\h]+)/', ' ', $html));
|
226 |
+
$html = trim(preg_replace('/\h(?:[\t\v\h]+)/', ' ', $html));
|
227 |
+
return $html;
|
228 |
+
}
|
229 |
+
|
230 |
+
# remove all cache files
|
231 |
+
function fastvelocity_rrmdir($dir) {
|
232 |
+
if(is_dir(rtrim($dir, '/'))) {
|
233 |
+
if ($handle = opendir($dir.'/')) {
|
234 |
+
while (false !== ($file = readdir($handle))) {
|
235 |
+
@unlink($dir.'/'.$file);
|
236 |
+
}
|
237 |
+
closedir($handle); }
|
238 |
+
}
|
239 |
+
}
|
240 |
+
|
241 |
+
|
242 |
+
|
243 |
+
|
244 |
+
# return size in human format
|
245 |
+
function fastvelocity_format_filesize($bytes, $decimals = 2) {
|
246 |
+
$units = array( 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' );
|
247 |
+
for ($i = 0; ($bytes / 1024) > 0.9; $i++, $bytes /= 1024) {}
|
248 |
+
return sprintf( "%1.{$decimals}f %s", round( $bytes, $decimals ), $units[$i] );
|
249 |
+
}
|
250 |
+
|
251 |
+
|
252 |
+
# get cache size and count
|
253 |
+
function fastvelocity_get_cachestats() {
|
254 |
+
|
255 |
+
# info
|
256 |
+
$cachepath = fvm_cachepath();
|
257 |
+
$tmpdir = $cachepath['tmpdir'];
|
258 |
+
$cachedir = $cachepath['cachedir'];
|
259 |
+
$search = array($tmpdir, $cachedir);
|
260 |
+
$size = 0;
|
261 |
+
$count = 0;
|
262 |
+
|
263 |
+
foreach ($search as $dir) {
|
264 |
+
if(is_dir(rtrim($dir, '/'))) {
|
265 |
+
if ($handle = opendir($dir.'/')) {
|
266 |
+
while (false !== ($file = readdir($handle))) { $f = $dir.'/'.$file; $size = $size + filesize($f); $count++; }
|
267 |
+
closedir($handle);
|
268 |
+
}
|
269 |
+
}
|
270 |
+
}
|
271 |
+
|
272 |
+
return array('size'=>fastvelocity_format_filesize($size), 'count'=>$count);
|
273 |
+
}
|
274 |
+
|
275 |
+
|
276 |
+
|
277 |
+
|
278 |
+
# minify css on demand (one file at one time, for compatibility)
|
279 |
+
function fastvelocity_min_get_css($url, $css, $disable_css_minification) {
|
280 |
+
global $wp_domain;
|
281 |
+
|
282 |
+
# remove BOM
|
283 |
+
$css = fastvelocity_min_remove_utf8_bom($css);
|
284 |
+
|
285 |
+
# fix url paths
|
286 |
+
if(!empty($url)) { $css = preg_replace("/url\(\s*['\"]?(?!data:)(?!http)(?![\/'\"])(.+?)['\"]?\s*\)/ui", "url(".dirname($url)."/$1)", $css); }
|
287 |
+
|
288 |
+
# remove query strings from fonts (for better seo, but add a small cache buster based on most recent updates)
|
289 |
+
$ctime = get_option('fvm-last-cache-update', '0'); # last update or zero
|
290 |
+
$css = preg_replace('/(.eot|.woff2|.woff|.ttf)+[?+](.+?)(\)|\'|\")/ui', "$1"."#".$ctime."$3", $css); # fonts cache buster
|
291 |
+
|
292 |
+
# minify CSS
|
293 |
+
if(!$disable_css_minification) {
|
294 |
+
$css = fastvelocity_min_minify_css_string($css);
|
295 |
+
} else {
|
296 |
+
$css = fvm_compat_urls($css);
|
297 |
+
}
|
298 |
+
|
299 |
+
# cdn urls
|
300 |
+
$fvm_cdn_url = get_option('fastvelocity_min_fvm_cdn_url');
|
301 |
+
if(!empty($fvm_cdn_url) && filter_var($fvm_cdn_url, FILTER_VALIDATE_URL) !== FALSE) {
|
302 |
+
$fvm_cdn_url = trim(trim(str_ireplace(array('http://', 'https://'), '', trim($fvm_cdn_url, '/'))), '/');
|
303 |
+
$css = str_ireplace($wp_domain, $fvm_cdn_url, $css);
|
304 |
+
}
|
305 |
+
|
306 |
+
# return html
|
307 |
+
return $css;
|
308 |
+
}
|
309 |
+
|
310 |
+
|
311 |
+
|
312 |
+
# get remote urls with curl
|
313 |
+
function fvm_file_get_contents_curl($url, $uagent=NULL) {
|
314 |
+
$ch = curl_init();
|
315 |
+
if(isset($uagent) && !empty($uagent)) { curl_setopt($ch,CURLOPT_USERAGENT, $uagent); }
|
316 |
+
curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
|
317 |
+
curl_setopt($ch, CURLOPT_HEADER, 0);
|
318 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
319 |
+
curl_setopt($ch, CURLOPT_URL, $url);
|
320 |
+
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
|
321 |
+
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT , 10);
|
322 |
+
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
|
323 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
324 |
+
$data = curl_exec($ch);
|
325 |
+
curl_close($ch);
|
326 |
+
return $data;
|
327 |
+
}
|
328 |
+
|
329 |
+
|
330 |
+
|
331 |
+
# download and cache css and js files
|
332 |
+
function fvm_download_and_cache($hurl, $tkey, $inline=null, $disable_minification=false, $type=null){
|
333 |
+
global $cachedir, $cachedirurl, $wp_domain, $wp_home, $wp_home_path;
|
334 |
+
|
335 |
+
# filters and defaults
|
336 |
+
$printurl = str_ireplace(array(site_url(), home_url(), 'http:', 'https:'), '', $hurl);
|
337 |
+
|
338 |
+
# try to open locally first, but skip if we are on windows
|
339 |
+
if(fvm_server_is_windows() === false) {
|
340 |
+
if (stripos($hurl, $wp_domain) !== false) {
|
341 |
+
# default
|
342 |
+
$f = str_ireplace(rtrim($wp_home, '/'), rtrim($wp_home_path, '/'), $hurl);
|
343 |
+
if (file_exists($f)) {
|
344 |
+
if($type == 'js') { $code = fastvelocity_min_get_js($hurl, file_get_contents($f), $disable_minification); }
|
345 |
+
else { $code = fastvelocity_min_get_css($hurl, file_get_contents($f).$inline, $disable_minification); }
|
346 |
+
set_transient($tkey, $code, 7 * DAY_IN_SECONDS );
|
347 |
+
fvm_update_transient_keys($tkey); # keep track
|
348 |
+
$log = "$printurl --- Debug: File was opened from $f ---\n";
|
349 |
+
return array('log'=>$log, 'code'=>$code);
|
350 |
+
}
|
351 |
+
|
352 |
+
# failover when home_url != site_url
|
353 |
+
$nhurl = str_ireplace(site_url(), home_url(), $hurl);
|
354 |
+
$f = str_ireplace(rtrim($wp_home, '/'), rtrim($wp_home_path, '/'), $nhurl);
|
355 |
+
if (file_exists($f)) {
|
356 |
+
if($type == 'js') { $code = fastvelocity_min_get_js($hurl, file_get_contents($f), $disable_minification); }
|
357 |
+
else { $code = fastvelocity_min_get_css($hurl, file_get_contents($f).$inline, $disable_minification); }
|
358 |
+
set_transient($tkey, $code, 7 * DAY_IN_SECONDS );
|
359 |
+
fvm_update_transient_keys($tkey); # keep track
|
360 |
+
$log = "$printurl --- Debug: File was opened from $f ---\n";
|
361 |
+
return array('log'=>$log, 'code'=>$code);
|
362 |
+
}
|
363 |
+
}
|
364 |
+
}
|
365 |
+
|
366 |
+
|
367 |
+
# else, fallback to remote urls (or windows)
|
368 |
+
$ttl = 3600 * 24 * 7; # 7 days
|
369 |
+
$code = fastvelocity_download($hurl, $tkey, $ttl);
|
370 |
+
if($code !== false) {
|
371 |
+
if($type == 'js') { $code = fastvelocity_min_get_js($hurl, $code, $disable_minification); }
|
372 |
+
else { $code = fastvelocity_min_get_css($hurl, $code.$inline, $disable_minification); }
|
373 |
+
set_transient($tkey, $code, 7 * DAY_IN_SECONDS );
|
374 |
+
fvm_update_transient_keys($tkey); # keep track
|
375 |
+
$log = "$printurl --- Debug: Fetched url at $hurl \n";
|
376 |
+
return array('log'=>$log, 'code'=>$code);
|
377 |
+
}
|
378 |
+
|
379 |
+
|
380 |
+
# fallback when home_url != site_url
|
381 |
+
if(stripos($hurl, $wp_domain) !== false && home_url() != site_url()) {
|
382 |
+
$nhurl = str_ireplace(site_url(), home_url(), $hurl);
|
383 |
+
$code = fastvelocity_download($nhurl, $tkey, $ttl);
|
384 |
+
if($code !== false) {
|
385 |
+
if($type == 'js') { $code = fastvelocity_min_get_js($hurl, $code, $disable_minification); }
|
386 |
+
else { $code = fastvelocity_min_get_css($hurl, $code.$inline, $disable_minification); }
|
387 |
+
set_transient($tkey, $code, 7 * DAY_IN_SECONDS );
|
388 |
+
fvm_update_transient_keys($tkey); # keep track
|
389 |
+
$log = "$printurl --- Debug: Fetched url at $hurl \n";
|
390 |
+
return array('log'=>$log, 'code'=>$code);
|
391 |
+
}
|
392 |
+
}
|
393 |
+
|
394 |
+
|
395 |
+
# if remote urls failed... try to open locally again, regardless of OS in use
|
396 |
+
if (stripos($hurl, $wp_domain) !== false) {
|
397 |
+
# default
|
398 |
+
$f = str_ireplace(rtrim($wp_home, '/'), rtrim($wp_home_path, '/'), $hurl);
|
399 |
+
if (file_exists($f)) {
|
400 |
+
if($type == 'js') { $code = fastvelocity_min_get_js($hurl, file_get_contents($f), $disable_minification); }
|
401 |
+
else { $code = fastvelocity_min_get_css($hurl, file_get_contents($f).$inline, $disable_minification); }
|
402 |
+
set_transient($tkey, $code, 7 * DAY_IN_SECONDS );
|
403 |
+
fvm_update_transient_keys($tkey); # keep track
|
404 |
+
$log = "$printurl --- Debug: File was opened from $f ---\n";
|
405 |
+
return array('log'=>$log, 'code'=>$code);
|
406 |
+
}
|
407 |
+
|
408 |
+
# failover when home_url != site_url
|
409 |
+
$nhurl = str_ireplace(site_url(), home_url(), $hurl);
|
410 |
+
$f = str_ireplace(rtrim($wp_home, '/'), rtrim($wp_home_path, '/'), $nhurl);
|
411 |
+
if (file_exists($f)) {
|
412 |
+
if($type == 'js') { $code = fastvelocity_min_get_js($hurl, file_get_contents($f), $disable_minification); }
|
413 |
+
else { $code = fastvelocity_min_get_css($hurl, file_get_contents($f).$inline, $disable_minification); }
|
414 |
+
set_transient($tkey, $code, 7 * DAY_IN_SECONDS );
|
415 |
+
fvm_update_transient_keys($tkey); # keep track
|
416 |
+
$log = "$printurl --- Debug: File was opened from $f ---\n";
|
417 |
+
return array('log'=>$log, 'code'=>$code);
|
418 |
+
}
|
419 |
+
}
|
420 |
+
|
421 |
+
|
422 |
+
# else fail
|
423 |
+
$code = false;
|
424 |
+
$log = " - FAILED --- Debug: Tried to fetch via wp_remote_get, curl and also to open it locally. URL: $hurl ---\n";
|
425 |
+
return array('log'=>$log, 'code'=>$code);
|
426 |
+
}
|
427 |
+
|
428 |
+
|
429 |
+
|
430 |
+
# Concatenate Google Fonts tags (http://fonts.googleapis.com/css?...)
|
431 |
+
function fastvelocity_min_concatenate_google_fonts($array) {
|
432 |
+
|
433 |
+
# extract unique font families
|
434 |
+
$families = array(); foreach ($array as $font) {
|
435 |
+
|
436 |
+
# get fonts name, type and subset, remove wp query strings
|
437 |
+
$font = explode('family=', htmlspecialchars_decode(rawurldecode(urldecode($font))));
|
438 |
+
$a = explode('&v', end($font)); $font = trim(trim(trim(current($a)), ','));
|
439 |
+
|
440 |
+
# reprocess if fonts are already concatenated in this url
|
441 |
+
if(stristr($font, '|') !== FALSE) {
|
442 |
+
$multiple = explode('|', $font); if (count($multiple) > 0) { foreach ($multiple as $f) { $families[] = trim($f); } }
|
443 |
+
} else { $families[] = $font; }
|
444 |
+
}
|
445 |
+
|
446 |
+
# process types, subsets, merge, etc
|
447 |
+
$fonts = array();
|
448 |
+
foreach ($families as $font) {
|
449 |
+
|
450 |
+
# if no type or subset
|
451 |
+
if(stristr($font, ':') === FALSE) {
|
452 |
+
$fonts[] = array('name'=>$font, 'type'=>'', 'sub'=>'');
|
453 |
+
} else {
|
454 |
+
|
455 |
+
# get type and subset
|
456 |
+
$name = stristr($font, ':', true); # font name, before :
|
457 |
+
$ftype = trim(stristr($font, ':'), ':'); # second part of the string, after :
|
458 |
+
|
459 |
+
# get font types and subset
|
460 |
+
if(stristr($ftype, '&subset=') === FALSE) {
|
461 |
+
$fonts[] = array('name'=>$name, 'type'=>$ftype, 'sub'=>'');
|
462 |
+
} else {
|
463 |
+
$newftype = stristr($ftype, '&', true); # font type, before &
|
464 |
+
$subset = trim(str_ireplace('&subset=', '', stristr($ftype, '&'))); # second part of the string, after &
|
465 |
+
$fonts[] = array('name'=>$name, 'type'=>$newftype, 'sub'=>$subset);
|
466 |
+
}
|
467 |
+
|
468 |
+
}
|
469 |
+
}
|
470 |
+
|
471 |
+
# make sure we have unique font names, types and subsets
|
472 |
+
$ufonts = array(); foreach ($fonts as $f) { $ufonts[$f['name']] = $f['name']; } # unique font names
|
473 |
+
$usubsets = array(); foreach ($fonts as $f) { if(!empty($f['sub'])) { $usubsets[$f['sub']] = $f['sub']; } } # unique subsets
|
474 |
+
|
475 |
+
# prepare
|
476 |
+
$fonts_and_types = $ufonts;
|
477 |
+
|
478 |
+
# get unique types and subsets for each unique font name
|
479 |
+
foreach ($ufonts as $uf) {
|
480 |
+
|
481 |
+
# types
|
482 |
+
$utypes = array();
|
483 |
+
foreach ($fonts as $f) {
|
484 |
+
if($f['name'] == $uf && !empty($f['type'])) { $utypes = array_merge($utypes, explode(',', $f['type'])); }
|
485 |
+
}
|
486 |
+
|
487 |
+
# filter types
|
488 |
+
$utypes = array_unique($utypes);
|
489 |
+
sort($utypes);
|
490 |
+
$ntype = ''; if(count($utypes) > 0) { $ntype = ':'.implode(',', $utypes); } # types to append to the font name
|
491 |
+
|
492 |
+
# generate font url queries
|
493 |
+
$fonts_and_types[$uf] = str_ireplace(' ', '+', $uf).$ntype;
|
494 |
+
}
|
495 |
+
|
496 |
+
# concat fonts, generate unique google fonts url
|
497 |
+
if(count($fonts_and_types) > 0) {
|
498 |
+
$msubsets = ''; if(count($usubsets) > 0 && implode(',', $usubsets) != 'latin') { $msubsets = "&subset=".implode(',', $usubsets); } # merge subsets
|
499 |
+
return trim('https://fonts.googleapis.com/css?family='.implode('|', $fonts_and_types).$msubsets); # process
|
500 |
+
}
|
501 |
+
|
502 |
+
return false;
|
503 |
+
}
|
504 |
+
|
505 |
+
|
506 |
+
|
507 |
+
# readme parser
|
508 |
+
function fastvelocity_min_readme($url) {
|
509 |
+
|
510 |
+
# read file
|
511 |
+
$file = @file_get_contents( $url );
|
512 |
+
if (empty($file)) { return '<strong>Readme Parser: readme.txt not found!</strong>'; }
|
513 |
+
|
514 |
+
// line end to \n
|
515 |
+
$file = preg_replace("/(\n\r|\r\n|\r|\n)/", "\n", $file);
|
516 |
+
|
517 |
+
// headlines
|
518 |
+
$s = array('===','==','=' );
|
519 |
+
$r = array('h2' ,'h3','h4');
|
520 |
+
for ( $x = 0; $x < sizeof($s); $x++ ) {
|
521 |
+
$file = preg_replace('/(.*?)'.$s[$x].'(?!\")(.*?)'.$s[$x].'(.*?)/', '$1<'.$r[$x].'>$2</'.$r[$x].'>$3', $file);
|
522 |
+
}
|
523 |
+
|
524 |
+
// inline
|
525 |
+
$s = array('\*\*','\`');
|
526 |
+
$r = array('b' ,'code');
|
527 |
+
for ( $x = 0; $x < sizeof($s); $x++ ) {
|
528 |
+
$file = preg_replace('/(.*?)'.$s[$x].'(?!\s)(.*?)(?!\s)'.$s[$x].'(.*?)/', '$1<'.$r[$x].'>$2</'.$r[$x].'>$3', $file);
|
529 |
+
}
|
530 |
+
|
531 |
+
// ' _italic_ '
|
532 |
+
$file = preg_replace('/(\s)_(\S.*?\S)_(\s|$)/', ' <em>$2</em> ', $file);
|
533 |
+
|
534 |
+
// ul lists
|
535 |
+
$s = array('\*','\+','\-');
|
536 |
+
for ( $x = 0; $x < sizeof($s); $x++ )
|
537 |
+
$file = preg_replace('/^['.$s[$x].'](\s)(.*?)(\n|$)/m', '<li>$2</li>', $file);
|
538 |
+
$file = preg_replace('/\n<li>(.*?)/', '<ul><li>$1', $file);
|
539 |
+
$file = preg_replace('/(<\/li>)(?!<li>)/', '$1</ul>', $file);
|
540 |
+
|
541 |
+
// ol lists
|
542 |
+
$file = preg_replace('/(\d{1,2}\.)\s(.*?)(\n|$)/', '<li>$2</li>', $file);
|
543 |
+
$file = preg_replace('/\n<li>(.*?)/', '<ol><li>$1', $file);
|
544 |
+
$file = preg_replace('/(<\/li>)(?!(\<li\>|\<\/ul\>))/', '$1</ol>', $file);
|
545 |
+
|
546 |
+
// ol screenshots style
|
547 |
+
$file = preg_replace('/(?=Screenshots)(.*?)<ol>/', '$1<ol class="readme-parser-screenshots">', $file);
|
548 |
+
|
549 |
+
// line breaks
|
550 |
+
$file = preg_replace('/(.*?)(\n)/', "<p>$1</p>", $file);
|
551 |
+
$file = preg_replace('/(1|2|3|4)(><br\/>)/', '$1>', $file);
|
552 |
+
$file = str_ireplace('</ul><br/>', '</ul>', $file);
|
553 |
+
|
554 |
+
# cleanup
|
555 |
+
$file = str_ireplace('<p></p>', '', $file);
|
556 |
+
$file = str_ireplace('<p><h4>', '<h4>', $file);
|
557 |
+
$file = str_ireplace('</h4></p>', '</h4>', $file);
|
558 |
+
|
559 |
+
// urls
|
560 |
+
$file = str_replace('http://www.', 'www.', $file);
|
561 |
+
$file = str_replace('www.', 'http://www.', $file);
|
562 |
+
$file = preg_replace('#(^|[^\"=]{1})(http://|ftp://|mailto:|https://)([^\s<>]+)([\s\n<>]|$)#', '$1<a target="_blank" href="$2$3">$2$3</a>$4', $file);
|
563 |
+
|
564 |
+
# extract faqs
|
565 |
+
$prefix = "Frequently Asked Questions";
|
566 |
+
$faq = substr($file, strpos($file, $prefix) + strlen($prefix));
|
567 |
+
$faq = substr($faq, 0, strpos($faq, '<p><h3>'));
|
568 |
+
|
569 |
+
|
570 |
+
return trim($faq);
|
571 |
+
}
|
572 |
+
|
573 |
+
|
574 |
+
# remove emoji support
|
575 |
+
function fastvelocity_min_disable_wp_emojicons() {
|
576 |
+
remove_action('wp_head', 'print_emoji_detection_script', 7);
|
577 |
+
remove_action('wp_print_styles', 'print_emoji_styles');
|
578 |
+
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
|
579 |
+
remove_action( 'admin_print_styles', 'print_emoji_styles' );
|
580 |
+
}
|
581 |
+
|
582 |
+
# escape double quotes
|
583 |
+
function fastvelocity_escape_double($string) {
|
584 |
+
return str_ireplace(array('"', '\\"', '\\\"'), '\"', $string);
|
585 |
+
}
|
586 |
+
|
587 |
+
|
588 |
+
# remove UTF8 BOM
|
589 |
+
function fastvelocity_min_remove_utf8_bom($text) {
|
590 |
+
$bom = pack('H*','EFBBBF');
|
591 |
+
$text = preg_replace("/^$bom/ui", '', $text);
|
592 |
+
return $text;
|
593 |
+
}
|
594 |
+
|
595 |
+
|
596 |
+
# Remove query string from static css files
|
597 |
+
function fastvelocity_remove_cssjs_ver( $src ) {
|
598 |
+
if(stripos($src, '?ver=')) { $src = remove_query_arg('ver', $src); }
|
599 |
+
return $src;
|
600 |
+
}
|
601 |
+
|
602 |
+
|
603 |
+
# rewrite cache files to http, https or dynamic
|
604 |
+
function fvm_get_protocol($url) {
|
605 |
+
$url = ltrim(str_ireplace(array('http://', 'https://'), '', $url), '/'); # better compatibility
|
606 |
+
|
607 |
+
# cdn support
|
608 |
+
$fvm_cdn_url = get_option('fastvelocity_min_fvm_cdn_url');
|
609 |
+
if(!empty($fvm_cdn_url) && filter_var($fvm_cdn_url, FILTER_VALIDATE_URL) !== FALSE) {
|
610 |
+
$fvm_cdn_url = trim(trim(str_ireplace(array('http://', 'https://'), '', trim($fvm_cdn_url, '/'))), '/');
|
611 |
+
$url = str_ireplace($wp_domain, $fvm_cdn_url, $url);
|
612 |
+
}
|
613 |
+
|
614 |
+
# enforce protocol if needed
|
615 |
+
$fp = get_option('fastvelocity_min_default_protocol', 'dynamic');
|
616 |
+
if($fp == 'http') { $url = 'http://'.$url; } elseif($fp == 'https') { $url = 'https://'.$url; } else { $url = '//'.$url; }
|
617 |
+
|
618 |
+
# return
|
619 |
+
return $url;
|
620 |
+
}
|
621 |
+
|
622 |
+
# keep track of transients, whenever we save a transient.
|
623 |
+
function fvm_update_transient_keys($new_transient_key) {
|
624 |
+
$transient_keys = get_option('fvm_transient_keys'); # get
|
625 |
+
$transient_keys[]= $new_transient_key; # append
|
626 |
+
update_option( 'fvm_transient_keys', $transient_keys); # save
|
627 |
+
}
|
628 |
+
|
629 |
+
# keep track of transients, dump our plugin transients as needed
|
630 |
+
function fvm_transients_purge() {
|
631 |
+
update_option('fvm-last-cache-update', time()); # last cache update to now
|
632 |
+
$transient_keys = get_option( 'fvm_transient_keys' ); # get
|
633 |
+
update_option( 'fvm_transient_keys', array()); # reset
|
634 |
+
foreach( $transient_keys as $t ) { delete_transient( $t ); } # delete
|
635 |
+
}
|
636 |
+
|
637 |
+
|
638 |
+
# purge all caches
|
639 |
+
function fvm_purge_all() {
|
640 |
+
|
641 |
+
# get cache directories and urls
|
642 |
+
$cachepath = fvm_cachepath();
|
643 |
+
$tmpdir = $cachepath['tmpdir'];
|
644 |
+
$cachedir = $cachepath['cachedir'];
|
645 |
+
$cachedirurl = $cachepath['cachedirurl'];
|
646 |
+
|
647 |
+
# delete minification files and transients
|
648 |
+
if(!is_dir($cachedir)) { return false; }
|
649 |
+
fastvelocity_rrmdir($cachedir);
|
650 |
+
fvm_transients_purge();
|
651 |
+
|
652 |
+
return true;
|
653 |
+
}
|
654 |
+
|
655 |
+
|
656 |
+
|
657 |
+
# exclude processing from some pages / posts / contents
|
658 |
+
function fastvelocity_exclude_contents() {
|
659 |
+
|
660 |
+
# customizer preview, visual composer
|
661 |
+
$arr = array('customize_theme', 'preview_id', 'preview');
|
662 |
+
foreach ($arr as $a) { if(isset($_GET[$a])) { return true; } }
|
663 |
+
|
664 |
+
# Thrive plugins and other post_types
|
665 |
+
$arr = array('tve_form_type', 'tve_lead_shortcode', 'tqb_splash');
|
666 |
+
foreach ($arr as $a) { if(isset($_GET['post_type']) && $_GET['post_type'] == $a) { return true; } }
|
667 |
+
|
668 |
+
# default
|
669 |
+
return false;
|
670 |
+
}
|
671 |
+
|
672 |
+
# Know files that should always be ignored
|
673 |
+
function fastvelocity_default_ignore($ignore) {
|
674 |
+
if(is_array($ignore)) {
|
675 |
+
|
676 |
+
# defaults, to be overwriten by api or transient
|
677 |
+
$exc = array('/fvm/cache/', '/Avada/assets/js/main.min.js', '/woocommerce-product-search/js/product-search.js', '/includes/builder/scripts/frontend-builder-scripts.js', '/assets/js/jquery.themepunch.tools.min.js');
|
678 |
+
|
679 |
+
# info and api call
|
680 |
+
$api = 'https://fastvelocity.com/api/fvm/ignore.txt';
|
681 |
+
$ctime = get_option('fvm-last-cache-update', '0');
|
682 |
+
$tkey = 'fvm-api-ignore-'.$ctime;
|
683 |
+
$ttl = 24 * 3600; # one day, in seconds
|
684 |
+
$json = fastvelocity_download($api, $tkey, $ttl);
|
685 |
+
if($json !== false) {
|
686 |
+
$data = json_decode($json, true);
|
687 |
+
if (json_last_error() === JSON_ERROR_NONE && is_array($data)) { $exc = $data; }
|
688 |
+
}
|
689 |
+
|
690 |
+
# should we exclude jquery when defer is enabled?
|
691 |
+
$exclude_defer_jquery = get_option('fastvelocity_min_exclude_defer_jquery');
|
692 |
+
$enable_defer_js = get_option('fastvelocity_min_enable_defer_js');
|
693 |
+
if($enable_defer_js == true && $exclude_defer_jquery == true) {
|
694 |
+
$exc[] = '/jquery.js';
|
695 |
+
$exc[] = '/jquery.min.js';
|
696 |
+
}
|
697 |
+
|
698 |
+
# make sure it's unique and not empty
|
699 |
+
$uniq = array();
|
700 |
+
foreach ($ignore as $i) { $k = hash('adler32', $i); if(!empty($i)) { $uniq[$k] = $i; } }
|
701 |
+
foreach ($exc as $e) { $k = hash('adler32', $e); if(!empty($e)) { $uniq[$k] = $e; } }
|
702 |
+
|
703 |
+
# merge and return
|
704 |
+
return $uniq;
|
705 |
+
} else { return $ignore; }
|
706 |
+
}
|
707 |
+
|
708 |
+
|
709 |
+
# IE only files that should always be ignored, without incrementing our groups
|
710 |
+
function fastvelocity_ie_blacklist($url) {
|
711 |
+
|
712 |
+
# defaults, to be overwriten by api or transient
|
713 |
+
$exc = array('/html5shiv.js', '/excanvas.js', '/avada-ie9.js', '/respond.js', '/respond.min.js', '/selectivizr.js', '/Avada/assets/css/ie.css', '/html5.js', '/IE9.js', '/fusion-ie9.js', '/vc_lte_ie9.min.css', '/old-ie.css', '/ie.css', '/vc-ie8.min.css', '/mailchimp-for-wp/assets/js/third-party/placeholders.min.js');
|
714 |
+
|
715 |
+
# info and api call
|
716 |
+
$api = 'https://fastvelocity.com/api/fvm/ie_blacklist.txt';
|
717 |
+
$ctime = get_option('fvm-last-cache-update', '0');
|
718 |
+
$tkey = 'fvm-api-ie-blacklist-'.$ctime;
|
719 |
+
$ttl = 24 * 3600; # one day, in seconds
|
720 |
+
$json = fastvelocity_download($api, $tkey, $ttl);
|
721 |
+
if($json !== false) {
|
722 |
+
$data = json_decode($json, true);
|
723 |
+
if (json_last_error() === JSON_ERROR_NONE && is_array($data)) { $exc = $data; }
|
724 |
+
}
|
725 |
+
|
726 |
+
# is the url on our list and return
|
727 |
+
$res = fastvelocity_min_in_arrayi($url, $exc);
|
728 |
+
if($res == true) { return true; } else { return false; }
|
729 |
+
}
|
730 |
+
|
731 |
+
|
732 |
+
# download function with cache support and fallback
|
733 |
+
function fastvelocity_download($url, $tkey, $ttl) {
|
734 |
+
|
735 |
+
# rate limit requests, prevent slowdowns
|
736 |
+
$rtlim = false; $rtlim = get_transient($tkey.'_access');
|
737 |
+
if ( $rtlim !== false) { return false; }
|
738 |
+
|
739 |
+
# info (needed for google fonts woff files)
|
740 |
+
$uagent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12';
|
741 |
+
$data = false; $data = get_transient($tkey);
|
742 |
+
if ( $data === false) {
|
743 |
+
|
744 |
+
# get updated list from our api and cache it for 24 hours
|
745 |
+
$response = wp_remote_get($url, array('user-agent'=>$uagent, 'timeout' => 7, 'httpversion' => '1.1', 'sslverify'=>false));
|
746 |
+
$res_code = wp_remote_retrieve_response_code($response);
|
747 |
+
if($res_code == '200') {
|
748 |
+
$data = wp_remote_retrieve_body($response);
|
749 |
+
if(strlen($data) > 1 && $ttl > 0) {
|
750 |
+
set_transient($tkey, $data, $ttl);
|
751 |
+
fvm_update_transient_keys($tkey); # keep track
|
752 |
+
return $data;
|
753 |
+
}
|
754 |
+
}
|
755 |
+
|
756 |
+
# fallback, let's try curl if available
|
757 |
+
if(function_exists('curl_version')) {
|
758 |
+
$curl = fvm_file_get_contents_curl($url, $uagent);
|
759 |
+
if(!empty($curl) && strlen($curl) > 1 && $ttl > 0) {
|
760 |
+
set_transient($tkey, $data, $ttl);
|
761 |
+
fvm_update_transient_keys($tkey); # keep track
|
762 |
+
return $data;
|
763 |
+
}
|
764 |
+
}
|
765 |
+
|
766 |
+
# error
|
767 |
+
set_transient($tkey.'_access', "Failed to fetch: $url on ".current_time('timestamp'), $ttl);
|
768 |
+
return false;
|
769 |
+
}
|
770 |
+
|
771 |
+
# return transient
|
772 |
+
return $data;
|
773 |
+
}
|
774 |
+
|
775 |
+
|
776 |
+
# Purge Godaddy Managed WordPress Hosting (Varnish)
|
777 |
+
# https://github.com/wp-media/wp-rocket/blob/master/inc/3rd-party/hosting/godaddy.php
|
778 |
+
function fastvelocity_godaddy_request( $method, $url = null ) {
|
779 |
+
$url = empty( $url ) ? home_url() : $url;
|
780 |
+
$host = parse_url( $url, PHP_URL_HOST );
|
781 |
+
$url = set_url_scheme( str_replace( $host, WPaas\Plugin::vip(), $url ), 'http' );
|
782 |
+
wp_cache_flush();
|
783 |
+
update_option( 'gd_system_last_cache_flush', time() ); # purge apc
|
784 |
+
wp_remote_request( esc_url_raw( $url ), array('method' => $method, 'blocking' => false, 'headers' => array('Host' => $host)) );
|
785 |
+
}
|
786 |
+
|
787 |
+
|
788 |
+
function fastvelocity_purge_others(){
|
789 |
+
|
790 |
+
# wodpress default cache
|
791 |
+
if (function_exists('wp_cache_flush')) {
|
792 |
+
wp_cache_flush();
|
793 |
+
}
|
794 |
+
|
795 |
+
# Purge all W3 Total Cache
|
796 |
+
if (function_exists('w3tc_pgcache_flush')) {
|
797 |
+
w3tc_pgcache_flush();
|
798 |
+
return __('<div class="notice notice-info is-dismissible"><p>All caches from <strong>W3 Total Cache</strong> have also been purged.</p></div>');
|
799 |
+
}
|
800 |
+
|
801 |
+
# Purge WP Super Cache
|
802 |
+
if (function_exists('wp_cache_clear_cache')) {
|
803 |
+
wp_cache_clear_cache();
|
804 |
+
return __('<div class="notice notice-info is-dismissible"><p>All caches from <strong>WP Super Cache</strong> have also been purged.</p></div>');
|
805 |
+
}
|
806 |
+
|
807 |
+
# Purge WP Rocket
|
808 |
+
if (function_exists('rocket_clean_domain')) {
|
809 |
+
rocket_clean_domain();
|
810 |
+
return __('<div class="notice notice-info is-dismissible"><p>All caches from <strong>WP Rocket</strong> have also been purged.</p></div>');
|
811 |
+
}
|
812 |
+
|
813 |
+
# Purge Wp Fastest Cache
|
814 |
+
if(isset($GLOBALS['wp_fastest_cache']) && method_exists($GLOBALS['wp_fastest_cache'], 'deleteCache')){
|
815 |
+
$GLOBALS['wp_fastest_cache']->deleteCache();
|
816 |
+
return __('<div class="notice notice-info is-dismissible"><p>All caches from <strong>Wp Fastest Cache</strong> have also been purged.</p></div>');
|
817 |
+
}
|
818 |
+
|
819 |
+
# Purge Cachify
|
820 |
+
if (function_exists('cachify_flush_cache')) {
|
821 |
+
cachify_flush_cache();
|
822 |
+
return __('<div class="notice notice-info is-dismissible"><p>All caches from <strong>Cachify</strong> have also been purged.</p></div>');
|
823 |
+
}
|
824 |
+
|
825 |
+
# Purge Comet Cache
|
826 |
+
if ( class_exists("comet_cache") ) {
|
827 |
+
comet_cache::clear();
|
828 |
+
return __('<div class="notice notice-info is-dismissible"><p>All caches from <strong>Comet Cache</strong> have also been purged.</p></div>');
|
829 |
+
}
|
830 |
+
|
831 |
+
# Purge Zen Cache
|
832 |
+
if ( class_exists("zencache") ) {
|
833 |
+
zencache::clear();
|
834 |
+
return __('<div class="notice notice-info is-dismissible"><p>All caches from <strong>Comet Cache</strong> have also been purged.</p></div>');
|
835 |
+
}
|
836 |
+
|
837 |
+
# Purge LiteSpeed Cache
|
838 |
+
if (class_exists('LiteSpeed_Cache_Tags')) {
|
839 |
+
LiteSpeed_Cache_Tags::add_purge_tag('*');
|
840 |
+
return __('<div class="notice notice-info is-dismissible"><p>All caches from <strong>LiteSpeed Cache</strong> have also been purged.</p></div>');
|
841 |
+
}
|
842 |
+
|
843 |
+
# Purge SG Optimizer
|
844 |
+
if (function_exists('sg_cachepress_purge_cache')) {
|
845 |
+
sg_cachepress_purge_cache();
|
846 |
+
return __('<div class="notice notice-info is-dismissible"><p>All caches from <strong>SG Optimizer</strong> have also been purged.</p></div>');
|
847 |
+
}
|
848 |
+
|
849 |
+
# Purge Godaddy Managed WordPress Hosting (Varnish + APC)
|
850 |
+
if (class_exists('WPaaS\Plugin')) {
|
851 |
+
fastvelocity_godaddy_request('BAN');
|
852 |
+
return __('<div class="notice notice-info is-dismissible"><p>All caches from <strong>WP Engine</strong> have also been purged.</p></div>');
|
853 |
+
}
|
854 |
+
|
855 |
+
# Purge WP Engine
|
856 |
+
if (class_exists("WpeCommon")) {
|
857 |
+
if (method_exists('WpeCommon', 'purge_memcached')) { WpeCommon::purge_memcached(); }
|
858 |
+
if (method_exists('WpeCommon', 'clear_maxcdn_cache')) { WpeCommon::clear_maxcdn_cache(); }
|
859 |
+
if (method_exists('WpeCommon', 'purge_varnish_cache')) { WpeCommon::purge_varnish_cache(); }
|
860 |
+
}
|
861 |
+
|
862 |
+
}
|
libs/index.html
ADDED
File without changes
|
libs/jar/index.html
ADDED
File without changes
|
libs/jar/yuicompressor-2.4.8.jar
ADDED
Binary file
|
libs/matthiasmullie/index.html
ADDED
File without changes
|
libs/matthiasmullie/minify/bin/index.html
ADDED
File without changes
|
libs/matthiasmullie/minify/bin/minifycss
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env php
|
2 |
+
<?php
|
3 |
+
use MatthiasMullie\Minify;
|
4 |
+
|
5 |
+
// command line utility to minify CSS
|
6 |
+
if (file_exists(__DIR__ . '/../../../autoload.php')) {
|
7 |
+
// if composer install
|
8 |
+
require_once __DIR__ . '/../../../autoload.php';
|
9 |
+
} else {
|
10 |
+
require_once __DIR__ . '/../src/Minify.php';
|
11 |
+
require_once __DIR__ . '/../src/CSS.php';
|
12 |
+
require_once __DIR__ . '/../src/Exception.php';
|
13 |
+
}
|
14 |
+
|
15 |
+
error_reporting(E_ALL);
|
16 |
+
// check PHP setup for cli arguments
|
17 |
+
if (!isset($_SERVER['argv']) && !isset($argv)) {
|
18 |
+
fwrite(STDERR, 'Please enable the "register_argc_argv" directive in your php.ini' . PHP_EOL);
|
19 |
+
exit(1);
|
20 |
+
} elseif (!isset($argv)) {
|
21 |
+
$argv = $_SERVER['argv'];
|
22 |
+
}
|
23 |
+
// check if path to file given
|
24 |
+
if (!isset($argv[1])) {
|
25 |
+
fwrite(STDERR, 'Argument expected: path to file' . PHP_EOL);
|
26 |
+
exit(1);
|
27 |
+
}
|
28 |
+
// check if script run in cli environment
|
29 |
+
if ('cli' !== php_sapi_name()) {
|
30 |
+
fwrite(STDERR, $argv[1] . ' must be run in the command line' . PHP_EOL);
|
31 |
+
exit(1);
|
32 |
+
}
|
33 |
+
// check if source file exists
|
34 |
+
if (!file_exists($argv[1])) {
|
35 |
+
fwrite(STDERR, 'Source file "' . $argv[1] . '" not found' . PHP_EOL);
|
36 |
+
exit(1);
|
37 |
+
}
|
38 |
+
|
39 |
+
try {
|
40 |
+
$minifier = new Minify\CSS($argv[1]);
|
41 |
+
echo $minifier->minify();
|
42 |
+
} catch (Exception $e) {
|
43 |
+
fwrite(STDERR, $e->getMessage(), PHP_EOL);
|
44 |
+
exit(1);
|
45 |
+
}
|
libs/matthiasmullie/minify/bin/minifyjs
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env php
|
2 |
+
<?php
|
3 |
+
use MatthiasMullie\Minify;
|
4 |
+
|
5 |
+
// command line utility to minify JS
|
6 |
+
if (file_exists(__DIR__ . '/../../../autoload.php')) {
|
7 |
+
// if composer install
|
8 |
+
require_once __DIR__ . '/../../../autoload.php';
|
9 |
+
} else {
|
10 |
+
require_once __DIR__ . '/../src/Minify.php';
|
11 |
+
require_once __DIR__ . '/../src/JS.php';
|
12 |
+
require_once __DIR__ . '/../src/Exception.php';
|
13 |
+
}
|
14 |
+
|
15 |
+
error_reporting(E_ALL);
|
16 |
+
// check PHP setup for cli arguments
|
17 |
+
if (!isset($_SERVER['argv']) && !isset($argv)) {
|
18 |
+
fwrite(STDERR, 'Please enable the "register_argc_argv" directive in your php.ini' . PHP_EOL);
|
19 |
+
exit(1);
|
20 |
+
} elseif (!isset($argv)) {
|
21 |
+
$argv = $_SERVER['argv'];
|
22 |
+
}
|
23 |
+
// check if path to file given
|
24 |
+
if (!isset($argv[1])) {
|
25 |
+
fwrite(STDERR, 'Argument expected: path to file' . PHP_EOL);
|
26 |
+
exit(1);
|
27 |
+
}
|
28 |
+
// check if script run in cli environment
|
29 |
+
if ('cli' !== php_sapi_name()) {
|
30 |
+
fwrite(STDERR, $argv[1] . ' must be run in the command line' . PHP_EOL);
|
31 |
+
exit(1);
|
32 |
+
}
|
33 |
+
// check if source file exists
|
34 |
+
if (!file_exists($argv[1])) {
|
35 |
+
fwrite(STDERR, 'Source file "' . $argv[1] . '" not found' . PHP_EOL);
|
36 |
+
exit(1);
|
37 |
+
}
|
38 |
+
|
39 |
+
try {
|
40 |
+
$minifier = new Minify\JS($argv[1]);
|
41 |
+
echo $minifier->minify();
|
42 |
+
} catch (Exception $e) {
|
43 |
+
fwrite(STDERR, $e->getMessage(), PHP_EOL);
|
44 |
+
exit(1);
|
45 |
+
}
|
libs/matthiasmullie/minify/data/index.html
ADDED
File without changes
|
libs/matthiasmullie/minify/data/js/index.html
ADDED
File without changes
|
libs/matthiasmullie/minify/data/js/keywords_after.txt
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
in
|
2 |
+
public
|
3 |
+
extends
|
4 |
+
private
|
5 |
+
protected
|
6 |
+
implements
|
7 |
+
instanceof
|
libs/matthiasmullie/minify/data/js/keywords_before.txt
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
do
|
2 |
+
in
|
3 |
+
let
|
4 |
+
new
|
5 |
+
var
|
6 |
+
case
|
7 |
+
else
|
8 |
+
enum
|
9 |
+
void
|
10 |
+
with
|
11 |
+
class
|
12 |
+
const
|
13 |
+
yield
|
14 |
+
delete
|
15 |
+
export
|
16 |
+
import
|
17 |
+
public
|
18 |
+
static
|
19 |
+
typeof
|
20 |
+
extends
|
21 |
+
package
|
22 |
+
private
|
23 |
+
function
|
24 |
+
protected
|
25 |
+
implements
|
26 |
+
instanceof
|
libs/matthiasmullie/minify/data/js/keywords_reserved.txt
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
do
|
2 |
+
if
|
3 |
+
in
|
4 |
+
for
|
5 |
+
let
|
6 |
+
new
|
7 |
+
try
|
8 |
+
var
|
9 |
+
case
|
10 |
+
else
|
11 |
+
enum
|
12 |
+
eval
|
13 |
+
null
|
14 |
+
this
|
15 |
+
true
|
16 |
+
void
|
17 |
+
with
|
18 |
+
break
|
19 |
+
catch
|
20 |
+
class
|
21 |
+
const
|
22 |
+
false
|
23 |
+
super
|
24 |
+
throw
|
25 |
+
while
|
26 |
+
yield
|
27 |
+
delete
|
28 |
+
export
|
29 |
+
import
|
30 |
+
public
|
31 |
+
return
|
32 |
+
static
|
33 |
+
switch
|
34 |
+
typeof
|
35 |
+
default
|
36 |
+
extends
|
37 |
+
finally
|
38 |
+
package
|
39 |
+
private
|
40 |
+
continue
|
41 |
+
debugger
|
42 |
+
function
|
43 |
+
arguments
|
44 |
+
interface
|
45 |
+
protected
|
46 |
+
implements
|
47 |
+
instanceof
|
48 |
+
abstract
|
49 |
+
boolean
|
50 |
+
byte
|
51 |
+
char
|
52 |
+
double
|
53 |
+
final
|
54 |
+
float
|
55 |
+
goto
|
56 |
+
int
|
57 |
+
long
|
58 |
+
native
|
59 |
+
short
|
60 |
+
synchronized
|
61 |
+
throws
|
62 |
+
transient
|
63 |
+
volatile
|
libs/matthiasmullie/minify/data/js/operators.txt
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
+
|
2 |
+
-
|
3 |
+
*
|
4 |
+
/
|
5 |
+
%
|
6 |
+
=
|
7 |
+
+=
|
8 |
+
-=
|
9 |
+
*=
|
10 |
+
/=
|
11 |
+
%=
|
12 |
+
<<=
|
13 |
+
>>=
|
14 |
+
>>>=
|
15 |
+
&=
|
16 |
+
^=
|
17 |
+
|=
|
18 |
+
&
|
19 |
+
|
|
20 |
+
^
|
21 |
+
~
|
22 |
+
<<
|
23 |
+
>>
|
24 |
+
>>>
|
25 |
+
==
|
26 |
+
===
|
27 |
+
!=
|
28 |
+
!==
|
29 |
+
>
|
30 |
+
<
|
31 |
+
>=
|
32 |
+
<=
|
33 |
+
&&
|
34 |
+
||
|
35 |
+
!
|
36 |
+
.
|
37 |
+
[
|
38 |
+
]
|
39 |
+
?
|
40 |
+
:
|
41 |
+
,
|
42 |
+
;
|
43 |
+
(
|
44 |
+
)
|
45 |
+
{
|
46 |
+
}
|
libs/matthiasmullie/minify/data/js/operators_after.txt
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
+
|
2 |
+
-
|
3 |
+
*
|
4 |
+
/
|
5 |
+
%
|
6 |
+
=
|
7 |
+
+=
|
8 |
+
-=
|
9 |
+
*=
|
10 |
+
/=
|
11 |
+
%=
|
12 |
+
<<=
|
13 |
+
>>=
|
14 |
+
>>>=
|
15 |
+
&=
|
16 |
+
^=
|
17 |
+
|=
|
18 |
+
&
|
19 |
+
|
|
20 |
+
^
|
21 |
+
~
|
22 |
+
<<
|
23 |
+
>>
|
24 |
+
>>>
|
25 |
+
==
|
26 |
+
===
|
27 |
+
!=
|
28 |
+
!==
|
29 |
+
>
|
30 |
+
<
|
31 |
+
>=
|
32 |
+
<=
|
33 |
+
&&
|
34 |
+
||
|
35 |
+
.
|
36 |
+
[
|
37 |
+
]
|
38 |
+
?
|
39 |
+
:
|
40 |
+
,
|
41 |
+
;
|
42 |
+
(
|
43 |
+
)
|
44 |
+
}
|
libs/matthiasmullie/minify/data/js/operators_before.txt
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
+
|
2 |
+
-
|
3 |
+
*
|
4 |
+
/
|
5 |
+
%
|
6 |
+
=
|
7 |
+
+=
|
8 |
+
-=
|
9 |
+
*=
|
10 |
+
/=
|
11 |
+
%=
|
12 |
+
<<=
|
13 |
+
>>=
|
14 |
+
>>>=
|
15 |
+
&=
|
16 |
+
^=
|
17 |
+
|=
|
18 |
+
&
|
19 |
+
|
|
20 |
+
^
|
21 |
+
~
|
22 |
+
<<
|
23 |
+
>>
|
24 |
+
>>>
|
25 |
+
==
|
26 |
+
===
|
27 |
+
!=
|
28 |
+
!==
|
29 |
+
>
|
30 |
+
<
|
31 |
+
>=
|
32 |
+
<=
|
33 |
+
&&
|
34 |
+
||
|
35 |
+
!
|
36 |
+
.
|
37 |
+
[
|
38 |
+
?
|
39 |
+
:
|
40 |
+
,
|
41 |
+
;
|
42 |
+
(
|
43 |
+
{
|
libs/matthiasmullie/minify/index.html
ADDED
File without changes
|
libs/matthiasmullie/minify/src/CSS.php
ADDED
@@ -0,0 +1,690 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\Minify;
|
4 |
+
|
5 |
+
use MatthiasMullie\Minify\Exceptions\FileImportException;
|
6 |
+
use MatthiasMullie\PathConverter\ConverterInterface;
|
7 |
+
use MatthiasMullie\PathConverter\Converter;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* CSS minifier.
|
11 |
+
*
|
12 |
+
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
13 |
+
*
|
14 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
15 |
+
* @author Tijs Verkoyen <minify@verkoyen.eu>
|
16 |
+
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
17 |
+
* @license MIT License
|
18 |
+
*/
|
19 |
+
class CSS extends Minify
|
20 |
+
{
|
21 |
+
/**
|
22 |
+
* @var int
|
23 |
+
*/
|
24 |
+
protected $maxImportSize = 5;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @var string[]
|
28 |
+
*/
|
29 |
+
protected $importExtensions = array(
|
30 |
+
'gif' => 'data:image/gif',
|
31 |
+
'png' => 'data:image/png',
|
32 |
+
'jpe' => 'data:image/jpeg',
|
33 |
+
'jpg' => 'data:image/jpeg',
|
34 |
+
'jpeg' => 'data:image/jpeg',
|
35 |
+
'svg' => 'data:image/svg+xml',
|
36 |
+
'woff' => 'data:application/x-font-woff',
|
37 |
+
'tif' => 'image/tiff',
|
38 |
+
'tiff' => 'image/tiff',
|
39 |
+
'xbm' => 'image/x-xbitmap',
|
40 |
+
);
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Set the maximum size if files to be imported.
|
44 |
+
*
|
45 |
+
* Files larger than this size (in kB) will not be imported into the CSS.
|
46 |
+
* Importing files into the CSS as data-uri will save you some connections,
|
47 |
+
* but we should only import relatively small decorative images so that our
|
48 |
+
* CSS file doesn't get too bulky.
|
49 |
+
*
|
50 |
+
* @param int $size Size in kB
|
51 |
+
*/
|
52 |
+
public function setMaxImportSize($size)
|
53 |
+
{
|
54 |
+
$this->maxImportSize = $size;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Set the type of extensions to be imported into the CSS (to save network
|
59 |
+
* connections).
|
60 |
+
* Keys of the array should be the file extensions & respective values
|
61 |
+
* should be the data type.
|
62 |
+
*
|
63 |
+
* @param string[] $extensions Array of file extensions
|
64 |
+
*/
|
65 |
+
public function setImportExtensions(array $extensions)
|
66 |
+
{
|
67 |
+
$this->importExtensions = $extensions;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Move any import statements to the top.
|
72 |
+
*
|
73 |
+
* @param string $content Nearly finished CSS content
|
74 |
+
*
|
75 |
+
* @return string
|
76 |
+
*/
|
77 |
+
protected function moveImportsToTop($content)
|
78 |
+
{
|
79 |
+
if (preg_match_all('/@import[^;]+;/', $content, $matches)) {
|
80 |
+
// remove from content
|
81 |
+
foreach ($matches[0] as $import) {
|
82 |
+
$content = str_replace($import, '', $content);
|
83 |
+
}
|
84 |
+
|
85 |
+
// add to top
|
86 |
+
$content = implode('', $matches[0]).$content;
|
87 |
+
}
|
88 |
+
|
89 |
+
return $content;
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Combine CSS from import statements.
|
94 |
+
*
|
95 |
+
* @import's will be loaded and their content merged into the original file,
|
96 |
+
* to save HTTP requests.
|
97 |
+
*
|
98 |
+
* @param string $source The file to combine imports for
|
99 |
+
* @param string $content The CSS content to combine imports for
|
100 |
+
* @param string[] $parents Parent paths, for circular reference checks
|
101 |
+
*
|
102 |
+
* @return string
|
103 |
+
*
|
104 |
+
* @throws FileImportException
|
105 |
+
*/
|
106 |
+
protected function combineImports($source, $content, $parents)
|
107 |
+
{
|
108 |
+
$importRegexes = array(
|
109 |
+
// @import url(xxx)
|
110 |
+
'/
|
111 |
+
# import statement
|
112 |
+
@import
|
113 |
+
|
114 |
+
# whitespace
|
115 |
+
\s+
|
116 |
+
|
117 |
+
# open url()
|
118 |
+
url\(
|
119 |
+
|
120 |
+
# (optional) open path enclosure
|
121 |
+
(?P<quotes>["\']?)
|
122 |
+
|
123 |
+
# fetch path
|
124 |
+
(?P<path>.+?)
|
125 |
+
|
126 |
+
# (optional) close path enclosure
|
127 |
+
(?P=quotes)
|
128 |
+
|
129 |
+
# close url()
|
130 |
+
\)
|
131 |
+
|
132 |
+
# (optional) trailing whitespace
|
133 |
+
\s*
|
134 |
+
|
135 |
+
# (optional) media statement(s)
|
136 |
+
(?P<media>[^;]*)
|
137 |
+
|
138 |
+
# (optional) trailing whitespace
|
139 |
+
\s*
|
140 |
+
|
141 |
+
# (optional) closing semi-colon
|
142 |
+
;?
|
143 |
+
|
144 |
+
/ix',
|
145 |
+
|
146 |
+
// @import 'xxx'
|
147 |
+
'/
|
148 |
+
|
149 |
+
# import statement
|
150 |
+
@import
|
151 |
+
|
152 |
+
# whitespace
|
153 |
+
\s+
|
154 |
+
|
155 |
+
# open path enclosure
|
156 |
+
(?P<quotes>["\'])
|
157 |
+
|
158 |
+
# fetch path
|
159 |
+
(?P<path>.+?)
|
160 |
+
|
161 |
+
# close path enclosure
|
162 |
+
(?P=quotes)
|
163 |
+
|
164 |
+
# (optional) trailing whitespace
|
165 |
+
\s*
|
166 |
+
|
167 |
+
# (optional) media statement(s)
|
168 |
+
(?P<media>[^;]*)
|
169 |
+
|
170 |
+
# (optional) trailing whitespace
|
171 |
+
\s*
|
172 |
+
|
173 |
+
# (optional) closing semi-colon
|
174 |
+
;?
|
175 |
+
|
176 |
+
/ix',
|
177 |
+
);
|
178 |
+
|
179 |
+
// find all relative imports in css
|
180 |
+
$matches = array();
|
181 |
+
foreach ($importRegexes as $importRegex) {
|
182 |
+
if (preg_match_all($importRegex, $content, $regexMatches, PREG_SET_ORDER)) {
|
183 |
+
$matches = array_merge($matches, $regexMatches);
|
184 |
+
}
|
185 |
+
}
|
186 |
+
|
187 |
+
$search = array();
|
188 |
+
$replace = array();
|
189 |
+
|
190 |
+
// loop the matches
|
191 |
+
foreach ($matches as $match) {
|
192 |
+
// get the path for the file that will be imported
|
193 |
+
$importPath = dirname($source).'/'.$match['path'];
|
194 |
+
|
195 |
+
// only replace the import with the content if we can grab the
|
196 |
+
// content of the file
|
197 |
+
if (!$this->canImportByPath($match['path']) || !$this->canImportFile($importPath)) {
|
198 |
+
continue;
|
199 |
+
}
|
200 |
+
|
201 |
+
// check if current file was not imported previously in the same
|
202 |
+
// import chain.
|
203 |
+
if (in_array($importPath, $parents)) {
|
204 |
+
throw new FileImportException('Failed to import file "'.$importPath.'": circular reference detected.');
|
205 |
+
}
|
206 |
+
|
207 |
+
// grab referenced file & minify it (which may include importing
|
208 |
+
// yet other @import statements recursively)
|
209 |
+
$minifier = new static($importPath);
|
210 |
+
$importContent = $minifier->execute($source, $parents);
|
211 |
+
|
212 |
+
// check if this is only valid for certain media
|
213 |
+
if (!empty($match['media'])) {
|
214 |
+
$importContent = '@media '.$match['media'].'{'.$importContent.'}';
|
215 |
+
}
|
216 |
+
|
217 |
+
// add to replacement array
|
218 |
+
$search[] = $match[0];
|
219 |
+
$replace[] = $importContent;
|
220 |
+
}
|
221 |
+
|
222 |
+
// replace the import statements
|
223 |
+
return str_replace($search, $replace, $content);
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Import files into the CSS, base64-ized.
|
228 |
+
*
|
229 |
+
* @url(image.jpg) images will be loaded and their content merged into the
|
230 |
+
* original file, to save HTTP requests.
|
231 |
+
*
|
232 |
+
* @param string $source The file to import files for
|
233 |
+
* @param string $content The CSS content to import files for
|
234 |
+
*
|
235 |
+
* @return string
|
236 |
+
*/
|
237 |
+
protected function importFiles($source, $content)
|
238 |
+
{
|
239 |
+
$regex = '/url\((["\']?)(.+?)\\1\)/i';
|
240 |
+
if ($this->importExtensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {
|
241 |
+
$search = array();
|
242 |
+
$replace = array();
|
243 |
+
|
244 |
+
// loop the matches
|
245 |
+
foreach ($matches as $match) {
|
246 |
+
$extension = substr(strrchr($match[2], '.'), 1);
|
247 |
+
if ($extension && !array_key_exists($extension, $this->importExtensions)) {
|
248 |
+
continue;
|
249 |
+
}
|
250 |
+
|
251 |
+
// get the path for the file that will be imported
|
252 |
+
$path = $match[2];
|
253 |
+
$path = dirname($source).'/'.$path;
|
254 |
+
|
255 |
+
// only replace the import with the content if we're able to get
|
256 |
+
// the content of the file, and it's relatively small
|
257 |
+
if ($this->canImportFile($path) && $this->canImportBySize($path)) {
|
258 |
+
// grab content && base64-ize
|
259 |
+
$importContent = $this->load($path);
|
260 |
+
$importContent = base64_encode($importContent);
|
261 |
+
|
262 |
+
// build replacement
|
263 |
+
$search[] = $match[0];
|
264 |
+
$replace[] = 'url('.$this->importExtensions[$extension].';base64,'.$importContent.')';
|
265 |
+
}
|
266 |
+
}
|
267 |
+
|
268 |
+
// replace the import statements
|
269 |
+
$content = str_replace($search, $replace, $content);
|
270 |
+
}
|
271 |
+
|
272 |
+
return $content;
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Minify the data.
|
277 |
+
* Perform CSS optimizations.
|
278 |
+
*
|
279 |
+
* @param string[optional] $path Path to write the data to
|
280 |
+
* @param string[] $parents Parent paths, for circular reference checks
|
281 |
+
*
|
282 |
+
* @return string The minified data
|
283 |
+
*/
|
284 |
+
public function execute($path = null, $parents = array())
|
285 |
+
{
|
286 |
+
$content = '';
|
287 |
+
|
288 |
+
// loop CSS data (raw data and files)
|
289 |
+
foreach ($this->data as $source => $css) {
|
290 |
+
/*
|
291 |
+
* Let's first take out strings & comments, since we can't just
|
292 |
+
* remove whitespace anywhere. If whitespace occurs inside a string,
|
293 |
+
* we should leave it alone. E.g.:
|
294 |
+
* p { content: "a test" }
|
295 |
+
*/
|
296 |
+
$this->extractStrings();
|
297 |
+
$this->stripComments();
|
298 |
+
$css = $this->replace($css);
|
299 |
+
|
300 |
+
$css = $this->stripWhitespace($css);
|
301 |
+
$css = $this->shortenHex($css);
|
302 |
+
$css = $this->shortenZeroes($css);
|
303 |
+
$css = $this->shortenFontWeights($css);
|
304 |
+
$css = $this->stripEmptyTags($css);
|
305 |
+
|
306 |
+
// restore the string we've extracted earlier
|
307 |
+
$css = $this->restoreExtractedData($css);
|
308 |
+
|
309 |
+
$source = is_int($source) ? '' : $source;
|
310 |
+
$parents = $source ? array_merge($parents, array($source)) : $parents;
|
311 |
+
$css = $this->combineImports($source, $css, $parents);
|
312 |
+
$css = $this->importFiles($source, $css);
|
313 |
+
|
314 |
+
/*
|
315 |
+
* If we'll save to a new path, we'll have to fix the relative paths
|
316 |
+
* to be relative no longer to the source file, but to the new path.
|
317 |
+
* If we don't write to a file, fall back to same path so no
|
318 |
+
* conversion happens (because we still want it to go through most
|
319 |
+
* of the move code, which also addresses url() & @import syntax...)
|
320 |
+
*/
|
321 |
+
$converter = $this->getPathConverter($source, $path ?: $source);
|
322 |
+
$css = $this->move($converter, $css);
|
323 |
+
|
324 |
+
// combine css
|
325 |
+
$content .= $css;
|
326 |
+
}
|
327 |
+
|
328 |
+
$content = $this->moveImportsToTop($content);
|
329 |
+
|
330 |
+
return $content;
|
331 |
+
}
|
332 |
+
|
333 |
+
/**
|
334 |
+
* Moving a css file should update all relative urls.
|
335 |
+
* Relative references (e.g. ../images/image.gif) in a certain css file,
|
336 |
+
* will have to be updated when a file is being saved at another location
|
337 |
+
* (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper).
|
338 |
+
*
|
339 |
+
* @param ConverterInterface $converter Relative path converter
|
340 |
+
* @param string $content The CSS content to update relative urls for
|
341 |
+
*
|
342 |
+
* @return string
|
343 |
+
*/
|
344 |
+
protected function move(ConverterInterface $converter, $content)
|
345 |
+
{
|
346 |
+
/*
|
347 |
+
* Relative path references will usually be enclosed by url(). @import
|
348 |
+
* is an exception, where url() is not necessary around the path (but is
|
349 |
+
* allowed).
|
350 |
+
* This *could* be 1 regular expression, where both regular expressions
|
351 |
+
* in this array are on different sides of a |. But we're using named
|
352 |
+
* patterns in both regexes, the same name on both regexes. This is only
|
353 |
+
* possible with a (?J) modifier, but that only works after a fairly
|
354 |
+
* recent PCRE version. That's why I'm doing 2 separate regular
|
355 |
+
* expressions & combining the matches after executing of both.
|
356 |
+
*/
|
357 |
+
$relativeRegexes = array(
|
358 |
+
// url(xxx)
|
359 |
+
'/
|
360 |
+
# open url()
|
361 |
+
url\(
|
362 |
+
|
363 |
+
\s*
|
364 |
+
|
365 |
+
# open path enclosure
|
366 |
+
(?P<quotes>["\'])?
|
367 |
+
|
368 |
+
# fetch path
|
369 |
+
(?P<path>.+?)
|
370 |
+
|
371 |
+
# close path enclosure
|
372 |
+
(?(quotes)(?P=quotes))
|
373 |
+
|
374 |
+
\s*
|
375 |
+
|
376 |
+
# close url()
|
377 |
+
\)
|
378 |
+
|
379 |
+
/ix',
|
380 |
+
|
381 |
+
// @import "xxx"
|
382 |
+
'/
|
383 |
+
# import statement
|
384 |
+
@import
|
385 |
+
|
386 |
+
# whitespace
|
387 |
+
\s+
|
388 |
+
|
389 |
+
# we don\'t have to check for @import url(), because the
|
390 |
+
# condition above will already catch these
|
391 |
+
|
392 |
+
# open path enclosure
|
393 |
+
(?P<quotes>["\'])
|
394 |
+
|
395 |
+
# fetch path
|
396 |
+
(?P<path>.+?)
|
397 |
+
|
398 |
+
# close path enclosure
|
399 |
+
(?P=quotes)
|
400 |
+
|
401 |
+
/ix',
|
402 |
+
);
|
403 |
+
|
404 |
+
// find all relative urls in css
|
405 |
+
$matches = array();
|
406 |
+
foreach ($relativeRegexes as $relativeRegex) {
|
407 |
+
if (preg_match_all($relativeRegex, $content, $regexMatches, PREG_SET_ORDER)) {
|
408 |
+
$matches = array_merge($matches, $regexMatches);
|
409 |
+
}
|
410 |
+
}
|
411 |
+
|
412 |
+
$search = array();
|
413 |
+
$replace = array();
|
414 |
+
|
415 |
+
// loop all urls
|
416 |
+
foreach ($matches as $match) {
|
417 |
+
// determine if it's a url() or an @import match
|
418 |
+
$type = (strpos($match[0], '@import') === 0 ? 'import' : 'url');
|
419 |
+
|
420 |
+
$url = $match['path'];
|
421 |
+
if ($this->canImportByPath($url)) {
|
422 |
+
// attempting to interpret GET-params makes no sense, so let's discard them for awhile
|
423 |
+
$params = strrchr($url, '?');
|
424 |
+
$url = $params ? substr($url, 0, -strlen($params)) : $url;
|
425 |
+
|
426 |
+
// fix relative url
|
427 |
+
$url = $converter->convert($url);
|
428 |
+
|
429 |
+
// now that the path has been converted, re-apply GET-params
|
430 |
+
$url .= $params;
|
431 |
+
}
|
432 |
+
|
433 |
+
/*
|
434 |
+
* Urls with control characters above 0x7e should be quoted.
|
435 |
+
* According to Mozilla's parser, whitespace is only allowed at the
|
436 |
+
* end of unquoted urls.
|
437 |
+
* Urls with `)` (as could happen with data: uris) should also be
|
438 |
+
* quoted to avoid being confused for the url() closing parentheses.
|
439 |
+
* And urls with a # have also been reported to cause issues.
|
440 |
+
*
|
441 |
+
* @see https://developer.mozilla.org/nl/docs/Web/CSS/url#The_url()_functional_notation
|
442 |
+
* @see https://hg.mozilla.org/mozilla-central/rev/14abca4e7378
|
443 |
+
*/
|
444 |
+
$url = trim($url);
|
445 |
+
if (preg_match('/[\s\)#\x{7f}-\x{9f}]/u', $url)) {
|
446 |
+
$url = $match['quotes'] . $url . $match['quotes'];
|
447 |
+
}
|
448 |
+
|
449 |
+
// build replacement
|
450 |
+
$search[] = $match[0];
|
451 |
+
if ($type === 'url') {
|
452 |
+
$replace[] = 'url('.$url.')';
|
453 |
+
} elseif ($type === 'import') {
|
454 |
+
$replace[] = '@import "'.$url.'"';
|
455 |
+
}
|
456 |
+
}
|
457 |
+
|
458 |
+
// replace urls
|
459 |
+
return str_replace($search, $replace, $content);
|
460 |
+
}
|
461 |
+
|
462 |
+
/**
|
463 |
+
* Shorthand hex color codes.
|
464 |
+
* #FF0000 -> #F00.
|
465 |
+
*
|
466 |
+
* @param string $content The CSS content to shorten the hex color codes for
|
467 |
+
*
|
468 |
+
* @return string
|
469 |
+
*/
|
470 |
+
protected function shortenHex($content)
|
471 |
+
{
|
472 |
+
$content = preg_replace('/(?<=[: ])#([0-9a-z])\\1([0-9a-z])\\2([0-9a-z])\\3(?=[; }])/i', '#$1$2$3', $content);
|
473 |
+
|
474 |
+
// we can shorten some even more by replacing them with their color name
|
475 |
+
$colors = array(
|
476 |
+
'#F0FFFF' => 'azure',
|
477 |
+
'#F5F5DC' => 'beige',
|
478 |
+
'#A52A2A' => 'brown',
|
479 |
+
'#FF7F50' => 'coral',
|
480 |
+
'#FFD700' => 'gold',
|
481 |
+
'#808080' => 'gray',
|
482 |
+
'#008000' => 'green',
|
483 |
+
'#4B0082' => 'indigo',
|
484 |
+
'#FFFFF0' => 'ivory',
|
485 |
+
'#F0E68C' => 'khaki',
|
486 |
+
'#FAF0E6' => 'linen',
|
487 |
+
'#800000' => 'maroon',
|
488 |
+
'#000080' => 'navy',
|
489 |
+
'#808000' => 'olive',
|
490 |
+
'#CD853F' => 'peru',
|
491 |
+
'#FFC0CB' => 'pink',
|
492 |
+
'#DDA0DD' => 'plum',
|
493 |
+
'#800080' => 'purple',
|
494 |
+
'#F00' => 'red',
|
495 |
+
'#FA8072' => 'salmon',
|
496 |
+
'#A0522D' => 'sienna',
|
497 |
+
'#C0C0C0' => 'silver',
|
498 |
+
'#FFFAFA' => 'snow',
|
499 |
+
'#D2B48C' => 'tan',
|
500 |
+
'#FF6347' => 'tomato',
|
501 |
+
'#EE82EE' => 'violet',
|
502 |
+
'#F5DEB3' => 'wheat',
|
503 |
+
);
|
504 |
+
|
505 |
+
return preg_replace_callback(
|
506 |
+
'/(?<=[: ])('.implode(array_keys($colors), '|').')(?=[; }])/i',
|
507 |
+
function ($match) use ($colors) {
|
508 |
+
return $colors[strtoupper($match[0])];
|
509 |
+
},
|
510 |
+
$content
|
511 |
+
);
|
512 |
+
}
|
513 |
+
|
514 |
+
/**
|
515 |
+
* Shorten CSS font weights.
|
516 |
+
*
|
517 |
+
* @param string $content The CSS content to shorten the font weights for
|
518 |
+
*
|
519 |
+
* @return string
|
520 |
+
*/
|
521 |
+
protected function shortenFontWeights($content)
|
522 |
+
{
|
523 |
+
$weights = array(
|
524 |
+
'normal' => 400,
|
525 |
+
'bold' => 700,
|
526 |
+
);
|
527 |
+
|
528 |
+
$callback = function ($match) use ($weights) {
|
529 |
+
return $match[1].$weights[$match[2]];
|
530 |
+
};
|
531 |
+
|
532 |
+
return preg_replace_callback('/(font-weight\s*:\s*)('.implode('|', array_keys($weights)).')(?=[;}])/', $callback, $content);
|
533 |
+
}
|
534 |
+
|
535 |
+
/**
|
536 |
+
* Shorthand 0 values to plain 0, instead of e.g. -0em.
|
537 |
+
*
|
538 |
+
* @param string $content The CSS content to shorten the zero values for
|
539 |
+
*
|
540 |
+
* @return string
|
541 |
+
*/
|
542 |
+
protected function shortenZeroes($content)
|
543 |
+
{
|
544 |
+
// reusable bits of code throughout these regexes:
|
545 |
+
// before & after are used to make sure we don't match lose unintended
|
546 |
+
// 0-like values (e.g. in #000, or in http://url/1.0)
|
547 |
+
// units can be stripped from 0 values, or used to recognize non 0
|
548 |
+
// values (where wa may be able to strip a .0 suffix)
|
549 |
+
$before = '(?<=[:(, ])';
|
550 |
+
$after = '(?=[ ,);}])';
|
551 |
+
$units = '(em|ex|%|px|cm|mm|in|pt|pc|ch|rem|vh|vw|vmin|vmax|vm)';
|
552 |
+
|
553 |
+
// strip units after zeroes (0px -> 0)
|
554 |
+
// NOTE: it should be safe to remove all units for a 0 value, but in
|
555 |
+
// practice, Webkit (especially Safari) seems to stumble over at least
|
556 |
+
// 0%, potentially other units as well. Only stripping 'px' for now.
|
557 |
+
// @see https://github.com/matthiasmullie/minify/issues/60
|
558 |
+
$content = preg_replace('/'.$before.'(-?0*(\.0+)?)(?<=0)px'.$after.'/', '\\1', $content);
|
559 |
+
|
560 |
+
// strip 0-digits (.0 -> 0)
|
561 |
+
$content = preg_replace('/'.$before.'\.0+'.$units.'?'.$after.'/', '0\\1', $content);
|
562 |
+
// strip trailing 0: 50.10 -> 50.1, 50.10px -> 50.1px
|
563 |
+
$content = preg_replace('/'.$before.'(-?[0-9]+\.[0-9]+)0+'.$units.'?'.$after.'/', '\\1\\2', $content);
|
564 |
+
// strip trailing 0: 50.00 -> 50, 50.00px -> 50px
|
565 |
+
$content = preg_replace('/'.$before.'(-?[0-9]+)\.0+'.$units.'?'.$after.'/', '\\1\\2', $content);
|
566 |
+
// strip leading 0: 0.1 -> .1, 01.1 -> 1.1
|
567 |
+
$content = preg_replace('/'.$before.'(-?)0+([0-9]*\.[0-9]+)'.$units.'?'.$after.'/', '\\1\\2\\3', $content);
|
568 |
+
|
569 |
+
// strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0)
|
570 |
+
$content = preg_replace('/'.$before.'-?0+'.$units.'?'.$after.'/', '0\\1', $content);
|
571 |
+
|
572 |
+
// remove zeroes where they make no sense in calc: e.g. calc(100px - 0)
|
573 |
+
// the 0 doesn't have any effect, and this isn't even valid without unit
|
574 |
+
// strip all `+ 0` or `- 0` occurrences: calc(10% + 0) -> calc(10%)
|
575 |
+
// looped because there may be multiple 0s inside 1 group of parentheses
|
576 |
+
do {
|
577 |
+
$previous = $content;
|
578 |
+
$content = preg_replace('/\(([^\(\)]+) [\+\-] 0( [^\(\)]+)?\)/', '(\\1\\2)', $content);
|
579 |
+
} while ($content !== $previous);
|
580 |
+
// strip all `0 +` occurrences: calc(0 + 10%) -> calc(10%)
|
581 |
+
$content = preg_replace('/\(0 \+ ([^\(\)]+)\)/', '(\\1)', $content);
|
582 |
+
// strip all `0 -` occurrences: calc(0 - 10%) -> calc(-10%)
|
583 |
+
$content = preg_replace('/\(0 \- ([^\(\)]+)\)/', '(-\\1)', $content);
|
584 |
+
// I'm not going to attempt to optimize away `x * 0` instances:
|
585 |
+
// it's dumb enough code already that it likely won't occur, and it's
|
586 |
+
// too complex to do right (order of operations would have to be
|
587 |
+
// respected etc)
|
588 |
+
// what I cared about most here was fixing incorrectly truncated units
|
589 |
+
|
590 |
+
// IE doesn't seem to understand a unitless flex-basis value, so let's
|
591 |
+
// add it in again (make it `%`, which is only 1 char: 0%, 0px, 0
|
592 |
+
// anything, it's all just the same)
|
593 |
+
$content = preg_replace('/flex:([^ ]+ [^ ]+ )0([;\}])/', 'flex:${1}0%${2}', $content);
|
594 |
+
$content = preg_replace('/flex-basis:0([;\}])/', 'flex-basis:0%${1}', $content);
|
595 |
+
|
596 |
+
return $content;
|
597 |
+
}
|
598 |
+
|
599 |
+
/**
|
600 |
+
* Strip comments from source code.
|
601 |
+
*
|
602 |
+
* @param string $content
|
603 |
+
*
|
604 |
+
* @return string
|
605 |
+
*/
|
606 |
+
protected function stripEmptyTags($content)
|
607 |
+
{
|
608 |
+
return preg_replace('/(^|\}|;)[^\{\};]+\{\s*\}/', '\\1', $content);
|
609 |
+
}
|
610 |
+
|
611 |
+
/**
|
612 |
+
* Strip comments from source code.
|
613 |
+
*/
|
614 |
+
protected function stripComments()
|
615 |
+
{
|
616 |
+
$this->registerPattern('/\/\*.*?\*\//s', '');
|
617 |
+
}
|
618 |
+
|
619 |
+
/**
|
620 |
+
* Strip whitespace.
|
621 |
+
*
|
622 |
+
* @param string $content The CSS content to strip the whitespace for
|
623 |
+
*
|
624 |
+
* @return string
|
625 |
+
*/
|
626 |
+
protected function stripWhitespace($content)
|
627 |
+
{
|
628 |
+
// remove leading & trailing whitespace
|
629 |
+
$content = preg_replace('/^\s*/m', '', $content);
|
630 |
+
$content = preg_replace('/\s*$/m', '', $content);
|
631 |
+
|
632 |
+
// replace newlines with a single space
|
633 |
+
$content = preg_replace('/\s+/', ' ', $content);
|
634 |
+
|
635 |
+
// remove whitespace around meta characters
|
636 |
+
// inspired by stackoverflow.com/questions/15195750/minify-compress-css-with-regex
|
637 |
+
$content = preg_replace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content);
|
638 |
+
$content = preg_replace('/([\[(:])\s+/', '$1', $content);
|
639 |
+
$content = preg_replace('/\s+([\]\)])/', '$1', $content);
|
640 |
+
$content = preg_replace('/\s+(:)(?![^\}]*\{)/', '$1', $content);
|
641 |
+
|
642 |
+
// whitespace around + and - can only be stripped in selectors, like
|
643 |
+
// :nth-child(3+2n), not in things like calc(3px + 2px) or shorthands
|
644 |
+
// like 3px -2px
|
645 |
+
$content = preg_replace('/\s*([+-])\s*(?=[^}]*{)/', '$1', $content);
|
646 |
+
|
647 |
+
// remove semicolon/whitespace followed by closing bracket
|
648 |
+
$content = str_replace(';}', '}', $content);
|
649 |
+
|
650 |
+
return trim($content);
|
651 |
+
}
|
652 |
+
|
653 |
+
/**
|
654 |
+
* Check if file is small enough to be imported.
|
655 |
+
*
|
656 |
+
* @param string $path The path to the file
|
657 |
+
*
|
658 |
+
* @return bool
|
659 |
+
*/
|
660 |
+
protected function canImportBySize($path)
|
661 |
+
{
|
662 |
+
return ($size = @filesize($path)) && $size <= $this->maxImportSize * 1024;
|
663 |
+
}
|
664 |
+
|
665 |
+
/**
|
666 |
+
* Check if file a file can be imported, going by the path.
|
667 |
+
*
|
668 |
+
* @param string $path
|
669 |
+
*
|
670 |
+
* @return bool
|
671 |
+
*/
|
672 |
+
protected function canImportByPath($path)
|
673 |
+
{
|
674 |
+
return preg_match('/^(data:|https?:|\\/)/', $path) === 0;
|
675 |
+
}
|
676 |
+
|
677 |
+
/**
|
678 |
+
* Return a converter to update relative paths to be relative to the new
|
679 |
+
* destination.
|
680 |
+
*
|
681 |
+
* @param string $source
|
682 |
+
* @param string $target
|
683 |
+
*
|
684 |
+
* @return ConverterInterface
|
685 |
+
*/
|
686 |
+
protected function getPathConverter($source, $target)
|
687 |
+
{
|
688 |
+
return new Converter($source, $target);
|
689 |
+
}
|
690 |
+
}
|
libs/matthiasmullie/minify/src/Exception.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\Minify;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* @deprecated Use Exceptions\BasicException instead
|
7 |
+
*
|
8 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
9 |
+
*/
|
10 |
+
abstract class Exception extends \Exception
|
11 |
+
{
|
12 |
+
}
|
libs/matthiasmullie/minify/src/Exceptions/BasicException.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\Minify\Exceptions;
|
4 |
+
|
5 |
+
use MatthiasMullie\Minify\Exception;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
9 |
+
*/
|
10 |
+
abstract class BasicException extends Exception
|
11 |
+
{
|
12 |
+
}
|
libs/matthiasmullie/minify/src/Exceptions/FileImportException.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\Minify\Exceptions;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
7 |
+
*/
|
8 |
+
class FileImportException extends BasicException
|
9 |
+
{
|
10 |
+
}
|
libs/matthiasmullie/minify/src/Exceptions/IOException.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\Minify\Exceptions;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
7 |
+
*/
|
8 |
+
class IOException extends BasicException
|
9 |
+
{
|
10 |
+
}
|
libs/matthiasmullie/minify/src/Exceptions/index.html
ADDED
File without changes
|
libs/matthiasmullie/minify/src/JS.php
ADDED
@@ -0,0 +1,529 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\Minify;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* JavaScript minifier.
|
7 |
+
*
|
8 |
+
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
9 |
+
*
|
10 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
11 |
+
* @author Tijs Verkoyen <minify@verkoyen.eu>
|
12 |
+
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
13 |
+
* @license MIT License
|
14 |
+
*/
|
15 |
+
class JS extends Minify
|
16 |
+
{
|
17 |
+
/**
|
18 |
+
* Var-matching regex based on http://stackoverflow.com/a/9337047/802993.
|
19 |
+
*
|
20 |
+
* Note that regular expressions using that bit must have the PCRE_UTF8
|
21 |
+
* pattern modifier (/u) set.
|
22 |
+
*
|
23 |
+
* @var string
|
24 |
+
*/
|
25 |
+
const REGEX_VARIABLE = '\b[$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}][$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}0-9\x{0300}-\x{036f}\x{0483}-\x{0487}\x{0591}-\x{05bd}\x{05bf}\x{05c1}\x{05c2}\x{05c4}\x{05c5}\x{05c7}\x{0610}-\x{061a}\x{064b}-\x{0669}\x{0670}\x{06d6}-\x{06dc}\x{06df}-\x{06e4}\x{06e7}\x{06e8}\x{06ea}-\x{06ed}\x{06f0}-\x{06f9}\x{0711}\x{0730}-\x{074a}\x{07a6}-\x{07b0}\x{07c0}-\x{07c9}\x{07eb}-\x{07f3}\x{0816}-\x{0819}\x{081b}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082d}\x{0859}-\x{085b}\x{08e4}-\x{08fe}\x{0900}-\x{0903}\x{093a}-\x{093c}\x{093e}-\x{094f}\x{0951}-\x{0957}\x{0962}\x{0963}\x{0966}-\x{096f}\x{0981}-\x{0983}\x{09bc}\x{09be}-\x{09c4}\x{09c7}\x{09c8}\x{09cb}-\x{09cd}\x{09d7}\x{09e2}\x{09e3}\x{09e6}-\x{09ef}\x{0a01}-\x{0a03}\x{0a3c}\x{0a3e}-\x{0a42}\x{0a47}\x{0a48}\x{0a4b}-\x{0a4d}\x{0a51}\x{0a66}-\x{0a71}\x{0a75}\x{0a81}-\x{0a83}\x{0abc}\x{0abe}-\x{0ac5}\x{0ac7}-\x{0ac9}\x{0acb}-\x{0acd}\x{0ae2}\x{0ae3}\x{0ae6}-\x{0aef}\x{0b01}-\x{0b03}\x{0b3c}\x{0b3e}-\x{0b44}\x{0b47}\x{0b48}\x{0b4b}-\x{0b4d}\x{0b56}\x{0b57}\x{0b62}\x{0b63}\x{0b66}-\x{0b6f}\x{0b82}\x{0bbe}-\x{0bc2}\x{0bc6}-\x{0bc8}\x{0bca}-\x{0bcd}\x{0bd7}\x{0be6}-\x{0bef}\x{0c01}-\x{0c03}\x{0c3e}-\x{0c44}\x{0c46}-\x{0c48}\x{0c4a}-\x{0c4d}\x{0c55}\x{0c56}\x{0c62}\x{0c63}\x{0c66}-\x{0c6f}\x{0c82}\x{0c83}\x{0cbc}\x{0cbe}-\x{0cc4}\x{0cc6}-\x{0cc8}\x{0cca}-\x{0ccd}\x{0cd5}\x{0cd6}\x{0ce2}\x{0ce3}\x{0ce6}-\x{0cef}\x{0d02}\x{0d03}\x{0d3e}-\x{0d44}\x{0d46}-\x{0d48}\x{0d4a}-\x{0d4d}\x{0d57}\x{0d62}\x{0d63}\x{0d66}-\x{0d6f}\x{0d82}\x{0d83}\x{0dca}\x{0dcf}-\x{0dd4}\x{0dd6}\x{0dd8}-\x{0ddf}\x{0df2}\x{0df3}\x{0e31}\x{0e34}-\x{0e3a}\x{0e47}-\x{0e4e}\x{0e50}-\x{0e59}\x{0eb1}\x{0eb4}-\x{0eb9}\x{0ebb}\x{0ebc}\x{0ec8}-\x{0ecd}\x{0ed0}-\x{0ed9}\x{0f18}\x{0f19}\x{0f20}-\x{0f29}\x{0f35}\x{0f37}\x{0f39}\x{0f3e}\x{0f3f}\x{0f71}-\x{0f84}\x{0f86}\x{0f87}\x{0f8d}-\x{0f97}\x{0f99}-\x{0fbc}\x{0fc6}\x{102b}-\x{103e}\x{1040}-\x{1049}\x{1056}-\x{1059}\x{105e}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106d}\x{1071}-\x{1074}\x{1082}-\x{108d}\x{108f}-\x{109d}\x{135d}-\x{135f}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}\x{1753}\x{1772}\x{1773}\x{17b4}-\x{17d3}\x{17dd}\x{17e0}-\x{17e9}\x{180b}-\x{180d}\x{1810}-\x{1819}\x{18a9}\x{1920}-\x{192b}\x{1930}-\x{193b}\x{1946}-\x{194f}\x{19b0}-\x{19c0}\x{19c8}\x{19c9}\x{19d0}-\x{19d9}\x{1a17}-\x{1a1b}\x{1a55}-\x{1a5e}\x{1a60}-\x{1a7c}\x{1a7f}-\x{1a89}\x{1a90}-\x{1a99}\x{1b00}-\x{1b04}\x{1b34}-\x{1b44}\x{1b50}-\x{1b59}\x{1b6b}-\x{1b73}\x{1b80}-\x{1b82}\x{1ba1}-\x{1bad}\x{1bb0}-\x{1bb9}\x{1be6}-\x{1bf3}\x{1c24}-\x{1c37}\x{1c40}-\x{1c49}\x{1c50}-\x{1c59}\x{1cd0}-\x{1cd2}\x{1cd4}-\x{1ce8}\x{1ced}\x{1cf2}-\x{1cf4}\x{1dc0}-\x{1de6}\x{1dfc}-\x{1dff}\x{200c}\x{200d}\x{203f}\x{2040}\x{2054}\x{20d0}-\x{20dc}\x{20e1}\x{20e5}-\x{20f0}\x{2cef}-\x{2cf1}\x{2d7f}\x{2de0}-\x{2dff}\x{302a}-\x{302f}\x{3099}\x{309a}\x{a620}-\x{a629}\x{a66f}\x{a674}-\x{a67d}\x{a69f}\x{a6f0}\x{a6f1}\x{a802}\x{a806}\x{a80b}\x{a823}-\x{a827}\x{a880}\x{a881}\x{a8b4}-\x{a8c4}\x{a8d0}-\x{a8d9}\x{a8e0}-\x{a8f1}\x{a900}-\x{a909}\x{a926}-\x{a92d}\x{a947}-\x{a953}\x{a980}-\x{a983}\x{a9b3}-\x{a9c0}\x{a9d0}-\x{a9d9}\x{aa29}-\x{aa36}\x{aa43}\x{aa4c}\x{aa4d}\x{aa50}-\x{aa59}\x{aa7b}\x{aab0}\x{aab2}-\x{aab4}\x{aab7}\x{aab8}\x{aabe}\x{aabf}\x{aac1}\x{aaeb}-\x{aaef}\x{aaf5}\x{aaf6}\x{abe3}-\x{abea}\x{abec}\x{abed}\x{abf0}-\x{abf9}\x{fb1e}\x{fe00}-\x{fe0f}\x{fe20}-\x{fe26}\x{fe33}\x{fe34}\x{fe4d}-\x{fe4f}\x{ff10}-\x{ff19}\x{ff3f}]*\b';
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Full list of JavaScript reserved words.
|
29 |
+
* Will be loaded from /data/js/keywords_reserved.txt.
|
30 |
+
*
|
31 |
+
* @see https://mathiasbynens.be/notes/reserved-keywords
|
32 |
+
*
|
33 |
+
* @var string[]
|
34 |
+
*/
|
35 |
+
protected $keywordsReserved = array();
|
36 |
+
|
37 |
+
/**
|
38 |
+
* List of JavaScript reserved words that accept a <variable, value, ...>
|
39 |
+
* after them. Some end of lines are not the end of a statement, like with
|
40 |
+
* these keywords.
|
41 |
+
*
|
42 |
+
* E.g.: we shouldn't insert a ; after this else
|
43 |
+
* else
|
44 |
+
* console.log('this is quite fine')
|
45 |
+
*
|
46 |
+
* Will be loaded from /data/js/keywords_before.txt
|
47 |
+
*
|
48 |
+
* @var string[]
|
49 |
+
*/
|
50 |
+
protected $keywordsBefore = array();
|
51 |
+
|
52 |
+
/**
|
53 |
+
* List of JavaScript reserved words that accept a <variable, value, ...>
|
54 |
+
* before them. Some end of lines are not the end of a statement, like when
|
55 |
+
* continued by one of these keywords on the newline.
|
56 |
+
*
|
57 |
+
* E.g.: we shouldn't insert a ; before this instanceof
|
58 |
+
* variable
|
59 |
+
* instanceof String
|
60 |
+
*
|
61 |
+
* Will be loaded from /data/js/keywords_after.txt
|
62 |
+
*
|
63 |
+
* @var string[]
|
64 |
+
*/
|
65 |
+
protected $keywordsAfter = array();
|
66 |
+
|
67 |
+
/**
|
68 |
+
* List of all JavaScript operators.
|
69 |
+
*
|
70 |
+
* Will be loaded from /data/js/operators.txt
|
71 |
+
*
|
72 |
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
|
73 |
+
*
|
74 |
+
* @var string[]
|
75 |
+
*/
|
76 |
+
protected $operators = array();
|
77 |
+
|
78 |
+
/**
|
79 |
+
* List of JavaScript operators that accept a <variable, value, ...> after
|
80 |
+
* them. Some end of lines are not the end of a statement, like with these
|
81 |
+
* operators.
|
82 |
+
*
|
83 |
+
* Note: Most operators are fine, we've only removed !, ++ and --.
|
84 |
+
* There can't be a newline separating ! and whatever it is negating.
|
85 |
+
* ++ & -- have to be joined with the value they're in-/decrementing.
|
86 |
+
*
|
87 |
+
* Will be loaded from /data/js/operators_before.txt
|
88 |
+
*
|
89 |
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
|
90 |
+
*
|
91 |
+
* @var string[]
|
92 |
+
*/
|
93 |
+
protected $operatorsBefore = array();
|
94 |
+
|
95 |
+
/**
|
96 |
+
* List of JavaScript operators that accept a <variable, value, ...> before
|
97 |
+
* them. Some end of lines are not the end of a statement, like when
|
98 |
+
* continued by one of these operators on the newline.
|
99 |
+
*
|
100 |
+
* Note: Most operators are fine, we've only removed ), ], ++ and --.
|
101 |
+
* ++ & -- have to be joined with the value they're in-/decrementing.
|
102 |
+
* ) & ] are "special" in that they have lots or usecases. () for example
|
103 |
+
* is used for function calls, for grouping, in if () and for (), ...
|
104 |
+
*
|
105 |
+
* Will be loaded from /data/js/operators_after.txt
|
106 |
+
*
|
107 |
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
|
108 |
+
*
|
109 |
+
* @var string[]
|
110 |
+
*/
|
111 |
+
protected $operatorsAfter = array();
|
112 |
+
|
113 |
+
/**
|
114 |
+
* {@inheritdoc}
|
115 |
+
*/
|
116 |
+
public function __construct()
|
117 |
+
{
|
118 |
+
call_user_func_array(array('parent', '__construct'), func_get_args());
|
119 |
+
|
120 |
+
$dataDir = __DIR__.'/../data/js/';
|
121 |
+
$options = FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES;
|
122 |
+
$this->keywordsReserved = file($dataDir.'keywords_reserved.txt', $options);
|
123 |
+
$this->keywordsBefore = file($dataDir.'keywords_before.txt', $options);
|
124 |
+
$this->keywordsAfter = file($dataDir.'keywords_after.txt', $options);
|
125 |
+
$this->operators = file($dataDir.'operators.txt', $options);
|
126 |
+
$this->operatorsBefore = file($dataDir.'operators_before.txt', $options);
|
127 |
+
$this->operatorsAfter = file($dataDir.'operators_after.txt', $options);
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Minify the data.
|
132 |
+
* Perform JS optimizations.
|
133 |
+
*
|
134 |
+
* @param string[optional] $path Path to write the data to
|
135 |
+
*
|
136 |
+
* @return string The minified data
|
137 |
+
*/
|
138 |
+
public function execute($path = null)
|
139 |
+
{
|
140 |
+
$content = '';
|
141 |
+
|
142 |
+
// loop files
|
143 |
+
foreach ($this->data as $source => $js) {
|
144 |
+
/*
|
145 |
+
* Combine js: separating the scripts by a ;
|
146 |
+
* I'm also adding a newline: it will be eaten when whitespace is
|
147 |
+
* stripped, but we need to make sure we're not just appending
|
148 |
+
* a new script right after a previous script that ended with a
|
149 |
+
* singe-line comment on the last line (in which case it would also
|
150 |
+
* be seen as part of that comment)
|
151 |
+
*/
|
152 |
+
$content .= $js."\n;";
|
153 |
+
}
|
154 |
+
|
155 |
+
/*
|
156 |
+
* Let's first take out strings, comments and regular expressions.
|
157 |
+
* All of these can contain JS code-like characters, and we should make
|
158 |
+
* sure any further magic ignores anything inside of these.
|
159 |
+
*
|
160 |
+
* Consider this example, where we should not strip any whitespace:
|
161 |
+
* var str = "a test";
|
162 |
+
*
|
163 |
+
* Comments will be removed altogether, strings and regular expressions
|
164 |
+
* will be replaced by placeholder text, which we'll restore later.
|
165 |
+
*/
|
166 |
+
$this->extractStrings('\'"`');
|
167 |
+
$this->stripComments();
|
168 |
+
$this->extractRegex();
|
169 |
+
$content = $this->replace($content);
|
170 |
+
|
171 |
+
$content = $this->propertyNotation($content);
|
172 |
+
$content = $this->shortenBools($content);
|
173 |
+
$content = $this->stripWhitespace($content);
|
174 |
+
|
175 |
+
/*
|
176 |
+
* Earlier, we extracted strings & regular expressions and replaced them
|
177 |
+
* with placeholder text. This will restore them.
|
178 |
+
*/
|
179 |
+
$content = $this->restoreExtractedData($content);
|
180 |
+
|
181 |
+
return $content;
|
182 |
+
}
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Strip comments from source code.
|
186 |
+
*/
|
187 |
+
protected function stripComments()
|
188 |
+
{
|
189 |
+
// single-line comments
|
190 |
+
$this->registerPattern('/\/\/.*$/m', '');
|
191 |
+
|
192 |
+
// multi-line comments
|
193 |
+
$this->registerPattern('/\/\*.*?\*\//s', '');
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* JS can have /-delimited regular expressions, like: /ab+c/.match(string).
|
198 |
+
*
|
199 |
+
* The content inside the regex can contain characters that may be confused
|
200 |
+
* for JS code: e.g. it could contain whitespace it needs to match & we
|
201 |
+
* don't want to strip whitespace in there.
|
202 |
+
*
|
203 |
+
* The regex can be pretty simple: we don't have to care about comments,
|
204 |
+
* (which also use slashes) because stripComments() will have stripped those
|
205 |
+
* already.
|
206 |
+
*
|
207 |
+
* This method will replace all string content with simple REGEX#
|
208 |
+
* placeholder text, so we've rid all regular expressions from characters
|
209 |
+
* that may be misinterpreted. Original regex content will be saved in
|
210 |
+
* $this->extracted and after doing all other minifying, we can restore the
|
211 |
+
* original content via restoreRegex()
|
212 |
+
*/
|
213 |
+
protected function extractRegex()
|
214 |
+
{
|
215 |
+
// PHP only supports $this inside anonymous functions since 5.4
|
216 |
+
$minifier = $this;
|
217 |
+
$callback = function ($match) use ($minifier) {
|
218 |
+
$count = count($minifier->extracted);
|
219 |
+
$placeholder = '/'.$count.'/';
|
220 |
+
$minifier->extracted[$placeholder] = $match[0];
|
221 |
+
|
222 |
+
return $placeholder;
|
223 |
+
};
|
224 |
+
|
225 |
+
$pattern = '\/.*?(?<!\\\\)(\\\\\\\\)*\/[gimy]*(?![0-9a-zA-Z\/])';
|
226 |
+
|
227 |
+
// a regular expression can only be followed by a few operators or some
|
228 |
+
// of the RegExp methods (a `\` followed by a variable or value is
|
229 |
+
// likely part of a division, not a regex)
|
230 |
+
$after = '[\.,;\)\}]';
|
231 |
+
$methods = '\.(exec|test|match|search|replace|split)\(';
|
232 |
+
$this->registerPattern('/'.$pattern.'(?=\s*('.$after.'|'.$methods.'))/', $callback);
|
233 |
+
|
234 |
+
// 1 more edge case: a regex can be followed by a lot more operators or
|
235 |
+
// keywords if there's a newline (ASI) in between, where the operator
|
236 |
+
// actually starts a new statement
|
237 |
+
// (https://github.com/matthiasmullie/minify/issues/56)
|
238 |
+
$operators = $this->getOperatorsForRegex($this->operatorsBefore, '/');
|
239 |
+
$operators += $this->getOperatorsForRegex($this->keywordsReserved, '/');
|
240 |
+
$this->registerPattern('/'.$pattern.'\s*\n(?=\s*('.implode('|', $operators).'))/', $callback);
|
241 |
+
}
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Strip whitespace.
|
245 |
+
*
|
246 |
+
* We won't strip *all* whitespace, but as much as possible. The thing that
|
247 |
+
* we'll preserve are newlines we're unsure about.
|
248 |
+
* JavaScript doesn't require statements to be terminated with a semicolon.
|
249 |
+
* It will automatically fix missing semicolons with ASI (automatic semi-
|
250 |
+
* colon insertion) at the end of line causing errors (without semicolon.)
|
251 |
+
*
|
252 |
+
* Because it's sometimes hard to tell if a newline is part of a statement
|
253 |
+
* that should be terminated or not, we'll just leave some of them alone.
|
254 |
+
*
|
255 |
+
* @param string $content The content to strip the whitespace for
|
256 |
+
*
|
257 |
+
* @return string
|
258 |
+
*/
|
259 |
+
protected function stripWhitespace($content)
|
260 |
+
{
|
261 |
+
// uniform line endings, make them all line feed
|
262 |
+
$content = str_replace(array("\r\n", "\r"), "\n", $content);
|
263 |
+
|
264 |
+
// collapse all non-line feed whitespace into a single space
|
265 |
+
$content = preg_replace('/[^\S\n]+/', ' ', $content);
|
266 |
+
|
267 |
+
// strip leading & trailing whitespace
|
268 |
+
$content = str_replace(array(" \n", "\n "), "\n", $content);
|
269 |
+
|
270 |
+
// collapse consecutive line feeds into just 1
|
271 |
+
$content = preg_replace('/\n+/', "\n", $content);
|
272 |
+
|
273 |
+
$operatorsBefore = $this->getOperatorsForRegex($this->operatorsBefore, '/');
|
274 |
+
$operatorsAfter = $this->getOperatorsForRegex($this->operatorsAfter, '/');
|
275 |
+
$operators = $this->getOperatorsForRegex($this->operators, '/');
|
276 |
+
$keywordsBefore = $this->getKeywordsForRegex($this->keywordsBefore, '/');
|
277 |
+
$keywordsAfter = $this->getKeywordsForRegex($this->keywordsAfter, '/');
|
278 |
+
|
279 |
+
// strip whitespace that ends in (or next line begin with) an operator
|
280 |
+
// that allows statements to be broken up over multiple lines
|
281 |
+
unset($operatorsBefore['+'], $operatorsBefore['-'], $operatorsAfter['+'], $operatorsAfter['-']);
|
282 |
+
$content = preg_replace(
|
283 |
+
array(
|
284 |
+
'/('.implode('|', $operatorsBefore).')\s+/',
|
285 |
+
'/\s+('.implode('|', $operatorsAfter).')/',
|
286 |
+
), '\\1', $content
|
287 |
+
);
|
288 |
+
|
289 |
+
// make sure + and - can't be mistaken for, or joined into ++ and --
|
290 |
+
$content = preg_replace(
|
291 |
+
array(
|
292 |
+
'/(?<![\+\-])\s*([\+\-])(?![\+\-])/',
|
293 |
+
'/(?<![\+\-])([\+\-])\s*(?![\+\-])/',
|
294 |
+
), '\\1', $content
|
295 |
+
);
|
296 |
+
|
297 |
+
// collapse whitespace around reserved words into single space
|
298 |
+
$content = preg_replace('/(^|[;\}\s])\K('.implode('|', $keywordsBefore).')\s+/', '\\2 ', $content);
|
299 |
+
$content = preg_replace('/\s+('.implode('|', $keywordsAfter).')(?=([;\{\s]|$))/', ' \\1', $content);
|
300 |
+
|
301 |
+
/*
|
302 |
+
* We didn't strip whitespace after a couple of operators because they
|
303 |
+
* could be used in different contexts and we can't be sure it's ok to
|
304 |
+
* strip the newlines. However, we can safely strip any non-line feed
|
305 |
+
* whitespace that follows them.
|
306 |
+
*/
|
307 |
+
$operatorsDiffBefore = array_diff($operators, $operatorsBefore);
|
308 |
+
$operatorsDiffAfter = array_diff($operators, $operatorsAfter);
|
309 |
+
$content = preg_replace('/('.implode('|', $operatorsDiffBefore).')[^\S\n]+/', '\\1', $content);
|
310 |
+
$content = preg_replace('/[^\S\n]+('.implode('|', $operatorsDiffAfter).')/', '\\1', $content);
|
311 |
+
|
312 |
+
/*
|
313 |
+
* Get rid of double semicolons, except where they can be used like:
|
314 |
+
* "for(v=1,_=b;;)", "for(v=1;;v++)" or "for(;;ja||(ja=true))".
|
315 |
+
* I'll safeguard these double semicolons inside for-loops by
|
316 |
+
* temporarily replacing them with an invalid condition: they won't have
|
317 |
+
* a double semicolon and will be easy to spot to restore afterwards.
|
318 |
+
*/
|
319 |
+
$content = preg_replace('/\bfor\(([^;]*);;([^;]*)\)/', 'for(\\1;-;\\2)', $content);
|
320 |
+
$content = preg_replace('/;+/', ';', $content);
|
321 |
+
$content = preg_replace('/\bfor\(([^;]*);-;([^;]*)\)/', 'for(\\1;;\\2)', $content);
|
322 |
+
|
323 |
+
/*
|
324 |
+
* Next, we'll be removing all semicolons where ASI kicks in.
|
325 |
+
* for-loops however, can have an empty body (ending in only a
|
326 |
+
* semicolon), like: `for(i=1;i<3;i++);`, of `for(i in list);`
|
327 |
+
* Here, nothing happens during the loop; it's just used to keep
|
328 |
+
* increasing `i`. With that ; omitted, the next line would be expected
|
329 |
+
* to be the for-loop's body...
|
330 |
+
* I'm going to double that semicolon (if any) so after the next line,
|
331 |
+
* which strips semicolons here & there, we're still left with this one.
|
332 |
+
*/
|
333 |
+
$content = preg_replace('/(for\([^;\{]*;[^;\{]*;[^;\{]*\));(\}|$)/s', '\\1;;\\2', $content);
|
334 |
+
$content = preg_replace('/(for\([^;\{]+\s+in\s+[^;\{]+\));(\}|$)/s', '\\1;;\\2', $content);
|
335 |
+
|
336 |
+
/*
|
337 |
+
* We also can't strip empty else-statements. Even though they're
|
338 |
+
* useless and probably shouldn't be in the code in the first place, we
|
339 |
+
* shouldn't be stripping the `;` that follows it as it breaks the code.
|
340 |
+
* We can just remove those useless else-statements completely.
|
341 |
+
*
|
342 |
+
* @see https://github.com/matthiasmullie/minify/issues/91
|
343 |
+
*/
|
344 |
+
$content = preg_replace('/else;/s', '', $content);
|
345 |
+
|
346 |
+
/*
|
347 |
+
* We also don't really want to terminate statements followed by closing
|
348 |
+
* curly braces (which we've ignored completely up until now) or end-of-
|
349 |
+
* script: ASI will kick in here & we're all about minifying.
|
350 |
+
* Semicolons at beginning of the file don't make any sense either.
|
351 |
+
*/
|
352 |
+
$content = preg_replace('/;(\}|$)/s', '\\1', $content);
|
353 |
+
$content = ltrim($content, ';');
|
354 |
+
|
355 |
+
// get rid of remaining whitespace af beginning/end
|
356 |
+
return trim($content);
|
357 |
+
}
|
358 |
+
|
359 |
+
/**
|
360 |
+
* We'll strip whitespace around certain operators with regular expressions.
|
361 |
+
* This will prepare the given array by escaping all characters.
|
362 |
+
*
|
363 |
+
* @param string[] $operators
|
364 |
+
* @param string $delimiter
|
365 |
+
*
|
366 |
+
* @return string[]
|
367 |
+
*/
|
368 |
+
protected function getOperatorsForRegex(array $operators, $delimiter = '/')
|
369 |
+
{
|
370 |
+
// escape operators for use in regex
|
371 |
+
$delimiters = array_fill(0, count($operators), $delimiter);
|
372 |
+
$escaped = array_map('preg_quote', $operators, $delimiters);
|
373 |
+
|
374 |
+
$operators = array_combine($operators, $escaped);
|
375 |
+
|
376 |
+
// ignore + & - for now, they'll get special treatment
|
377 |
+
unset($operators['+'], $operators['-']);
|
378 |
+
|
379 |
+
// dot can not just immediately follow a number; it can be confused for
|
380 |
+
// decimal point, or calling a method on it, e.g. 42 .toString()
|
381 |
+
$operators['.'] = '(?<![0-9]\s)\.';
|
382 |
+
|
383 |
+
// don't confuse = with other assignment shortcuts (e.g. +=)
|
384 |
+
$chars = preg_quote('+-*\=<>%&|', $delimiter);
|
385 |
+
$operators['='] = '(?<!['.$chars.'])\=';
|
386 |
+
|
387 |
+
return $operators;
|
388 |
+
}
|
389 |
+
|
390 |
+
/**
|
391 |
+
* We'll strip whitespace around certain keywords with regular expressions.
|
392 |
+
* This will prepare the given array by escaping all characters.
|
393 |
+
*
|
394 |
+
* @param string[] $keywords
|
395 |
+
* @param string $delimiter
|
396 |
+
*
|
397 |
+
* @return string[]
|
398 |
+
*/
|
399 |
+
protected function getKeywordsForRegex(array $keywords, $delimiter = '/')
|
400 |
+
{
|
401 |
+
// escape keywords for use in regex
|
402 |
+
$delimiter = array_fill(0, count($keywords), $delimiter);
|
403 |
+
$escaped = array_map('preg_quote', $keywords, $delimiter);
|
404 |
+
|
405 |
+
// add word boundaries
|
406 |
+
array_walk($keywords, function ($value) {
|
407 |
+
return '\b'.$value.'\b';
|
408 |
+
});
|
409 |
+
|
410 |
+
$keywords = array_combine($keywords, $escaped);
|
411 |
+
|
412 |
+
return $keywords;
|
413 |
+
}
|
414 |
+
|
415 |
+
/**
|
416 |
+
* Replaces all occurrences of array['key'] by array.key.
|
417 |
+
*
|
418 |
+
* @param string $content
|
419 |
+
*
|
420 |
+
* @return string
|
421 |
+
*/
|
422 |
+
protected function propertyNotation($content)
|
423 |
+
{
|
424 |
+
// PHP only supports $this inside anonymous functions since 5.4
|
425 |
+
$minifier = $this;
|
426 |
+
$keywords = $this->keywordsReserved;
|
427 |
+
$callback = function ($match) use ($minifier, $keywords) {
|
428 |
+
$property = trim($minifier->extracted[$match[1]], '\'"');
|
429 |
+
|
430 |
+
/*
|
431 |
+
* Check if the property is a reserved keyword. In this context (as
|
432 |
+
* property of an object literal/array) it shouldn't matter, but IE8
|
433 |
+
* freaks out with "Expected identifier".
|
434 |
+
*/
|
435 |
+
if (in_array($property, $keywords)) {
|
436 |
+
return $match[0];
|
437 |
+
}
|
438 |
+
|
439 |
+
/*
|
440 |
+
* See if the property is in a variable-like format (e.g.
|
441 |
+
* array['key-here'] can't be replaced by array.key-here since '-'
|
442 |
+
* is not a valid character there.
|
443 |
+
*/
|
444 |
+
if (!preg_match('/^'.$minifier::REGEX_VARIABLE.'$/u', $property)) {
|
445 |
+
return $match[0];
|
446 |
+
}
|
447 |
+
|
448 |
+
return '.'.$property;
|
449 |
+
};
|
450 |
+
|
451 |
+
/*
|
452 |
+
* Figure out if previous character is a variable name (of the array
|
453 |
+
* we want to use property notation on) - this is to make sure
|
454 |
+
* standalone ['value'] arrays aren't confused for keys-of-an-array.
|
455 |
+
* We can (and only have to) check the last character, because PHP's
|
456 |
+
* regex implementation doesn't allow unfixed-length look-behind
|
457 |
+
* assertions.
|
458 |
+
*/
|
459 |
+
preg_match('/(\[[^\]]+\])[^\]]*$/', static::REGEX_VARIABLE, $previousChar);
|
460 |
+
$previousChar = $previousChar[1];
|
461 |
+
|
462 |
+
/*
|
463 |
+
* Make sure word preceding the ['value'] is not a keyword, e.g.
|
464 |
+
* return['x']. Because -again- PHP's regex implementation doesn't allow
|
465 |
+
* unfixed-length look-behind assertions, I'm just going to do a lot of
|
466 |
+
* separate look-behind assertions, one for each keyword.
|
467 |
+
*/
|
468 |
+
$keywords = $this->getKeywordsForRegex($keywords);
|
469 |
+
$keywords = '(?<!'.implode(')(?<!', $keywords).')';
|
470 |
+
|
471 |
+
return preg_replace_callback('/(?<='.$previousChar.'|\])'.$keywords.'\[\s*(([\'"])[0-9]+\\2)\s*\]/u', $callback, $content);
|
472 |
+
}
|
473 |
+
|
474 |
+
/**
|
475 |
+
* Replaces true & false by !0 and !1.
|
476 |
+
*
|
477 |
+
* @param string $content
|
478 |
+
*
|
479 |
+
* @return string
|
480 |
+
*/
|
481 |
+
protected function shortenBools($content)
|
482 |
+
{
|
483 |
+
/*
|
484 |
+
* 'true' or 'false' could be used as property names (which may be
|
485 |
+
* followed by whitespace) - we must not replace those!
|
486 |
+
* Since PHP doesn't allow variable-length (to account for the
|
487 |
+
* whitespace) lookbehind assertions, I need to capture the leading
|
488 |
+
* character and check if it's a `.`
|
489 |
+
*/
|
490 |
+
$callback = function ($match) {
|
491 |
+
if (trim($match[1]) === '.') {
|
492 |
+
return $match[0];
|
493 |
+
}
|
494 |
+
|
495 |
+
return $match[1].($match[2] === 'true' ? '!0' : '!1');
|
496 |
+
};
|
497 |
+
$content = preg_replace_callback('/(^|.\s*)\b(true|false)\b(?!:)/', $callback, $content);
|
498 |
+
|
499 |
+
// for(;;) is exactly the same as while(true), but shorter :)
|
500 |
+
$content = preg_replace('/\bwhile\(!0\){/', 'for(;;){', $content);
|
501 |
+
|
502 |
+
// now make sure we didn't turn any do ... while(true) into do ... for(;;)
|
503 |
+
preg_match_all('/\bdo\b/', $content, $dos, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
|
504 |
+
|
505 |
+
// go backward to make sure positional offsets aren't altered when $content changes
|
506 |
+
$dos = array_reverse($dos);
|
507 |
+
foreach ($dos as $do) {
|
508 |
+
$offsetDo = $do[0][1];
|
509 |
+
|
510 |
+
// find all `while` (now `for`) following `do`: one of those must be
|
511 |
+
// associated with the `do` and be turned back into `while`
|
512 |
+
preg_match_all('/\bfor\(;;\)/', $content, $whiles, PREG_OFFSET_CAPTURE | PREG_SET_ORDER, $offsetDo);
|
513 |
+
foreach ($whiles as $while) {
|
514 |
+
$offsetWhile = $while[0][1];
|
515 |
+
|
516 |
+
$open = substr_count($content, '{', $offsetDo, $offsetWhile - $offsetDo);
|
517 |
+
$close = substr_count($content, '}', $offsetDo, $offsetWhile - $offsetDo);
|
518 |
+
if ($open === $close) {
|
519 |
+
// only restore `while` if amount of `{` and `}` are the same;
|
520 |
+
// otherwise, that `for` isn't associated with this `do`
|
521 |
+
$content = substr_replace($content, 'while(!0)', $offsetWhile, strlen('for(;;)'));
|
522 |
+
break;
|
523 |
+
}
|
524 |
+
}
|
525 |
+
}
|
526 |
+
|
527 |
+
return $content;
|
528 |
+
}
|
529 |
+
}
|
libs/matthiasmullie/minify/src/Minify.php
ADDED
@@ -0,0 +1,434 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\Minify;
|
4 |
+
|
5 |
+
use MatthiasMullie\Minify\Exceptions\IOException;
|
6 |
+
use Psr\Cache\CacheItemInterface;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Abstract minifier class.
|
10 |
+
*
|
11 |
+
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
12 |
+
*
|
13 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
14 |
+
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
15 |
+
* @license MIT License
|
16 |
+
*/
|
17 |
+
abstract class Minify
|
18 |
+
{
|
19 |
+
/**
|
20 |
+
* The data to be minified.
|
21 |
+
*
|
22 |
+
* @var string[]
|
23 |
+
*/
|
24 |
+
protected $data = array();
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Array of patterns to match.
|
28 |
+
*
|
29 |
+
* @var string[]
|
30 |
+
*/
|
31 |
+
protected $patterns = array();
|
32 |
+
|
33 |
+
/**
|
34 |
+
* This array will hold content of strings and regular expressions that have
|
35 |
+
* been extracted from the JS source code, so we can reliably match "code",
|
36 |
+
* without having to worry about potential "code-like" characters inside.
|
37 |
+
*
|
38 |
+
* @var string[]
|
39 |
+
*/
|
40 |
+
public $extracted = array();
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Init the minify class - optionally, code may be passed along already.
|
44 |
+
*/
|
45 |
+
public function __construct(/* $data = null, ... */)
|
46 |
+
{
|
47 |
+
// it's possible to add the source through the constructor as well ;)
|
48 |
+
if (func_num_args()) {
|
49 |
+
call_user_func_array(array($this, 'add'), func_get_args());
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Add a file or straight-up code to be minified.
|
55 |
+
*
|
56 |
+
* @param string|string[] $data
|
57 |
+
*
|
58 |
+
* @return static
|
59 |
+
*/
|
60 |
+
public function add($data /* $data = null, ... */)
|
61 |
+
{
|
62 |
+
// bogus "usage" of parameter $data: scrutinizer warns this variable is
|
63 |
+
// not used (we're using func_get_args instead to support overloading),
|
64 |
+
// but it still needs to be defined because it makes no sense to have
|
65 |
+
// this function without argument :)
|
66 |
+
$args = array($data) + func_get_args();
|
67 |
+
|
68 |
+
// this method can be overloaded
|
69 |
+
foreach ($args as $data) {
|
70 |
+
if (is_array($data)) {
|
71 |
+
call_user_func_array(array($this, 'add'), $data);
|
72 |
+
continue;
|
73 |
+
}
|
74 |
+
|
75 |
+
// redefine var
|
76 |
+
$data = (string) $data;
|
77 |
+
|
78 |
+
// load data
|
79 |
+
$value = $this->load($data);
|
80 |
+
$key = ($data != $value) ? $data : count($this->data);
|
81 |
+
|
82 |
+
// replace CR linefeeds etc.
|
83 |
+
// @see https://github.com/matthiasmullie/minify/pull/139
|
84 |
+
$value = str_replace(array("\r\n", "\r"), "\n", $value);
|
85 |
+
|
86 |
+
// store data
|
87 |
+
$this->data[$key] = $value;
|
88 |
+
}
|
89 |
+
|
90 |
+
return $this;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Minify the data & (optionally) saves it to a file.
|
95 |
+
*
|
96 |
+
* @param string[optional] $path Path to write the data to
|
97 |
+
*
|
98 |
+
* @return string The minified data
|
99 |
+
*/
|
100 |
+
public function minify($path = null)
|
101 |
+
{
|
102 |
+
$content = $this->execute($path);
|
103 |
+
|
104 |
+
// save to path
|
105 |
+
if ($path !== null) {
|
106 |
+
$this->save($content, $path);
|
107 |
+
}
|
108 |
+
|
109 |
+
return $content;
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Minify & gzip the data & (optionally) saves it to a file.
|
114 |
+
*
|
115 |
+
* @param string[optional] $path Path to write the data to
|
116 |
+
* @param int[optional] $level Compression level, from 0 to 9
|
117 |
+
*
|
118 |
+
* @return string The minified & gzipped data
|
119 |
+
*/
|
120 |
+
public function gzip($path = null, $level = 9)
|
121 |
+
{
|
122 |
+
$content = $this->execute($path);
|
123 |
+
$content = gzencode($content, $level, FORCE_GZIP);
|
124 |
+
|
125 |
+
// save to path
|
126 |
+
if ($path !== null) {
|
127 |
+
$this->save($content, $path);
|
128 |
+
}
|
129 |
+
|
130 |
+
return $content;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Minify the data & write it to a CacheItemInterface object.
|
135 |
+
*
|
136 |
+
* @param CacheItemInterface $item Cache item to write the data to
|
137 |
+
*
|
138 |
+
* @return CacheItemInterface Cache item with the minifier data
|
139 |
+
*/
|
140 |
+
public function cache(CacheItemInterface $item)
|
141 |
+
{
|
142 |
+
$content = $this->execute();
|
143 |
+
$item->set($content);
|
144 |
+
|
145 |
+
return $item;
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Minify the data.
|
150 |
+
*
|
151 |
+
* @param string[optional] $path Path to write the data to
|
152 |
+
*
|
153 |
+
* @return string The minified data
|
154 |
+
*/
|
155 |
+
abstract public function execute($path = null);
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Load data.
|
159 |
+
*
|
160 |
+
* @param string $data Either a path to a file or the content itself
|
161 |
+
*
|
162 |
+
* @return string
|
163 |
+
*/
|
164 |
+
protected function load($data)
|
165 |
+
{
|
166 |
+
// check if the data is a file
|
167 |
+
if ($this->canImportFile($data)) {
|
168 |
+
$data = file_get_contents($data);
|
169 |
+
|
170 |
+
// strip BOM, if any
|
171 |
+
if (substr($data, 0, 3) == "\xef\xbb\xbf") {
|
172 |
+
$data = substr($data, 3);
|
173 |
+
}
|
174 |
+
}
|
175 |
+
|
176 |
+
return $data;
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Save to file.
|
181 |
+
*
|
182 |
+
* @param string $content The minified data
|
183 |
+
* @param string $path The path to save the minified data to
|
184 |
+
*
|
185 |
+
* @throws IOException
|
186 |
+
*/
|
187 |
+
protected function save($content, $path)
|
188 |
+
{
|
189 |
+
$handler = $this->openFileForWriting($path);
|
190 |
+
|
191 |
+
$this->writeToFile($handler, $content);
|
192 |
+
|
193 |
+
@fclose($handler);
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Register a pattern to execute against the source content.
|
198 |
+
*
|
199 |
+
* @param string $pattern PCRE pattern
|
200 |
+
* @param string|callable $replacement Replacement value for matched pattern
|
201 |
+
*/
|
202 |
+
protected function registerPattern($pattern, $replacement = '')
|
203 |
+
{
|
204 |
+
// study the pattern, we'll execute it more than once
|
205 |
+
$pattern .= 'S';
|
206 |
+
|
207 |
+
$this->patterns[] = array($pattern, $replacement);
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* We can't "just" run some regular expressions against JavaScript: it's a
|
212 |
+
* complex language. E.g. having an occurrence of // xyz would be a comment,
|
213 |
+
* unless it's used within a string. Of you could have something that looks
|
214 |
+
* like a 'string', but inside a comment.
|
215 |
+
* The only way to accurately replace these pieces is to traverse the JS one
|
216 |
+
* character at a time and try to find whatever starts first.
|
217 |
+
*
|
218 |
+
* @param string $content The content to replace patterns in
|
219 |
+
*
|
220 |
+
* @return string The (manipulated) content
|
221 |
+
*/
|
222 |
+
protected function replace($content)
|
223 |
+
{
|
224 |
+
$processed = '';
|
225 |
+
$positions = array_fill(0, count($this->patterns), -1);
|
226 |
+
$matches = array();
|
227 |
+
|
228 |
+
while ($content) {
|
229 |
+
// find first match for all patterns
|
230 |
+
foreach ($this->patterns as $i => $pattern) {
|
231 |
+
list($pattern, $replacement) = $pattern;
|
232 |
+
|
233 |
+
// no need to re-run matches that are still in the part of the
|
234 |
+
// content that hasn't been processed
|
235 |
+
if ($positions[$i] >= 0) {
|
236 |
+
continue;
|
237 |
+
}
|
238 |
+
|
239 |
+
$match = null;
|
240 |
+
if (preg_match($pattern, $content, $match)) {
|
241 |
+
$matches[$i] = $match;
|
242 |
+
|
243 |
+
// we'll store the match position as well; that way, we
|
244 |
+
// don't have to redo all preg_matches after changing only
|
245 |
+
// the first (we'll still know where those others are)
|
246 |
+
$positions[$i] = strpos($content, $match[0]);
|
247 |
+
} else {
|
248 |
+
// if the pattern couldn't be matched, there's no point in
|
249 |
+
// executing it again in later runs on this same content;
|
250 |
+
// ignore this one until we reach end of content
|
251 |
+
unset($matches[$i]);
|
252 |
+
$positions[$i] = strlen($content);
|
253 |
+
}
|
254 |
+
}
|
255 |
+
|
256 |
+
// no more matches to find: everything's been processed, break out
|
257 |
+
if (!$matches) {
|
258 |
+
$processed .= $content;
|
259 |
+
break;
|
260 |
+
}
|
261 |
+
|
262 |
+
// see which of the patterns actually found the first thing (we'll
|
263 |
+
// only want to execute that one, since we're unsure if what the
|
264 |
+
// other found was not inside what the first found)
|
265 |
+
$discardLength = min($positions);
|
266 |
+
$firstPattern = array_search($discardLength, $positions);
|
267 |
+
$match = $matches[$firstPattern][0];
|
268 |
+
|
269 |
+
// execute the pattern that matches earliest in the content string
|
270 |
+
list($pattern, $replacement) = $this->patterns[$firstPattern];
|
271 |
+
$replacement = $this->replacePattern($pattern, $replacement, $content);
|
272 |
+
|
273 |
+
// figure out which part of the string was unmatched; that's the
|
274 |
+
// part we'll execute the patterns on again next
|
275 |
+
$content = substr($content, $discardLength);
|
276 |
+
$unmatched = (string) substr($content, strpos($content, $match) + strlen($match));
|
277 |
+
|
278 |
+
// move the replaced part to $processed and prepare $content to
|
279 |
+
// again match batch of patterns against
|
280 |
+
$processed .= substr($replacement, 0, strlen($replacement) - strlen($unmatched));
|
281 |
+
$content = $unmatched;
|
282 |
+
|
283 |
+
// first match has been replaced & that content is to be left alone,
|
284 |
+
// the next matches will start after this replacement, so we should
|
285 |
+
// fix their offsets
|
286 |
+
foreach ($positions as $i => $position) {
|
287 |
+
$positions[$i] -= $discardLength + strlen($match);
|
288 |
+
}
|
289 |
+
}
|
290 |
+
|
291 |
+
return $processed;
|
292 |
+
}
|
293 |
+
|
294 |
+
/**
|
295 |
+
* This is where a pattern is matched against $content and the matches
|
296 |
+
* are replaced by their respective value.
|
297 |
+
* This function will be called plenty of times, where $content will always
|
298 |
+
* move up 1 character.
|
299 |
+
*
|
300 |
+
* @param string $pattern Pattern to match
|
301 |
+
* @param string|callable $replacement Replacement value
|
302 |
+
* @param string $content Content to match pattern against
|
303 |
+
*
|
304 |
+
* @return string
|
305 |
+
*/
|
306 |
+
protected function replacePattern($pattern, $replacement, $content)
|
307 |
+
{
|
308 |
+
if (is_callable($replacement)) {
|
309 |
+
return preg_replace_callback($pattern, $replacement, $content, 1, $count);
|
310 |
+
} else {
|
311 |
+
return preg_replace($pattern, $replacement, $content, 1, $count);
|
312 |
+
}
|
313 |
+
}
|
314 |
+
|
315 |
+
/**
|
316 |
+
* Strings are a pattern we need to match, in order to ignore potential
|
317 |
+
* code-like content inside them, but we just want all of the string
|
318 |
+
* content to remain untouched.
|
319 |
+
*
|
320 |
+
* This method will replace all string content with simple STRING#
|
321 |
+
* placeholder text, so we've rid all strings from characters that may be
|
322 |
+
* misinterpreted. Original string content will be saved in $this->extracted
|
323 |
+
* and after doing all other minifying, we can restore the original content
|
324 |
+
* via restoreStrings().
|
325 |
+
*
|
326 |
+
* @param string[optional] $chars
|
327 |
+
*/
|
328 |
+
protected function extractStrings($chars = '\'"')
|
329 |
+
{
|
330 |
+
// PHP only supports $this inside anonymous functions since 5.4
|
331 |
+
$minifier = $this;
|
332 |
+
$callback = function ($match) use ($minifier) {
|
333 |
+
// check the second index here, because the first always contains a quote
|
334 |
+
if ($match[2] === '') {
|
335 |
+
/*
|
336 |
+
* Empty strings need no placeholder; they can't be confused for
|
337 |
+
* anything else anyway.
|
338 |
+
* But we still needed to match them, for the extraction routine
|
339 |
+
* to skip over this particular string.
|
340 |
+
*/
|
341 |
+
return $match[0];
|
342 |
+
}
|
343 |
+
|
344 |
+
$count = count($minifier->extracted);
|
345 |
+
$placeholder = $match[1].$count.$match[1];
|
346 |
+
$minifier->extracted[$placeholder] = $match[1].$match[2].$match[1];
|
347 |
+
|
348 |
+
return $placeholder;
|
349 |
+
};
|
350 |
+
|
351 |
+
/*
|
352 |
+
* The \\ messiness explained:
|
353 |
+
* * Don't count ' or " as end-of-string if it's escaped (has backslash
|
354 |
+
* in front of it)
|
355 |
+
* * Unless... that backslash itself is escaped (another leading slash),
|
356 |
+
* in which case it's no longer escaping the ' or "
|
357 |
+
* * So there can be either no backslash, or an even number
|
358 |
+
* * multiply all of that times 4, to account for the escaping that has
|
359 |
+
* to be done to pass the backslash into the PHP string without it being
|
360 |
+
* considered as escape-char (times 2) and to get it in the regex,
|
361 |
+
* escaped (times 2)
|
362 |
+
*/
|
363 |
+
$this->registerPattern('/(['.$chars.'])(.*?(?<!\\\\)(\\\\\\\\)*+)\\1/s', $callback);
|
364 |
+
}
|
365 |
+
|
366 |
+
/**
|
367 |
+
* This method will restore all extracted data (strings, regexes) that were
|
368 |
+
* replaced with placeholder text in extract*(). The original content was
|
369 |
+
* saved in $this->extracted.
|
370 |
+
*
|
371 |
+
* @param string $content
|
372 |
+
*
|
373 |
+
* @return string
|
374 |
+
*/
|
375 |
+
protected function restoreExtractedData($content)
|
376 |
+
{
|
377 |
+
if (!$this->extracted) {
|
378 |
+
// nothing was extracted, nothing to restore
|
379 |
+
return $content;
|
380 |
+
}
|
381 |
+
|
382 |
+
$content = strtr($content, $this->extracted);
|
383 |
+
|
384 |
+
$this->extracted = array();
|
385 |
+
|
386 |
+
return $content;
|
387 |
+
}
|
388 |
+
|
389 |
+
/**
|
390 |
+
* Check if the path is a regular file and can be read.
|
391 |
+
*
|
392 |
+
* @param string $path
|
393 |
+
*
|
394 |
+
* @return bool
|
395 |
+
*/
|
396 |
+
protected function canImportFile($path)
|
397 |
+
{
|
398 |
+
return strlen($path) < PHP_MAXPATHLEN && @is_file($path) && is_readable($path);
|
399 |
+
}
|
400 |
+
|
401 |
+
/**
|
402 |
+
* Attempts to open file specified by $path for writing.
|
403 |
+
*
|
404 |
+
* @param string $path The path to the file
|
405 |
+
*
|
406 |
+
* @return resource Specifier for the target file
|
407 |
+
*
|
408 |
+
* @throws IOException
|
409 |
+
*/
|
410 |
+
protected function openFileForWriting($path)
|
411 |
+
{
|
412 |
+
if (($handler = @fopen($path, 'w')) === false) {
|
413 |
+
throw new IOException('The file "'.$path.'" could not be opened for writing. Check if PHP has enough permissions.');
|
414 |
+
}
|
415 |
+
|
416 |
+
return $handler;
|
417 |
+
}
|
418 |
+
|
419 |
+
/**
|
420 |
+
* Attempts to write $content to the file specified by $handler. $path is used for printing exceptions.
|
421 |
+
*
|
422 |
+
* @param resource $handler The resource to write to
|
423 |
+
* @param string $content The content to write
|
424 |
+
* @param string $path The path to the file (for exception printing only)
|
425 |
+
*
|
426 |
+
* @throws IOException
|
427 |
+
*/
|
428 |
+
protected function writeToFile($handler, $content, $path = '')
|
429 |
+
{
|
430 |
+
if (($result = @fwrite($handler, $content)) === false || ($result < strlen($content))) {
|
431 |
+
throw new IOException('The file "'.$path.'" could not be written to. Check your disk space and file permissions.');
|
432 |
+
}
|
433 |
+
}
|
434 |
+
}
|
libs/matthiasmullie/minify/src/index.html
ADDED
File without changes
|
libs/matthiasmullie/path-converter/index.html
ADDED
File without changes
|
libs/matthiasmullie/path-converter/src/Converter.php
ADDED
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\PathConverter;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Convert paths relative from 1 file to another.
|
7 |
+
*
|
8 |
+
* E.g.
|
9 |
+
* ../../images/icon.jpg relative to /css/imports/icons.css
|
10 |
+
* becomes
|
11 |
+
* ../images/icon.jpg relative to /css/minified.css
|
12 |
+
*
|
13 |
+
* Please report bugs on https://github.com/matthiasmullie/path-converter/issues
|
14 |
+
*
|
15 |
+
* @author Matthias Mullie <pathconverter@mullie.eu>
|
16 |
+
* @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
|
17 |
+
* @license MIT License
|
18 |
+
*/
|
19 |
+
class Converter implements ConverterInterface
|
20 |
+
{
|
21 |
+
/**
|
22 |
+
* @var string
|
23 |
+
*/
|
24 |
+
protected $from;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @var string
|
28 |
+
*/
|
29 |
+
protected $to;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @param string $from The original base path (directory, not file!)
|
33 |
+
* @param string $to The new base path (directory, not file!)
|
34 |
+
*/
|
35 |
+
public function __construct($from, $to)
|
36 |
+
{
|
37 |
+
$shared = $this->shared($from, $to);
|
38 |
+
if ($shared === '') {
|
39 |
+
// when both paths have nothing in common, one of them is probably
|
40 |
+
// absolute while the other is relative
|
41 |
+
$cwd = getcwd();
|
42 |
+
$from = strpos($from, $cwd) === 0 ? $from : $cwd.'/'.$from;
|
43 |
+
$to = strpos($to, $cwd) === 0 ? $to : $cwd.'/'.$to;
|
44 |
+
|
45 |
+
// or traveling the tree via `..`
|
46 |
+
// attempt to resolve path, or assume it's fine if it doesn't exist
|
47 |
+
$from = realpath($from) ?: $from;
|
48 |
+
$to = realpath($to) ?: $to;
|
49 |
+
}
|
50 |
+
|
51 |
+
$from = $this->dirname($from);
|
52 |
+
$to = $this->dirname($to);
|
53 |
+
|
54 |
+
$from = $this->normalize($from);
|
55 |
+
$to = $this->normalize($to);
|
56 |
+
|
57 |
+
$this->from = $from;
|
58 |
+
$this->to = $to;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Normalize path.
|
63 |
+
*
|
64 |
+
* @param string $path
|
65 |
+
*
|
66 |
+
* @return string
|
67 |
+
*/
|
68 |
+
protected function normalize($path)
|
69 |
+
{
|
70 |
+
// deal with different operating systems' directory structure
|
71 |
+
$path = rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $path), '/');
|
72 |
+
|
73 |
+
/*
|
74 |
+
* Example:
|
75 |
+
* /home/forkcms/frontend/cache/compiled_templates/../../core/layout/css/../images/img.gif
|
76 |
+
* to
|
77 |
+
* /home/forkcms/frontend/core/layout/images/img.gif
|
78 |
+
*/
|
79 |
+
do {
|
80 |
+
$path = preg_replace('/[^\/]+(?<!\.\.)\/\.\.\//', '', $path, -1, $count);
|
81 |
+
} while ($count);
|
82 |
+
|
83 |
+
return $path;
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Figure out the shared path of 2 locations.
|
88 |
+
*
|
89 |
+
* Example:
|
90 |
+
* /home/forkcms/frontend/core/layout/images/img.gif
|
91 |
+
* and
|
92 |
+
* /home/forkcms/frontend/cache/minified_css
|
93 |
+
* share
|
94 |
+
* /home/forkcms/frontend
|
95 |
+
*
|
96 |
+
* @param string $path1
|
97 |
+
* @param string $path2
|
98 |
+
*
|
99 |
+
* @return string
|
100 |
+
*/
|
101 |
+
protected function shared($path1, $path2)
|
102 |
+
{
|
103 |
+
// $path could theoretically be empty (e.g. no path is given), in which
|
104 |
+
// case it shouldn't expand to array(''), which would compare to one's
|
105 |
+
// root /
|
106 |
+
$path1 = $path1 ? explode('/', $path1) : array();
|
107 |
+
$path2 = $path2 ? explode('/', $path2) : array();
|
108 |
+
|
109 |
+
$shared = array();
|
110 |
+
|
111 |
+
// compare paths & strip identical ancestors
|
112 |
+
foreach ($path1 as $i => $chunk) {
|
113 |
+
if (isset($path2[$i]) && $path1[$i] == $path2[$i]) {
|
114 |
+
$shared[] = $chunk;
|
115 |
+
} else {
|
116 |
+
break;
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
return implode('/', $shared);
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* Convert paths relative from 1 file to another.
|
125 |
+
*
|
126 |
+
* E.g.
|
127 |
+
* ../images/img.gif relative to /home/forkcms/frontend/core/layout/css
|
128 |
+
* should become:
|
129 |
+
* ../../core/layout/images/img.gif relative to
|
130 |
+
* /home/forkcms/frontend/cache/minified_css
|
131 |
+
*
|
132 |
+
* @param string $path The relative path that needs to be converted
|
133 |
+
*
|
134 |
+
* @return string The new relative path
|
135 |
+
*/
|
136 |
+
public function convert($path)
|
137 |
+
{
|
138 |
+
// quit early if conversion makes no sense
|
139 |
+
if ($this->from === $this->to) {
|
140 |
+
return $path;
|
141 |
+
}
|
142 |
+
|
143 |
+
$path = $this->normalize($path);
|
144 |
+
// if we're not dealing with a relative path, just return absolute
|
145 |
+
if (strpos($path, '/') === 0) {
|
146 |
+
return $path;
|
147 |
+
}
|
148 |
+
|
149 |
+
// normalize paths
|
150 |
+
$path = $this->normalize($this->from.'/'.$path);
|
151 |
+
|
152 |
+
// strip shared ancestor paths
|
153 |
+
$shared = $this->shared($path, $this->to);
|
154 |
+
$path = mb_substr($path, mb_strlen($shared));
|
155 |
+
$to = mb_substr($this->to, mb_strlen($shared));
|
156 |
+
|
157 |
+
// add .. for every directory that needs to be traversed to new path
|
158 |
+
$to = str_repeat('../', mb_substr_count($to, '/'));
|
159 |
+
|
160 |
+
return $to.ltrim($path, '/');
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Attempt to get the directory name from a path.
|
165 |
+
*
|
166 |
+
* @param string $path
|
167 |
+
*
|
168 |
+
* @return string
|
169 |
+
*/
|
170 |
+
protected function dirname($path)
|
171 |
+
{
|
172 |
+
if (is_file($path)) {
|
173 |
+
return dirname($path);
|
174 |
+
}
|
175 |
+
|
176 |
+
if (is_dir($path)) {
|
177 |
+
return rtrim($path, '/');
|
178 |
+
}
|
179 |
+
|
180 |
+
// no known file/dir, start making assumptions
|
181 |
+
|
182 |
+
// ends in / = dir
|
183 |
+
if (mb_substr($path, -1) === '/') {
|
184 |
+
return rtrim($path, '/');
|
185 |
+
}
|
186 |
+
|
187 |
+
// has a dot in the name, likely a file
|
188 |
+
if (preg_match('/.*\..*$/', basename($path)) !== 0) {
|
189 |
+
return dirname($path);
|
190 |
+
}
|
191 |
+
|
192 |
+
// you're on your own here!
|
193 |
+
return $path;
|
194 |
+
}
|
195 |
+
}
|
libs/matthiasmullie/path-converter/src/ConverterInterface.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\PathConverter;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Convert file paths.
|
7 |
+
*
|
8 |
+
* Please report bugs on https://github.com/matthiasmullie/path-converter/issues
|
9 |
+
*
|
10 |
+
* @author Matthias Mullie <pathconverter@mullie.eu>
|
11 |
+
* @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
|
12 |
+
* @license MIT License
|
13 |
+
*/
|
14 |
+
interface ConverterInterface
|
15 |
+
{
|
16 |
+
/**
|
17 |
+
* Convert file paths.
|
18 |
+
*
|
19 |
+
* @param string $path The path to be converted
|
20 |
+
*
|
21 |
+
* @return string The new path
|
22 |
+
*/
|
23 |
+
public function convert($path);
|
24 |
+
}
|
libs/matthiasmullie/path-converter/src/NoConverter.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\PathConverter;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Don't convert paths.
|
7 |
+
*
|
8 |
+
* Please report bugs on https://github.com/matthiasmullie/path-converter/issues
|
9 |
+
*
|
10 |
+
* @author Matthias Mullie <pathconverter@mullie.eu>
|
11 |
+
* @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
|
12 |
+
* @license MIT License
|
13 |
+
*/
|
14 |
+
class NoConverter implements ConverterInterface
|
15 |
+
{
|
16 |
+
/**
|
17 |
+
* {@inheritdoc}
|
18 |
+
*/
|
19 |
+
public function convert($path)
|
20 |
+
{
|
21 |
+
return $path;
|
22 |
+
}
|
23 |
+
}
|
libs/matthiasmullie/path-converter/src/index.html
ADDED
File without changes
|
libs/mrclay/HTML.php
ADDED
@@ -0,0 +1,241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/* https://github.com/mrclay/minify/blob/2.x/min/lib/Minify/HTML.php - same as WP ROCKET v2.91 + custom changes */
|
4 |
+
# line:
|
5 |
+
|
6 |
+
class fastvelocity_min_Minify_HTML {
|
7 |
+
protected $_jsCleanComments = true;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* "Minify" an HTML page
|
11 |
+
*
|
12 |
+
* @param string $html
|
13 |
+
*
|
14 |
+
* @param array $options
|
15 |
+
*
|
16 |
+
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
17 |
+
* elements.
|
18 |
+
*
|
19 |
+
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
20 |
+
* elements. Note: the type attribute is ignored.
|
21 |
+
*
|
22 |
+
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
23 |
+
* unset, minify will sniff for an XHTML doctype.
|
24 |
+
*
|
25 |
+
* @return string
|
26 |
+
*/
|
27 |
+
public static function minify($html, $options = array()) {
|
28 |
+
$min = new self($html, $options);
|
29 |
+
return $min->process();
|
30 |
+
}
|
31 |
+
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Create a minifier object
|
35 |
+
*
|
36 |
+
* @param string $html
|
37 |
+
*
|
38 |
+
* @param array $options
|
39 |
+
*
|
40 |
+
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
41 |
+
* elements.
|
42 |
+
*
|
43 |
+
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
44 |
+
* elements. Note: the type attribute is ignored.
|
45 |
+
*
|
46 |
+
* 'jsCleanComments' : (optional) whether to remove HTML comments beginning and end of script block
|
47 |
+
*
|
48 |
+
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
49 |
+
* unset, minify will sniff for an XHTML doctype.
|
50 |
+
*/
|
51 |
+
public function __construct($html, $options = array())
|
52 |
+
{
|
53 |
+
$this->_html = str_replace("\r\n", "\n", trim($html));
|
54 |
+
if (isset($options['xhtml'])) {
|
55 |
+
$this->_isXhtml = (bool)$options['xhtml'];
|
56 |
+
}
|
57 |
+
if (isset($options['cssMinifier'])) {
|
58 |
+
$this->_cssMinifier = $options['cssMinifier'];
|
59 |
+
}
|
60 |
+
if (isset($options['jsMinifier'])) {
|
61 |
+
$this->_jsMinifier = $options['jsMinifier'];
|
62 |
+
}
|
63 |
+
if (isset($options['jsCleanComments'])) {
|
64 |
+
$this->_jsCleanComments = (bool)$options['jsCleanComments'];
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Minify the markeup given in the constructor
|
71 |
+
*
|
72 |
+
* @return string
|
73 |
+
*/
|
74 |
+
public function process()
|
75 |
+
{
|
76 |
+
if ($this->_isXhtml === null) {
|
77 |
+
$this->_isXhtml = (false !== strpos($this->_html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML'));
|
78 |
+
}
|
79 |
+
|
80 |
+
$this->_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']);
|
81 |
+
$this->_placeholders = array();
|
82 |
+
|
83 |
+
// replace SCRIPTs (and minify) with placeholders
|
84 |
+
$this->_html = preg_replace_callback(
|
85 |
+
'/(\\s*)<script(\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i'
|
86 |
+
,array($this, '_removeScriptCB')
|
87 |
+
,$this->_html);
|
88 |
+
|
89 |
+
// replace STYLEs (and minify) with placeholders
|
90 |
+
$this->_html = preg_replace_callback(
|
91 |
+
'/\\s*<style(\\b[^>]*>)([\\s\\S]*?)<\\/style>\\s*/i'
|
92 |
+
,array($this, '_removeStyleCB')
|
93 |
+
,$this->_html);
|
94 |
+
|
95 |
+
// remove HTML comments (not containing IE conditional comments).
|
96 |
+
global $strip_htmlcomments;
|
97 |
+
if($strip_htmlcomments) {
|
98 |
+
$this->_html = preg_replace_callback('/<!--([\\s\\S]*?)-->/' ,array($this, '_commentCB') ,$this->_html);
|
99 |
+
}
|
100 |
+
|
101 |
+
// replace PREs with placeholders
|
102 |
+
$this->_html = preg_replace_callback('/\\s*<pre(\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
|
103 |
+
,array($this, '_removePreCB')
|
104 |
+
,$this->_html);
|
105 |
+
|
106 |
+
// replace TEXTAREAs with placeholders
|
107 |
+
$this->_html = preg_replace_callback(
|
108 |
+
'/\\s*<textarea(\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
|
109 |
+
,array($this, '_removeTextareaCB')
|
110 |
+
,$this->_html);
|
111 |
+
|
112 |
+
// trim each line.
|
113 |
+
// @todo take into account attribute values that span multiple lines.
|
114 |
+
$this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html);
|
115 |
+
|
116 |
+
// remove ws around block/undisplayed elements
|
117 |
+
$this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body'
|
118 |
+
.'|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form'
|
119 |
+
.'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta'
|
120 |
+
.'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)'
|
121 |
+
.'|ul)\\b[^>]*>)/i', '$1', $this->_html);
|
122 |
+
|
123 |
+
// remove ws outside of all elements
|
124 |
+
$this->_html = preg_replace_callback(
|
125 |
+
'/>([^<]+)</'
|
126 |
+
,array($this, '_outsideTagCB')
|
127 |
+
,$this->_html);
|
128 |
+
|
129 |
+
// use newlines before 1st attribute in open tags (to limit line lengths)
|
130 |
+
//$this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html);
|
131 |
+
|
132 |
+
// fill placeholders
|
133 |
+
$this->_html = str_replace(
|
134 |
+
array_keys($this->_placeholders)
|
135 |
+
,array_values($this->_placeholders)
|
136 |
+
,$this->_html
|
137 |
+
);
|
138 |
+
// issue 229: multi-pass to catch scripts that didn't get replaced in textareas
|
139 |
+
$this->_html = str_replace(
|
140 |
+
array_keys($this->_placeholders)
|
141 |
+
,array_values($this->_placeholders)
|
142 |
+
,$this->_html
|
143 |
+
);
|
144 |
+
return $this->_html;
|
145 |
+
}
|
146 |
+
|
147 |
+
protected function _commentCB($m)
|
148 |
+
{
|
149 |
+
return (0 === strpos($m[1], '[') || false !== strpos($m[1], '<![') || 0 === strpos($m[1], 'esi')) ? $m[0] : '';
|
150 |
+
}
|
151 |
+
|
152 |
+
protected function _reservePlace($content)
|
153 |
+
{
|
154 |
+
$placeholder = '%' . $this->_replacementHash . count($this->_placeholders) . '%';
|
155 |
+
$this->_placeholders[$placeholder] = $content;
|
156 |
+
return $placeholder;
|
157 |
+
}
|
158 |
+
|
159 |
+
protected $_isXhtml = null;
|
160 |
+
protected $_replacementHash = null;
|
161 |
+
protected $_placeholders = array();
|
162 |
+
protected $_cssMinifier = null;
|
163 |
+
protected $_jsMinifier = null;
|
164 |
+
|
165 |
+
protected function _outsideTagCB($m)
|
166 |
+
{
|
167 |
+
return '>' . preg_replace('/^\\s+|\\s+$/', ' ', $m[1]) . '<';
|
168 |
+
}
|
169 |
+
|
170 |
+
protected function _removePreCB($m)
|
171 |
+
{
|
172 |
+
return $this->_reservePlace("<pre{$m[1]}");
|
173 |
+
}
|
174 |
+
|
175 |
+
protected function _removeTextareaCB($m)
|
176 |
+
{
|
177 |
+
return $this->_reservePlace("<textarea{$m[1]}");
|
178 |
+
}
|
179 |
+
|
180 |
+
protected function _removeStyleCB($m)
|
181 |
+
{
|
182 |
+
$openStyle = "<style{$m[1]}";
|
183 |
+
$css = $m[2];
|
184 |
+
// remove css comments
|
185 |
+
$css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
|
186 |
+
|
187 |
+
// remove CDATA section markers
|
188 |
+
$css = $this->_removeCdata($css);
|
189 |
+
|
190 |
+
// minify
|
191 |
+
$minifier = $this->_cssMinifier ? $this->_cssMinifier : 'trim';
|
192 |
+
$css = call_user_func($minifier, $css);
|
193 |
+
$css = preg_replace('/\s+/', ' ', $css);
|
194 |
+
|
195 |
+
return $this->_reservePlace($this->_needsCdata($css)
|
196 |
+
? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
|
197 |
+
: "{$openStyle}{$css}</style>"
|
198 |
+
);
|
199 |
+
}
|
200 |
+
|
201 |
+
protected function _removeScriptCB($m)
|
202 |
+
{
|
203 |
+
$openScript = "<script{$m[2]}";
|
204 |
+
$js = $m[3];
|
205 |
+
|
206 |
+
// whitespace surrounding? preserve at least one space
|
207 |
+
$ws1 = ($m[1] === '') ? '' : ' ';
|
208 |
+
$ws2 = ($m[4] === '') ? '' : ' ';
|
209 |
+
|
210 |
+
// remove HTML comments (and ending "//" if present)
|
211 |
+
if ($this->_jsCleanComments) {
|
212 |
+
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
|
213 |
+
}
|
214 |
+
|
215 |
+
// remove CDATA section markers
|
216 |
+
$js = $this->_removeCdata($js);
|
217 |
+
|
218 |
+
// minify
|
219 |
+
$minifier = $this->_jsMinifier
|
220 |
+
? $this->_jsMinifier
|
221 |
+
: 'trim';
|
222 |
+
$js = call_user_func($minifier, $js);
|
223 |
+
|
224 |
+
return $this->_reservePlace($this->_needsCdata($js)
|
225 |
+
? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}"
|
226 |
+
: "{$ws1}{$openScript}{$js}</script>{$ws2}"
|
227 |
+
);
|
228 |
+
}
|
229 |
+
|
230 |
+
protected function _removeCdata($str)
|
231 |
+
{
|
232 |
+
return (false !== strpos($str, '<![CDATA['))
|
233 |
+
? str_replace(array('<![CDATA[', ']]>'), '', $str)
|
234 |
+
: $str;
|
235 |
+
}
|
236 |
+
|
237 |
+
protected function _needsCdata($str)
|
238 |
+
{
|
239 |
+
return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
|
240 |
+
}
|
241 |
+
}
|
libs/mrclay/index.html
ADDED
File without changes
|
readme.txt
ADDED
@@ -0,0 +1,365 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Fast Velocity Minify ===
|
2 |
+
Contributors: Alignak
|
3 |
+
Tags: merge, combine, concatenate, PHP Minify, YUI Compressor, CSS, javascript, JS, minification, minify, optimization, optimize, stylesheet, aggregate, cache, CSS, html, minimize, pagespeed, performance, speed, GTmetrix, pingdom
|
4 |
+
Requires at least: 4.5
|
5 |
+
Stable tag: 2.2.0
|
6 |
+
Tested up to: 4.8.1
|
7 |
+
License: GPLv3 or later
|
8 |
+
License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
9 |
+
|
10 |
+
Improve your speed score on GTmetrix, Pingdom Tools and Google PageSpeed Insights by merging and minifying CSS, JavaScript and HTML.
|
11 |
+
|
12 |
+
|
13 |
+
== Description ==
|
14 |
+
|
15 |
+
This plugin reduces HTTP requests by merging CSS & Javascript files into groups of files, while attempting to use the least amount of files as possible. It minifies CSS and JS files with PHP Minify (no extra requirements).
|
16 |
+
|
17 |
+
Minification is done in real time and done on the frontend only during the first uncached request. Once the first request is processed, any other pages that require the same set of CSS and JavaScript will be served that same static cache file.
|
18 |
+
|
19 |
+
This plugin includes options for developers and advanced users, however the default settings should work just fine for most sites.
|
20 |
+
|
21 |
+
= Aditional Optimization =
|
22 |
+
|
23 |
+
I can offer you aditional `custom made` optimization on top of this plugin. If you would like to hire me, please visit my profile links for further information.
|
24 |
+
|
25 |
+
|
26 |
+
= Features =
|
27 |
+
|
28 |
+
* Merge JS and CSS files into groups to reduce the number of HTTP requests
|
29 |
+
* Google Fonts merging and optimization
|
30 |
+
* Handles scripts loaded both in the header & footer separately
|
31 |
+
* Keeps the order of the scripts even if you exclude some files from minification
|
32 |
+
* Supports localized scripts (https://codex.wordpress.org/Function_Reference/wp_localize_script)
|
33 |
+
* Minifies CSS and JS with PHP Minify only, no third party software or libraries needed.
|
34 |
+
* Option to use YUI Compressor rather than PHP Minify (you you have "exec" and "java" available on your system).
|
35 |
+
* Option to defer JavaScript and CSS files.
|
36 |
+
* Stores the cache files in the uploads directory.
|
37 |
+
* View the status and logs on the WordPress admin page.
|
38 |
+
* Option to Minify HTML for further improvements.
|
39 |
+
* Ability to turn off minification
|
40 |
+
* Ability to turn off CSS or JS optimization seperatly (by disabling either css or js processing)
|
41 |
+
* Ability to manually ignore scripts or css
|
42 |
+
* Support for conditional scripts and styles
|
43 |
+
* Support for multisite installations
|
44 |
+
* Support for gzip_static on Nginx
|
45 |
+
* Support for the CDN Enabler plugin
|
46 |
+
* Auto purging of cache files on W3 Total Cache, WP Supercache, WP Rocket, Wp Fastest Cache, Cachify, Comet Cache, Zen Cache, LiteSpeed Cache, Nginx Cache (by Till Krüss ), SG Optimizer, Godaddy Managed WordPress Hosting and WP Engine (read the FAQs)
|
47 |
+
* Support for preconnect and preload headers
|
48 |
+
* and some more...
|
49 |
+
|
50 |
+
|
51 |
+
= Notes =
|
52 |
+
* The JavaScript minification is by [PHP Minify](https://github.com/matthiasmullie/minify)
|
53 |
+
* The alternative JavaScript minification is by [YUI Compressor](http://yui.github.io/yuicompressor/)
|
54 |
+
* Compatible with Nginx, HHVM and PHP 7.
|
55 |
+
* Minimum requirements are PHP 5.5 and WP 4.4, from version 1.4.0 onwards
|
56 |
+
|
57 |
+
|
58 |
+
== Installation ==
|
59 |
+
|
60 |
+
1. Upload the plugin folder to the `/wp-content/plugins/` directory or upload the zip within WordPress
|
61 |
+
2. Activate the plugin through the `Plugins` menu in WordPress
|
62 |
+
3. Configure the options under: `Settings > Fast Velocity Minify` and that's it.
|
63 |
+
|
64 |
+
|
65 |
+
== Screenshots ==
|
66 |
+
|
67 |
+
1. You can view the logs and purge the cache files.
|
68 |
+
2. The settings page.
|
69 |
+
|
70 |
+
|
71 |
+
== Frequently Asked Questions ==
|
72 |
+
|
73 |
+
= How can I exclude certain assets by wildcard? =
|
74 |
+
|
75 |
+
By default, each line on the ignore list will try to match a substring against all css or js urls, for example: `//yoursite.com/wp-content/plugins/some-plugin/js/` will ignore all files inside that directory. You can also shorten the url like `/some-plugin/js/` and then it will match any css or js url that has `/some-plugin/js/` on the path. Obviously, doing `/js/` would match any files inside any "/js/" directory and in any location, so to avoid unexpected situations please always use the longest, most specific path you can use.
|
76 |
+
|
77 |
+
...
|
78 |
+
|
79 |
+
= Why is the ignore list not working? =
|
80 |
+
|
81 |
+
The ignore list is working but you need to remove query vars from static urls (ex: ?ver=) and use partial (see wildcard help above) and use relative urls only.
|
82 |
+
|
83 |
+
...
|
84 |
+
|
85 |
+
|
86 |
+
= Why are there several or a lot's of js and css files listed on the status page? =
|
87 |
+
|
88 |
+
Those files are created whenever a new set of javascript or css files are found on your front end and it's due to your plugins and themes needing different js and css files per page, post, category, tag, homepage or even custom post types. If you always load the exact same css and javascript in every page on your site, you won't see as many files. Likewise, if you have some dynamic url for css or js that always changes in each pageview, you should add it to the ignore list.
|
89 |
+
|
90 |
+
...
|
91 |
+
|
92 |
+
= Can I update other plugins and themes? =
|
93 |
+
|
94 |
+
Yes, but it's recommended that you purge the cached files (from the plugin status page) in order for the merging and minification cache files to be regenerated. The plugin will try to automatically purge some popular cache plugins. We still recommend, however, that you purge all caches on your cache plugin (whatever you use) "after" purging Fast Velocity Minify cache.
|
95 |
+
|
96 |
+
...
|
97 |
+
|
98 |
+
= Is it compatible with other caching plugins? =
|
99 |
+
|
100 |
+
The plugin will try to automatically purge several popular cache plugins, however we still recommend you to purge all caches (on whatever you use) if you also manually purge the cache on the plugin settings for some reason.
|
101 |
+
The automatic purge is active for the following plugins and hosting: W3 Total Cache, WP Supercache, WP Rocket, Wp Fastest Cache, Cachify, Comet Cache, Zen Cache, LiteSpeed Cache, SG Optimizer, Godaddy Managed WordPress Hosting and WP Engine
|
102 |
+
|
103 |
+
...
|
104 |
+
|
105 |
+
= Is it resource intensive, or will it use too much CPU on my shared hosting plan? =
|
106 |
+
|
107 |
+
No it's not. The generation of the minified files is done only once per group of CSS or JS files (and only if needed). All pages that request the same group of CSS or JS files will also make use of that cache file. The cache file will be served from the uploads directory as a static file and there is no PHP involved.
|
108 |
+
|
109 |
+
...
|
110 |
+
|
111 |
+
= Is it compatible with multisites? =
|
112 |
+
|
113 |
+
Yes, it generates a new cache file for every different set of JS and CSS requirements it finds.
|
114 |
+
|
115 |
+
...
|
116 |
+
|
117 |
+
= Is it compatible with Adsense and other ad networks? =
|
118 |
+
|
119 |
+
The plugin is compatible with any add network but also depends on how you're loading the ads into the site. We only merge and minify css and javascript files enqueued in the header and footer which would exclude any ads. If you're using a plugin that uses JS to insert the ads on the page, there could be issues. Please report on the support forum if you found such case.
|
120 |
+
|
121 |
+
...
|
122 |
+
|
123 |
+
= After installing, why did my site became slow? =
|
124 |
+
|
125 |
+
Please note that the cache regeration happen's once per page or if the requested CSS + JS files change. If you need the same set of CSS and JS files in every page, the cache file will only be generated once and reused for all other pages. If you have a CSS or JS that uses a different name on every pageview, try to add it to the ignore list by using wildcards.
|
126 |
+
|
127 |
+
...
|
128 |
+
|
129 |
+
= How do I use the precompressed files with gzip_static on Nginx? =
|
130 |
+
|
131 |
+
When we merge and minify the css and js files, we also create a `.gz` file to be used with `gzip_static` on Nginx. You need to enable this feature on your Nginx configuration file if you want to make use of it. If you're upgrading from 1.2.3 or earlier, you need to clear the plugin cache.
|
132 |
+
|
133 |
+
...
|
134 |
+
|
135 |
+
= Where is the YUI Compressor option gone to? =
|
136 |
+
|
137 |
+
This functionality depends on wheter you have exec and java available on your system. It will be visible on the basic Settings page under the JavaScript Options section and it only applies to JS files.
|
138 |
+
|
139 |
+
...
|
140 |
+
|
141 |
+
= After installing, why is my design or layout broken or some images and sliders are not showing? =
|
142 |
+
|
143 |
+
First thing to check is, are you doing double minification?
|
144 |
+
You must disable any features on your theme and other plugins, that perform minification of css, html and js.
|
145 |
+
You cannot also have other optimization plugins, because you are forcing wordpress to do double work.
|
146 |
+
I recommend W3 Total Cache (with css, js and html minifcation disabled) + Fast Velocity Minify, for minification of CSS and JS files.
|
147 |
+
Also, kindly review the "Why are some of the CSS and JS files not being merged or why is my layout broken ?" below for better insights.
|
148 |
+
|
149 |
+
Additionally, the Advanced Otions should only be used by advanced users or developers that understand what the settings mean and do, especially the "defer JS" options. Having said that, this is how you can solve most issues on the settings tab when not using any options on the advanced tab:
|
150 |
+
|
151 |
+
* `Disabling CSS processing but keeping JS processing enabled:` This will leave CSS files alone and it's useful to determine if the problem is CSS or JS related. If isabling CSS processing fixed the layout problems, now you know it's related to CSS...
|
152 |
+
Likewise, you can keep CSS processing and disable JS processing to find out if the problem is on JS processing.
|
153 |
+
If you determine it's a CSS issue, check the log file on the status page for possible css file urls that should not be there (such as Internet Explorer only files) and add them to the ignore list.
|
154 |
+
Also kindly report those files on the support forum so they can be blacklisted for future releases.
|
155 |
+
Sometimes there are JS files than conflict with each other when merged so they may need to be excluded too.
|
156 |
+
|
157 |
+
* `JS Defer:` If you have a theme that heavily relies on javascript and jQuery (usually with sliders, paralax animations, etc) most probably, you cannot `defer JavaScript` for all JS files, but you could try to add the jQuery library as well as the specific JS files that need to be render blocking to the ignore list.
|
158 |
+
|
159 |
+
* `Developers only:` Note that if you defer jQuery, the library will not run until after the html DOM page loads. That means that whatever jQuery code is inlined on the HTML will not work and trigger an "undefined" error on the browser console log.
|
160 |
+
On Google Chrome you can look at the console by pressing CTRL + SHIFT + J on your keyboard and refreshing the page. If there are errors you need to track down which JS file is causing trouble and add it to the ignore list.
|
161 |
+
If you have no idea which files to add, I recommend checking the log file on the status page, adding them all to the ignore list and then one by one trying to delete each url until you find the one causing trouble.
|
162 |
+
Also beware of any cache plugin in use (and cloudflare) when testing, because that cache needs to be off or purged when configuring things around.
|
163 |
+
|
164 |
+
...
|
165 |
+
|
166 |
+
= Why are some of the CSS and JS files not being merged or why is my layout broken ? =
|
167 |
+
|
168 |
+
There are thousands of plugins and themes out there and not every developer follows the standard way of enqueueing their files on WordPress.
|
169 |
+
|
170 |
+
For example, some choose to "print" the html tag directly into the header or footer, rather than to use the official method outlined here: https://developer.wordpress.org/themes/basics/including-css-javascript/
|
171 |
+
|
172 |
+
Some developers enqueue all files properly but still "print" conditional tags, such as IE only comments around some CSS or JS files , while they should be following the example as explained on the codex: https://developer.wordpress.org/reference/functions/wp_script_add_data/
|
173 |
+
|
174 |
+
Because "printing CSS and JS tags on the header and footer" is evil (seriously), we cannot capture those files and merge them together.
|
175 |
+
There are also files meant to be loaded for IE users only, mobile users, desktop users, printers, so the enqueing of all the files needs to follow the official method of enqueing data and files.
|
176 |
+
|
177 |
+
This can also cause layout issues because some files that should be for IE only can be merged together with other users, thus overwriting the usual layout (please check if any of those got merged together and add it to the ignore list). Also, to avoid some of these, we have implemented an IE only blacklist of "known" file names that are "always" added to the ignore list behind the scenes.
|
178 |
+
|
179 |
+
Please feel free to open a support topic if you found some more JS or CSS files on your theme or plugins that "must always" also blacklisted and why.
|
180 |
+
|
181 |
+
The default ignore list can be found here:
|
182 |
+
https://fastvelocity.com/api/fvm/ignore.txt
|
183 |
+
|
184 |
+
The IE only blacklist (mostly IE only files or that cause trouble most of the times when merged with others), can be found here: https://fastvelocity.com/api/fvm/ie_blacklist.txt
|
185 |
+
|
186 |
+
These files are downloaded directly by the plugin, once every 24 hours from our cdn provider.
|
187 |
+
|
188 |
+
...
|
189 |
+
|
190 |
+
= Why is it that even though I have disabled or removed the plugin, the design is still broken? =
|
191 |
+
|
192 |
+
While this is rare, it can happen if you have some sort of cache enabled on your site or server. A cache means that the site or server makes a static copy of your page and serves it for a while (until it's deleted or expires) instead of loading wordpress directly to the users. Some hosting providers such as Godaddy (and their derivates) enforce their own cache plugin to be installed and creates a new menu which allows you to purge the cache.
|
193 |
+
|
194 |
+
If you don't see any option anywhere to clear your cache, you can contact your hosting provider or developer to clear the cache for you or ask them how you can do it in the future.
|
195 |
+
|
196 |
+
...
|
197 |
+
|
198 |
+
= Why is my frontend editor not working ? =
|
199 |
+
|
200 |
+
Some plugins and themes need to edit the layout and styles on the frontend. When they need to do that, they enqueue several extra js and css files that are caught by this plugin and get merged together, thus sometimes, it breaks things. If you encounter such issue of your page editor not working on the frontend, kindly enable the "Fix Page Editors" on the Troubleshooting page.
|
201 |
+
|
202 |
+
...
|
203 |
+
|
204 |
+
= What is the "Fix Page Editors" on the Troubleshooting page ? =
|
205 |
+
|
206 |
+
This hides all optimization from editors and administrators, as long as they are logged in. This also means that you will see the site exactly as it was before installing the plugin and it's meant to fix compatibility with frontend page editors, or plugins that edit things in preview mode using the frontend.
|
207 |
+
|
208 |
+
...
|
209 |
+
|
210 |
+
= Is it compatible with Visual Composer and other editors ? =
|
211 |
+
|
212 |
+
Visual composer, adds some style tags into your header and/or footer, however they simply print the code and don't use the wordpress `wp_add_inline_style` hook.
|
213 |
+
This means, we cannot easily capture that csa code and therefore it's left out of all the merging by Fast Velocity Minify.
|
214 |
+
You may have all else merged and minified correctly, however if that generated visual composer css code is important, those styles might be overwritten by the merged file, or that code can also overwrite the rules inside the css generated file.
|
215 |
+
If you experience some styles missing, this could be the cause... but try the ignore list first.
|
216 |
+
|
217 |
+
...
|
218 |
+
|
219 |
+
= How should I use the "Preload Images" and what is it for? =
|
220 |
+
|
221 |
+
Certain themes and plugins, either load large images or sliders on the homepage. Most of them will also load "above the fold" causing the "Prioritize visible content" or the "Eliminate render-blocking JavaScript and CSS in above-the-fold content" message on pagespeed insights (see the previous faq question above).
|
222 |
+
|
223 |
+
How you can use the "Preload Images" is by adding the url of the first relevant images that load above the fold, such as the first background image (and the first image only) of the slider. Any big or large enough image that is above the fold should be added here, however note that the images you add here "must" actually exist on the page, else it will trigger a warning on the browser console such as "The resource [...] was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it wasn't preloaded for nothing." which is not good practice.
|
224 |
+
|
225 |
+
Don't put too many resources here as those are downloaded in high priority and it will slow down the page load on mobile or slower connections (because the browser won't process the rest until it finishes downloading all of those big "preload" images).
|
226 |
+
|
227 |
+
...
|
228 |
+
|
229 |
+
= What are the recommended cloudflare settings for this plugin? =
|
230 |
+
|
231 |
+
On the "Speed" tab, deselect the Auto Minify for JavaScript, CSS and HTML as well as the Rocket Loader option. There is no benefit of using them with our plugin (we already minify things). Those options sometimes can also break the design due to double minification or the fact that the Rocket Loader is still experimental (you can read about that on the "Help" link under each selected option on cloudflare).
|
232 |
+
|
233 |
+
...
|
234 |
+
|
235 |
+
= How to undo all changes done by the plugin? =
|
236 |
+
|
237 |
+
The plugin itself doesn't do any "changes" to your site and all original files are untouched. It intercepts the enqueued CSS and JS files, processes and hides them, while enqueuing the newly optimized cached version of those files. As with any plugin, simply disable or uninstall the plugin, purge all caches you may have in use (plugins, server, cloudflare, etc) and the site will go back to what it was before installing it. The plugin doesn't delete anything from the database or modify any of your files.
|
238 |
+
|
239 |
+
...
|
240 |
+
|
241 |
+
= I have a complaint or I need support right now. Why haven't you replied to my topic on the support forum yet? =
|
242 |
+
|
243 |
+
Before getting angry because you have no answer within a few hours (even with paid plugins, sometimes it takes weeks...), please be informed about how wordpress.org and the plugins directory work.
|
244 |
+
|
245 |
+
The plugins directory is an open source, free service where developers and programmers contribute (on their free time) with plugins that can be downloaded and installed by anyone "at their own risk" and are all released under the GPL license.
|
246 |
+
|
247 |
+
While all plugins have to be approved and reviewed by the wordpress team before being published ( for dangerous code, spam, etc ) this doesn't change the license or add any warranty. All plugins are provided as they are, free of charge and should be used at your own risk (so you should make backups before installing any plugin or performing updates) and it's your sole responsability if you break your site after installing a plugin from the plugins directory.
|
248 |
+
|
249 |
+
Support is provided by plugin authors on their free time and without warranty of a reply, so you can experience different levels of support level from plugin to plugin. As the author of this plugin I strive to provide support on a daily basis and I can take a look and help you with some issues related with my plugin, but please note that this is done out of my goodwill and in no way I have any legal or moral obligation for doing this. I'm also available for hiring if you need custom made speed optimizations (check my profile links).
|
250 |
+
|
251 |
+
For a full version of the license, please read: https://wordpress.org/about/gpl/
|
252 |
+
|
253 |
+
...
|
254 |
+
|
255 |
+
= Where can I get support or report bugs? =
|
256 |
+
|
257 |
+
You can get support on the official wordpress plugin page at: https://wordpress.org/support/plugin/fast-velocity-minify
|
258 |
+
You can also see my profile and check my links if you wish to hire me for custom speed optimization on wordpress or extra features.
|
259 |
+
|
260 |
+
...
|
261 |
+
|
262 |
+
= How can I donate to the plugin author? =
|
263 |
+
|
264 |
+
If you would like to donate any amount to the plugin author (thank you in advance), you can do it via Paypal at https://goo.gl/vpLrSV
|
265 |
+
|
266 |
+
...
|
267 |
+
|
268 |
+
|
269 |
+
== Upgrade Notice ==
|
270 |
+
|
271 |
+
= 2.1.6 =
|
272 |
+
Note: Kindly purge the plugin cache as well as your server /plugin cache after updating.
|
273 |
+
|
274 |
+
|
275 |
+
== Changelog ==
|
276 |
+
|
277 |
+
= 2.2.0 [2017.08.13] =
|
278 |
+
* fixed some debug notices
|
279 |
+
* fixed the alternative html minification option
|
280 |
+
|
281 |
+
= 2.1.9 [2017.08.11] =
|
282 |
+
* fixed a devolopment bug
|
283 |
+
|
284 |
+
= 2.1.8 [2017.08.11] =
|
285 |
+
* fixed the html minification not working
|
286 |
+
* added support for the cdn enabler plugin (force http or https method)
|
287 |
+
|
288 |
+
= 2.1.7 [2017.07.17] =
|
289 |
+
* improved html minification speed and response time to the first byte
|
290 |
+
* fixed a random bug with the html minification library on large html pages (white pages)
|
291 |
+
* added support for the "Nginx Cache" plugin purge, by Till Krüss
|
292 |
+
|
293 |
+
= 2.1.6 [2017.07.17] =
|
294 |
+
* fixed a php notice in debug mode
|
295 |
+
* children styles (added with wp_add_inline_style) are now kept in order and merged together in place
|
296 |
+
* added faqs for possible "visual composer" issues
|
297 |
+
|
298 |
+
= 2.1.5 [2017.07.17] =
|
299 |
+
* css bug fixes and performance improvements
|
300 |
+
* added support for auto purging on WP Engine
|
301 |
+
|
302 |
+
= 2.1.4 [2017.07.14] =
|
303 |
+
* added compatibility with WP Engine.com and other providers that use a CNAME with their own subdomain
|
304 |
+
|
305 |
+
= 2.1.3 [2017.07.11] =
|
306 |
+
* updated PHP Minify for better compatibility
|
307 |
+
* added an alternative mode for html minification (because PHP Minify sometimes breaks things)
|
308 |
+
* css bug fixes and performance improvements
|
309 |
+
|
310 |
+
= 2.1.2 [2017.06.27] =
|
311 |
+
* fixed another error notice when debug mode is on
|
312 |
+
|
313 |
+
= 2.1.1 [2017.06.24] =
|
314 |
+
* fixed an error notice
|
315 |
+
|
316 |
+
= 2.1.0 [2017.06.21] =
|
317 |
+
* some performance improvements
|
318 |
+
|
319 |
+
= 2.0.9 [2017.06.01] =
|
320 |
+
* several bug and compatibility fixes
|
321 |
+
|
322 |
+
= 2.0.8 [2017.05.28] =
|
323 |
+
* fixed a notice alert on php for undefined function
|
324 |
+
|
325 |
+
= 2.0.7 [2017.05.28] =
|
326 |
+
* added support for auto purging of LiteSpeed Cache
|
327 |
+
* added support for auto purging on Godaddy Managed WordPress Hosting
|
328 |
+
* added the ie only blacklist, wich doesn't split merged files anymore, like the ignore list does
|
329 |
+
* added auto updates for the default ignore list and blacklist from our api once every 24 hours
|
330 |
+
* added cdn rewrite support for generated css and js files only
|
331 |
+
* removed url protocol rewrites and set default to dynamic "//" protocols
|
332 |
+
* updated the faqs
|
333 |
+
|
334 |
+
= 2.0.6 [2017.05.22] =
|
335 |
+
* added a "Troubleshooting" option to fix frontend editors for admin and editor level users
|
336 |
+
* updated the faqs
|
337 |
+
|
338 |
+
= 2.0.5 [2017.05.15] =
|
339 |
+
* fixed preserving the SVG namespace definition "http://www.w3.org/2000/svg" used on Bootstrap 4
|
340 |
+
* added some exclusions for Thrive and Visual Composer frontend preview and editors
|
341 |
+
|
342 |
+
= 2.0.4 [2017.05.15] =
|
343 |
+
* improved compatibility with Windows operating systems
|
344 |
+
|
345 |
+
= 2.0.3 [2017.05.15] =
|
346 |
+
* fixed an "undefined" notice
|
347 |
+
|
348 |
+
= 2.0.2 [2017.05.14] =
|
349 |
+
* improved compatibility on JS merging and minification
|
350 |
+
|
351 |
+
= 2.0.1 [2017.05.11] =
|
352 |
+
* fixed missing file that caused some errors on new installs
|
353 |
+
|
354 |
+
= 2.0.0 [2017.05.11] =
|
355 |
+
* moved the css and js merging base code back to 1.4.3 because it was better for compatibility
|
356 |
+
* removed the font awesome optimization tweaks because people have multiple versions and requirements (but duplicate css and js files are always removed)
|
357 |
+
* added all usable improvements and features up to 1.5.2, except for the "Defer CSS" and "Critical Path" features (will consider for the future)
|
358 |
+
* added info to the FAQ's about our internal blacklist for known CSS or JS files that are always ignored by the plugin
|
359 |
+
* changed the way CSS and JS files are fetched and merged to make use of the new improvements that were supposed to be on 1.4.4+
|
360 |
+
* changed the advanced settings tab back to the settings page for quicker selection of options by the advanced users
|
361 |
+
* changed the cache purging option to also delete our plugin transients via the API, rather than just let them expire
|
362 |
+
* changed the "Inline all CSS" option into header and footer separately
|
363 |
+
|
364 |
+
= 1.0 [2016.06.19] =
|
365 |
+
* Initial Release
|