Fast Velocity Minify - Version 2.4.2

Version Description

[2018.11.29] = * fixed a bug with the "Exclude JS files in the ignore list from PSI" option (it wasn't excluding properly) * improved functionality with the "Exclude CSS files from PSI" option (now works with both inline and link stylesheets) * added an option to automatically preload the CSS and JS files generated by FVM (beware that some server caches like Pantheon may push old css and js files even after purging caches on FVM) * improved JavaScript minification

Download this release

Release Info

Developer Alignak
Plugin Icon 128x128 Fast Velocity Minify
Version 2.4.2
Comparing to
See all releases

Code changes from version 2.4.1 to 2.4.2

Files changed (3) hide show
  1. fvm.php +266 -45
  2. inc/functions.php +9 -5
  3. readme.txt +10 -1
fvm.php CHANGED
@@ -5,7 +5,7 @@ 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.4.1
9
  License: GPL2
10
 
11
  ------------------------------------------------------------------------
@@ -61,7 +61,8 @@ add_action('admin_init', 'fvm_compat_checker');
61
 
62
 
63
  # get plugin version
64
- $fastvelocity_plugin_version = get_file_data(__FILE__, array('Version' => 'Version'), false)['Version'];
 
65
 
66
  # get the plugin directory
67
  $plugindir = plugin_dir_path( __FILE__ ); # prints with trailing slash
@@ -96,6 +97,8 @@ closedir($handle);
96
  # default globals
97
  $fastvelocity_min_global_js_done = array();
98
  $fvm_collect_google_fonts = array();
 
 
99
  $fvm_debug = get_option('fastvelocity_fvm_debug');
100
 
101
  ###########################################
@@ -132,6 +135,8 @@ $fvm_fix_editor = get_option('fastvelocity_min_fvm_fix_editor');
132
  $fvmloadcss = get_option('fastvelocity_min_loadcss');
133
  $fvm_remove_css = get_option('fastvelocity_min_fvm_removecss');
134
  $fvm_cdn_url = get_option('fastvelocity_min_fvm_cdn_url');
 
 
135
 
136
  # default options
137
  $used_css_files = array();
@@ -223,15 +228,13 @@ if(is_admin()) {
223
  add_action('template_redirect', 'fastvelocity_min_html_compression_start', PHP_INT_MAX);
224
  }
225
 
226
- # add the CSS async polyfil
227
- if ($min_async_googlefonts == true || $fvmloadcss !== false) {
228
- add_action('wp_footer', 'fvm_add_loadcss', PHP_INT_MAX);
229
- }
230
-
231
  # remove query from static assets and process defering (if enabled)
232
  add_filter('style_loader_src', 'fastvelocity_remove_cssjs_ver', 10, 2);
233
  add_filter('script_loader_tag', 'fastvelocity_min_defer_js', 10, 3);
234
- add_filter('script_loader_tag', 'fastvelocity_min_excludejslist_optimize', 10, 3);
235
 
236
  }
237
  }
@@ -250,7 +253,7 @@ global $fvm_fix_editor, $disable_js_merge, $disable_css_merge, $skip_emoji_remov
250
  remove_action('template_redirect', 'fastvelocity_min_html_compression_start', PHP_INT_MAX);
251
  remove_filter('style_loader_src', 'fastvelocity_remove_cssjs_ver', 10, 2);
252
  remove_filter('script_loader_tag', 'fastvelocity_min_defer_js', 10, 3);
253
- remove_filter('script_loader_tag', 'fastvelocity_min_excludejslist_optimize', 10, 3);
254
  }
255
  }
256
 
@@ -369,6 +372,8 @@ function fastvelocity_min_register_settings() {
369
 
370
  # dev tab
371
  register_setting('fvm-group-dev', 'fastvelocity_fvm_debug');
 
 
372
  register_setting('fvm-group-dev', 'fastvelocity_min_hpreload');
373
  register_setting('fvm-group-dev', 'fastvelocity_min_hpreconnect');
374
  register_setting('fvm-group-dev', 'fastvelocity_min_loadcss');
@@ -765,7 +770,8 @@ I know what I'm doing... <span class="note-info">[ Load my JS files from the CDN
765
 
766
  <div style="height: 20px;"></div>
767
  <h2 class="title">Special JS and CSS Exceptions</h2>
768
- <p class="fvm-bold-green">You can use this section to edit or change our default exclusions, as well as to add your own.<br />It's recommeded that you use the Ignore List before touching these settings.</p>
 
769
 
770
  <div style="height: 20px;"></div>
771
  <table class="form-table fvm-settings">
@@ -807,7 +813,7 @@ I know what I'm doing... <span class="note-info">[ Load my JS files from the CDN
807
  <p>
808
  <textarea name="fastvelocity_min_excludejslist" rows="7" cols="50" id="fastvelocity_min_excludejslist" class="large-text code" placeholder="ex: /pixelyoursite/js/public.js"><?php echo get_option('fastvelocity_min_excludejslist'); ?></textarea>
809
  </p>
810
- <p class="description">[ Any JS file that can load Async and independently from the rest, such as analytics or pixel scripts ]</p>
811
 
812
  </fieldset></td>
813
  </tr>
@@ -823,8 +829,7 @@ I know what I'm doing... <span class="note-info">[ Load my JS files from the CDN
823
  <p>
824
  <textarea name="fastvelocity_min_excludecsslist" rows="7" cols="50" id="fastvelocity_min_excludecsslist" class="large-text code" placeholder="ex: /wp-content/themes/my-theme/css/fontawesome.css"><?php echo get_option('fastvelocity_min_excludecsslist'); ?></textarea>
825
  </p>
826
- <p class="description">[ Any CSS file that can load independently from the rest, such as fontawesome or other icons ]</p>
827
- <p class="description">[ Note: Under development, currently only works when "Inline all CSS files" is enabled ]</p>
828
 
829
  </fieldset></td>
830
  </tr>
@@ -876,26 +881,40 @@ if( $active_tab == 'dev' ) { ?>
876
  <?php settings_fields('fvm-group-dev'); do_settings_sections('fvm-group-dev'); ?>
877
 
878
  <div style="height: 20px;"></div>
879
- <h2 class="title">Debug</h2>
880
- <p class="fvm-bold-green">This will print some debug info on the status page log files, as well as some HTML comments on the frontend for certain actions and situations. This is still experimental and under developement!</p>
 
881
 
882
  <table class="form-table fvm-settings">
883
  <tbody>
884
  <tr>
885
- <th scope="row">Enable FVM Debug Mode</th>
886
  <td><fieldset>
887
  <label for="fastvelocity_fvm_debug">
888
  <input name="fastvelocity_fvm_debug" type="checkbox" id="fastvelocity_fvm_debug" value="1" <?php echo checked(1 == get_option('fastvelocity_fvm_debug'), true, false); ?>>
889
- Enable FVM Debug Mode<span class="note-info">[ Add debug info to the status page logs as well as some comments on the HTML frontend (beta) ]</span></label>
 
 
 
 
 
 
 
 
 
 
 
890
 
891
  </fieldset>
892
  </td>
893
  </tr>
894
-
895
  </tbody></table>
896
 
897
 
898
 
 
 
 
899
  <div style="height: 20px;"></div>
900
  <h2 class="title">HTTP Headers</h2>
901
  <p class="fvm-bold-green">Preconnect Headers: This will add link headers to your http response to instruct the browser to preconnect to other domains (ex: fonts, images, videos, etc)</p>
@@ -1362,6 +1381,10 @@ for($i=0,$l=count($footer);$i<$l;$i++) {
1362
  # register minified file
1363
  wp_register_script("fvm-footer-$i", $file_url, array(), null, false);
1364
 
 
 
 
 
1365
  # add all extra data from wp_localize_script
1366
  $data = array();
1367
  foreach($footer[$i]['handles'] as $handle) {
@@ -1434,11 +1457,13 @@ if($enable_defer_js == true) { return $tagdefer; }
1434
  # return if no defer, and there's no defer for pagespeed... else pagespeed processing
1435
  if ($defer_for_pagespeed != true) { return $tag; } else {
1436
 
 
 
 
1437
  # return if external script url https://www.chromestatus.com/feature/5718547946799104
1438
  if (fvm_is_local_domain($src) !== true) { return $tag; }
1439
 
1440
- # return if there are linebreaks (will break document.write)
1441
- if (stripos($tag, PHP_EOL) !== false) { return $tag; }
1442
 
1443
  # print code if there are no linebreaks, or return
1444
  if(!empty($tagdefer)) {
@@ -1459,7 +1484,7 @@ return $tag;
1459
  # process header css ######################
1460
  ###########################################
1461
  function fastvelocity_min_merge_header_css() {
1462
- 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_googlefonts, $css_hide_googlefonts, $min_async_googlefonts, $remove_googlefonts, $fvmloadcss, $fvm_remove_css, $fvmualist, $fvm_min_excludecsslist, $fvm_debug;
1463
  if(!is_object($wp_styles)) { return false; }
1464
  $ctime = get_option('fvm-last-cache-update', '0');
1465
  $styles = wp_clone($wp_styles);
@@ -1506,6 +1531,15 @@ foreach( $styles->to_do as $handle):
1506
  if (isset($uniq[$key])) { $done = array_merge($done, array($handle)); continue; } else { $uniq[$key] = $handle; }
1507
  }
1508
 
 
 
 
 
 
 
 
 
 
1509
  # array of info to save
1510
  $arr = array('handle'=>$handle, 'url'=>$hurl, 'conditional'=>$conditional, 'mediatype'=>$mediatype);
1511
 
@@ -1760,8 +1794,11 @@ for($i=0,$l=count($header);$i<$l;$i++) {
1760
  } else {
1761
  $check = ''; $check = trim(file_get_contents($file));
1762
  if(file_exists($file) && !empty($check)) {
 
 
1763
  wp_register_style("fvm-header-$i", $file_url, array(), null, $header[$i]['media']);
1764
  wp_enqueue_style("fvm-header-$i");
 
1765
  }
1766
  }
1767
  }
@@ -2068,8 +2105,11 @@ for($i=0,$l=count($footer);$i<$l;$i++) {
2068
  } else {
2069
  $check = ''; $check = trim(file_get_contents($file));
2070
  if(file_exists($file) && !empty($check)) {
 
 
2071
  wp_register_style("fvm-footer-$i", $file_url, array(), null, $footer[$i]['media']);
2072
  wp_enqueue_style("fvm-footer-$i");
 
2073
  }
2074
  }
2075
  }
@@ -2096,6 +2136,8 @@ function fvm_add_loadcss() {
2096
 
2097
  echo <<<EOF
2098
  <script>
 
 
2099
  /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
2100
  !function(n){"use strict";n.loadCSS||(n.loadCSS=function(){});var o=loadCSS.relpreload={};if(o.support=function(){var e;try{e=n.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),o.bindMediaToggle=function(t){var e=t.media||"all";function a(){t.media=e}t.addEventListener?t.addEventListener("load",a):t.attachEvent&&t.attachEvent("onload",a),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(a,3e3)},o.poly=function(){if(!o.support())for(var t=n.document.getElementsByTagName("link"),e=0;e<t.length;e++){var a=t[e];"preload"!==a.rel||"style"!==a.getAttribute("as")||a.getAttribute("data-loadcss")||(a.setAttribute("data-loadcss",!0),o.bindMediaToggle(a))}},!o.support()){o.poly();var t=n.setInterval(o.poly,500);n.addEventListener?n.addEventListener("load",function(){o.poly(),n.clearInterval(t)}):n.attachEvent&&n.attachEvent("onload",function(){o.poly(),n.clearInterval(t)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:n.loadCSS=loadCSS}("undefined"!=typeof global?global:this);
2101
  </script>
@@ -2156,50 +2198,82 @@ if(is_array($preconnect) && count($preconnect) > 0) {
2156
  }
2157
  }
2158
 
 
 
 
 
 
 
 
 
 
 
 
2159
  }
2160
 
2161
 
2162
 
2163
  ###########################################
2164
- # optimize the ignore list for pagespeed insights
2165
  ###########################################
2166
- function fastvelocity_min_excludejslist_optimize($tag, $handle, $src) {
2167
- global $fvm_min_excludejslist, $fvm_fix_editor, $fvmualist, $fvm_debug;
2168
 
2169
  # return if there are linebreaks (will break document.write)
2170
- if (stripos($tag, PHP_EOL) !== false) { return $tag; }
2171
 
2172
  # fix page editors
2173
  if($fvm_fix_editor == true && is_user_logged_in()) { return $tag; }
2174
 
2175
- # return if the exclude JS files from PSI option is empty
2176
- if($fvm_min_excludejslist == false || !is_array($fvm_min_excludejslist)) {
2177
- return $tag;
2178
- }
2179
 
2180
- # check for string match
2181
- foreach($fvm_min_excludejslist as $l) {
2182
- if (stripos($src, $l) !== false) {
2183
-
2184
- # print code if there are no linebreaks, or return
2185
- echo '<script type="text/javascript" async>if(!navigator.userAgent.match(/'.implode('|', $fvmualist).'/i)){';
2186
- echo "loadAsync('$src', null);";
2187
- echo '}</script>';
2188
- return false;
2189
- }
2190
  }
2191
 
2192
- # fallback
2193
- return $tag;
 
 
 
 
 
 
 
 
 
 
 
2194
  }
2195
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2196
 
 
 
 
 
 
2197
 
 
2198
 
2199
-
2200
-
2201
-
2202
-
2203
 
2204
 
2205
  # inline css in place, instead of inlining the large file
@@ -2422,3 +2496,150 @@ function fastvelocity_add_google_fonts_merged() {
2422
 
2423
  }
2424
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.4.2
9
  License: GPL2
10
 
11
  ------------------------------------------------------------------------
61
 
62
 
63
  # get plugin version
64
+ $fastvelocity_plugin_version_get_data = get_file_data(__FILE__, array('Version' => 'Version'), false);
65
+ $fastvelocity_plugin_version = $fastvelocity_plugin_version_get_data['Version'];
66
 
67
  # get the plugin directory
68
  $plugindir = plugin_dir_path( __FILE__ ); # prints with trailing slash
97
  # default globals
98
  $fastvelocity_min_global_js_done = array();
99
  $fvm_collect_google_fonts = array();
100
+ $collect_preload_css = array();
101
+ $collect_preload_js = array();
102
  $fvm_debug = get_option('fastvelocity_fvm_debug');
103
 
104
  ###########################################
135
  $fvmloadcss = get_option('fastvelocity_min_loadcss');
136
  $fvm_remove_css = get_option('fastvelocity_min_fvm_removecss');
137
  $fvm_cdn_url = get_option('fastvelocity_min_fvm_cdn_url');
138
+ $fvm_enabled_css_preload = get_option('fastvelocity_enabled_css_preload');
139
+ $fvm_enabled_js_preload = get_option('fastvelocity_enabled_css_preload');
140
 
141
  # default options
142
  $used_css_files = array();
228
  add_action('template_redirect', 'fastvelocity_min_html_compression_start', PHP_INT_MAX);
229
  }
230
 
231
+ # add the CSS async polyfil + LoadAsync JavaScript functions
232
+ add_action('wp_footer', 'fvm_add_loadcss', PHP_INT_MAX);
233
+
 
 
234
  # remove query from static assets and process defering (if enabled)
235
  add_filter('style_loader_src', 'fastvelocity_remove_cssjs_ver', 10, 2);
236
  add_filter('script_loader_tag', 'fastvelocity_min_defer_js', 10, 3);
237
+ add_filter('script_loader_tag', 'fastvelocity_min_defer_js_optimize', PHP_INT_MAX, 3);
238
 
239
  }
240
  }
253
  remove_action('template_redirect', 'fastvelocity_min_html_compression_start', PHP_INT_MAX);
254
  remove_filter('style_loader_src', 'fastvelocity_remove_cssjs_ver', 10, 2);
255
  remove_filter('script_loader_tag', 'fastvelocity_min_defer_js', 10, 3);
256
+ remove_filter('script_loader_tag', 'fastvelocity_min_defer_js_optimize', 10, 3);
257
  }
258
  }
259
 
372
 
373
  # dev tab
374
  register_setting('fvm-group-dev', 'fastvelocity_fvm_debug');
375
+ register_setting('fvm-group-dev', 'fastvelocity_enabled_css_preload');
376
+ register_setting('fvm-group-dev', 'fastvelocity_enabled_js_preload');
377
  register_setting('fvm-group-dev', 'fastvelocity_min_hpreload');
378
  register_setting('fvm-group-dev', 'fastvelocity_min_hpreconnect');
379
  register_setting('fvm-group-dev', 'fastvelocity_min_loadcss');
770
 
771
  <div style="height: 20px;"></div>
772
  <h2 class="title">Special JS and CSS Exceptions</h2>
773
+ <p class="fvm-bold-green">You can use this section to edit or change our default exclusions, as well as to add your own.<br />Make sure you understand the difference between Defer and Async.</p>
774
+ <p class="fvm-bold-green">When you use an option here that uses "Async", styles and scripts load "out of order" and completely independent from the others. That means, the files that end up loading later, will overwrite any previously loaded code. On the other hand, when you use the "ignore list" or when you select an option to "defer", the order of scripts and styles is preserved and should not overwrite previously loaded code, unless there is an higher specificy somewhere else.</p>
775
 
776
  <div style="height: 20px;"></div>
777
  <table class="form-table fvm-settings">
813
  <p>
814
  <textarea name="fastvelocity_min_excludejslist" rows="7" cols="50" id="fastvelocity_min_excludejslist" class="large-text code" placeholder="ex: /pixelyoursite/js/public.js"><?php echo get_option('fastvelocity_min_excludejslist'); ?></textarea>
815
  </p>
816
+ <p class="description">[ Any JS file that can load Async and completely independent, such as analytics or pixel scripts ]</p>
817
 
818
  </fieldset></td>
819
  </tr>
829
  <p>
830
  <textarea name="fastvelocity_min_excludecsslist" rows="7" cols="50" id="fastvelocity_min_excludecsslist" class="large-text code" placeholder="ex: /wp-content/themes/my-theme/css/fontawesome.css"><?php echo get_option('fastvelocity_min_excludecsslist'); ?></textarea>
831
  </p>
832
+ <p class="description">[ Any CSS file that can load completely independent, such as fontawesome or other icons ]</p>
 
833
 
834
  </fieldset></td>
835
  </tr>
881
  <?php settings_fields('fvm-group-dev'); do_settings_sections('fvm-group-dev'); ?>
882
 
883
  <div style="height: 20px;"></div>
884
+ <h2 class="title">Development</h2>
885
+ <p class="fvm-bold-green">This are handy things for the plugin author, but may be of use to you if you are looking to debug some issue.</p>
886
+ <p class="fvm-bold-green">Please note that the automatic headers, are only available after the first, uncached pageview (you may need to purge your cache to see them, or your server may not support this at all).</p>
887
 
888
  <table class="form-table fvm-settings">
889
  <tbody>
890
  <tr>
891
+ <th scope="row">Dev Options</th>
892
  <td><fieldset>
893
  <label for="fastvelocity_fvm_debug">
894
  <input name="fastvelocity_fvm_debug" type="checkbox" id="fastvelocity_fvm_debug" value="1" <?php echo checked(1 == get_option('fastvelocity_fvm_debug'), true, false); ?>>
895
+ Enable FVM Debug Mode<span class="note-info">[ Add extra info to the "status page" logs as well as some comments on the HTML frontend (beta) ]</span></label>
896
+
897
+ <br />
898
+ <label for="fastvelocity_enabled_css_preload">
899
+ <input name="fastvelocity_enabled_css_preload" type="checkbox" id="fastvelocity_enabled_css_preload" value="1" <?php echo checked(1 == get_option('fastvelocity_enabled_css_preload'), true, false); ?>>
900
+ Enable FVM CSS files Preload<span class="note-info">[ Automatically create http headers for FVM generated CSS files, when enqueued ]</span></label>
901
+
902
+ <br />
903
+ <label for="fastvelocity_enabled_js_preload">
904
+ <input name="fastvelocity_enabled_js_preload" type="checkbox" id="fastvelocity_enabled_js_preload" value="1" <?php echo checked(1 == get_option('fastvelocity_enabled_js_preload'), true, false); ?>>
905
+ Enable FVM JS files Preload<span class="note-info">[ Automatically create http headers for FVM generated JS files, when enqueued ]</span></label>
906
+
907
 
908
  </fieldset>
909
  </td>
910
  </tr>
 
911
  </tbody></table>
912
 
913
 
914
 
915
+
916
+
917
+
918
  <div style="height: 20px;"></div>
919
  <h2 class="title">HTTP Headers</h2>
920
  <p class="fvm-bold-green">Preconnect Headers: This will add link headers to your http response to instruct the browser to preconnect to other domains (ex: fonts, images, videos, etc)</p>
1381
  # register minified file
1382
  wp_register_script("fvm-footer-$i", $file_url, array(), null, false);
1383
 
1384
+ # associate generated file to current url so it can be send with preload later
1385
+
1386
+
1387
+
1388
  # add all extra data from wp_localize_script
1389
  $data = array();
1390
  foreach($footer[$i]['handles'] as $handle) {
1457
  # return if no defer, and there's no defer for pagespeed... else pagespeed processing
1458
  if ($defer_for_pagespeed != true) { return $tag; } else {
1459
 
1460
+ # return if there are linebreaks (will break document.write)
1461
+ if (stripos($tag, PHP_EOL) !== false) { return $tag; }
1462
+
1463
  # return if external script url https://www.chromestatus.com/feature/5718547946799104
1464
  if (fvm_is_local_domain($src) !== true) { return $tag; }
1465
 
1466
+
 
1467
 
1468
  # print code if there are no linebreaks, or return
1469
  if(!empty($tagdefer)) {
1484
  # process header css ######################
1485
  ###########################################
1486
  function fastvelocity_min_merge_header_css() {
1487
+ 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_googlefonts, $css_hide_googlefonts, $min_async_googlefonts, $remove_googlefonts, $fvmloadcss, $fvm_remove_css, $fvmualist, $fvm_min_excludecsslist, $fvm_debug, $fvm_min_excludecsslist;
1488
  if(!is_object($wp_styles)) { return false; }
1489
  $ctime = get_option('fvm-last-cache-update', '0');
1490
  $styles = wp_clone($wp_styles);
1531
  if (isset($uniq[$key])) { $done = array_merge($done, array($handle)); continue; } else { $uniq[$key] = $handle; }
1532
  }
1533
 
1534
+ # Exclude specific CSS files from PSI?
1535
+ if($fvm_min_excludecsslist != false && is_array($fvm_min_excludecsslist) && fastvelocity_min_in_arrayi($hurl, $fvm_min_excludecsslist)) {
1536
+ $cssguid = 'fvm'.hash('adler32', $hurl);
1537
+ echo '<script type="text/javascript">if(!navigator.userAgent.match(/'.implode('|', $fvmualist).'/i)){';
1538
+ echo 'var '.$cssguid.'=document.createElement("link");'.$cssguid.'.rel="stylesheet",'.$cssguid.'.type="text/css",'.$cssguid.'.media="async",'.$cssguid.'.href="'.$hurl.'",'.$cssguid.'.onload=function(){'.$cssguid.'.media="'.$mediatype.'"},document.getElementsByTagName("head")[0].appendChild('.$cssguid.');';
1539
+ echo '}</script>';
1540
+ $done = array_merge($done, array($handle)); continue;
1541
+ }
1542
+
1543
  # array of info to save
1544
  $arr = array('handle'=>$handle, 'url'=>$hurl, 'conditional'=>$conditional, 'mediatype'=>$mediatype);
1545
 
1794
  } else {
1795
  $check = ''; $check = trim(file_get_contents($file));
1796
  if(file_exists($file) && !empty($check)) {
1797
+
1798
+ # enqueue it
1799
  wp_register_style("fvm-header-$i", $file_url, array(), null, $header[$i]['media']);
1800
  wp_enqueue_style("fvm-header-$i");
1801
+
1802
  }
1803
  }
1804
  }
2105
  } else {
2106
  $check = ''; $check = trim(file_get_contents($file));
2107
  if(file_exists($file) && !empty($check)) {
2108
+
2109
+ # enqueue it
2110
  wp_register_style("fvm-footer-$i", $file_url, array(), null, $footer[$i]['media']);
2111
  wp_enqueue_style("fvm-footer-$i");
2112
+
2113
  }
2114
  }
2115
  }
2136
 
2137
  echo <<<EOF
2138
  <script>
2139
+ /*! fvm load async scripts with clallback */
2140
+ function loadAsync(e,a){var t=document.createElement("script");t.src=e,null!==a&&(t.readyState?t.onreadystatechange=function(){"loaded"!=t.readyState&&"complete"!=t.readyState||(t.onreadystatechange=null,a())}:t.onload=function(){a()}),document.getElementsByTagName("head")[0].appendChild(t)}
2141
  /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
2142
  !function(n){"use strict";n.loadCSS||(n.loadCSS=function(){});var o=loadCSS.relpreload={};if(o.support=function(){var e;try{e=n.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),o.bindMediaToggle=function(t){var e=t.media||"all";function a(){t.media=e}t.addEventListener?t.addEventListener("load",a):t.attachEvent&&t.attachEvent("onload",a),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(a,3e3)},o.poly=function(){if(!o.support())for(var t=n.document.getElementsByTagName("link"),e=0;e<t.length;e++){var a=t[e];"preload"!==a.rel||"style"!==a.getAttribute("as")||a.getAttribute("data-loadcss")||(a.setAttribute("data-loadcss",!0),o.bindMediaToggle(a))}},!o.support()){o.poly();var t=n.setInterval(o.poly,500);n.addEventListener?n.addEventListener("load",function(){o.poly(),n.clearInterval(t)}):n.attachEvent&&n.attachEvent("onload",function(){o.poly(),n.clearInterval(t)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:n.loadCSS=loadCSS}("undefined"!=typeof global?global:this);
2143
  </script>
2198
  }
2199
  }
2200
 
2201
+ # fvm css and js generated files
2202
+ $fvm_headers = fastvelocity_get_preload_headers();
2203
+ if($fvm_headers != false) {
2204
+ $nh = array_map('trim', explode(PHP_EOL, $fvm_headers));
2205
+ foreach ($nh as $h) {
2206
+ if(!empty($h)) {
2207
+ header($h, false);
2208
+ }
2209
+ }
2210
+ }
2211
+
2212
  }
2213
 
2214
 
2215
 
2216
  ###########################################
2217
+ # optimize the ignore list for pagespeed insights + Exclude JS files from PSI (Async)
2218
  ###########################################
2219
+ function fastvelocity_min_defer_js_optimize($tag, $handle, $src) {
2220
+ global $defer_for_pagespeed, $defer_for_pagespeed_optimize, $fvm_fix_editor, $fvm_min_excludejslist, $fvmualist;
2221
 
2222
  # return if there are linebreaks (will break document.write)
2223
+ if (stripos($tag, "\n") !== false) { return $tag; }
2224
 
2225
  # fix page editors
2226
  if($fvm_fix_editor == true && is_user_logged_in()) { return $tag; }
2227
 
2228
+ # return if external script url https://www.chromestatus.com/feature/5718547946799104
2229
+ if (fvm_is_local_domain($src) !== true) { return $tag; }
 
 
2230
 
2231
+ # filter src for extra atributes
2232
+ if (stripos($src, '?ver') !== false) {
2233
+ $src = stristr($src, '?ver', true);
 
 
 
 
 
 
 
2234
  }
2235
 
2236
+ # Exclude JS files from PSI (Async) takes priority over defering the ignore list
2237
+ if($fvm_min_excludejslist != false || is_array($fvm_min_excludejslist)) {
2238
+ # check for string match
2239
+ foreach($fvm_min_excludejslist as $l) {
2240
+ if (stripos($src, $l) !== false) {
2241
+
2242
+ # print code if there are no linebreaks, or return
2243
+ echo '<script type="text/javascript">if(!navigator.userAgent.match(/'.implode('|', $fvmualist).'/i)){';
2244
+ echo "loadAsync('$src', null);";
2245
+ echo '}</script>';
2246
+ return false;
2247
+ }
2248
+ }
2249
  }
2250
 
2251
+ # exclude ignored scripts
2252
+ if(substr($handle, 0, 4) != "fvm-" && $defer_for_pagespeed == true && $defer_for_pagespeed_optimize == true) {
2253
+
2254
+ # get available nodes and add create with defer tag (if not async)
2255
+ $dom = new DOMDocument();
2256
+ libxml_use_internal_errors(true);
2257
+ @$dom->loadHTML($tag);
2258
+ $nodes = $dom->getElementsByTagName('script');
2259
+ $tagdefer = '';
2260
+ if ($nodes->length != 0) {
2261
+ $node = $dom->getElementsByTagName('script')->item(0);
2262
+ if (!$node->hasAttribute('async')) { $node->setAttribute('defer','defer'); };
2263
+ $tagdefer = $dom->saveHTML($node);
2264
+ }
2265
 
2266
+ # print code if there are no linebreaks, or return
2267
+ if(!empty($tagdefer)) {
2268
+ $deferinsights = '<script type="text/javascript">if(!navigator.userAgent.match(/'.implode('|', $fvmualist).'/i)){document.write('.json_encode($tag).');}</script>';
2269
+ return preg_replace('#<script(.*?)>(.*?)</script>#is', $deferinsights, $tag);
2270
+ }
2271
 
2272
+ }
2273
 
2274
+ # fallback
2275
+ return $tag;
2276
+ }
 
2277
 
2278
 
2279
  # inline css in place, instead of inlining the large file
2496
 
2497
  }
2498
 
2499
+
2500
+
2501
+ # collect all fvm CSS files and save them to an headers file
2502
+ add_filter('style_loader_tag', 'fastvelocity_collect_css_preload_headers', PHP_INT_MAX, 4 );
2503
+ function fastvelocity_collect_css_preload_headers($html, $handle, $href, $media){
2504
+ global $collect_preload_css, $fvm_enabled_css_preload, $fvm_enabled_js_preload;
2505
+
2506
+ # return if disabled
2507
+ if ($fvm_enabled_css_preload != true) {
2508
+ return $html;
2509
+ }
2510
+
2511
+ # collect
2512
+ if (stripos($href, '/fvm/out/') !== false) {
2513
+ $collect_preload_css[] = $href;
2514
+ }
2515
+ return $html;
2516
+ }
2517
+
2518
+ add_filter('script_loader_tag', 'fastvelocity_collect_js_preload_headers', PHP_INT_MAX, 3 );
2519
+ function fastvelocity_collect_js_preload_headers($html, $handle, $src){
2520
+ global $collect_preload_js, $fvm_enabled_css_preload, $fvm_enabled_js_preload;
2521
+
2522
+ # return if disabled
2523
+ if ($fvm_enabled_js_preload != true) {
2524
+ return $html;
2525
+ }
2526
+
2527
+ # collect
2528
+ if (stripos($src, '/fvm/out/') !== false) {
2529
+ $collect_preload_js[] = $src;
2530
+ }
2531
+ return $html;
2532
+ }
2533
+
2534
+ # generate css headers file
2535
+ add_action('wp_footer', 'fastvelocity_generate_preload_headers', PHP_INT_MAX);
2536
+ function fastvelocity_generate_preload_headers(){
2537
+ global $collect_preload_css, $collect_preload_js, $fvm_enabled_css_preload, $fvm_enabled_js_preload;
2538
+
2539
+ # return if disabled
2540
+ if ($fvm_enabled_css_preload != true && $fvm_enabled_js_preload != true) {
2541
+ return false;
2542
+ }
2543
+
2544
+ # get host with multisite support and query strings
2545
+ $host = htmlentities($_SERVER['SERVER_NAME']);
2546
+ if(empty($hosts)) { $host = htmlentities($_SERVER['HTTP_HOST']); }
2547
+ $request_query = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY);
2548
+ $request_uri = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
2549
+ $is_admin = strpos( $request_uri, '/wp-admin/' );
2550
+
2551
+ # always false for admin pages
2552
+ if( false !== $is_admin){
2553
+ return false;
2554
+ }
2555
+
2556
+ # initialize headers
2557
+ $headers = array();
2558
+
2559
+ # css headers
2560
+ if ($fvm_enabled_css_preload != false && is_array($collect_preload_css) && count($collect_preload_css) > 0) {
2561
+ foreach($collect_preload_css as $u) {
2562
+ $headers[] = "Link: <$u>; rel=preload; as=style";
2563
+ }
2564
+ }
2565
+
2566
+ # js headers
2567
+ if ($fvm_enabled_js_preload != false && is_array($collect_preload_js) && count($collect_preload_js) > 0) {
2568
+ foreach($collect_preload_js as $u) {
2569
+ $headers[] = "Link: <$u>; rel=preload; as=script";
2570
+ }
2571
+ }
2572
+
2573
+ # must have something
2574
+ if(count($headers) == 0) {
2575
+ return false;
2576
+ } else {
2577
+ $headers = implode(PHP_EOL, $headers);
2578
+ }
2579
+
2580
+ # get cache path
2581
+ $cachepath = fvm_cachepath();
2582
+ $headerdir = $cachepath['headerdir'];
2583
+ $cachefilebase = $headerdir.'/';
2584
+
2585
+ # possible cache file locations
2586
+ $b = $cachefilebase . md5($host.'-'.$request_uri).'.header';
2587
+ $a = $cachefilebase . md5($host.'-'.$request_uri.$request_query).'.header';
2588
+
2589
+ # reset file cache
2590
+ clearstatcache();
2591
+
2592
+ # if there are no query strings
2593
+ if($b == $a) {
2594
+ if(!file_exists($a)) { file_put_contents($a, $headers); }
2595
+ return false;
2596
+ }
2597
+
2598
+ # b fallback
2599
+ if($b != $a && !file_exists($b)) {
2600
+ file_put_contents($b, $headers);
2601
+ }
2602
+
2603
+ return false;
2604
+ }
2605
+
2606
+
2607
+ # get current headers file for the url
2608
+ function fastvelocity_get_preload_headers(){
2609
+ global $fvm_enabled_css_preload, $fvm_enabled_js_preload;
2610
+
2611
+ # return if disabled
2612
+ if ($fvm_enabled_css_preload != true && $fvm_enabled_js_preload != true) {
2613
+ return false;
2614
+ }
2615
+
2616
+ # get host with multisite support and query strings
2617
+ $host = htmlentities($_SERVER['SERVER_NAME']);
2618
+ if(empty($hosts)) { $host = htmlentities($_SERVER['HTTP_HOST']); }
2619
+ $request_query = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY);
2620
+ $request_uri = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
2621
+ $is_admin = strpos( $request_uri, '/wp-admin/' );
2622
+
2623
+ # always false for admin pages
2624
+ if( false !== $is_admin){
2625
+ return false;
2626
+ }
2627
+
2628
+ # get cache path
2629
+ $cachepath = fvm_cachepath();
2630
+ $headerdir = $cachepath['headerdir'];
2631
+ $cachefilebase = $headerdir.'/';
2632
+
2633
+ # possible cache file locations
2634
+ $b = $cachefilebase . md5($host.'-'.$request_uri).'.header';
2635
+ $a = $cachefilebase . md5($host.'-'.$request_uri.$request_query).'.header';
2636
+
2637
+ # reset file cache
2638
+ clearstatcache();
2639
+
2640
+ # return header files or fallback
2641
+ if($b == $a && file_exists($a)) { return file_get_contents($a); }
2642
+ if($b != $a && file_exists($b)) { return file_get_contents($b); }
2643
+
2644
+ return false;
2645
+ }
inc/functions.php CHANGED
@@ -42,12 +42,14 @@ $cachebase = rtrim($upload['basedir'], '/').'/fvm';
42
  $cachedir = rtrim($upload['basedir'], '/').'/fvm/out';
43
  $tmpdir = rtrim($upload['basedir'], '/').'/fvm/tmp';
44
  $cachedirurl = rtrim($upload['baseurl'], '/').'/fvm/out';
 
45
  if(!is_dir($cachebase)) { mkdir($cachebase, 0755, true); }
46
  if(!is_dir($cachedir)) { mkdir($cachedir, 0755, true); }
47
  if(!is_dir($tmpdir)) { mkdir($tmpdir, 0755, true); }
 
48
 
49
  # return
50
- return array('cachebase'=>$cachebase,'tmpdir'=>$tmpdir, 'cachedir'=>$cachedir, 'cachedirurl'=>$cachedirurl);
51
  }
52
 
53
 
@@ -255,6 +257,7 @@ function fvm_server_is_windows() {
255
 
256
  # minify js on demand (one file at one time, for compatibility)
257
  function fastvelocity_min_get_js($url, $js, $disable_js_minification) {
 
258
 
259
  # exclude minification on already minified files + jquery (because minification might break those)
260
  $excl = array('jquery.js', '.min.js', '-min.js', '/uploads/fusion-scripts/', '/min/', '.packed.js');
@@ -273,10 +276,10 @@ if(!$disable_js_minification) {
273
  # needed when merging js files
274
  $js = trim($js);
275
  if(substr($js, -1) != ';'){ $js = $js.';'; }
276
- $js = '/* info: ' . $url . ' */' . PHP_EOL . $js . PHP_EOL;
277
 
278
  # return html
279
- return $js;
280
  }
281
 
282
 
@@ -355,7 +358,7 @@ function fastvelocity_get_cachestats() {
355
 
356
  # minify css on demand (one file at one time, for compatibility)
357
  function fastvelocity_min_get_css($url, $css, $disable_css_minification) {
358
- global $wp_domain;
359
 
360
  # remove BOM
361
  $css = fastvelocity_min_remove_utf8_bom($css);
@@ -384,7 +387,8 @@ if(!empty($fvm_cdn_url)) {
384
  }
385
 
386
  # add css comment
387
- $css = '/* info: ' . $url . ' */' . PHP_EOL . trim($css) . PHP_EOL;
 
388
 
389
  # return html
390
  return $css;
42
  $cachedir = rtrim($upload['basedir'], '/').'/fvm/out';
43
  $tmpdir = rtrim($upload['basedir'], '/').'/fvm/tmp';
44
  $cachedirurl = rtrim($upload['baseurl'], '/').'/fvm/out';
45
+ $headerdir = rtrim($upload['basedir'], '/').'/fvm/header';
46
  if(!is_dir($cachebase)) { mkdir($cachebase, 0755, true); }
47
  if(!is_dir($cachedir)) { mkdir($cachedir, 0755, true); }
48
  if(!is_dir($tmpdir)) { mkdir($tmpdir, 0755, true); }
49
+ if(!is_dir($headerdir)) { mkdir($headerdir, 0755, true); }
50
 
51
  # return
52
+ return array('cachebase'=>$cachebase,'tmpdir'=>$tmpdir, 'cachedir'=>$cachedir, 'cachedirurl'=>$cachedirurl, 'headerdir'=>$headerdir);
53
  }
54
 
55
 
257
 
258
  # minify js on demand (one file at one time, for compatibility)
259
  function fastvelocity_min_get_js($url, $js, $disable_js_minification) {
260
+ global $fvm_debug;
261
 
262
  # exclude minification on already minified files + jquery (because minification might break those)
263
  $excl = array('jquery.js', '.min.js', '-min.js', '/uploads/fusion-scripts/', '/min/', '.packed.js');
276
  # needed when merging js files
277
  $js = trim($js);
278
  if(substr($js, -1) != ';'){ $js = $js.';'; }
279
+ if($fvm_debug == true) { $js = '/* info: ' . $url . ' */' . PHP_EOL . $js; }
280
 
281
  # return html
282
+ return $js . PHP_EOL;
283
  }
284
 
285
 
358
 
359
  # minify css on demand (one file at one time, for compatibility)
360
  function fastvelocity_min_get_css($url, $css, $disable_css_minification) {
361
+ global $wp_domain, $fvm_debug;
362
 
363
  # remove BOM
364
  $css = fastvelocity_min_remove_utf8_bom($css);
387
  }
388
 
389
  # add css comment
390
+ $css = trim($css);
391
+ if($fvm_debug == true) { $css = '/* info: ' . $url . ' */' . PHP_EOL . trim($css); }
392
 
393
  # return html
394
  return $css;
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: Alignak
3
  Tags: PHP Minify, Lighthouse, GTmetrix, Pingdom, Pagespeed, CSS Merging, JS Merging, CSS Minification, JS Minification, Speed Optimization, HTML Minification, Performance, Optimization, Speed, Fast
4
  Requires at least: 4.5
5
- Stable tag: 2.4.1
6
  Tested up to: 5.0
7
  License: GPLv3 or later
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
@@ -111,6 +111,9 @@ The ignore list "is" working, just try to use partial paths (see wildcard help a
111
 
112
  Please note, you must disable any features on your theme or cache plugins, which perform minification of css, html and js. Double minification not only slows the whole process, but also has the high potential of causing conflicts in javascript. The plugin will try to automatically purge several popular cache plugins, however if you have a cache on the server side (some hosting services have this) you may need to purge it manually, after you purge FVM. 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, Cache Enabler, SG Optimizer, Godaddy Managed WordPress Hosting and WP Engine
113
 
 
 
 
114
 
115
  = Is it resource intensive, or will it use too much CPU on my shared hosting plan? =
116
 
@@ -199,6 +202,12 @@ If you would like to donate any amount to the plugin author (thank you in advanc
199
 
200
  == Changelog ==
201
 
 
 
 
 
 
 
202
  = 2.4.1 [2018.11.27] =
203
  * better FVM default settings
204
 
2
  Contributors: Alignak
3
  Tags: PHP Minify, Lighthouse, GTmetrix, Pingdom, Pagespeed, CSS Merging, JS Merging, CSS Minification, JS Minification, Speed Optimization, HTML Minification, Performance, Optimization, Speed, Fast
4
  Requires at least: 4.5
5
+ Stable tag: 2.4.2
6
  Tested up to: 5.0
7
  License: GPLv3 or later
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
111
 
112
  Please note, you must disable any features on your theme or cache plugins, which perform minification of css, html and js. Double minification not only slows the whole process, but also has the high potential of causing conflicts in javascript. The plugin will try to automatically purge several popular cache plugins, however if you have a cache on the server side (some hosting services have this) you may need to purge it manually, after you purge FVM. 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, Cache Enabler, SG Optimizer, Godaddy Managed WordPress Hosting and WP Engine
113
 
114
+ = Do you recommend a specific Cache Plugin? =
115
+ Yes! Currently FVM recommends the "Cache Enabler" plugin, for it's simplicity, compatibility with most systems and performance.
116
+
117
 
118
  = Is it resource intensive, or will it use too much CPU on my shared hosting plan? =
119
 
202
 
203
  == Changelog ==
204
 
205
+ = 2.4.2 [2018.11.29] =
206
+ * fixed a bug with the "Exclude JS files in the ignore list from PSI" option (it wasn't excluding properly)
207
+ * improved functionality with the "Exclude CSS files from PSI" option (now works with both inline and link stylesheets)
208
+ * added an option to automatically preload the CSS and JS files generated by FVM (beware that some server caches like Pantheon may push old css and js files even after purging caches on FVM)
209
+ * improved JavaScript minification
210
+
211
  = 2.4.1 [2018.11.27] =
212
  * better FVM default settings
213