Fast Velocity Minify - Version 3.1.5

Version Description

[2021.04.24] = * added support for WP Cloudflare Super Page Cache plugin * fixed support for LiteSpeed Cache purging * changed the cache directory to the uploads directory (WP_Filesystem_Direct) * deprecated CSS and JS merging as this is no longer recommended for HTTP/2 servers * stop removing RSS feeds references on the header cleanup option * changed some descriptions and updated the HELP section * other bug fixes

Download this release

Release Info

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

Code changes from version 3.1.4 to 3.1.5

assets/fvm.js CHANGED
@@ -3,26 +3,19 @@ function fvm_get_logs() {
3
 
4
  // ajax request
5
  jQuery( document ).ready(function() {
6
- var data = { 'action': 'fvm_get_logs' };
7
- jQuery.post(ajaxurl, data, function(resp) {
8
- if(resp.success == 'OK') {
9
-
10
- // cache stats
11
- jQuery('.fvm-cache-stats').html("There are "+resp.stats_css.count+" CSS files and "+resp.stats_js.count+" JS files using a total of "+resp.stats_total.size+" on your cache directory");
 
12
 
13
- // css log
14
- jQuery('textarea.log-css').val(resp.css_log);
15
- jQuery('textarea.log-css').scrollTop(0);
16
-
17
- // js log
18
- jQuery('textarea.log-js').val(resp.js_log);
19
- jQuery('textarea.log-js').scrollTop(0);
20
-
21
- } else {
22
- // error log
23
- console.error(resp.success);
24
- }
25
- });
26
  });
27
  }
28
 
3
 
4
  // ajax request
5
  jQuery( document ).ready(function() {
6
+ var data = { 'action': 'fvm_get_logs' };
7
+ jQuery.post(ajaxurl, data, function(resp) {
8
+ if(resp.success == 'OK') {
9
+
10
+ // logs
11
+ jQuery('.log-stats textarea').val(resp.log);
12
+ jQuery('.log-stats textarea').scrollTop(jQuery('.log-stats textarea')[0].scrollHeight);
13
 
14
+ } else {
15
+ // error log
16
+ console.error(resp.success);
17
+ }
18
+ });
 
 
 
 
 
 
 
 
19
  });
20
  }
21
 
fvm.php CHANGED
@@ -6,7 +6,7 @@ Description: Improve your speed score on GTmetrix, Pingdom Tools and Google Page
6
  Author: Raul Peixoto
7
  Author URI: http://fastvelocity.com
8
  Text Domain: fast-velocity-minify
9
- Version: 3.1.4
10
  License: GPL2
11
 
12
  ------------------------------------------------------------------------
@@ -54,9 +54,6 @@ if (defined('WP_CLI') && WP_CLI) {
54
  # get all options from database
55
  $fvm_settings = fvm_get_settings();
56
 
57
- # get cache paths and info
58
- $fvm_cache_paths = fvm_cachepath();
59
-
60
  # site url, domain name
61
  $fvm_urls = array('wp_site_url'=>site_url(), 'wp_domain'=>fvm_get_domain());
62
 
6
  Author: Raul Peixoto
7
  Author URI: http://fastvelocity.com
8
  Text Domain: fast-velocity-minify
9
+ Version: 3.1.5
10
  License: GPL2
11
 
12
  ------------------------------------------------------------------------
54
  # get all options from database
55
  $fvm_settings = fvm_get_settings();
56
 
 
 
 
57
  # site url, domain name
58
  $fvm_urls = array('wp_site_url'=>site_url(), 'wp_domain'=>fvm_get_domain());
59
 
inc/admin.php CHANGED
@@ -45,24 +45,45 @@ function fvm_check_minimum_requirements() {
45
 
46
  # check for soft errors and misconfiguration
47
  function fvm_check_misconfiguration() {
48
- if(current_user_can('manage_options')) {
49
-
50
- global $fvm_settings, $fvm_cache_paths;
51
-
52
- # check if custom cache directory exists
53
- if(isset($fvm_settings['cache']['path']) && !empty($fvm_settings['cache']['path']) && !is_dir($fvm_settings['cache']['path']) && !is_writeable($fvm_settings['cache']['path'])) {
54
- add_settings_error( 'fvm_admin_notice', 'fvm_admin_notice', __( 'FVM needs writing permissions.', 'fast-velocity-minify' ).
55
- ' ['.$fvm_settings['cache']['path'].']' , 'success' );
 
 
 
 
 
 
 
 
56
  }
57
 
58
- # cache permissions
59
- if(!is_dir($fvm_cache_paths['cache_base_dir']) && !is_writeable($fvm_settings['cache']['path'])) {
60
- $error = __( 'FVM needs writing permissions.', 'fast-velocity-minify' ) . ' ['.$fvm_cache_paths['cache_base_dir'].']';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  }
62
 
63
- # initialize database routine if not available
64
- fvm_initialize_database();
65
-
66
  }
67
  }
68
 
@@ -229,155 +250,40 @@ function fvm_get_logs_callback() {
229
 
230
  # must be able to cleanup cache
231
  if (!current_user_can('manage_options')) {
232
- wp_die( __('You do not have sufficient permissions to access this page.', 'fast-velocity-minify'), __('Error:', 'fast-velocity-minify'), array('response'=>200));
233
  }
234
 
235
  # must have
236
  if(!defined('WP_CONTENT_DIR')) {
237
- wp_die( __('WP_CONTENT_DIR is undefined!', 'fast-velocity-minify'), __('Error:', 'fast-velocity-minify'), array('response'=>200));
238
  }
239
 
240
- # get info
241
- global $fvm_cache_paths;
242
-
243
- # must have valid cache paths
244
- if(isset($fvm_cache_paths['cache_dir_min']) && !empty($fvm_cache_paths['cache_dir_min'])) {
245
-
246
- # defaults
247
- $count_css = 0;
248
- $count_js = 0;
249
- $size_css = 0;
250
- $size_js = 0;
251
 
252
- # scan min directory recursively
253
- $errora = false;
254
- if(is_dir($fvm_cache_paths['cache_dir_min'])) {
255
- try {
256
- $i = new DirectoryIterator($fvm_cache_paths['cache_dir_min']);
257
- foreach($i as $f){
258
- if($f->isFile()){
259
-
260
- # javascript
261
- if(stripos($f->getRealPath(), '.js') !== false) {
262
- $count_js = $count_js + 1;
263
- $size_js = $size_js + intval($f->getSize());
264
- }
265
-
266
- # css
267
- if(stripos($f->getRealPath(), '.css') !== false) {
268
- $count_css = $count_css + 1;
269
- $size_css = $size_css + intval($f->getSize());
270
- }
271
-
272
- }
273
- }
274
- } catch (Exception $e) {
275
- $errora = get_class($e) . ": " . $e->getMessage();
276
- }
277
- }
278
-
279
- # return early if errors
280
- if($errora != false) {
281
- header('Content-Type: application/json');
282
- echo json_encode(array('error' => $errora));
283
- exit();
284
- }
285
-
286
 
287
- # defaults
288
- global $wpdb;
289
- $tbl_name_log = $wpdb->prefix .'fvm_logs';
290
- $tbl_name_cache = $wpdb->prefix .'fvm_cache';
291
-
292
- # initialize log
293
- $css_log = '';
294
-
295
- # build css logs from database
296
 
297
- $results = $wpdb->get_results("SELECT date, content, meta FROM `$tbl_name_log` WHERE type = 'css' ORDER BY id DESC LIMIT 20");
298
-
299
- # build second query
300
- foreach ($results as $log) {
301
-
302
- # get meta into an array
303
- $meta = json_decode($log->meta, true);
304
-
305
- # start log
306
- $css_log.= '+++++++++' . PHP_EOL;
307
- $css_log.= 'PROCESSED - ' . date('r', $log->date) . ' - VIA - '. $meta['loc'] . PHP_EOL;
308
- $css_log.= 'GENERATED - ' . $meta['fl'] . PHP_EOL;
309
- $css_log.= 'MEDIATYPE - ' . $meta['mt'] . PHP_EOL;
310
- $css_log.= '---' . PHP_EOL;
311
-
312
- # generate uid's from json
313
- $list = array(); $list = json_decode($log->content);
314
-
315
- # get rows to log file
316
- if(count($list) > 0) {
317
- $listuids = implode(', ', array_fill(0, count($list), '%s'));
318
- if(!empty($listuids)) {
319
- $rs = array(); $rs = $wpdb->get_results($wpdb->prepare("SELECT meta FROM `$tbl_name_cache` WHERE uid IN (".$listuids.") ORDER BY FIELD(uid, '".implode("', '", $list)."')", $list));
320
- foreach ($rs as $r) {
321
- $imt = json_decode($r->meta, true);
322
- $css_log.= '[Size: '.str_pad(fvm_format_filesize($imt['fs']), 10,' ',STR_PAD_LEFT).']'."\t". $imt['url'] . PHP_EOL;
323
- }
324
- }
325
- $css_log.= '+++++++++' . PHP_EOL . PHP_EOL;
326
- }
327
  }
328
-
329
- # trim
330
- $css_log = trim($css_log);
 
331
 
332
- # initialize log
333
- $js_log = '';
334
-
335
- # build css logs from database
336
- $results = $wpdb->get_results("SELECT date, content, meta FROM `$tbl_name_log` WHERE type = 'js' ORDER BY id DESC LIMIT 20");
337
-
338
- # build second query
339
- foreach ($results as $log) {
340
-
341
- # get meta into an array
342
- $meta = json_decode($log->meta, true);
343
-
344
- # start log
345
- $js_log.= '+++++++++' . PHP_EOL;
346
- $js_log.= __( 'PROCESSED', 'fast-velocity-minify' ) . ' - ' . date('r', $log->date) . ' - VIA - '. $meta['loc'] . PHP_EOL;
347
- $js_log.= __( 'GENERATED', 'fast-velocity-minify' ) . ' - ' . $meta['fl'] . PHP_EOL;
348
- $js_log.= '---' . PHP_EOL;
349
-
350
- # generate uid's from json
351
- $list = array(); $list = json_decode($log->content);
352
-
353
- # get rows to log file
354
- if(count($list) > 0) {
355
- $listuids = implode(', ', array_fill(0, count($list), '%s'));
356
- if(!empty($listuids)) {
357
- $rs = array(); $rs = $wpdb->get_results($wpdb->prepare("SELECT meta FROM `$tbl_name_cache` WHERE uid IN (".$listuids.") ORDER BY FIELD(uid, '".implode("', '", $list)."')", $list));
358
- foreach ($rs as $r) {
359
- $imt = json_decode($r->meta, true);
360
- $js_log.= '['.__( 'Size:', 'fast-velocity-minify' ).' '.str_pad(fvm_format_filesize($imt['fs']), 10,' ',STR_PAD_LEFT).']'."\t". $imt['url'] . PHP_EOL;
361
- }
362
- }
363
- $js_log.= '+++++++++' . PHP_EOL . PHP_EOL;
364
- }
365
- }
366
-
367
- # trim
368
- $js_log = trim($js_log);
369
-
370
- # default message
371
- if(empty($css_log)) { $css_log = __( 'No CSS files generated yet.', 'fast-velocity-minify' ); }
372
- if(empty($js_log)) { $js_log = __( 'No JS files generated yet.', 'fast-velocity-minify' ); }
373
-
374
  # build info
375
  $result = array(
376
- 'stats_total' => array('count'=>($count_css+$count_js), 'size'=>fvm_format_filesize($size_css+$size_js)),
377
- 'stats_css' => array('count'=>$count_css, 'size'=>fvm_format_filesize($size_css)),
378
- 'stats_js' => array('count'=>$count_js, 'size'=>fvm_format_filesize($size_js)),
379
- 'js_log' => $js_log,
380
- 'css_log' => $css_log,
381
  'success' => 'OK'
382
  );
383
 
@@ -385,11 +291,7 @@ function fvm_get_logs_callback() {
385
  header('Content-Type: application/json');
386
  echo json_encode($result);
387
  exit();
388
-
389
- }
390
 
391
- # default
392
- wp_die( __('Unknown cache path!', 'fast-velocity-minify'), __('Error:', 'fast-velocity-minify'), array('response'=>200));
393
  }
394
 
395
 
@@ -397,47 +299,47 @@ function fvm_get_logs_callback() {
397
  register_activation_hook($fvm_var_file, 'fvm_plugin_activate');
398
  function fvm_plugin_activate() {
399
 
400
- # default variables
401
  global $wpdb;
402
- $charset_collate = $wpdb->get_charset_collate();
403
- $sqla_table_name = $wpdb->prefix . 'fvm_cache';
404
- $sqlb_table_name = $wpdb->prefix . 'fvm_logs';
 
 
405
 
406
- # prepare
407
- $sqla = "CREATE TABLE IF NOT EXISTS `$sqla_table_name` (
408
- `id` bigint(20) unsigned NOT NULL auto_increment,
409
- `uid` varchar(60) NOT NULL,
410
- `date` bigint(20) unsigned NOT NULL,
411
- `type` varchar(32) NOT NULL,
412
- `content` mediumtext NOT NULL,
413
- `meta` mediumtext NOT NULL,
414
- PRIMARY KEY (id),
415
- UNIQUE KEY uid (uid),
416
- KEY date (date), KEY type (type)
417
- ) $charset_collate;";
 
 
418
 
419
  # create logs table
420
-
421
- $sqlb = "CREATE TABLE IF NOT EXISTS `$sqlb_table_name` (
422
- `id` bigint(20) unsigned NOT NULL auto_increment,
423
- `uid` varchar(60) NOT NULL,
424
- `date` bigint(20) unsigned NOT NULL,
425
- `type` varchar(32) NOT NULL,
426
- `content` mediumtext NOT NULL,
427
- `meta` mediumtext NOT NULL,
428
- PRIMARY KEY (id),
429
- UNIQUE KEY uid (uid),
430
- KEY date (date),
431
- KEY type (type)
432
- ) $charset_collate;";
 
433
 
434
  # run sql
435
- require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
436
- dbDelta( $sqla );
437
- dbDelta( $sqlb );
438
-
439
- # initialize cache time
440
- fvm_cache_increment();
441
 
442
  }
443
 
@@ -445,71 +347,35 @@ function fvm_plugin_activate() {
445
  # run during deactivation
446
  register_deactivation_hook($fvm_var_file, 'fvm_plugin_deactivate');
447
  function fvm_plugin_deactivate() {
448
- global $wpdb, $fvm_settings, $fvm_cache_paths;
449
-
450
- # remove all caches on deactivation
451
- if(isset($fvm_cache_paths['cache_dir_min']) && stripos($fvm_cache_paths['cache_dir_min'], '/fvm') !== false) {
452
- fvm_rrmdir($fvm_cache_paths['cache_base_dir']);
453
- }
454
 
455
- # delete cache table
456
- $tbl_name = $wpdb->prefix .'fvm_cache';
457
- $sql = $wpdb->prepare( "DROP TABLE IF EXISTS `$tbl_name`", $tbl_name);
458
- $wpdb->query($sql);
459
 
460
- # delete logs table
461
- $tbl_name = $wpdb->prefix .'fvm_logs';
462
- $sql = $wpdb->prepare( "DROP TABLE IF EXISTS `$tbl_name`", $tbl_name);
463
- $wpdb->query($sql);
464
 
465
  }
466
 
467
  # run during uninstall
468
  register_uninstall_hook($fvm_var_file, 'fvm_plugin_uninstall');
469
  function fvm_plugin_uninstall() {
470
- global $wpdb, $fvm_settings, $fvm_cache_paths;
471
-
472
- # fetch settings on wp-cli
473
- if(is_null($fvm_settings)) { $fvm_settings = fvm_get_settings(); }
474
- if(is_null($fvm_cache_paths)) { $fvm_cache_paths = fvm_cachepath(); }
475
-
476
- # remove settings, unless disabled
477
- if(!isset($fvm_settings['global']['preserve_settings']) || ( isset($fvm_settings['global']['preserve_settings']) && $fvm_settings['global']['preserve_settings'] != true)) {
478
-
479
- # prepare and delete
480
- $tbl_name = $wpdb->prefix .'options';
481
- $sql = $wpdb->prepare( "DELETE FROM `$tbl_name` WHERE option_name = 'fvm_settings'");
482
- $wpdb->query($sql);
483
- $sql = $wpdb->prepare( "DELETE FROM `$tbl_name` WHERE option_name = 'fvm_last_cache_update'");
484
- $wpdb->query($sql);
485
-
486
- }
487
 
488
- # delete cache table
489
- $tbl_name = $wpdb->prefix .'fvm_cache';
490
- $sql = $wpdb->prepare( "DROP TABLE IF EXISTS `$tbl_name`");
491
- $wpdb->query($sql);
 
492
 
493
- # delete logs table
494
- $tbl_name = $wpdb->prefix .'fvm_logs';
495
- $sql = $wpdb->prepare( "DROP TABLE IF EXISTS `$tbl_name`");
496
- $wpdb->query($sql);
497
 
498
- # remove all cache directories
499
- if(isset($fvm_cache_paths['cache_dir_min']) && stripos($fvm_cache_paths['cache_dir_min'], '/fvm') !== false) {
500
- fvm_rrmdir($fvm_cache_paths['cache_base_dir']);
501
- }
502
- }
503
-
504
- # initialize database if it doesn't exist
505
- function fvm_initialize_database() {
506
- require_once ABSPATH . 'wp-admin/includes/upgrade.php';
507
- global $wpdb;
508
- $tbl_name = $wpdb->prefix .'fvm_cache';
509
- $sql = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $tbl_name ) );
510
- if ( $wpdb->get_var( $sql ) !== $tbl_name ) {
511
- fvm_plugin_activate();
512
- }
513
  }
514
 
515
 
45
 
46
  # check for soft errors and misconfiguration
47
  function fvm_check_misconfiguration() {
48
+ try {
49
+
50
+ # plugin version
51
+ global $fvm_var_plugin_version;
52
+ if(is_null($fvm_var_plugin_version)) { return false; }
53
+
54
+ # if no database version, regenerate
55
+ $plugin_meta = get_option('fvm_plugin_meta');
56
+ if($plugin_meta === false) {
57
+
58
+ # startup routines
59
+ fvm_plugin_deactivate();
60
+ fvm_plugin_activate();
61
+
62
+ # save
63
+ update_option('fvm_plugin_meta', json_encode(array('dbv'=>0)) );
64
  }
65
 
66
+ # updates
67
+ if($plugin_meta !== false) {
68
+
69
+ # future updates
70
+ $meta = json_decode($plugin_meta, true);
71
+ $previous_version = $meta['dbv'];
72
+ if($fvm_var_plugin_version != $previous_version) {
73
+
74
+ # startup routines
75
+ fvm_plugin_deactivate();
76
+ fvm_plugin_activate();
77
+
78
+ # save
79
+ update_option('fvm_plugin_meta', json_encode(array('dbv'=>$fvm_var_plugin_version)) );
80
+
81
+ }
82
+
83
  }
84
 
85
+ } catch (Exception $e) {
86
+ error_log('Caught exception (fvm_initialize_database): '.$e->getMessage(), 0);
 
87
  }
88
  }
89
 
250
 
251
  # must be able to cleanup cache
252
  if (!current_user_can('manage_options')) {
253
+ wp_die( __('You do not have sufficient permissions to access this page.'), __('Error:'), array('response'=>200));
254
  }
255
 
256
  # must have
257
  if(!defined('WP_CONTENT_DIR')) {
258
+ wp_die( __('WP_CONTENT_DIR is undefined!'), __('Error:'), array('response'=>200));
259
  }
260
 
261
+ # defaults
262
+ global $wpdb;
263
+ if(is_null($wpdb)) {
264
+ wp_die( __('Database error!'), __('Error:'), array('response'=>200));
265
+ }
 
 
 
 
 
 
266
 
267
+ # initialize log
268
+ $log = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
 
270
+ # build css logs from database
271
+ $results = $wpdb->get_results("SELECT date, msg FROM ".$wpdb->prefix."fvm_logs ORDER BY id DESC LIMIT 500", 'ARRAY_A');
 
 
 
 
 
 
 
272
 
273
+ # build log
274
+ if(is_array($results)) {
275
+ foreach (array_reverse($results, true) as $r) {
276
+ $log.= 'PROCESSED ON - ' . date('r', $r['date']) . PHP_EOL;
277
+ $log.= $r['msg'] . PHP_EOL . PHP_EOL;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  }
279
+ }
280
+
281
+ # default message
282
+ if(empty($log)) { $log = 'No logs generated yet.'; }
283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  # build info
285
  $result = array(
286
+ 'log' => $log,
 
 
 
 
287
  'success' => 'OK'
288
  );
289
 
291
  header('Content-Type: application/json');
292
  echo json_encode($result);
293
  exit();
 
 
294
 
 
 
295
  }
296
 
297
 
299
  register_activation_hook($fvm_var_file, 'fvm_plugin_activate');
300
  function fvm_plugin_activate() {
301
 
 
302
  global $wpdb;
303
+ if(is_null($wpdb)) { return false; }
304
+
305
+ # defauls
306
+ $sql = array();
307
+ $wpdb_collate = $wpdb->collate;
308
 
309
+ # create cache table
310
+ $sqla_table_name = $wpdb->prefix . 'fvm_cache';
311
+ $sqla = "CREATE TABLE IF NOT EXISTS {$sqla_table_name} (
312
+ `id` bigint(20) unsigned NOT NULL auto_increment ,
313
+ `uid` varchar(64) NOT NULL,
314
+ `date` bigint(10) unsigned NOT NULL,
315
+ `type` varchar(3) NOT NULL,
316
+ `content` mediumtext NOT NULL,
317
+ `meta` mediumtext NOT NULL,
318
+ PRIMARY KEY (id),
319
+ UNIQUE KEY uid (uid),
320
+ KEY date (date), KEY type (type)
321
+ )
322
+ COLLATE {$wpdb_collate}";
323
 
324
  # create logs table
325
+ $sqlb_table_name = $wpdb->prefix . 'fvm_logs';
326
+ $sqlb = "CREATE TABLE IF NOT EXISTS {$sqlb_table_name} (
327
+ `id` bigint(20) unsigned NOT NULL auto_increment,
328
+ `uid` varchar(64) NOT NULL,
329
+ `date` bigint(10) unsigned NOT NULL,
330
+ `type` varchar(10) NOT NULL,
331
+ `msg` mediumtext NOT NULL,
332
+ `meta` mediumtext NOT NULL,
333
+ PRIMARY KEY (id),
334
+ UNIQUE KEY uid (uid),
335
+ KEY date (date),
336
+ KEY type (type)
337
+ )
338
+ COLLATE {$wpdb_collate}";
339
 
340
  # run sql
341
+ $wpdb->query($sqla);
342
+ $wpdb->query($sqlb);
 
 
 
 
343
 
344
  }
345
 
347
  # run during deactivation
348
  register_deactivation_hook($fvm_var_file, 'fvm_plugin_deactivate');
349
  function fvm_plugin_deactivate() {
350
+
351
+ global $wpdb;
352
+ if(is_null($wpdb)) { return false; }
 
 
 
353
 
354
+ # remove options and tables
355
+ $wpdb->query("DELETE FROM {$wpdb->prefix}options WHERE option_name = 'fvm_last_cache_update'");
356
+ $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}fvm_cache");
357
+ $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}fvm_logs");
358
 
359
+ # process cache settings
360
+ fvm_purge_static_files();
 
 
361
 
362
  }
363
 
364
  # run during uninstall
365
  register_uninstall_hook($fvm_var_file, 'fvm_plugin_uninstall');
366
  function fvm_plugin_uninstall() {
367
+ global $wpdb;
368
+ if(is_null($wpdb)) { return false; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
369
 
370
+ # remove options and tables
371
+ $wpdb->query("DELETE FROM {$wpdb->prefix}options WHERE option_name = 'fvm_settings'");
372
+ $wpdb->query("DELETE FROM {$wpdb->prefix}options WHERE option_name = 'fvm_last_cache_update'");
373
+ $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}fvm_cache");
374
+ $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}fvm_logs");
375
 
376
+ # process cache settings
377
+ fvm_purge_static_files();
 
 
378
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  }
380
 
381
 
inc/common.php CHANGED
@@ -74,7 +74,7 @@ function fvm_process_cache_purge_request(){
74
  if($_GET['fvm_do'] == 'clear_all') {
75
 
76
  # purge everything
77
- $cache = fvm_purge_minification();
78
  $others = fvm_purge_others();
79
 
80
  if(is_admin()) {
@@ -100,163 +100,13 @@ function fvm_process_cache_purge_request(){
100
  }
101
 
102
 
103
- # get cache directories and urls
104
- function fvm_cachepath() {
105
-
106
- # must have
107
- if(!defined('WP_CONTENT_DIR')) { return false; }
108
- if(!defined('WP_CONTENT_URL')) { return false; }
109
-
110
- # to var
111
- $wp_content_dir = WP_CONTENT_DIR;
112
- $wp_content_url = WP_CONTENT_URL;
113
-
114
- # globals
115
- global $fvm_settings;
116
-
117
- # force https option
118
- if(isset($fvm_settings['global']['force-ssl']) && $fvm_settings['global']['force-ssl'] == true) {
119
- $wp_content_url = str_ireplace('http:', 'https:', $wp_content_url);
120
- }
121
-
122
- # define cache directory
123
- $cache_dir = $wp_content_dir . DIRECTORY_SEPARATOR . 'cache';
124
- $cache_base_dir = $cache_dir . DIRECTORY_SEPARATOR .'fvm';
125
- $cache_base_dirurl = $wp_content_url . '/cache/fvm';
126
-
127
- # use alternative directory?
128
- if(isset($fvm_settings['cache']['path']) && !empty($fvm_settings['cache']['path']) && isset($fvm_settings['cache']['url']) && !empty($fvm_settings['cache']['url']) && is_dir($fvm_settings['cache']['path'])) {
129
- $cache_dir = rtrim($fvm_settings['cache']['path'], '/');
130
- $cache_base_dir = $cache_dir . DIRECTORY_SEPARATOR .'fvm';
131
- $cache_base_dirurl = rtrim($fvm_settings['cache']['url'], '/') . '/fvm';
132
- }
133
-
134
- # get requested hostname
135
- $host = fvm_get_domain();
136
-
137
- $cache_dir_min = $cache_base_dir . DIRECTORY_SEPARATOR . 'min' . DIRECTORY_SEPARATOR . $host;
138
- $cache_url_min = $cache_base_dirurl . '/min/' .$host;
139
-
140
- # mkdir and check if umask requires chmod, but only for hosts matching the site_url'
141
- $dirs = array($cache_dir, $cache_base_dir, $cache_dir_min);
142
- foreach ($dirs as $d) {
143
- fvm_create_dir($d);
144
- }
145
-
146
- # return
147
- return array(
148
- 'cache_base_dir'=>$cache_base_dir,
149
- 'cache_base_dirurl'=>$cache_base_dirurl,
150
- 'cache_dir_min'=>$cache_dir_min,
151
- 'cache_url_min'=>$cache_url_min
152
- );
153
- }
154
-
155
-
156
  # Purge everything
157
  function fvm_purge_all() {
158
- fvm_purge_minification();
159
  fvm_purge_others();
160
  return true;
161
  }
162
 
163
- # Purge minification only
164
- function fvm_purge_minification() {
165
-
166
- # flush opcache
167
- if(function_exists('opcache_reset')) {
168
- @opcache_reset();
169
- }
170
-
171
- # increment cache file names
172
- $now = fvm_cache_increment();
173
-
174
- # truncate cache table (doesn't work with prepared statements)
175
- global $wpdb;
176
-
177
- # purge cache table
178
- $tbl_name = "{$wpdb->prefix}fvm_cache";
179
- $wpdb->query("TRUNCATE TABLE `$tbl_name`");
180
-
181
- # purge logs table
182
- $tbl_name = "{$wpdb->prefix}fvm_logs";
183
- $wpdb->query("TRUNCATE TABLE `$tbl_name`");
184
-
185
- # get cache and min directories
186
- global $fvm_cache_paths, $fvm_settings;
187
-
188
- # fetch settings on wp-cli
189
- if(is_null($fvm_settings)) { $fvm_settings = fvm_get_settings(); }
190
- if(is_null($fvm_cache_paths)) { $fvm_cache_paths = fvm_cachepath(); }
191
-
192
- # purge html directory?
193
- if(isset($fvm_cache_paths['cache_dir_min']) && is_dir($fvm_cache_paths['cache_dir_min']) && is_writable($fvm_cache_paths['cache_dir_min']) && stripos($fvm_cache_paths['cache_dir_min'], DIRECTORY_SEPARATOR . 'fvm') !== false) {
194
-
195
- # purge css/js files instantly
196
- if(isset($fvm_settings['cache']['min_instant_purge']) && $fvm_settings['cache']['min_instant_purge'] == true) {
197
- $result = fvm_purge_minification_now();
198
- return $result;
199
- } else {
200
- # schedule purge for 24 hours later, only once
201
- add_action( 'fvm_purge_minification_later', 'fvm_purge_minification_expired' );
202
- wp_schedule_single_event(time() + 3600 * 24, 'fvm_purge_minification_later');
203
- return __( 'Expired minification files are set to be deleted in 24 hours.', 'fast-velocity-minify' );
204
- }
205
-
206
- } else {
207
- return __( 'The cache directory is not writeable!', 'fast-velocity-minify' );
208
- }
209
-
210
- return false;
211
- }
212
-
213
-
214
- # purge minified files right now
215
- function fvm_purge_minification_now() {
216
- global $fvm_cache_paths;
217
- if(isset($fvm_cache_paths['cache_dir_min']) && stripos($fvm_cache_paths['cache_dir_min'], DIRECTORY_SEPARATOR . 'fvm') !== false) {
218
- $result = fvm_rrmdir($fvm_cache_paths['cache_dir_min']);
219
- return $result;
220
- } else {
221
- return __( 'The cache directory is not writeable!', 'fast-velocity-minify' );
222
- }
223
- }
224
-
225
- # purge expired minification files only
226
- function fvm_purge_minification_expired() {
227
- global $fvm_cache_paths;
228
- if(isset($fvm_cache_paths['cache_dir_min']) && !empty($fvm_cache_paths['cache_dir_min']) && stripos($fvm_cache_paths['cache_dir_min'], DIRECTORY_SEPARATOR . 'fvm') !== false) {
229
-
230
- # must be on the allowed path
231
- $wd = $fvm_cache_paths['cache_dir_min'];
232
- if(empty($wd) || !defined('WP_CONTENT_DIR') || stripos($wd, DIRECTORY_SEPARATOR . 'fvm') === false) {
233
- return __( 'Requested purge path is not allowed!', 'fast-velocity-minify' );
234
- }
235
-
236
- # prefix
237
- $skip = get_option('fvm_last_cache_update', '0');
238
-
239
- # purge only the expired cache that doesn't match the current cache version prefix and it's older than 24 hours
240
- clearstatcache();
241
- if(is_dir($wd)) {
242
- try {
243
- $i = new DirectoryIterator($wd);
244
- foreach($i as $f){
245
- if($f->isFile() && stripos(basename($f->getRealPath()), $skip) === false){
246
- if($f->getMTime() <= time() - 86400) {
247
- @unlink($f->getRealPath());
248
- }
249
- }
250
- }
251
- } catch (Exception $e) {
252
- return get_class($e) . ": " . $e->getMessage();
253
- }
254
- }
255
-
256
- return __( 'Expired cache is now deleted!', 'fast-velocity-minify' );
257
- }
258
- }
259
-
260
 
261
  # purge supported hosting and plugins
262
  function fvm_purge_others(){
@@ -299,11 +149,17 @@ function fvm_purge_others(){
299
  return __( 'All caches on <strong>Comet Cache</strong> have been purged.', 'fast-velocity-minify' );
300
  }
301
 
302
- # Purge LiteSpeed Cache
303
- if (class_exists('LiteSpeed_Cache_Tags')) {
304
- LiteSpeed_Cache_Tags::add_purge_tag('*');
305
  return __( 'All caches on <strong>LiteSpeed Cache</strong> have been purged.', 'fast-velocity-minify' );
306
  }
 
 
 
 
 
 
307
 
308
  # Purge Hyper Cache
309
  if (class_exists( 'HyperCache' )) {
@@ -425,149 +281,164 @@ function fvm_godaddy_request( $method, $url = null ) {
425
  }
426
 
427
 
 
428
  # check if we can minify the page
429
- function fvm_can_minify() {
 
 
 
 
430
 
431
- global $fvm_urls;
 
432
 
433
- # must have
434
- if(!isset($_SERVER['REQUEST_URI']) || !isset($_SERVER['REQUEST_METHOD'])){
435
- return false;
436
- }
437
 
438
- # only GET requests allowed
439
- if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
 
 
 
440
  return false;
441
  }
442
 
443
- # disable on nocache query string
444
- if (!empty($_SERVER['REQUEST_URI'])) {
445
 
446
- $parseurl = parse_url($_SERVER['REQUEST_URI']);
447
- if(isset($parseurl["query"]) && !empty($parseurl["query"])) {
448
-
449
- # parse query string to array
450
- $query_string_arr = array();
451
- parse_str($parseurl["query"], $query_string_arr);
452
-
453
- # specifically allowed query strings
454
- $allowed = array('_ga', 'age-verified', 'ao_noptimize', 'cn-reloaded', 'fb_action_ids', 'fb_action_types', 'fb_source', 'fbclid', 'gclid', 'usqp', 'utm_campaign', 'utm_content', 'utm_expid', 'utm_medium', 'utm_source', 'utm_term');
455
-
456
- foreach ( $allowed as $qs) {
457
- if(isset($query_string_arr[$qs])) { unset($query_string_arr[$qs]); }
458
- }
459
 
460
- # return false if there are any query strings left
461
- if(count($query_string_arr) > 0) {
462
- return false;
463
- }
464
- }
465
-
466
- }
467
-
468
- # compatibility with DONOTCACHEPAGE
469
- if( defined('DONOTCACHEPAGE') && DONOTCACHEPAGE ){ return false; }
470
 
471
- # detect api requests (only defined after parse_request hook)
472
- if( defined('REST_REQUEST') && REST_REQUEST ){ return false; }
 
473
 
474
- # always skip on these tasks
475
- if( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ){ return false; }
476
- if( defined('WP_INSTALLING') && WP_INSTALLING ){ return false; }
477
- if( defined('WP_REPAIRING') && WP_REPAIRING ){ return false; }
478
- if( defined('WP_IMPORTING') && WP_IMPORTING ){ return false; }
479
- if( defined('DOING_AJAX') && DOING_AJAX ){ return false; }
480
- if( defined('WP_CLI') && WP_CLI ){ return false; }
481
- if( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST ){ return false; }
482
- if( defined('WP_ADMIN') && WP_ADMIN ){ return false; }
483
- if( defined('SHORTINIT') && SHORTINIT ){ return false; }
484
- if( defined('IFRAME_REQUEST') && IFRAME_REQUEST ){ return false; }
485
 
486
- # don't minify specific WordPress areas
487
- if(function_exists('is_404') && is_404()){ return false; }
488
- if(function_exists('is_feed') && is_feed()){ return false; }
489
- if(function_exists('is_comment_feed') && is_comment_feed()){ return false; }
490
- if(function_exists('is_attachment') && is_attachment()){ return false; }
491
- if(function_exists('is_trackback') && is_trackback()){ return false; }
492
- if(function_exists('is_robots') && is_robots()){ return false; }
493
- if(function_exists('is_preview') && is_preview()){ return false; }
494
- if(function_exists('is_customize_preview') && is_customize_preview()){ return false; }
495
- if(function_exists('is_embed') && is_embed()){ return false; }
496
- if(function_exists('is_admin') && is_admin()){ return false; }
497
- if(function_exists('is_blog_admin') && is_blog_admin()){ return false; }
498
- if(function_exists('is_network_admin') && is_network_admin()){ return false; }
499
 
500
- # don't minify specific WooCommerce areas
501
- if(function_exists('is_checkout') && is_checkout()){ return false; }
502
- if(function_exists('is_account_page') && is_account_page()){ return false; }
503
- if(function_exists('is_ajax') && is_ajax()){ return false; }
504
- if(function_exists('is_wc_endpoint_url') && is_wc_endpoint_url()){ return false; }
505
 
506
- # don't minify amp pages by known amp plugins
507
- if(function_exists('is_amp_endpoint') && is_amp_endpoint()){ return false; }
508
- if(function_exists('ampforwp_is_amp_endpoint') && ampforwp_is_amp_endpoint()){ return false; }
509
- if(function_exists('is_wp_amp') && is_wp_amp()){ return false; }
 
 
 
 
 
510
 
511
- # get requested hostname
512
- $host = fvm_get_domain();
 
513
 
514
- # only for hosts matching the site_url
515
- if(isset($fvm_urls['wp_domain']) && !empty($fvm_urls['wp_domain'])) {
516
- if($host != $fvm_urls['wp_domain']) {
517
- return false;
518
- }
519
- }
520
 
521
- # if there is an url, avoid known static files
522
- $ruri = fvm_get_uripath();
523
- if($ruri !== false && !empty($ruri)) {
524
 
525
- # avoid robots.txt and other situations
526
- $noext = array('.txt', '.xml', '.map', '.css', '.js', '.png', '.jpeg', '.jpg', '.gif', '.webp', '.ico', '.php', '.htaccess', '.json', '.pdf', '.mp4', '.webm', '.zip', '.sql', '.gz');
527
- foreach ($noext as $ext) {
528
- if(substr($ruri, -strlen($ext)) == $ext) {
529
- return false;
530
- }
531
- }
532
-
533
  }
534
 
535
- # user roles
536
- if(function_exists('is_user_logged_in')) {
537
- if(is_user_logged_in()) {
538
-
539
- # get user roles
540
- global $fvm_settings;
541
- $user = wp_get_current_user();
542
- $roles = (array) $user->roles;
543
- foreach($roles as $role) {
544
- if(isset($fvm_settings['minify'][$role])) { return true; }
545
- }
546
-
547
- # disable for logged in users by default
548
- return false;
549
- }
550
  }
551
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
552
 
 
 
553
 
554
  # default
555
  return true;
556
  }
557
 
558
 
559
- # create a directory, recursively
560
- function fvm_create_dir($d) {
 
 
 
 
 
 
561
 
562
- # create recursively
563
- if(!is_dir($d) && function_exists('wp_mkdir_p')) {
564
- wp_mkdir_p($d);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
565
  }
566
 
567
- return true;
 
568
  }
569
 
570
 
 
 
 
 
 
571
  # check if PHP has some functions disabled
572
  function fvm_function_available($func) {
573
  if (ini_get('safe_mode')) return false;
@@ -605,43 +476,58 @@ function fvm_format_filesize($bytes, $decimals = 2) {
605
  return sprintf( "%1.{$decimals}f %s", round( $bytes, $decimals ), $units[$i] );
606
  }
607
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
608
 
609
- # increment file names
610
- function fvm_cache_increment() {
611
- $now = time();
612
- update_option('fvm_last_cache_update', $now, 'no');
613
- return $now;
614
- }
615
-
616
-
617
- # remove a director, recursively
618
- function fvm_rrmdir($path) {
619
-
620
- # must be on the allowed path
621
- if(empty($path) || !defined('WP_CONTENT_DIR') || stripos($path, DIRECTORY_SEPARATOR . 'fvm') === false) {
622
- return __( 'Requested purge path is not allowed!', 'fast-velocity-minify' );
623
- }
624
-
625
- # purge recursively
626
- clearstatcache();
627
- if(is_dir($path)) {
628
- try {
629
- $i = new DirectoryIterator($path);
630
- foreach($i as $f){
631
- if($f->isFile()){ @unlink($f->getRealPath());
632
- } else if(!$f->isDot() && $f->isDir()){
633
- fvm_rrmdir($f->getRealPath());
634
- if(is_dir($f->getRealPath())) { @rmdir($f->getRealPath()); }
635
  }
 
636
  }
637
- } catch (Exception $e) {
638
- return get_class($e) . ": " . $e->getMessage();
639
  }
640
-
641
- # self
642
- if(is_dir($path)) { @rmdir($path); }
643
  }
644
-
645
  }
646
 
647
 
@@ -732,10 +618,6 @@ function fvm_get_default_settings($fvm_settings) {
732
  # css
733
  $fvm_settings['css']['enable'] = 1;
734
  $fvm_settings['css']['noprint'] = 1;
735
-
736
- # cdn
737
- $arr = array('img[src*=/wp-content/], img[data-src*=/wp-content/], img[data-srcset*=/wp-content/]', 'picture source[srcset*=/wp-content/]', 'video source[type*=video]', 'image[height]', 'link[rel=icon], link[rel=apple-touch-icon]', 'meta[name=msapplication-TileImage]', 'a[data-interchange*=/wp-content/]', 'rs-slide[data-thumb]', 'form[data-product_variations]', 'div[data-background-image], section[data-background-image]');
738
- $fvm_settings['cdn']['integration'] = implode(PHP_EOL, fvm_array_order($arr));
739
 
740
  }
741
 
@@ -846,9 +728,6 @@ function fvm_get_updated_field_routines($fvm_settings) {
846
 
847
  }
848
 
849
- # clear old cron
850
- wp_clear_scheduled_hook( 'fastvelocity_purge_old_cron_event' );
851
-
852
  # mark as done
853
  update_option('fastvelocity_upgraded', true);
854
 
@@ -861,174 +740,541 @@ function fvm_get_updated_field_routines($fvm_settings) {
861
  }
862
 
863
  # save log to database
 
864
  function fvm_save_log($arr) {
865
 
866
  # must have
867
- if(!is_array($arr) || (is_array($arr) && (count($arr) == 0 || empty($arr)))) { return false; }
868
- if(!isset($arr['uid']) || !isset($arr['date']) || !isset($arr['type']) || !isset($arr['content']) || !isset($arr['meta'])) { return false; }
869
 
870
- # normalize unknown keys
871
- if(strlen($arr['uid']) != 40) { $arr['uid'] = hash('sha1', $arr['uid']); }
872
-
873
- # else insert
874
- global $wpdb, $fvm_cache_paths;
 
 
875
 
876
  # initialize arrays (fields, types, values)
877
  $fld = array();
878
  $tpe = array();
879
  $vls = array();
880
-
881
- # define possible data types
882
- $str = array('uid', 'type', 'content', 'meta');
883
- $int = array('date');
884
- $all = array_merge($str, $int);
885
 
886
  # process only recognized columns
887
  foreach($arr as $k=>$v) {
888
  if(in_array($k, $all)) {
889
- if(in_array($k, $str)) { $tpe[] = '%s'; } else { $tpe[] = '%d'; }
890
- if($k == 'content') { $v = json_encode($v); }
891
- if($k == 'meta') { $v = json_encode($v); }
892
- if($k == 'uid') { $v = hash('sha1', $v); }
893
-
894
- # array for prepare
895
  $fld[] = $k;
896
  $vls[] = $v;
897
  }
898
  }
899
 
900
- # prepare and insert to database
901
- $tbl_name = "{$wpdb->prefix}fvm_logs";
902
- $sql = $wpdb->prepare("INSERT IGNORE INTO `$tbl_name` (".implode(', ', $fld).") VALUES (".implode(', ', $tpe).")", $vls);
903
- $result = $wpdb->query($sql);
904
-
905
- # check if it already exists
906
- if($result) {
907
- return true;
 
 
 
 
 
 
 
 
 
 
908
  }
909
-
910
  # fallback
911
  return false;
912
 
913
  }
914
 
915
 
 
 
 
 
916
 
917
 
918
- # try to open the file from the disk, before downloading
919
- function fvm_maybe_download($url) {
920
-
921
- # must have
922
- if(is_null($url) || empty($url)) {
923
- return array('error'=> __( 'Invalid URL', 'fast-velocity-minify' ));
924
- }
925
-
926
- # get domain
927
- global $fvm_urls;
928
 
929
- # check if we can open the file locally first
930
- if (stripos($url, $fvm_urls['wp_domain']) !== false && defined('ABSPATH') && !empty('ABSPATH') && substr($url, -4) != '.php') {
931
-
932
- # file path + windows compatibility
933
- $f = str_replace('/', DIRECTORY_SEPARATOR, str_replace(rtrim($fvm_urls['wp_site_url'], '/'), ABSPATH, $url));
934
-
935
- # did it work?
936
- if (file_exists($f)) {
937
-
938
- # check contents
939
- $code = file_get_contents($f);
940
- if(fvm_not_php_html($code)) {
941
- return array('content'=>$code, 'src'=>'Disk');
942
- }
943
- }
944
- }
945
 
946
- # fallback to downloading
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
947
 
948
- # this useragent is needed for google fonts (woff files only + hinted fonts)
949
- $uagent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586';
 
 
 
950
 
951
- # parse uri path
952
- $parsedUrl = parse_url($url);
953
- if (!isset($parsedUrl['path']) || (isset($parsedUrl['path']) && $parsedUrl['path'] === null)) {
954
- $url .= '/';
 
 
 
 
 
 
 
 
 
955
  }
956
 
957
- # cache buster
958
- $query = 'nocache='.time();
959
- $separator = '&';
960
- if (!isset($parsedUrl['query']) || $parsedUrl['query'] === null) { $separator = '?'; }
 
 
 
 
961
 
962
- # final url
963
- $url .= $separator.$query;
 
 
 
 
 
964
 
965
- # fetch via wordpress functions
966
- $response = wp_remote_get($url, array('user-agent'=>$uagent, 'timeout' => 7, 'httpversion' => '1.1', 'sslverify'=>false));
967
- $res_code = wp_remote_retrieve_response_code($response);
968
- if($res_code == '200') {
969
- $content = wp_remote_retrieve_body($response);
970
- if(strlen($content) > 1) {
971
- return array('content'=>$content, 'src'=>'Web');
972
- } else {
973
- return array('error'=> __( 'Empty content!', 'fast-velocity-minify' ) . ' ['. $url . ']');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
974
  }
975
  }
976
 
977
- # failed
978
- return array('error'=> __( 'Could not read or fetch from URL', 'fast-velocity-minify' ) . ' ['. $url . ']');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
979
  }
980
 
981
 
982
- # save cache file, if allowed
983
- function fvm_save_file($file, $content) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
984
 
985
- # get directory
986
- $path = dirname($file);
 
 
 
 
 
 
 
987
 
988
- # must be on the allowed path
989
- if(empty($path) || !defined('WP_CONTENT_DIR') || stripos($path, DIRECTORY_SEPARATOR . 'fvm') === false) {
990
- return __( 'Requested path is not allowed!', 'fast-velocity-minify' );
991
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
992
 
993
- # create directory structure
994
- fvm_create_dir($path);
995
 
996
- # save file
997
- file_put_contents($file, $content);
998
- fvm_fix_permission_bits($file);
999
- return true;
1000
 
 
 
 
 
 
 
1001
  }
1002
 
1003
 
1004
- # get transients
1005
- function fvm_get_transient($key, $check=null) {
 
1006
 
1007
- # defaults
1008
- global $wpdb;
1009
- $tbl_name = "{$wpdb->prefix}fvm_cache";
1010
 
1011
- # normalize unknown keys
1012
- if(strlen($key) != 40) { $key = hash('sha1', $key); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1013
 
1014
- # check or fetch
1015
- if($check) {
1016
- $sql = $wpdb->prepare("SELECT id FROM `$tbl_name` WHERE uid = '%s' LIMIT 1", $key);
1017
  } else {
1018
- $sql = $wpdb->prepare("SELECT content FROM `$tbl_name` WHERE uid = '%s' LIMIT 1", $key);
 
1019
  }
 
 
 
 
 
1020
 
1021
- # get result from database
1022
- $result = $wpdb->get_row($sql);
 
1023
 
1024
- # return true if just checking if it exists
1025
- if(isset($result->id)) {
1026
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1027
  }
1028
 
1029
- # return content if found
1030
- if(isset($result->content)) {
1031
- return $result->content;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1032
  }
1033
 
1034
  # fallback
@@ -1040,17 +1286,19 @@ function fvm_set_transient($arr) {
1040
 
1041
  # must have
1042
  if(!is_array($arr) || (is_array($arr) && (count($arr) == 0 || empty($arr)))) { return false; }
1043
- if(!isset($arr['uid']) || !isset($arr['date']) || !isset($arr['type']) || !isset($arr['content']) || !isset($arr['meta'])) { return false; }
1044
 
1045
  # normalize unknown keys
1046
- if(strlen($arr['uid']) != 40) { $arr['uid'] = hash('sha1', $arr['uid']); }
1047
 
1048
- # check if it already exists and return early if it does
1049
  $status = fvm_get_transient($arr['uid'], true);
1050
- if($status) { return true; }
1051
-
1052
- # else insert
1053
  global $wpdb;
 
 
1054
 
1055
  # initialize arrays (fields, types, values)
1056
  $fld = array();
@@ -1066,22 +1314,23 @@ function fvm_set_transient($arr) {
1066
  foreach($arr as $k=>$v) {
1067
  if(in_array($k, $all)) {
1068
  if(in_array($k, $str)) { $tpe[] = '%s'; } else { $tpe[] = '%d'; }
1069
- if($k == 'meta') { $v = json_encode($v); }
1070
  $fld[] = $k;
1071
  $vls[] = $v;
1072
  }
1073
  }
1074
-
1075
- # prepare and insert to database
1076
- $tbl_name = "{$wpdb->prefix}fvm_cache";
1077
- $sql = $wpdb->prepare("INSERT IGNORE INTO `$tbl_name` (".implode(', ', $fld).") VALUES (".implode(', ', $tpe).")", $vls);
1078
- $result = $wpdb->query($sql);
1079
 
1080
- # check if it already exists
1081
- if($result) {
1082
- return true;
 
 
 
 
 
 
 
1083
  }
1084
-
1085
  # fallback
1086
  return false;
1087
 
@@ -1090,74 +1339,74 @@ function fvm_set_transient($arr) {
1090
  # delete transient
1091
  function fvm_del_transient($key) {
1092
 
1093
- global $wpdb;
1094
-
1095
  # normalize unknown keys
1096
- if(strlen($key) != 40) { $key = hash('sha1', $key); }
1097
 
1098
- # delete
1099
- $tbl_name = "{$wpdb->prefix}fvm_cache";
1100
- $sql = $wpdb->prepare("DELETE FROM `$tbl_name` WHERE uid = '%s'", $key);
1101
- $result = $wpdb->get_row($sql);
1102
- return true;
 
 
 
 
 
 
 
 
 
 
1103
  }
1104
 
1105
 
1106
  # functions, get full url
1107
- function fvm_normalize_url($src, $wp_domain, $wp_home) {
1108
 
1109
  # preserve empty source handles
1110
- $hurl = trim($src); if(empty($hurl)) { return $hurl; }
 
1111
 
1112
  # some fixes
1113
- $hurl = str_replace(array('&#038;', '&amp;'), '&', $hurl);
1114
-
1115
- #make sure wp_home doesn't have a forward slash
1116
- $wp_home = rtrim($wp_home, '/');
1117
 
1118
- # protocol scheme
1119
- $scheme = parse_url($wp_home)['scheme'].'://';
1120
-
1121
- # apply some filters
1122
- if (substr($hurl, 0, 2) === "//") { $hurl = $scheme.ltrim($hurl, "/"); } # protocol only
1123
- if (substr($hurl, 0, 4) === "http" && stripos($hurl, $wp_domain) === false) { return $hurl; } # return if external domain
1124
- if (substr($hurl, 0, 4) !== "http" && stripos($hurl, $wp_domain) !== false) { $hurl = $wp_home.'/'.ltrim($hurl, "/"); } # protocol + home
1125
-
1126
- # prevent double forward slashes in the middle
1127
- $hurl = str_replace('###', '://', str_replace('//', '/', str_replace('://', '###', $hurl)));
1128
-
1129
- # consider different wp-content directory for relative paths
1130
- $proceed = 0;
1131
- if(!empty($wp_home)) {
1132
- $alt_wp_content = basename($wp_home);
1133
- if(substr($hurl, 0, strlen($alt_wp_content)) === $alt_wp_content) { $proceed = 1; }
1134
- }
1135
-
1136
- # protocol + home for relative paths
1137
- if (substr($hurl, 0, 12) === "/wp-includes" || substr($hurl, 0, 9) === "/wp-admin" || substr($hurl, 0, 11) === "/wp-content" || $proceed == 1) {
1138
- $hurl = $wp_home.'/'.ltrim($hurl, "/");
 
 
 
 
1139
  }
1140
 
1141
- # make sure there is a protocol prefix as required
1142
- $hurl = $scheme.str_replace(array('http://', 'https://'), '', $hurl); # enforce protocol
1143
-
1144
- # no query strings on css and js files
1145
- if (stripos($hurl, '.js?') !== false) { $hurl = stristr($hurl, '.js?', true).'.js'; } # no query strings
1146
- if (stripos($hurl, '.css?') !== false) { $hurl = stristr($hurl, '.css?', true).'.css'; } # no query strings
1147
-
1148
- # add filter for developers
1149
- $hurl = apply_filters('fvm_get_url', $hurl);
1150
 
1151
- return $hurl;
1152
  }
1153
 
1154
 
1155
  # minify ld+json scripts
1156
  function fvm_minify_microdata($data) {
1157
- # remove // comments
1158
  $data = trim(preg_replace('/(\v)+(\h)+[\/]{2}(.*)+(\v)+/u', '', $data));
1159
-
1160
- # minify
1161
  $data = trim(preg_replace('/\s+/u', ' ', $data));
1162
  $data = str_replace(array('" ', ' "'), '"', $data);
1163
  $data = str_replace(array('[ ', ' ['), '[', $data);
@@ -1188,7 +1437,7 @@ function fvm_not_php_html($code) {
1188
 
1189
  # find if a string looks like HTML content
1190
  function fvm_is_html($html) {
1191
-
1192
  # return early if it's html
1193
  $html = trim($html);
1194
  $a = '<!doctype';
@@ -1232,16 +1481,6 @@ function fvm_is_html($html) {
1232
 
1233
  }
1234
 
1235
-
1236
- # remove UTF8 BOM
1237
- function fvm_remove_utf8_bom($text) {
1238
- $bom = pack('H*','EFBBBF');
1239
- while (preg_match("/^$bom/", $text)) {
1240
- $text = preg_replace("/^$bom/ui", '', $text);
1241
- }
1242
- return $text;
1243
- }
1244
-
1245
  # ensure that string is utf8
1246
  function fvm_ensure_utf8($str) {
1247
  $enc = mb_detect_encoding($str, mb_list_encodings(), true);
@@ -1258,20 +1497,175 @@ function fvm_ensure_utf8($str) {
1258
  }
1259
 
1260
 
1261
- # validate and minify css
1262
- function fvm_maybe_minify_css_file($css, $url, $min) {
 
1263
 
1264
- # ensure it's utf8
1265
- $css = fvm_ensure_utf8($css);
 
 
1266
 
1267
- # return early if empty
1268
- if(empty($css) || $css == false) { return false; }
 
 
 
 
 
 
 
 
 
1269
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1270
  # process css only if it's not php or html
1271
  if(fvm_not_php_html($css)) {
1272
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1273
  # filtering
1274
- $css = fvm_remove_utf8_bom($css);
1275
  $css = str_ireplace('@charset "UTF-8";', '', $css);
1276
 
1277
  # remove query strings from fonts
@@ -1287,32 +1681,27 @@ function fvm_maybe_minify_css_file($css, $url, $min) {
1287
  $css = preg_replace("/url\(\s*['\"]?(?!data:)(?!http)(?![\/'\"#])(.+?)['\"]?\s*\)/ui", "url(".dirname($url)."/$1)", $css);
1288
  }
1289
 
1290
-
1291
-
1292
  # minify string with relative urls
1293
- if($min) {
1294
- $css = fvm_minify_css_string($css);
1295
  }
1296
 
1297
  # add font-display block for all font faces
1298
  # https://developers.google.com/web/updates/2016/02/font-display
1299
- $mff = array();
1300
- $mff2 = array();
1301
- preg_match_all('/(\@font-face)([^}]+)(\})/usi', $css, $mff);
1302
- if(isset($mff[0]) && is_array($mff[0])) {
1303
- foreach($mff[0] as $ff) {
1304
- preg_match_all('/\{{1}(.*)\}{1}/usi', $ff, $mff2);
1305
- if(isset($mff2[1]) && is_array($mff2[1]) && isset($mff2[1][0])) {
1306
- if(stripos($mff2[1][0], 'font-display:') === false) {
1307
- $css = str_replace($mff2[1][0], 'font-display:block;'.$mff2[1][0], $css);
1308
- }
1309
  }
1310
- }
1311
- }
 
 
1312
 
1313
  # make relative urls when possible
1314
- global $fvm_urls;
1315
-
1316
  # get root url, preserve subdirectories
1317
  if(isset($fvm_urls['wp_site_url']) && !empty($fvm_urls['wp_site_url'])) {
1318
 
@@ -1325,18 +1714,44 @@ function fvm_maybe_minify_css_file($css, $url, $min) {
1325
 
1326
  # adjust paths
1327
  $bgimgs = array();
1328
- preg_match_all ('/url\s*\((\s*[\'"]?(http|\/\/)(s|:).+[\'"]?\s*)\)/Uui', $css, $bgimgs);
1329
  if(isset($bgimgs[1]) && is_array($bgimgs[1])) {
1330
  foreach($bgimgs[1] as $img) {
 
 
 
 
 
 
1331
  if(substr($img, 0, strlen($use_url)) == $use_url) {
1332
  $pos = strpos($img, $use_url);
1333
  if ($pos !== false) {
1334
- $relimg = substr_replace($img, '', $pos, strlen($use_url));
 
 
 
 
1335
  $css = str_replace($img, $relimg, $css);
 
1336
  }
1337
  }
1338
  }
1339
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1340
  }
1341
 
1342
  # return css
@@ -1344,7 +1759,7 @@ function fvm_maybe_minify_css_file($css, $url, $min) {
1344
 
1345
  }
1346
 
1347
- return false;
1348
  }
1349
 
1350
 
@@ -1364,7 +1779,7 @@ function fvm_maybe_minify_js($js, $url, $enable_js_minification) {
1364
  global $fvm_settings;
1365
 
1366
  # filtering
1367
- $js = fvm_remove_utf8_bom($js);
1368
 
1369
  # remove sourceMappingURL
1370
  $js = preg_replace('/(\/\/\s*[#]\s*sourceMappingURL\s*[=]\s*)([a-zA-Z0-9-_\.\/]+)(\.map)/ui', '', $js);
@@ -1421,8 +1836,8 @@ function fvm_escape_url_js($str) {
1421
 
1422
  # try catch wrapper for merged javascript
1423
  function fvm_try_catch_wrap($js, $href=null) {
1424
- $loc = ''; if(isset($href)) { $loc = '[ Merged: '. $href . ' ] '; }
1425
- return PHP_EOL . 'try{'. PHP_EOL . $js . PHP_EOL . '}catch(e){console.error("An error has occurred. '.$loc.'[ "+e.stack+" ]");}';
1426
  }
1427
 
1428
 
@@ -1490,99 +1905,40 @@ function fvm_rewrite_assets_cdn($html) {
1490
  }
1491
 
1492
 
1493
-
1494
- # replace css imports with origin css code
1495
- function fvm_replace_css_imports($css, $rq=null) {
1496
 
1497
- # globals
1498
- global $fvm_urls, $fvm_settings;
1499
-
1500
- # handle import url rules
1501
- $cssimports = array();
1502
- preg_match_all ("/@import[ ]*['\"]{0,}(url\()*['\"]*([^;'\"\)]*)['\"\)]*[;]{0,}/ui", $css, $cssimports);
1503
- if(isset($cssimports[0]) && isset($cssimports[2])) {
1504
- foreach($cssimports[0] as $k=>$cssimport) {
1505
-
1506
- # if @import url rule, or guess full url
1507
- if(stripos($cssimport, 'import url') !== false && isset($cssimports[2][$k])) {
1508
- $url = trim($cssimports[2][$k]);
1509
- } else {
1510
- if(!is_null($rq) && !empty($rq)) {
1511
- $url = dirname($rq) . '/' . trim($cssimports[2][$k]);
1512
- }
1513
- }
1514
 
1515
- # must have
1516
- if(!empty($url)) {
1517
-
1518
- # make sure we have a complete url
1519
- $href = fvm_normalize_url($url, $fvm_urls['wp_domain'], $fvm_urls['wp_site_url']);
1520
-
1521
- # download, minify, cache (no ver query string)
1522
- $tkey = hash('sha1', $href);
1523
- $subcss = fvm_get_transient($tkey);
1524
- if ($subcss === false) {
1525
-
1526
- # get minification settings for files
1527
- if(isset($fvm_settings['css']['min_files'])) {
1528
- $enable_css_minification = $fvm_settings['css']['min_files'];
1529
- }
1530
-
1531
- # force minification on google fonts
1532
- if(stripos($href, 'fonts.googleapis.com') !== false) {
1533
- $enable_css_minification = true;
1534
- }
1535
-
1536
- # download file, get contents, merge
1537
- $ddl = fvm_maybe_download($href);
1538
-
1539
- # if success
1540
- if(isset($ddl['content'])) {
1541
-
1542
- # contents
1543
- $subcss = $ddl['content'];
1544
-
1545
- # minify
1546
- $subcss = fvm_maybe_minify_css_file($subcss, $href, $enable_css_minification);
1547
-
1548
- # developers filter
1549
- $subcss = apply_filters( 'fvm_after_download_and_minify_code', $subcss, 'css');
1550
-
1551
- # remove specific, minified CSS code
1552
- if(isset($fvm_settings['css']['remove_code']) && !empty($fvm_settings['css']['remove_code'])) {
1553
- $arr = fvm_string_toarray($fvm_settings['css']['remove_code']);
1554
- if(is_array($arr) && count($arr) > 0) {
1555
- foreach($arr as $str) {
1556
- $subcss = str_replace($str, '', $subcss);
1557
- }
1558
- }
1559
- }
1560
-
1561
- # trim code
1562
- $subcss = trim($subcss);
1563
-
1564
- # size in bytes
1565
- $fs = strlen($subcss);
1566
- $ur = str_replace($fvm_urls['wp_site_url'], '', $href);
1567
- $tkey_meta = array('fs'=>$fs, 'url'=>str_replace($fvm_cache_paths['cache_url_min'].'/', '', $ur), 'mt'=>$media);
1568
-
1569
- # save
1570
- fvm_set_transient(array('uid'=>$tkey, 'date'=>$tvers, 'type'=>'css', 'content'=>$subcss, 'meta'=>$tkey_meta));
1571
- }
1572
- }
1573
-
1574
- # replace import rule with inline code
1575
- if ($subcss !== false && !empty($subcss)) {
1576
- $css = str_replace($cssimport, $subcss, $css);
1577
- }
1578
-
1579
- }
1580
  }
1581
  }
 
 
1582
 
1583
- # return
1584
- return $css;
1585
-
 
 
 
 
 
 
 
 
1586
  }
1587
 
1588
 
@@ -1603,25 +1959,59 @@ function fvm_add_header_function($html) {
1603
  return $html;
1604
  }
1605
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1606
 
1607
  # get the domain name
1608
  function fvm_get_domain() {
1609
- if(isset($_SERVER['SERVER_NAME']) && !empty($_SERVER['SERVER_NAME'])) {
 
 
 
1610
  return $_SERVER['SERVER_NAME'];
1611
  } elseif (isset($_SERVER['HTTP_HOST']) && !empty($_SERVER['HTTP_HOST'])) {
1612
  return $_SERVER['HTTP_HOST'];
1613
- } elseif (function_exists('site_url')) {
1614
- return parse_url(site_url())['host'];
1615
  } else {
1616
  return false;
1617
  }
1618
  }
1619
 
1620
-
1621
  # get the settings file path, current domain name, and uri path without query strings
1622
- function fvm_get_uripath() {
1623
  if (isset($_SERVER['REQUEST_URI']) && !empty($_SERVER['REQUEST_URI'])) {
1624
- $current_uri = strtok($_SERVER['REQUEST_URI'], '?');
 
 
 
 
 
 
 
 
1625
  $current_uri = str_replace('//', '/', str_replace('..', '', preg_replace( '/[ <>\'\"\r\n\t\(\)]/', '', $current_uri)));
1626
  return $current_uri;
1627
  } else {
74
  if($_GET['fvm_do'] == 'clear_all') {
75
 
76
  # purge everything
77
+ $cache = fvm_purge_static_files();
78
  $others = fvm_purge_others();
79
 
80
  if(is_admin()) {
100
  }
101
 
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  # Purge everything
104
  function fvm_purge_all() {
105
+ fvm_purge_static_files();
106
  fvm_purge_others();
107
  return true;
108
  }
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
  # purge supported hosting and plugins
112
  function fvm_purge_others(){
149
  return __( 'All caches on <strong>Comet Cache</strong> have been purged.', 'fast-velocity-minify' );
150
  }
151
 
152
+ # Purge LiteSpeed Cache
153
+ if ( has_action('litespeed_purge_all') ) {
154
+ do_action('litespeed_purge_all');
155
  return __( 'All caches on <strong>LiteSpeed Cache</strong> have been purged.', 'fast-velocity-minify' );
156
  }
157
+
158
+ # Purge WP Cloudflare Super Page Cache
159
+ if( class_exists('SW_CLOUDFLARE_PAGECACHE') ) {
160
+ do_action("swcfpc_purge_everything");
161
+ return __( 'All caches on <strong>WP Cloudflare Super Page Cache</strong> have been purged.', 'fast-velocity-minify' );
162
+ }
163
 
164
  # Purge Hyper Cache
165
  if (class_exists( 'HyperCache' )) {
281
  }
282
 
283
 
284
+
285
  # check if we can minify the page
286
+ function fvm_can_minify_js() {
287
+
288
+ # check if we hit any exclusions from the compatibility page
289
+ if(!fvm_can_process_common()) { return false; }
290
+ if(fvm_is_amp_page() === true) { return false; }
291
 
292
+ # url exclusions
293
+ if(!fvm_can_process_query_string('js')) { return false; }
294
 
295
+ # check if user role is allowed
296
+ if(!fvm_user_role_processing_allowed('js')) { return false; }
 
 
297
 
298
+ # settings
299
+ global $fvm_settings;
300
+
301
+ # disabled?
302
+ if(!isset($fvm_settings['js']['enable']) || (isset($fvm_settings['js']['enable']) && $fvm_settings['js']['enable'] != true)) {
303
  return false;
304
  }
305
 
306
+ # default
307
+ return true;
308
 
309
+ }
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
+ # check if we can minify the page
312
+ function fvm_can_process_html() {
 
 
 
 
 
 
 
 
313
 
314
+ # check if we hit any exclusions from the compatibility page
315
+ if(!fvm_can_process_common()) { return false; }
316
+ if(fvm_is_amp_page() === true) { return false; }
317
 
318
+ # url exclusions
319
+ if(!fvm_can_process_query_string('html')) { return false; }
 
 
 
 
 
 
 
 
 
320
 
321
+ # settings
322
+ global $fvm_settings;
 
 
 
 
 
 
 
 
 
 
 
323
 
324
+ # disabled?
325
+ if(!isset($fvm_settings['html']['enable']) || (isset($fvm_settings['html']['enable']) && $fvm_settings['html']['enable'] != true)) {
326
+ return false;
327
+ }
 
328
 
329
+ # check if user role is allowed
330
+ if(!fvm_user_role_processing_allowed('html')) { return false; }
331
+
332
+ # default
333
+ return true;
334
+ }
335
+
336
+ # check if we can minify the page
337
+ function fvm_can_process_cdn() {
338
 
339
+ # check if we hit any exclusions from the compatibility page
340
+ if(!fvm_can_process_common()) { return false; }
341
+ if(fvm_is_amp_page() === true) { return false; }
342
 
343
+ # url exclusions
344
+ if(!fvm_can_process_query_string('cdn')) { return false; }
 
 
 
 
345
 
346
+ # settings
347
+ global $fvm_settings;
 
348
 
349
+ # disabled?
350
+ if(!isset($fvm_settings['cdn']['enable']) || (isset($fvm_settings['cdn']['enable']) && $fvm_settings['cdn']['enable'] != true)) {
351
+ return false;
 
 
 
 
 
352
  }
353
 
354
+ # no domain
355
+ if(!isset($fvm_settings['cdn']['domain']) || (isset($fvm_settings['cdn']['domain']) && empty($fvm_settings['cdn']['domain']))) {
356
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
357
  }
358
 
359
+ # check if user role is allowed
360
+ if(!fvm_user_role_processing_allowed('cdn')) { return false; }
361
+
362
+ # default
363
+ return true;
364
+ }
365
+
366
+
367
+ # check if we can minify the page
368
+ function fvm_can_minify_css() {
369
+
370
+ # check if we hit any exclusions from the compatibility page
371
+ if(!fvm_can_process_common()) { return false; }
372
+ if(fvm_is_amp_page() === true) { return false; }
373
+
374
+ # url exclusions
375
+ if(!fvm_can_process_query_string('css')) { return false; }
376
+
377
+ # check if user role is allowed
378
+ if(!fvm_user_role_processing_allowed('css')) { return false; }
379
+
380
+ # settings
381
+ global $fvm_settings;
382
 
383
+ # disabled?
384
+ if(!isset($fvm_settings['css']['enable']) || (isset($fvm_settings['css']['enable']) && $fvm_settings['css']['enable'] != true)) { return false; }
385
 
386
  # default
387
  return true;
388
  }
389
 
390
 
391
+ # save minified code, if not yet available
392
+ function fvm_generate_min_url($url, $tkey, $type, $code) {
393
+
394
+ # files first, but only for js/css types
395
+ if(function_exists('wp_upload_dir')) {
396
+
397
+ # parse uripath and check if it matches against our rewrite format
398
+ $filename = $tkey .'.'. $type;
399
 
400
+ # set cache on the uploads directory
401
+ $upload_dir = wp_upload_dir();
402
+ if(isset($upload_dir['basedir']) && isset($upload_dir['baseurl']) && !empty($upload_dir['basedir'])) {
403
+
404
+ # define and create directory
405
+ $cache_dir = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'fvm-cache'. DIRECTORY_SEPARATOR . 'min';
406
+ $cache_dir_url = $upload_dir['baseurl'] . '/fvm-cache/min';
407
+ if(!is_dir($cache_dir) && function_exists('wp_mkdir_p')) { wp_mkdir_p($cache_dir); }
408
+
409
+ # filename
410
+ $file = $cache_dir . DIRECTORY_SEPARATOR . $filename;
411
+ $public = $cache_dir_url . '/' .$filename;
412
+
413
+ # cache date
414
+ $tvers = get_option('fvm_last_cache_update', '0');
415
+
416
+ # wordpress functions
417
+ require_once (ABSPATH . DIRECTORY_SEPARATOR . 'wp-admin'. DIRECTORY_SEPARATOR .'includes'. DIRECTORY_SEPARATOR .'class-wp-filesystem-base.php');
418
+ require_once (ABSPATH . DIRECTORY_SEPARATOR .'wp-admin'. DIRECTORY_SEPARATOR .'includes'. DIRECTORY_SEPARATOR .'class-wp-filesystem-direct.php');
419
+
420
+ # create if doesn't exist
421
+ $fileSystemDirect = new WP_Filesystem_Direct(false);
422
+ if(!$fileSystemDirect->exists($file) || ($fileSystemDirect->exists($file) && $fileSystemDirect->mtime($file) < $tvers)) {
423
+ $fileSystemDirect->put_contents($file, $code);
424
+ }
425
+
426
+ # return url
427
+ return $public;
428
+
429
+ }
430
  }
431
 
432
+ # default
433
+ return $url;
434
  }
435
 
436
 
437
+
438
+
439
+
440
+
441
+
442
  # check if PHP has some functions disabled
443
  function fvm_function_available($func) {
444
  if (ini_get('safe_mode')) return false;
476
  return sprintf( "%1.{$decimals}f %s", round( $bytes, $decimals ), $units[$i] );
477
  }
478
 
479
+ # purge static cache files directory
480
+ function fvm_purge_static_files() {
481
+
482
+ # globals
483
+ global $fvm_settings;
484
+
485
+ # truncate cache table
486
+ global $wpdb;
487
+ if(is_null($wpdb)) { return false; }
488
+ try {
489
+ $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}fvm_cache");
490
+ $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}fvm_logs");
491
+ } catch (Exception $e) {
492
+ error_log('Error: '.$e->getMessage(), 0);
493
+ }
494
+
495
+ # increment
496
+ update_option('fvm_last_cache_update', time());
497
+
498
+ # process
499
+ if( function_exists('wp_upload_dir') ) {
500
+
501
+ $upload_dir = wp_upload_dir();
502
+ if(isset($upload_dir['basedir']) && isset($upload_dir['baseurl']) && !empty($upload_dir['basedir'])) {
503
+ require_once (ABSPATH . DIRECTORY_SEPARATOR . 'wp-admin'. DIRECTORY_SEPARATOR .'includes'. DIRECTORY_SEPARATOR .'class-wp-filesystem-base.php');
504
+ require_once (ABSPATH . DIRECTORY_SEPARATOR .'wp-admin'. DIRECTORY_SEPARATOR .'includes'. DIRECTORY_SEPARATOR .'class-wp-filesystem-direct.php');
505
 
506
+ # instant purge
507
+ global $fvm_settings;
508
+ if(isset($fvm_settings['cache']['min_instant_purge']) && $fvm_settings['cache']['min_instant_purge'] == true) {
509
+ $cache_dir = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'fvm-cache';
510
+ $fileSystemDirect = new WP_Filesystem_Direct(false);
511
+ $fileSystemDirect->rmdir($cache_dir, true);
512
+ return true;
513
+ } else {
514
+ $cache_dir = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'fvm-cache'. DIRECTORY_SEPARATOR . 'min';
515
+ $fileSystemDirect = new WP_Filesystem_Direct(false);
516
+
517
+ # older than 3 days
518
+ $list = $fileSystemDirect->dirlist($cache_dir, false, true);
519
+ if(is_array($list) && count($list) > 0) {
520
+ foreach($list as $k=>$arr) {
521
+ if(isset($arr['lastmodunix']) && $arr['type'] == 'f' && intval($arr['lastmodunix']) <= time()-86400) {
522
+ $fileSystemDirect->delete($cache_dir . DIRECTORY_SEPARATOR . $arr['name'], false, 'f');
523
+ }
524
+ }
 
 
 
 
 
 
 
525
  }
526
+
527
  }
528
+
 
529
  }
 
 
 
530
  }
 
531
  }
532
 
533
 
618
  # css
619
  $fvm_settings['css']['enable'] = 1;
620
  $fvm_settings['css']['noprint'] = 1;
 
 
 
 
621
 
622
  }
623
 
728
 
729
  }
730
 
 
 
 
731
  # mark as done
732
  update_option('fastvelocity_upgraded', true);
733
 
740
  }
741
 
742
  # save log to database
743
+ # usage: $arr = array('type'=>'js', 'msg'=>'', 'meta'=>json_encode(array('loc'=>'function')));
744
  function fvm_save_log($arr) {
745
 
746
  # must have
747
+ if(is_null($arr) || !is_array($arr) || !isset($arr['msg'])) { return false; }
 
748
 
749
+ # uid, prevent duplicate or unique by date
750
+ if(!isset($arr['date'])) {
751
+ $arr['date'] = time();
752
+ $arr['uid'] = fvm_generate_hash_with_prefix($arr['msg'], 'log');
753
+ } else {
754
+ $arr['uid'] = fvm_generate_hash_with_prefix($arr['date'] . ' / ' . $arr['msg'], 'log');
755
+ }
756
 
757
  # initialize arrays (fields, types, values)
758
  $fld = array();
759
  $tpe = array();
760
  $vls = array();
761
+
762
+ # define possible fields
763
+ $all = array('date', 'uid', 'type', 'msg', 'meta');
 
 
764
 
765
  # process only recognized columns
766
  foreach($arr as $k=>$v) {
767
  if(in_array($k, $all)) {
768
+ $tpe[] = '%s';
 
 
 
 
 
769
  $fld[] = $k;
770
  $vls[] = $v;
771
  }
772
  }
773
 
774
+ try {
775
+
776
+ # connect
777
+ global $wpdb;
778
+ if(is_null($wpdb)) { return false; }
779
+
780
+ # check if exists before inserting
781
+ $result = $wpdb->get_row($wpdb->prepare("SELECT id FROM ".$wpdb->prefix."fvm_logs WHERE uid = %s LIMIT 1", $arr['uid']));
782
+ if(is_null($check) || !isset($result->id)) {
783
+
784
+ # prepare and insert to database
785
+ $wpdb->query($wpdb->prepare("INSERT IGNORE INTO ".$wpdb->prefix."fvm_logs (".implode(', ', $fld).") VALUES (".implode(', ', $tpe).")", $vls));
786
+ return true;
787
+
788
+ }
789
+
790
+ } catch (Exception $e) {
791
+ error_log('Error: '.$e->getMessage(), 0);
792
  }
793
+
794
  # fallback
795
  return false;
796
 
797
  }
798
 
799
 
800
+ # generate a 64 char string with prefix
801
+ function fvm_generate_hash_with_prefix($uid, $prefix) {
802
+ return substr($prefix .hash('sha256', $uid), 0, 64);
803
+ }
804
 
805
 
806
+ # replace css imports with origin css code
807
+ function fvm_replace_css_imports($css, $rq=null) {
 
 
 
 
 
 
 
 
808
 
809
+ # globals
810
+ global $fvm_urls, $fvm_settings;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
811
 
812
+ # handle import url rules
813
+ $cssimports = array();
814
+ preg_match_all ("/@import[ ]*['\"]{0,}(url\()*['\"]*([^\(\{'\"\)]*)['\"\)]*[;]{0,}/ui", $css, $cssimports);
815
+ if(isset($cssimports[0]) && isset($cssimports[2])) {
816
+ foreach($cssimports[0] as $k=>$cssimport) {
817
+
818
+ # if @import url rule, or guess full url
819
+ if(stripos($cssimport, 'import url') !== false && isset($cssimports[2][$k])) {
820
+ $url = trim($cssimports[2][$k]);
821
+ } else {
822
+ if(!is_null($rq) && !empty($rq)) {
823
+ $url = dirname($rq) . '/' . trim($cssimports[2][$k]);
824
+ }
825
+ }
826
+
827
+ # must have
828
+ if(!empty($url)) {
829
+
830
+ # make sure we have a complete url
831
+ $href = fvm_normalize_url($url);
832
+
833
+ # download, minify, cache (no ver query string)
834
+ $tkey = fvm_generate_hash_with_prefix($href, 'css');
835
+ $subcss = fvm_get_transient($tkey);
836
+ if ($subcss === false) {
837
+
838
+ # get minification settings for files
839
+ if(isset($fvm_settings['css']['css_enable_min_files'])) {
840
+ $enable_css_minification = $fvm_settings['css']['css_enable_min_files'];
841
+ }
842
+
843
+ # force minification on google fonts
844
+ if(stripos($href, 'fonts.googleapis.com') !== false) {
845
+ $enable_css_minification = true;
846
+ }
847
+
848
+ # download file, get contents, merge
849
+ $ddl = array();
850
+ $ddl = fvm_maybe_download($href);
851
+
852
+ # if success
853
+ if(isset($ddl['content'])) {
854
+
855
+ # contents
856
+ $subcss = $ddl['content'];
857
+
858
+ # minify
859
+ $subcss = fvm_maybe_minify_css_file($subcss, $href, $enable_css_minification);
860
+
861
+ # trim code
862
+ $subcss = trim($subcss);
863
+
864
+ # save
865
+ fvm_set_transient(array('uid'=>$tkey, 'date'=>$tvers, 'type'=>'css', 'content'=>$subcss));
866
+ }
867
+ }
868
+
869
+ # replace import rule with inline code
870
+ if ($subcss !== false && !empty($subcss)) {
871
+ $css = str_replace($cssimport, $subcss, $css);
872
+ }
873
+
874
+ }
875
+ }
876
+ }
877
 
878
+ # return
879
+ return trim($css);
880
+
881
+ }
882
+
883
 
884
+ # remove fonts and icons from final css
885
+ function fvm_extract_fonts($css_code) {
886
+
887
+ global $fvm_settings, $fvm_urls;
888
+ $critical_fonts = array();
889
+ $mff = array();
890
+ $css_preload = array();
891
+ $css_code_ff = '';
892
+
893
+ # get list of fonts that are on the critical path and are to be left alone
894
+ if( isset($fvm_settings['css']['css_optimize_critical_fonts']) &&
895
+ !empty($fvm_settings['css']['css_optimize_critical_fonts'])) {
896
+ $critical_fonts = fvm_string_toarray($fvm_settings['css']['css_optimize_critical_fonts']);
897
  }
898
 
899
+ # extract font faces
900
+ preg_match_all('/\@\s*font-face\s*\{([^}]+)\}/iUu', $css_code, $mff);
901
+ if(isset($mff[0]) && is_array($mff[0])) {
902
+ foreach($mff[0] as $ff) {
903
+
904
+ # strip and collect
905
+ $css_code = str_replace($ff, '', $css_code);
906
+ $css_code_ff.= $ff . PHP_EOL;
907
 
908
+ }
909
+ }
910
+
911
+ # relative paths
912
+ $css_code_ff = str_replace('https://'.$fvm_urls['wp_domain'], '', $css_code_ff);
913
+ $css_code_ff = str_replace('http://'.$fvm_urls['wp_domain'], '', $css_code_ff);
914
+ $css_code_ff = str_replace('//'.$fvm_urls['wp_domain'], '', $css_code_ff);
915
 
916
+ # return
917
+ $result = array('code'=>$css_code, 'fonts'=>$css_code_ff);
918
+ return $result;
919
+ }
920
+
921
+
922
+ # rewrite assets to cdn
923
+ function fvm_process_cdn($html) {
924
+
925
+ # settings
926
+ global $fvm_settings, $fvm_urls;
927
+
928
+ # html must be an object
929
+ if (!is_object($html)) {
930
+ $nobj = 1;
931
+ $html = str_get_html($html, true, true, 'UTF-8', false, PHP_EOL, ' ');
932
+ }
933
+
934
+ # default integration
935
+ $integration_defaults = array('a[data-interchange*=/wp-content/], div[data-background-image], section[data-background-image], form[data-product_variations], image[height], img[src*=/wp-content/], img[data-src*=/wp-content/], img[data-srcset*=/wp-content/], link[rel=icon], link[rel=apple-touch-icon], meta[name=msapplication-TileImage], picture source[srcset*=/wp-content/], rs-slide[data-thumb], video source[type*=video]');
936
+
937
+ # html integration
938
+ if(isset($fvm_urls['wp_domain']) && isset($fvm_settings['cdn']['domain']) && isset($fvm_settings['cdn']['integration'])) {
939
+ if(!empty($fvm_settings['cdn']['domain']) && !empty($fvm_urls['wp_domain'])) {
940
+ $arr = fvm_string_toarray($fvm_settings['cdn']['integration']);
941
+ $arr = array_unique(array_merge($arr, $integration_defaults)); # add defaults
942
+ if(is_array($arr) && count($arr) > 0) {
943
+ foreach($html->find(implode(', ', $arr) ) as $elem) {
944
+
945
+ # preserve some attributes but replace others
946
+ if (is_object($elem) && isset($elem->attr)) {
947
+
948
+ # get all attributes
949
+ foreach ($elem->attr as $key=>$val) {
950
+
951
+ # skip href attribute for links
952
+ if($key == 'href' && stripos($elem->outertext, '<a ') !== false) { continue; }
953
+
954
+ # skip certain attributes
955
+ if(in_array($key, array('id', 'class', 'action'))) { continue; }
956
+
957
+ # scheme + site url
958
+ $fcdn = str_replace($fvm_urls['wp_domain'], $fvm_settings['cdn']['domain'], $fvm_urls['wp_site_url']);
959
+
960
+ # known replacements
961
+ $elem->{$key} = str_ireplace('url(/wp-content/', 'url('.$fcdn.'/wp-content/', $elem->{$key});
962
+ $elem->{$key} = str_ireplace('url("/wp-content/', 'url("'.$fcdn.'/wp-content/', $elem->{$key});
963
+ $elem->{$key} = str_ireplace('url(\'/wp-content/', 'url(\''.$fcdn.'/wp-content/', $elem->{$key});
964
+
965
+ # normalize certain field
966
+ if(in_array($key, array('src', 'data-bg', 'data-lazy-src', 'audio', 'poster'))) {
967
+ $elem->{$key} = fvm_normalize_url($elem->{$key});
968
+ }
969
+
970
+ # replace other attributes
971
+ $elem->{$key} = str_replace('//'.$fvm_urls['wp_domain'], '//'.$fvm_settings['cdn']['domain'], $elem->{$key});
972
+ $elem->{$key} = str_replace('\/\/'.$fvm_urls['wp_domain'], '\/\/'.$fvm_settings['cdn']['domain'], $elem->{$key});
973
+
974
+ }
975
+
976
+ }
977
+
978
+ }
979
+ }
980
  }
981
  }
982
 
983
+
984
+ # add CDN support to Styles, CSS and JS files
985
+
986
+ # css
987
+ if(isset($fvm_settings['cdn']['cssok']) && $fvm_settings['cdn']['cssok'] == true) {
988
+
989
+ # scheme + site url
990
+ $fcdn = str_replace($fvm_urls['wp_domain'], $fvm_settings['cdn']['domain'], $fvm_urls['wp_site_url']);
991
+
992
+ # replace inside styles
993
+ foreach($html->find('style') as $elem) {
994
+
995
+ # fetch
996
+ $css = $elem->outertext;
997
+
998
+ # known replacements
999
+ $css = str_ireplace('url(/wp-content/', 'url('.$fcdn.'/wp-content/', $css);
1000
+ $css = str_ireplace('url("/wp-content/', 'url("'.$fcdn.'/wp-content/', $css);
1001
+ $css = str_ireplace('url(\'/wp-content/', 'url(\''.$fcdn.'/wp-content/', $css);
1002
+ $css = str_replace('//'.$fvm_urls['wp_domain'], '//'.$fvm_settings['cdn']['domain'], $css);
1003
+
1004
+ # save
1005
+ $elem->outertext = $css;
1006
+
1007
+ }
1008
+
1009
+ # replace link stylesheets
1010
+ if(isset($fvm_settings['cdn']['enable_css']) && $fvm_settings['cdn']['enable_css'] == true) {
1011
+ foreach($html->find('link[rel=stylesheet], link[rel=preload]') as $elem) {
1012
+ if(isset($elem->href)) {
1013
+ $elem->href = str_replace($fvm_urls['wp_site_url'], $fcdn, $elem->href);
1014
+ }
1015
+ }
1016
+ }
1017
+ }
1018
+
1019
+ # js
1020
+ if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
1021
+
1022
+ # replace script files
1023
+ foreach($html->find('script') as $elem) {
1024
+
1025
+ # js files
1026
+ if(isset($fvm_settings['cdn']['enable_js']) && $fvm_settings['cdn']['enable_js'] == true) {
1027
+ if(isset($elem->src) && stripos($elem->src, $fvm_urls['wp_domain']) !== false) {
1028
+ $elem->src = str_replace('//'.$fvm_urls['wp_domain'], '//'.$fvm_settings['cdn']['domain'], $elem->src);
1029
+ }
1030
+ }
1031
+ }
1032
+
1033
+ }
1034
+
1035
+ # convert html object to string, only when needed
1036
+ if(isset($nobj) && $nobj == 1) {
1037
+ $html = trim($html->save());
1038
+ }
1039
+
1040
+ # return
1041
+ return $html;
1042
  }
1043
 
1044
 
1045
+ # rewrite url with cdn
1046
+ function fvm_rewrite_cdn_url($url) {
1047
+ global $fvm_settings, $fvm_urls;
1048
+ if(isset($fvm_settings['cdn']['enable']) && $fvm_settings['cdn']['enable'] == true && isset($fvm_settings['cdn']['domain']) && !empty($fvm_settings['cdn']['domain'])) {
1049
+ $url = str_replace('//'.$fvm_urls['wp_domain'], '//'.$fvm_settings['cdn']['domain'], $url);
1050
+ }
1051
+ return $url;
1052
+ }
1053
+
1054
+ # get css font-face rules, original + simplified
1055
+ function fvm_simplify_fontface($css_code) {
1056
+
1057
+ $mff = array();
1058
+ $before = array();
1059
+ $after = array();
1060
+
1061
+ # extract font faces
1062
+ preg_match_all('/\@\s*font-face\s*\{([^}]+)\}/iUu', $css_code, $mff);
1063
+ if(isset($mff[0]) && isset($mff[1]) && is_array($mff[1])) {
1064
+ foreach($mff[1] as $kf=>$ff) {
1065
 
1066
+ # simplify font urls
1067
+ $cssrules = preg_split("/;(?![^(]*\))/iu", $ff);
1068
+ foreach ($cssrules as $k=>$csr) {
1069
+ if(preg_match('/src\s*\:\s*url/Uui', $csr)) {
1070
+
1071
+ # woff
1072
+ $fonts = array();
1073
+ preg_match('/url\s*\(\s*[\'\"]*([^,\'\"]*)[\'\"]*\)\s*format\s*\([\'\"]*woff[\'\"]*\s*\)/Uui', $csr, $fonts);
1074
+ if(isset($fonts[0])) { $cssrules[$k] = 'src:'.$fonts[0]; break; }
1075
 
1076
+ # woff2
1077
+ $fonts = array();
1078
+ preg_match('/url\s*\(\s*[\'\"]*([^,\'\"]*)[\'\"]*\)\s*format\s*\([\'\"]*woff2[\'\"]*\s*\)/Uui', $csr, $fonts);
1079
+ if(isset($fonts[0])) { $cssrules[$k] = 'src:'.$fonts[0]; break; }
1080
+
1081
+ # svg
1082
+ $fonts = array();
1083
+ preg_match('/url\s*\(\s*[\'\"]*([^,\'\"]*)[\'\"]*\)\s*format\s*\([\'\"]*svg[\'\"]*\s*\)/Uui', $csr, $fonts);
1084
+ if(isset($fonts[0])) { $cssrules[$k] = 'src:'.$fonts[0]; break; }
1085
+
1086
+ # truetype
1087
+ $fonts = array();
1088
+ preg_match('/url\s*\(\s*[\'\"]*([^,\'\"]*)[\'\"]*\)\s*format\s*\([\'\"]*truetype[\'\"]*\s*\)/Uui', $csr, $fonts);
1089
+ if(isset($fonts[0])) { $cssrules[$k] = 'src:'.$fonts[0]; break; }
1090
+
1091
+ # delete other src:url rules
1092
+ if(stripos($csr, 'format') === false) {
1093
+ unset($cssrules[$k]);
1094
+ }
1095
+
1096
+ }
1097
+ }
1098
+
1099
+ # merge and create font face rule
1100
+ $after[] = '@font-face{'.implode(';', $cssrules).'}';
1101
 
1102
+ # strip and collect
1103
+ $before[] = $mff[0][$kf];
1104
 
1105
+ }
1106
+ }
 
 
1107
 
1108
+ # return
1109
+ if(count($before) > 0) {
1110
+ return array('before'=>$before, 'after'=>$after);
1111
+ } else {
1112
+ return false;
1113
+ }
1114
  }
1115
 
1116
 
1117
+
1118
+ # get css code from css file
1119
+ function fvm_get_css_from_file($tag) {
1120
 
1121
+ # globals
1122
+ global $fvm_urls, $fvm_settings;
 
1123
 
1124
+ # variables
1125
+ $tvers = get_option('fvm_last_cache_update', '0');
1126
+
1127
+ # make sure we have a complete url
1128
+ $href = fvm_normalize_url($tag->href);
1129
+
1130
+ # download, minify, cache (no ver query string)
1131
+ $tkey = fvm_generate_hash_with_prefix($href, 'css');
1132
+ $css = fvm_get_transient($tkey);
1133
+
1134
+ # download
1135
+ if ($css === false) {
1136
+
1137
+ $ddl = array();
1138
+ $ddl = fvm_maybe_download($href);
1139
+
1140
+ # success
1141
+ if(isset($ddl['content'])) {
1142
+
1143
+ # minify flag
1144
+ $min = false;
1145
+ if(isset($fvm_settings['css']['css_enable_min_files']) && $fvm_settings['css']['css_enable_min_files'] == true) {
1146
+ $min = true;
1147
+ }
1148
+
1149
+ # minify
1150
+ $css = fvm_maybe_minify_css_file($ddl['content'], $href, $min);
1151
+
1152
+ # quick integrity check
1153
+ if($css !== false) {
1154
+
1155
+ # handle import rules
1156
+ $css = fvm_replace_css_imports($css, $href);
1157
+ $meta = json_encode(array('href'=>$href));
1158
+
1159
+ # save transient
1160
+ $verify = fvm_set_transient(array('uid'=>$tkey, 'date'=>$tvers, 'type'=>'css', 'content'=>$css, 'meta'=>$meta));
1161
+
1162
+ # success, from download
1163
+ return array('code'=>$css, 'tkey'=>$tkey, 'url'=> $href);
1164
+ }
1165
+ }
1166
 
 
 
 
1167
  } else {
1168
+ # success, from transient
1169
+ return array('code'=>$css, 'tkey'=>$tkey, 'url'=> $href);
1170
  }
1171
+
1172
+ # fallback
1173
+ return false;
1174
+
1175
+ }
1176
 
1177
+
1178
+ # get js code from css file
1179
+ function fvm_get_js_from_file($tag) {
1180
 
1181
+ # globals
1182
+ global $fvm_urls, $fvm_settings;
1183
+
1184
+ # variables
1185
+ $tvers = get_option('fvm_last_cache_update', '0');
1186
+
1187
+ # make sure we have a complete url
1188
+ $href = fvm_normalize_url($tag->src);
1189
+
1190
+ # download, minify, cache (no ver query string)
1191
+ $tkey = fvm_generate_hash_with_prefix($href, 'js');
1192
+ $js = fvm_get_transient($tkey);
1193
+
1194
+ # download
1195
+ if ($js === false) {
1196
+
1197
+ $ddl = array();
1198
+ $ddl = fvm_maybe_download($href);
1199
+
1200
+ # success
1201
+ if(isset($ddl['content'])) {
1202
+
1203
+ # minify?
1204
+ if(!isset($fvm_settings['js']['min_disable_inline']) || (isset($fvm_settings['js']['min_disable_inline'])&& $fvm_settings['js']['min_disable_inline'] != true)) {
1205
+ $js = fvm_maybe_minify_js($ddl['content'], $href, true);
1206
+ }
1207
+
1208
+ # wrap with try catch
1209
+ $js = fvm_try_catch_wrap($js, $href);
1210
+
1211
+ # quick integrity check
1212
+ if($js !== false) {
1213
+
1214
+ # meta
1215
+ $meta = json_encode(array('href'=>$href));
1216
+
1217
+ # save transient
1218
+ $verify = fvm_set_transient(array('uid'=>$tkey, 'date'=>$tvers, 'type'=>'js', 'content'=>$js, 'meta'=>$meta));
1219
+
1220
+ # success, from download
1221
+ return array('code'=>$js, 'tkey'=>$tkey, 'url'=> $href);
1222
+ }
1223
+ }
1224
+
1225
+ } else {
1226
+ # success, from transient
1227
+ return array('code'=>$js, 'tkey'=>$tkey, 'url'=> $href);
1228
  }
1229
 
1230
+ # fallback
1231
+ return false;
1232
+
1233
+ }
1234
+
1235
+
1236
+
1237
+
1238
+ # get transients
1239
+ function fvm_get_transient($key, $check=null, $with_meta=null) {
1240
+
1241
+ # must have
1242
+ global $wpdb;
1243
+ if(is_null($wpdb)) { return false; }
1244
+ $db_prefix = $wpdb->prefix;
1245
+
1246
+ try {
1247
+
1248
+ # check or fetch
1249
+ if(!is_null($check)) {
1250
+ $sql = $wpdb->prepare("SELECT id FROM {$db_prefix}fvm_cache WHERE uid = %s LIMIT 1", $key);
1251
+ } else if (!is_null($with_meta)) {
1252
+ $sql = $wpdb->prepare("SELECT date, content, meta FROM {$db_prefix}fvm_cache WHERE uid = %s LIMIT 1", $key);
1253
+ } else {
1254
+ $sql = $wpdb->prepare("SELECT content FROM {$db_prefix}fvm_cache WHERE uid = %s LIMIT 1", $key);
1255
+ }
1256
+
1257
+ # get result from database
1258
+ $result = $wpdb->get_row($sql);
1259
+
1260
+ # return true if just checking
1261
+ if(!is_null($check) && isset($result->id)) {
1262
+ return true;
1263
+ }
1264
+
1265
+ # return content only
1266
+ if(is_null($check) && is_null($with_meta) && isset($result->content)) {
1267
+ return $result->content;
1268
+ }
1269
+
1270
+ # return content and meta
1271
+ if(is_null($check) && !is_null($with_meta) && isset($result->date) && isset($result->content) && isset($result->meta)) {
1272
+ return array('date'=>$result->date, 'content'=>$result->content, 'meta'=>json_decode($result->meta, true), 'cache-method'=>$cache_method);
1273
+ }
1274
+
1275
+ } catch (Exception $e) {
1276
+ error_log('Error: '.$e->getMessage(), 0);
1277
+ return false;
1278
  }
1279
 
1280
  # fallback
1286
 
1287
  # must have
1288
  if(!is_array($arr) || (is_array($arr) && (count($arr) == 0 || empty($arr)))) { return false; }
1289
+ if(!isset($arr['uid']) || !isset($arr['date']) || !isset($arr['type']) || !isset($arr['content'])) { return false; }
1290
 
1291
  # normalize unknown keys
1292
+ if(strlen($arr['uid']) != 64) { $arr['uid'] = fvm_generate_hash_with_prefix($arr['uid'], $arr['type']); }
1293
 
1294
+ # check if it already exists, return early if it does
1295
  $status = fvm_get_transient($arr['uid'], true);
1296
+ if($status) { return $arr['uid']; }
1297
+
1298
+ # must have
1299
  global $wpdb;
1300
+ if(is_null($wpdb)) { return false; }
1301
+ $db_prefix = $wpdb->prefix;
1302
 
1303
  # initialize arrays (fields, types, values)
1304
  $fld = array();
1314
  foreach($arr as $k=>$v) {
1315
  if(in_array($k, $all)) {
1316
  if(in_array($k, $str)) { $tpe[] = '%s'; } else { $tpe[] = '%d'; }
 
1317
  $fld[] = $k;
1318
  $vls[] = $v;
1319
  }
1320
  }
 
 
 
 
 
1321
 
1322
+ try {
1323
+ # prepare and insert to database
1324
+ $result = $wpdb->query($wpdb->prepare("INSERT IGNORE INTO {$db_prefix}fvm_cache (".implode(', ', $fld).") VALUES (".implode(', ', $tpe).")", $vls));
1325
+
1326
+ # success
1327
+ if($result) {
1328
+ return $arr['uid'];
1329
+ }
1330
+ } catch (Exception $e) {
1331
+ error_log('Error: '.$e->getMessage(), 0);
1332
  }
1333
+
1334
  # fallback
1335
  return false;
1336
 
1339
  # delete transient
1340
  function fvm_del_transient($key) {
1341
 
 
 
1342
  # normalize unknown keys
1343
+ if(strlen($key) != 64) { $key = fvm_generate_hash_with_prefix($key, ''); }
1344
 
1345
+ # must have
1346
+ global $wpdb;
1347
+ if(is_null($wpdb)) { return false; }
1348
+ $db_prefix = $wpdb->prefix;
1349
+
1350
+ try {
1351
+ # delete
1352
+ $wpdb->query($wpdb->prepare("DELETE FROM {$db_prefix}fvm_cache WHERE uid = %s", $key));
1353
+ return true;
1354
+ } catch (Exception $e) {
1355
+ error_log('Error: '.$e->getMessage(), 0);
1356
+ }
1357
+
1358
+ # fallback
1359
+ return false;
1360
  }
1361
 
1362
 
1363
  # functions, get full url
1364
+ function fvm_normalize_url($href, $purl=null) {
1365
 
1366
  # preserve empty source handles
1367
+ $href = trim($href);
1368
+ if(empty($href)) { return false; }
1369
 
1370
  # some fixes
1371
+ $href = str_replace(array('&#038;', '&amp;'), '&', $href);
 
 
 
1372
 
1373
+ # external url
1374
+ if(!is_null($purl) && !empty($purl)) {
1375
+ $parse = parse_url($purl);
1376
+ } else {
1377
+ # local url
1378
+ global $fvm_urls;
1379
+ $parse = parse_url($fvm_urls['wp_site_url']);
1380
+ }
1381
+
1382
+ # domain info
1383
+ $scheme = $parse['scheme'];
1384
+ $host = $parse['host'];
1385
+ $path = $parse['path'];
1386
+
1387
+ # relative to full urls
1388
+ if (substr($href, 0, 2) === "//") {
1389
+ $href = $scheme.':'.$href; # scheme missing
1390
+ } else if (substr($href, 0, 1) === "/") {
1391
+ $href = $scheme.'://'.$host . $href; # scheme and domain missing
1392
+ } else if (substr($href, 0, 3) === '../' && !is_null($purl) && !empty($purl)) {
1393
+ $href = $scheme.':'.$host . dirname($path) . '/' . $href;
1394
+ } else if ($scheme == 'https' && substr($href, 0, 4) == 'http' && substr($href, 0, 5) !== $scheme) {
1395
+ $href = str_replace('http://', 'https://', $href); # force https
1396
+ } else {
1397
+ # url should be fine
1398
  }
1399
 
1400
+ # prevent double forward slashes in the middle
1401
+ $href = str_replace('###', '://', str_replace('//', '/', str_replace('://', '###', $href)));
 
 
 
 
 
 
 
1402
 
1403
+ return $href;
1404
  }
1405
 
1406
 
1407
  # minify ld+json scripts
1408
  function fvm_minify_microdata($data) {
 
1409
  $data = trim(preg_replace('/(\v)+(\h)+[\/]{2}(.*)+(\v)+/u', '', $data));
 
 
1410
  $data = trim(preg_replace('/\s+/u', ' ', $data));
1411
  $data = str_replace(array('" ', ' "'), '"', $data);
1412
  $data = str_replace(array('[ ', ' ['), '[', $data);
1437
 
1438
  # find if a string looks like HTML content
1439
  function fvm_is_html($html) {
1440
+
1441
  # return early if it's html
1442
  $html = trim($html);
1443
  $a = '<!doctype';
1481
 
1482
  }
1483
 
 
 
 
 
 
 
 
 
 
 
1484
  # ensure that string is utf8
1485
  function fvm_ensure_utf8($str) {
1486
  $enc = mb_detect_encoding($str, mb_list_encodings(), true);
1497
  }
1498
 
1499
 
1500
+ # check if we can process the page, minimum filters
1501
+ function fvm_can_process_common() {
1502
+ global $fvm_settings, $fvm_urls;
1503
 
1504
+ # only GET requests allowed
1505
+ if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
1506
+ return false;
1507
+ }
1508
 
1509
+ # always skip on these tasks
1510
+ if( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ){ return false; }
1511
+ if( defined('WP_INSTALLING') && WP_INSTALLING ){ return false; }
1512
+ if( defined('WP_REPAIRING') && WP_REPAIRING ){ return false; }
1513
+ if( defined('WP_IMPORTING') && WP_IMPORTING ){ return false; }
1514
+ if( defined('DOING_AJAX') && DOING_AJAX ){ return false; }
1515
+ if( defined('WP_CLI') && WP_CLI ){ return false; }
1516
+ if( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST ){ return false; }
1517
+ if( defined('WP_ADMIN') && WP_ADMIN ){ return false; }
1518
+ if( defined('SHORTINIT') && SHORTINIT ){ return false; }
1519
+ if( defined('IFRAME_REQUEST') && IFRAME_REQUEST ){ return false; }
1520
 
1521
+ # detect api requests (only defined after parse_request hook)
1522
+ if( defined('REST_REQUEST') && REST_REQUEST ){ return false; }
1523
+
1524
+ # don't minify specific WordPress areas
1525
+ if(function_exists('is_404') && is_404()){ return false; }
1526
+ if(function_exists('is_feed') && is_feed()){ return false; }
1527
+ if(function_exists('is_comment_feed') && is_comment_feed()){ return false; }
1528
+ if(function_exists('is_attachment') && is_attachment()){ return false; }
1529
+ if(function_exists('is_trackback') && is_trackback()){ return false; }
1530
+ if(function_exists('is_robots') && is_robots()){ return false; }
1531
+ if(function_exists('is_preview') && is_preview()){ return false; }
1532
+ if(function_exists('is_customize_preview') && is_customize_preview()){ return false; }
1533
+ if(function_exists('is_embed') && is_embed()){ return false; }
1534
+ if(function_exists('is_admin') && is_admin()){ return false; }
1535
+ if(function_exists('is_blog_admin') && is_blog_admin()){ return false; }
1536
+ if(function_exists('is_network_admin') && is_network_admin()){ return false; }
1537
+
1538
+ # don't minify specific WooCommerce areas
1539
+ if(function_exists('is_checkout') && is_checkout()){ return false; }
1540
+ if(function_exists('is_account_page') && is_account_page()){ return false; }
1541
+ if(function_exists('is_ajax') && is_ajax()){ return false; }
1542
+ if(function_exists('is_wc_endpoint_url') && is_wc_endpoint_url()){ return false; }
1543
+
1544
+ # get requested hostname
1545
+ $host = fvm_get_domain();
1546
+
1547
+ # only for hosts matching the site_url
1548
+ if(isset($fvm_urls['wp_domain']) && !empty($fvm_urls['wp_domain'])) {
1549
+ if($host != $fvm_urls['wp_domain']) {
1550
+ return false;
1551
+ }
1552
+ }
1553
+
1554
+ # if there is an url, skip common static files
1555
+ if(isset($_SERVER['REQUEST_URI']) && !empty($_SERVER['REQUEST_URI'])) {
1556
+
1557
+ # parse url (path, query)
1558
+ $ruri = fvm_get_uripath();
1559
+
1560
+ # no cache by extension as well, such as robots.txt and other situations
1561
+ $noext = array('.txt', '.xml', '.xsl', '.map', '.css', '.js', '.png', '.jpeg', '.jpg', '.gif', '.webp', '.ico', '.php', '.htaccess', '.json', '.pdf', '.mp4', '.webm');
1562
+ foreach ($noext as $ext) {
1563
+ if(substr($ruri, -strlen($ext)) == $ext) {
1564
+ return false;
1565
+ }
1566
+ }
1567
+
1568
+ }
1569
+
1570
+ # default
1571
+ return true;
1572
+ }
1573
+
1574
+ # check if the user is logged in, and if the user role allows optimization
1575
+ function fvm_user_role_processing_allowed($group) {
1576
+ if(function_exists('is_user_logged_in') && function_exists('wp_get_current_user')) {
1577
+ if(is_user_logged_in()) {
1578
+
1579
+ # get user roles
1580
+ global $fvm_settings;
1581
+ $user = wp_get_current_user();
1582
+ $roles = (array) $user->roles;
1583
+ foreach($roles as $role) {
1584
+ if(isset($fvm_settings['minify'][$role]) && $fvm_settings['minify'][$role] == true) {
1585
+ return true;
1586
+ }
1587
+ }
1588
+
1589
+ # disable for other logged in users by default
1590
+ return false;
1591
+ }
1592
+ }
1593
+
1594
+ # allow by default
1595
+ return true;
1596
+ }
1597
+
1598
+ # check if we can process the page, minimum filters
1599
+ function fvm_can_process_query_string($loc) {
1600
+
1601
+ # host and uri path
1602
+ $host = fvm_get_domain();
1603
+ $request_uri = fvm_get_uripath(true);
1604
+ $scheme = fvm_get_scheme();
1605
+ $url = $scheme.'://'.$host.$request_uri;
1606
+ $parse = parse_url($url);
1607
+
1608
+ # parse query string to array, check if should be ignored
1609
+ if(isset($parse["query"]) && !empty($parse["query"])) {
1610
+
1611
+ # check
1612
+ $qsarr = array(); parse_str($parse["query"], $qsarr);
1613
+
1614
+ # allowed queries by default
1615
+ if(isset($qsarr['s'])) { unset($qsarr['s']); } # search
1616
+ if(isset($qsarr['lang'])) { unset($qsarr['lang']); } # wpml
1617
+
1618
+ # if there are other queries left, bypass cache
1619
+ if(count($qsarr) > 0) {
1620
+ return false;
1621
+ }
1622
+ }
1623
+
1624
+ # allow by default
1625
+ return true;
1626
+ }
1627
+
1628
+
1629
+
1630
+ # check if page is amp
1631
+ function fvm_is_amp_page() {
1632
+
1633
+ # don't minify amp pages by the amp plugin
1634
+ if(function_exists('is_amp_endpoint') && is_amp_endpoint()){ return true; }
1635
+ if(function_exists('ampforwp_is_amp_endpoint') && ampforwp_is_amp_endpoint()){ return true; }
1636
+
1637
+ # query string or /amp/
1638
+ if(isset($_GET['amp'])) { return true; }
1639
+ if(substr(fvm_get_uripath(), -5) == '/amp/') { return true; }
1640
+
1641
+ # not amp
1642
+ return false;
1643
+ }
1644
+
1645
+
1646
+ # validate and minify css
1647
+ function fvm_maybe_minify_css_file($css, $url, $min) {
1648
+
1649
  # process css only if it's not php or html
1650
  if(fvm_not_php_html($css)) {
1651
+
1652
+ global $fvm_settings, $fvm_urls;
1653
+
1654
+ # do not minify files in the ignore list
1655
+ if(isset($fvm_settings['css']['css_ignore_min']) && !empty($fvm_settings['css']['css_ignore_min'])) {
1656
+ $arr = fvm_string_toarray($fvm_settings['css']['css_ignore_min']);
1657
+ if(is_array($arr) && count($arr) > 0) {
1658
+ foreach ($arr as $e) {
1659
+ if(stripos($url, $e) !== false) {
1660
+ $min = false;
1661
+ break;
1662
+ }
1663
+ }
1664
+ }
1665
+ }
1666
+
1667
  # filtering
1668
+ $css = fvm_ensure_utf8($css);
1669
  $css = str_ireplace('@charset "UTF-8";', '', $css);
1670
 
1671
  # remove query strings from fonts
1681
  $css = preg_replace("/url\(\s*['\"]?(?!data:)(?!http)(?![\/'\"#])(.+?)['\"]?\s*\)/ui", "url(".dirname($url)."/$1)", $css);
1682
  }
1683
 
 
 
1684
  # minify string with relative urls
1685
+ if($min === true) {
1686
+ $css = fvm_minify_css_string($css, $url);
1687
  }
1688
 
1689
  # add font-display block for all font faces
1690
  # https://developers.google.com/web/updates/2016/02/font-display
1691
+ $css = preg_replace_callback('/(?:@font-face)\s*{(?<value>[^}]+)}/i',
1692
+ function ($matches) {
1693
+ if ( preg_match('/font-display:\s*(?<swap_value>\w*);?/i', $matches['value'], $attribute)) {
1694
+ return 'swap' === strtolower($attribute['swap_value']) ? $matches[0] : str_replace($attribute['swap_value'], 'swap', $matches[0]);
1695
+ } else {
1696
+ $swap = "font-display:swap;{$matches['value']}";
 
 
 
 
1697
  }
1698
+ return str_replace( $matches['value'], $swap, $matches[0] );
1699
+ },
1700
+ $css
1701
+ );
1702
 
1703
  # make relative urls when possible
1704
+
 
1705
  # get root url, preserve subdirectories
1706
  if(isset($fvm_urls['wp_site_url']) && !empty($fvm_urls['wp_site_url'])) {
1707
 
1714
 
1715
  # adjust paths
1716
  $bgimgs = array();
1717
+ preg_match_all ('/url\s*\((\s*[\'"]?(http:|https:|\/\/).+[\'"]?\s*)\)/Uui', $css, $bgimgs);
1718
  if(isset($bgimgs[1]) && is_array($bgimgs[1])) {
1719
  foreach($bgimgs[1] as $img) {
1720
+
1721
+ # normalize
1722
+ $newimg = fvm_normalize_url($img);
1723
+ if($newimg != $img) { $css = str_replace($img, $newimg, $css); $img = $newimg; }
1724
+
1725
+ # process
1726
  if(substr($img, 0, strlen($use_url)) == $use_url) {
1727
  $pos = strpos($img, $use_url);
1728
  if ($pos !== false) {
1729
+
1730
+ # relative path image
1731
+ $relimg = '/' . ltrim(substr_replace($img, '', $pos, strlen($use_url)), '/');
1732
+
1733
+ # replace url
1734
  $css = str_replace($img, $relimg, $css);
1735
+
1736
  }
1737
  }
1738
  }
1739
  }
1740
+
1741
+ # remove empty url()
1742
+ $css = preg_replace('/url\s*\(\s*[\'"]?\s*[\'"]?\)/Uui', 'none', $css);
1743
+
1744
+ # relative paths
1745
+ $css = str_replace('https://'.$fvm_urls['wp_domain'], '', $css);
1746
+ $css = str_replace('http://'.$fvm_urls['wp_domain'], '', $css);
1747
+ $css = str_replace('//'.$fvm_urls['wp_domain'], '', $css);
1748
+
1749
+ }
1750
+
1751
+ # simplify font face
1752
+ $arr = fvm_simplify_fontface($css);
1753
+ if($arr !== false && is_array($arr)) {
1754
+ $css = str_replace($arr['before'], $arr['after'], $css);
1755
  }
1756
 
1757
  # return css
1759
 
1760
  }
1761
 
1762
+ return false;
1763
  }
1764
 
1765
 
1779
  global $fvm_settings;
1780
 
1781
  # filtering
1782
+ $js = fvm_ensure_utf8($js);
1783
 
1784
  # remove sourceMappingURL
1785
  $js = preg_replace('/(\/\/\s*[#]\s*sourceMappingURL\s*[=]\s*)([a-zA-Z0-9-_\.\/]+)(\.map)/ui', '', $js);
1836
 
1837
  # try catch wrapper for merged javascript
1838
  function fvm_try_catch_wrap($js, $href=null) {
1839
+ $loc = ''; if(isset($href)) { $loc = '[ File: '. $href . ' ] '; }
1840
+ return 'try{'. PHP_EOL . $js . PHP_EOL . '}catch(e){console.error("An error has occurred. '.$loc.'[ "+e.stack+" ]");}';
1841
  }
1842
 
1843
 
1905
  }
1906
 
1907
 
1908
+ # try to open the file from the disk, before downloading
1909
+ function fvm_maybe_download($url) {
 
1910
 
1911
+ # must have
1912
+ if(is_null($url) || empty($url)) { return false; }
1913
+
1914
+ # get domain
1915
+ global $fvm_urls;
1916
+
1917
+ # check if we can open the file locally first
1918
+ if (stripos($url, $fvm_urls['wp_domain']) !== false && defined('ABSPATH') && !empty('ABSPATH')) {
1919
+
1920
+ # file path + windows compatibility
1921
+ $f = strtok(str_replace('/', DIRECTORY_SEPARATOR, str_replace(rtrim($fvm_urls['wp_site_url'], '/'), rtrim(ABSPATH, '/'), $url)), '?');
 
 
 
 
 
 
1922
 
1923
+ # did it work?
1924
+ if (file_exists($f)) {
1925
+ return array('content'=>file_get_contents($f), 'src'=>'Disk');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1926
  }
1927
  }
1928
+
1929
+ # fallback to downloading
1930
 
1931
+ # this useragent is needed for google fonts (woff files only + hinted fonts)
1932
+ $uagent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586';
1933
+
1934
+ # fetch via wordpress functions
1935
+ $response = wp_remote_get($url, array('user-agent'=>$uagent, 'timeout' => 7, 'httpversion' => '1.1', 'sslverify'=>false));
1936
+ if ( is_wp_error( $response ) ) {
1937
+ $error_message = $response->get_error_message();
1938
+ return array('error'=>"Something went wrong: $error_message / $url");
1939
+ } else {
1940
+ return array('content'=>wp_remote_retrieve_body($response), 'src'=>'Web');
1941
+ }
1942
  }
1943
 
1944
 
1959
  return $html;
1960
  }
1961
 
1962
+ # add lazy load library
1963
+ function fvm_add_delay_scripts_logic($html) {
1964
+
1965
+ # based on v2.0.0: https://github.com/shinsenter/defer.js
1966
+ # delay to interaction
1967
+ $scripts = <<<'EOF'
1968
+ <script type='text/javascript' id='fvm-delayjs' data-cfasync='false'>
1969
+ !function(k,e,x){function r(d,a,g,b){return b=(a?e.getElementById(a):t)||e.createElement(d||"SCRIPT"),a&&(b.id=a),g&&(b.onload=g),b}function u(d){f(function(a){a=[].slice.call(e.querySelectorAll(d));(function v(b,c){if(b=a.shift()){b.parentNode.removeChild(b);var l=b,m,n=void 0;var p=r(l.nodeName);var q=0;for(m=l.attributes;q<m.length;q++)"type"!=(n=m[q]).name&&p.setAttribute(n.name,n.value);(c=(p.text=l.text,p)).src&&!c.hasAttribute("async")?(c.onload=c.onerror=v,e.head.appendChild(c)):(e.head.appendChild(c),
1970
+ v())}})()})}var f,t,h=[],w=/p/.test(e.readyState);Function();(f=function(d,a){w?x(d,a):h.push(d,a)}).all=u;f.js=function(d,a,g,b){f(function(c){(c=r(t,a,b)).src=d;e.head.appendChild(c)},g)};k.addEventListener("onpageshow"in k?"pageshow":"load",function(){for(w=!u();h[0];)f(h.shift(),h.shift())});k.Defer=f}(this,document,setTimeout);
1971
+ const userInteractionEvents=["mouseover","keydown","touchstart","touchmove","wheel"];userInteractionEvents.forEach(function(event){window.addEventListener(event,triggerScriptLoader,{passive:!0})});function triggerScriptLoader(){fvmloadscripts();userInteractionEvents.forEach(function(event){window.removeEventListener(event,triggerScriptLoader,{passive:!0})})}function fvmloadscripts(){Defer.all('script[type="fvm-script-delay"]')};
1972
+ </script>
1973
+ EOF;
1974
+
1975
+ # add code
1976
+ return str_replace('<!-- h_footer_fvm_scripts -->', '<!-- h_footer_fvm_scripts -->' . $scripts, $html);
1977
+
1978
+ }
1979
+
1980
+
1981
+ # get the domain name
1982
+ function fvm_get_scheme() {
1983
+ if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') { return 'https'; }
1984
+ if(isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) { return 'https'; }
1985
+ if(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { return 'https'; }
1986
+ return 'http';
1987
+ }
1988
 
1989
  # get the domain name
1990
  function fvm_get_domain() {
1991
+ if (function_exists('site_url')) {
1992
+ $parse = parse_url(site_url());
1993
+ return $parse['host'];
1994
+ } elseif(isset($_SERVER['SERVER_NAME']) && !empty($_SERVER['SERVER_NAME'])) {
1995
  return $_SERVER['SERVER_NAME'];
1996
  } elseif (isset($_SERVER['HTTP_HOST']) && !empty($_SERVER['HTTP_HOST'])) {
1997
  return $_SERVER['HTTP_HOST'];
 
 
1998
  } else {
1999
  return false;
2000
  }
2001
  }
2002
 
 
2003
  # get the settings file path, current domain name, and uri path without query strings
2004
+ function fvm_get_uripath($full=null) {
2005
  if (isset($_SERVER['REQUEST_URI']) && !empty($_SERVER['REQUEST_URI'])) {
2006
+
2007
+ # full or no query string
2008
+ if(!is_null($full)) {
2009
+ $current_uri = trim($_SERVER['REQUEST_URI']);
2010
+ } else {
2011
+ $current_uri = strtok($_SERVER['REQUEST_URI'], '?');
2012
+ }
2013
+
2014
+ # filter
2015
  $current_uri = str_replace('//', '/', str_replace('..', '', preg_replace( '/[ <>\'\"\r\n\t\(\)]/', '', $current_uri)));
2016
  return $current_uri;
2017
  } else {
inc/frontend.php CHANGED
@@ -34,7 +34,7 @@ include_once($fvm_var_inc_lib_mm . 'path-converter' . DIRECTORY_SEPARATOR . 'src
34
 
35
  # start buffering before template
36
  function fvm_start_buffer() {
37
- if(fvm_can_minify()) {
38
  ob_start('fvm_process_page', 0, PHP_OUTPUT_HANDLER_REMOVABLE);
39
  }
40
  }
@@ -45,96 +45,111 @@ function fvm_process_page($html) {
45
  # get globals
46
  global $fvm_settings, $fvm_cache_paths, $fvm_urls;
47
 
48
- # can process minification?
49
- if(fvm_can_minify()) {
50
-
51
- # return early if not html
52
- if(fvm_is_html($html) !== true) {
53
- return $html;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
55
-
 
 
 
 
 
56
  # defaults
57
- $tvers = get_option('fvm_last_cache_update', '0');
58
- $now = time();
59
- $htmlcssheader = array();
60
- $lp_css_last_ff_inline = '';
61
-
62
- # get html into an object
63
- # https://simplehtmldom.sourceforge.io/manual.htm
64
- $html_object = str_get_html($html, true, true, 'UTF-8', false, PHP_EOL, ' ');
 
 
 
 
 
 
 
 
 
65
 
66
- # return early if html is not an object, or overwrite html into an object for processing
67
- if (!is_object($html_object)) {
68
- return $html . '<!-- simplehtmldom failed to process the html -->';
69
- } else {
70
- $html = $html_object;
71
  }
72
 
73
-
74
- # collect all link preload headers
75
- $allpreloads = array();
76
- foreach($html->find('link[rel=preload]') as $tag) {
77
 
78
- # auto importance by default
79
- $importance = 'auto';
80
- if(isset($tag->importance)) {
81
- $importance = $tag->importance;
82
- } else {
83
- $tag->importance = 'auto';
84
- }
85
 
86
- # highest to high (but earlier in page)
87
- if(isset($tag->importance) && $tag->importance == 'highest') {
88
- $tag->importance = 'high';
89
- $importance = 'highest';
 
 
 
 
 
 
 
 
 
 
 
90
  }
91
 
92
- # collect, group by importance and remove
93
- $allpreloads[$importance][] = $tag->outertext;
94
- $tag->outertext = '';
95
- }
96
-
97
-
98
- # process css, if not disabled
99
- if(isset($fvm_settings['css']['enable']) && $fvm_settings['css']['enable'] == true) {
100
-
101
- # defaults
102
- $fvm_styles = array();
103
- $fvm_styles_log = array();
104
- $critical_path = array();
105
- $enable_css_minification = true;
106
 
107
- # exclude styles and link tags inside scripts, no scripts or html comments
108
- $excl = array();
109
- foreach($html->find('script link[rel=stylesheet], script style, noscript style, noscript link[rel=stylesheet], comment') as $element) {
110
- $excl[] = $element->outertext;
111
- }
112
 
113
- # collect all styles, but filter out if excluded
114
- $allcss = array();
115
- foreach($html->find('link[rel=stylesheet], style') as $element) {
116
- if(!in_array($element->outertext, $excl)) {
117
- $allcss[] = $element;
118
- }
119
- }
120
-
121
- # merge and process
122
- foreach($allcss as $k=>$tag) {
123
-
124
- # ignore list, leave these alone
125
- if(isset($tag->href) && isset($fvm_settings['css']['ignore']) && !empty($fvm_settings['css']['ignore'])) {
126
  $arr = fvm_string_toarray($fvm_settings['css']['ignore']);
127
  if(is_array($arr) && count($arr) > 0) {
128
  foreach ($arr as $e) {
129
  if(stripos($tag->href, $e) !== false) {
 
130
  continue 2;
131
  }
132
  }
133
  }
134
- }
135
-
136
- # remove css files
137
- if(isset($tag->href) && isset($fvm_settings['css']['remove']) && !empty($fvm_settings['css']['remove'])) {
138
  $arr = fvm_string_toarray($fvm_settings['css']['remove']);
139
  if(is_array($arr) && count($arr) > 0) {
140
  foreach ($arr as $e) {
@@ -147,368 +162,358 @@ function fvm_process_page($html) {
147
  }
148
  }
149
 
150
- # change the mediatype for files that are to be merged into the fonts css
151
- if(isset($tag->href) && isset($fvm_settings['css']['fonts']) && $fvm_settings['css']['fonts'] == true) {
152
- $arr = array('/fonts.googleapis.com', '/animate.css', '/animate.min.css', '/icomoon.css', '/animations/', '/eicons/css/', 'font-awesome', 'fontawesome', '/flag-icon.min.css', '/fonts.css', '/pe-icon-7-stroke.css', '/fontello.css', '/dashicons.min.css');
153
- if(is_array($arr) && count($arr) > 0) {
154
- foreach ($arr as $e) {
155
- if(stripos($tag->href, $e) !== false) {
156
- $tag->media = 'fonts';
157
- break;
158
- }
159
- }
160
- }
161
- }
162
-
163
-
164
- # normalize mediatypes
165
- $media = 'all';
166
- if(isset($tag->media)) {
167
- $media = $tag->media;
168
- if ($media == 'screen' || $media == 'screen, print' || empty($media) || is_null($media) || $media == false) {
169
- $media = 'all';
170
- }
171
- }
172
-
173
- # remove print mediatypes
174
- if(isset($fvm_settings['css']['noprint']) && $fvm_settings['css']['noprint'] == true && $media == 'print') {
175
- $tag->outertext = '';
176
- unset($allcss[$k]);
177
- continue;
178
- }
179
 
180
- # process css files
181
- if($tag->tag == 'link' && isset($tag->href)) {
182
-
183
- # default
184
- $css = '';
185
-
186
- # make sure we have a complete url
187
- $href = fvm_normalize_url($tag->href, $fvm_urls['wp_domain'], $fvm_urls['wp_site_url']);
188
-
189
- # get minification settings for files
190
- if(isset($fvm_settings['css']['min_disable']) && $fvm_settings['css']['min_disable'] == '1') {
191
- $enable_css_minification = false;
192
- }
193
-
194
- # force minification on google fonts
195
- if(stripos($href, 'fonts.googleapis.com') !== false) {
196
- $enable_css_minification = true;
197
- }
198
 
199
- # download, minify, cache (no ver query string)
200
- $tkey = hash('sha1', $href);
201
- $css = fvm_get_transient($tkey);
202
- if ($css === false) {
203
 
204
- # open or download file, get contents
205
- $ddl = array();
206
- $ddl = fvm_maybe_download($href);
207
-
208
- # if success
209
- if(isset($ddl['content'])) {
210
-
211
- # contents
212
- $css = $ddl['content'];
213
 
214
- # open or download file, get contents
215
- $css = fvm_maybe_minify_css_file($css, $href, $enable_css_minification);
216
-
217
- # developers filter
218
- $css = apply_filters( 'fvm_after_download_and_minify_code', $css, 'css');
 
 
 
219
 
220
- # quick integrity check
221
- if(!empty($css) && $css !== false) {
222
-
223
- # trim code
224
- $css = trim($css);
225
-
226
- # execution time in ms, size in bytes
227
- $fs = strlen($css);
228
- $ur = str_replace($fvm_urls['wp_site_url'], '', $href);
229
- $tkey_meta = array('fs'=>$fs, 'url'=>str_replace($fvm_cache_paths['cache_url_min'].'/', '', $ur), 'mt'=>$media);
230
-
231
- # save
232
- fvm_set_transient(array('uid'=>$tkey, 'date'=>$tvers, 'type'=>'css', 'content'=>$css, 'meta'=>$tkey_meta));
233
 
 
 
 
 
 
 
 
 
234
  }
235
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  }
 
 
 
 
 
237
 
 
 
238
 
239
- # success
240
- if($css !== false) {
241
 
242
- # inline all css
243
- if(isset($fvm_settings['css']['inline-all']) && $fvm_settings['css']['inline-all'] == true) {
244
- $mt = ''; if(isset($tag->media)) { $mt = ' media="'.$tag->media.'"'; }
245
- $tag->outertext = '<style type="text/css"'.$mt.'>'.$css.'</style>';
246
- unset($allcss[$k]);
247
- continue;
248
  } else {
249
- # collect for merging
250
- $fvm_styles[$media][] = $css;
251
- $fvm_styles_log[$media][] = $tkey;
 
 
252
  $tag->outertext = '';
253
  unset($allcss[$k]);
254
  continue;
 
 
255
  }
256
-
257
- } else {
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
- # there is an error, so leave them alone
260
- $err = ''; if(isset($ddl['error'])) { $err = '<!-- '.$ddl['error'].' -->'; }
261
- $tag->outertext = PHP_EOL . $tag->outertext.$err . PHP_EOL;
262
- unset($allcss[$k]);
263
- continue;
264
 
265
- }
266
-
267
- }
268
-
269
-
270
- # process styles
271
- if($tag->tag == 'style' && !isset($tag->href)) {
272
-
273
- # default
274
- $css = '';
275
-
276
- # get minification settings for files
277
- if(isset($fvm_settings['css']['min_disable']) && $fvm_settings['css']['min_disable'] == true) {
278
- $enable_css_minification = true;
279
- }
280
-
281
- # minify inline CSS
282
- $css = $tag->innertext;
283
- if($enable_css_minification) {
284
- $css = fvm_minify_css_string($css);
285
- }
286
-
287
- # handle import rules
288
- $css = fvm_replace_css_imports($css);
289
-
290
- # remove fonts and icons and collect for later
291
- if(isset($fvm_settings['css']['fonts']) && $fvm_settings['css']['fonts'] == true) {
292
- $mff = array();
293
- preg_match_all('/(\@font-face)([^}]+)(\})/', $css, $mff);
294
- if(isset($mff[0]) && is_array($mff[0])) {
295
- foreach($mff[0] as $ff) {
296
- $css = str_replace($ff, '', $css);
297
- $lp_css_last_ff_inline.= $ff . PHP_EOL;
298
  }
299
  }
300
- }
301
-
302
- # add cdn support
303
- if(isset($fvm_settings['cdn']['enable']) && $fvm_settings['cdn']['enable'] == true &&
304
- isset($fvm_settings['cdn']['domain']) && !empty($fvm_settings['cdn']['domain'])) {
305
- if(isset($fvm_settings['cdn']['cssok']) && $fvm_settings['cdn']['cssok'] == true) {
306
-
307
- # scheme + site url
308
- $fcdn = str_replace($fvm_urls['wp_domain'], $fvm_settings['cdn']['domain'], $fvm_urls['wp_site_url']);
309
-
310
- # replacements
311
- $css = str_ireplace('url(/wp-content/', 'url('.$fcdn.'/wp-content/', $css);
312
- $css = str_ireplace('url("/wp-content/', 'url("'.$fcdn.'/wp-content/', $css);
313
- $css = str_ireplace('url(\'/wp-content/', 'url(\''.$fcdn.'/wp-content/', $css);
314
 
 
 
 
 
 
 
315
  }
316
- }
317
-
318
- # critical path needs to come before the CSS file
319
- if(isset($fvm_settings['css']['async']) && $fvm_settings['css']['async'] == true) {
320
- if(isset($tag->id) && $tag->id == 'critical-path') {
321
- $critical_path[] = $tag->outertext;
322
- $tag->outertext = '';
323
- }
324
- }
325
-
326
- # trim code
327
- $css = trim($css);
328
-
329
- # decide what to do with the inlined css
330
- if(empty($css)) {
331
- # delete empty style tags
332
- $tag->outertext = '';
333
- unset($allcss[$k]);
334
- continue;
335
- } else {
336
- # process inlined styles
337
- $tag->innertext = $css;
338
  unset($allcss[$k]);
339
- continue;
340
  }
341
-
342
  }
343
-
344
  }
 
 
345
 
346
- # generate merged css files, foreach mediatype
347
- if(is_array($fvm_styles) && count($fvm_styles) > 0) {
 
 
 
 
 
 
 
348
 
349
- # collect fonts for last
350
- $lp_css_last = '';
351
- $lp_css_last_ff = '';
352
 
353
- # merge files
354
- foreach ($fvm_styles as $mediatype=>$css_process) {
355
-
356
- # skip fonts file
357
- if($mediatype == 'fonts') {
358
- $lp_css_last = $fvm_styles['fonts'];
359
- continue;
360
- }
361
 
362
- # merge code, generate cache file paths and urls
363
- $file_css_code = implode('', $css_process);
364
- $css_uid = $tvers.'-'.hash('sha1', $file_css_code);
365
- $file_css = $fvm_cache_paths['cache_dir_min'] . DIRECTORY_SEPARATOR . $css_uid.'.min.css';
366
- $file_css_url = $fvm_cache_paths['cache_url_min'].'/'.$css_uid.'.min.css';
367
-
368
- # remove fonts and icons from final css
369
- if(isset($fvm_settings['css']['fonts']) && $fvm_settings['css']['fonts'] == true) {
370
- $mff = array();
371
- preg_match_all('/(\@font-face)([^}]+)(\})/', $file_css_code, $mff);
372
- if(isset($mff[0]) && is_array($mff[0])) {
373
- foreach($mff[0] as $ff) {
374
- $file_css_code = str_replace($ff, '', $file_css_code);
375
- $lp_css_last_ff.= $ff . PHP_EOL;
376
- }
377
- }
378
- }
379
-
380
- # add cdn support
381
- if(isset($fvm_settings['cdn']['enable']) && $fvm_settings['cdn']['enable'] == true &&
382
- isset($fvm_settings['cdn']['domain']) && !empty($fvm_settings['cdn']['domain'])) {
383
- if(isset($fvm_settings['cdn']['cssok']) && $fvm_settings['cdn']['cssok'] == true) {
384
- $file_css_url = str_replace('//'.$fvm_urls['wp_domain'], '//'.$fvm_settings['cdn']['domain'], $file_css_url);
385
- }
386
- }
387
-
388
- # generate cache file
389
- clearstatcache();
390
- if (!file_exists($file_css)) {
391
-
392
- # prepare log
393
- $log = (array) array_values($fvm_styles_log[$mediatype]);
394
- $log_meta = array('loc'=>home_url(add_query_arg(NULL, NULL)), 'fl'=>$file_css_url, 'mt'=>$mediatype);
395
-
396
- # generate cache, write log
397
- if(!empty($file_css_code)) {
398
- fvm_save_log(array('uid'=>$file_css_url, 'date'=>$now, 'type'=>'css', 'meta'=>$log_meta, 'content'=>$log));
399
- fvm_save_file($file_css, $file_css_code);
400
- }
401
-
402
- }
403
-
404
- # if file exists
405
- clearstatcache();
406
- if (file_exists($file_css)) {
407
-
408
- # preload and save for html implementation (with priority order prefix)
409
- if((!isset($fvm_settings['css']['nopreload']) || (isset($fvm_settings['css']['nopreload']) && $fvm_settings['css']['nopreload'] != true)) && (!isset($fvm_settings['css']['inline-all']) || (isset($fvm_settings['css']['inline-all']) && $fvm_settings['css']['inline-all'] != true))) {
410
- $allpreloads['high'][] = '<link rel="preload" href="'.$file_css_url.'" as="style" media="'.$mediatype.'" importance="high" />';
411
- }
412
 
413
- # async or render block css
414
- if(isset($fvm_settings['css']['async']) && $fvm_settings['css']['async'] == true) {
415
- $htmlcssheader['b_'.$css_uid] = '<link rel="stylesheet" href="'.$file_css_url.'" media="print" onload="this.media=\''.$mediatype.'\'">';
416
- } else {
417
- $htmlcssheader['b_'.$css_uid] = '<link rel="stylesheet" href="'.$file_css_url.'" media="'.$mediatype.'" />';
418
- }
419
- }
420
-
 
 
 
 
421
  }
422
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
 
424
- # generate merged css files, foreach mediatype
425
- if(!empty($lp_css_last) || !empty($lp_css_last_ff) || !empty($lp_css_last_ff_inline)) {
 
 
 
 
426
 
427
- # reset to all
428
- $mediatype = 'all';
 
 
 
429
 
430
- # merge code, generate cache file paths and urls
431
- $file_css_code = implode('', $lp_css_last).$lp_css_last_ff.$lp_css_last_ff_inline;
432
- $css_uid = $tvers.'-'.hash('sha1', $file_css_code);
433
- $file_css = $fvm_cache_paths['cache_dir_min'] . DIRECTORY_SEPARATOR . $css_uid.'.min.css';
434
- $file_css_url = $fvm_cache_paths['cache_url_min'].'/'.$css_uid.'.min.css';
435
 
436
- # add cdn support
437
- if(isset($fvm_settings['cdn']['enable']) && $fvm_settings['cdn']['enable'] == true &&
438
- isset($fvm_settings['cdn']['domain']) && !empty($fvm_settings['cdn']['domain'])) {
439
- if(isset($fvm_settings['cdn']['cssok']) && $fvm_settings['cdn']['cssok'] == true) {
440
- $file_css_url = str_replace('//'.$fvm_urls['wp_domain'], '//'.$fvm_settings['cdn']['domain'], $file_css_url);
441
- }
442
  }
 
 
 
443
 
444
- # generate cache file
445
- clearstatcache();
446
- if (!file_exists($file_css)) {
447
 
448
- # prepare log
449
- $log = (array) array_values($fvm_styles_log[$mediatype]);
450
- $log_meta = array('loc'=>home_url(add_query_arg(NULL, NULL)), 'fl'=>$file_css_url, 'mt'=>$mediatype);
 
 
451
 
452
- # generate cache, write log
453
- if(!empty($file_css_code)) {
454
- fvm_save_log(array('uid'=>$file_css_url, 'date'=>$now, 'type'=>'css', 'meta'=>$log_meta, 'content'=>$log));
455
- fvm_save_file($file_css, $file_css_code);
456
- }
457
- }
458
-
459
- # if file exists
460
- clearstatcache();
461
- if (file_exists($file_css)) {
462
 
463
- # add file with js
464
- $htmlcssheader['a_'.$css_uid] = '<script data-cfasync="false" id="fvmlpcss">var fvmft;fvmuag()&&((fvmft=document.getElementById("fvmlpcss")).outerHTML='.fvm_escape_url_js("<link rel='stylesheet' href='". $file_css_url . "' media='".$mediatype."' />").');</script>'; # prepend
465
 
466
- }
467
-
468
- }
469
-
470
  }
471
  }
472
-
 
 
 
 
 
 
 
 
 
 
 
 
473
 
474
- # always disable js minification in certain areas
475
- $nojsmin = false;
476
- if(function_exists('is_cart') && is_cart()){ $nojsmin = true; } # cart
477
 
478
- # process js, if not disabled
479
- if(isset($fvm_settings['js']['enable']) && $fvm_settings['js']['enable'] == true && $nojsmin === false) {
480
-
481
- # defaults
482
- $scripts_duplicate_check = array();
483
- $enable_js_minification = true;
484
- $htmljscodeheader = array();
485
- $htmljscodedefer = array();
486
- $scripts_header = array();
487
- $scripts_footer = array();
488
 
489
- # get all scripts
490
- $allscripts = array();
491
- foreach($html->find('script') as $element) {
492
- $allscripts[] = $element;
493
- }
494
-
495
- # process all scripts
496
- if (is_array($allscripts) && count($allscripts) > 0) {
497
- foreach($allscripts as $k=>$tag) {
498
-
499
- # handle application/ld+json or application/json before anything else
500
- if(isset($tag->type) && ($tag->type == 'application/ld+json' || $tag->type == 'application/json')) {
501
- $tag->innertext = fvm_minify_microdata($tag->innertext);
502
- unset($allscripts[$k]);
503
- continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  }
505
 
506
- # remove js code
507
- if(isset($tag->outertext) && isset($fvm_settings['js']['remove']) && !empty($fvm_settings['js']['remove'])) {
508
  $arr = fvm_string_toarray($fvm_settings['js']['remove']);
509
  if(is_array($arr) && count($arr) > 0) {
510
- foreach ($arr as $e) {
511
- if(stripos($tag->outertext, $e) !== false) {
512
  $tag->outertext = '';
513
  unset($allscripts[$k]);
514
  continue 2;
@@ -517,490 +522,499 @@ function fvm_process_page($html) {
517
  }
518
  }
519
 
520
-
521
- # process inline scripts
522
- if(!isset($tag->src)) {
523
-
524
- # default
525
- $js = '';
526
-
527
- # get minification settings for files
528
- if(isset($fvm_settings['js']['min_disable']) && $fvm_settings['js']['min_disable'] == true) {
529
- $enable_js_minification = false;
530
- }
531
-
532
- # minify inline scripts
533
- $js = $tag->innertext;
534
- $js = fvm_maybe_minify_js($js, null, $enable_js_minification);
535
-
536
- # Delay third party scripts and tracking codes (uses PHP stripos against the script innerHTML or the src attribute)
537
- if(isset($fvm_settings['js']['thirdparty']) && !empty($fvm_settings['js']['thirdparty'])) {
538
- if(isset($fvm_settings['js']['thirdparty']) && !empty($fvm_settings['js']['thirdparty'])) {
539
- $arr = fvm_string_toarray($fvm_settings['js']['thirdparty']);
540
- if(is_array($arr) && count($arr) > 0) {
541
- foreach ($arr as $b) {
542
- if(stripos($js, $b) !== false) {
543
- $js = 'if(fvmuag()){window.addEventListener("load",function(){var c=setTimeout(b,5E3),d=["mouseover","keydown","touchmove","touchstart"];d.forEach(function(a){window.addEventListener(a,e,{passive:!0})});function e(){b();clearTimeout(c);d.forEach(function(a){window.removeEventListener(a,e,{passive:!0})})}function b(){console.log("FVM: Loading Third Party Script (inline)!");'.$js.'};});}';
544
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  }
546
- }
547
  }
548
  }
549
  }
550
 
551
- # delay inline scripts until after the 'window.load' event
552
- if(isset($fvm_settings['js']['defer_dependencies']) && !empty($fvm_settings['js']['defer_dependencies'])) {
553
- $arr = fvm_string_toarray($fvm_settings['js']['defer_dependencies']);
554
  if(is_array($arr) && count($arr) > 0) {
555
- foreach ($arr as $e) {
556
- if(stripos($js, $e) !== false && stripos($js, 'FVM:') === false) {
557
- $js = 'if(fvmuag()){window.addEventListener("load",function(){console.log("FVM: Loading Inline Dependency!");'.$js.'});}';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
558
  }
559
  }
560
  }
561
  }
562
-
563
 
564
- # replace tag on the html
565
- $tag->innertext = $js;
566
 
567
- # mark as processed, unset and break inner loop
568
- unset($allscripts[$k]);
569
- continue;
570
-
571
- }
572
-
573
-
574
- # process js files
575
- if(isset($tag->src)) {
576
-
577
- # make sure we have a complete url
578
- $href = fvm_normalize_url($tag->src, $fvm_urls['wp_domain'], $fvm_urls['wp_site_url']);
579
-
580
- # upgrade jQuery library and jQuery migrate to version 3
581
- if(isset($fvm_settings['js']['jqupgrade']) && $fvm_settings['js']['jqupgrade'] == true) {
582
- # jquery 3
583
- if(stripos($tag->src, '/jquery.js') !== false || stripos($tag->src, '/jquery.min.js') !== false) {
584
- $href = 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js';
585
  }
586
- # jquery migrate 3
587
- if(stripos($tag->src, '/jquery-migrate.') !== false || stripos($tag->src, '/jquery-migrate-') !== false) { $href = 'https://cdnjs.cloudflare.com/ajax/libs/jquery-migrate/3.3.1/jquery-migrate.min.js'; }
588
- }
589
-
590
- # get minification settings for files
591
- if(isset($fvm_settings['js']['min_disable']) && $fvm_settings['js']['min_disable'] == true) {
592
- $enable_js_minification = false;
593
- }
594
-
595
- # ignore list, leave these alone
596
- if(isset($fvm_settings['js']['ignore']) && !empty($fvm_settings['js']['ignore'])) {
597
- $arr = fvm_string_toarray($fvm_settings['js']['ignore']);
598
- if(is_array($arr) && count($arr) > 0) {
599
- foreach ($arr as $e) {
600
- if(stripos($tag->src, $e) !== false) {
601
- continue 2;
602
- }
603
- }
604
  }
605
- }
 
 
 
 
 
606
 
607
- # Delay third party scripts and tracking codes
608
- # uses PHP stripos against the script src, if it's async or deferred
609
- if(isset($tag->async) || isset($tag->defer)) {
610
- if(isset($fvm_settings['js']['thirdparty']) && !empty($fvm_settings['js']['thirdparty'])) {
611
- if(isset($fvm_settings['js']['thirdparty']) && !empty($fvm_settings['js']['thirdparty'])) {
612
- $arr = fvm_string_toarray($fvm_settings['js']['thirdparty']);
613
- if(is_array($arr) && count($arr) > 0) {
614
- foreach ($arr as $b) {
615
- if(stripos($tag->src, $b) !== false) {
616
-
617
- # get all extra attributes into $rem
618
- $rem = '';
619
- foreach($tag->getAllAttributes() as $k=>$v){
620
- $k = trim($k); $v = trim($v);
621
- if($k != 'async' && $k != 'defer' && $k != 'src' && $k != 'type') {
622
- $rem.= "b.setAttribute('$k','$v');";
623
- }
624
- }
625
-
626
- # defer attribute? (async is always by default)
627
- if(isset($tag->defer)) {
628
- $rem.= 'b.async=false;';
629
- }
630
-
631
- # generate and set delayed script tag
632
- $tag->outertext = "<script data-cfasync='false'>".'if(fvmuag()){window.addEventListener("load",function(){var c=setTimeout(b,5E3),d=["mouseover","keydown","touchmove","touchstart"];d.forEach(function(a){window.addEventListener(a,e,{passive:!0})});function e(){b();clearTimeout(c);d.forEach(function(a){window.removeEventListener(a,e,{passive:!0})})}function b(){'."(function(a){var b=a.createElement('script'),c=a.scripts[0];b.src='".trim($tag->src)."';".$rem."c.parentNode.insertBefore(b,c);}(document));".'};});}'."</script>";
633
- unset($allscripts[$k]);
634
- continue 2;
635
-
636
- }
637
- }
638
- }
639
- }
640
- }
641
- }
642
 
643
- # render blocking scripts in the header
644
  if(isset($fvm_settings['js']['merge_header']) && !empty($fvm_settings['js']['merge_header'])) {
645
  $arr = fvm_string_toarray($fvm_settings['js']['merge_header']);
646
  if(is_array($arr) && count($arr) > 0) {
647
- foreach ($arr as $e) {
648
- if(stripos($href, $e) !== false) {
649
 
650
- # download, minify, cache
651
- $tkey = hash('sha1', $href);
652
- $js = fvm_get_transient($tkey);
653
- if ($js === false) {
654
-
655
- # open or download file, get contents
656
- $ddl = array();
657
- $ddl = fvm_maybe_download($href);
658
 
659
- # if success
660
- if(isset($ddl['content'])) {
661
-
662
- # contents
663
- $js = $ddl['content'];
664
-
665
- # minify, save and wrap
666
- $js = fvm_maybe_minify_js($js, $href, $enable_js_minification);
667
-
668
- # quick integrity check
669
- if(!empty($js) && $js !== false) {
670
-
671
- # try catch
672
- $js = fvm_try_catch_wrap($js, $href);
673
-
674
- # developers filter
675
- $js = apply_filters( 'fvm_after_download_and_minify_code', $js, 'js');
676
-
677
- # execution time in ms, size in bytes
678
- $fs = strlen($js);
679
- $ur = str_replace($fvm_urls['wp_site_url'], '', $href);
680
- $tkey_meta = array('fs'=>$fs, 'url'=>str_replace($fvm_cache_paths['cache_url_min'].'/', '', $ur));
681
-
682
- # save
683
- fvm_set_transient(array('uid'=>$tkey, 'date'=>$tvers, 'type'=>'js', 'content'=>$js, 'meta'=>$tkey_meta));
684
-
685
- }
686
  }
687
- }
688
-
689
- # processed successfully?
690
- if ($js !== false) {
691
-
692
- # collect and mark as done for html removal
693
- $scripts_header[$tkey] = $js;
694
- $scripts_header_log[$tkey] = $tkey;
695
 
696
- # mark as processed, unset and break inner loop
697
- $tag->outertext = '';
698
- unset($allscripts[$k]);
699
- continue 2;
700
-
701
- } else {
702
-
703
- # there is an error, so leave them alone
704
- $err = ''; if(isset($ddl['error'])) { $err = '<!-- '.$ddl['error'].' -->'; }
705
- $tag->outertext = PHP_EOL . $tag->outertext.$err . PHP_EOL;
 
 
 
 
 
 
 
706
  unset($allscripts[$k]);
707
  continue 2;
708
 
709
  }
710
-
711
  }
712
  }
713
  }
714
  }
715
-
716
-
717
- # merge and defer scripts
718
  if(isset($fvm_settings['js']['merge_defer']) && !empty($fvm_settings['js']['merge_defer'])) {
719
  $arr = fvm_string_toarray($fvm_settings['js']['merge_defer']);
720
  if(is_array($arr) && count($arr) > 0) {
721
- foreach ($arr as $e) {
722
- if(stripos($href, $e) !== false) {
723
-
724
- # download, minify, cache
725
- $tkey = hash('sha1', $href);
726
- $js = fvm_get_transient($tkey);
727
- if ($js === false) {
728
-
729
- # open or download file, get contents
730
- $ddl = array();
731
- $ddl = fvm_maybe_download($href);
732
 
733
- # if success
734
- if(isset($ddl['content'])) {
735
-
736
- # contents
737
- $js = $ddl['content'];
738
-
739
- # minify, save and wrap
740
- $js = fvm_maybe_minify_js($js, $href, $enable_js_minification);
741
-
742
- # quick integrity check
743
- if(!empty($js) && $js !== false) {
744
-
745
- # try catch
746
- $js = fvm_try_catch_wrap($js, $href);
747
-
748
- # developers filter
749
- $js = apply_filters( 'fvm_after_download_and_minify_code', $js, 'js');
750
-
751
- # execution time in ms, size in bytes
752
- $fs = strlen($js);
753
- $ur = str_replace($fvm_urls['wp_site_url'], '', $href);
754
- $tkey_meta = array('fs'=>$fs, 'url'=>str_replace($fvm_cache_paths['cache_url_min'].'/', '', $ur));
755
-
756
- # save
757
- fvm_set_transient(array('uid'=>$tkey, 'date'=>$tvers, 'type'=>'js', 'content'=>$js, 'meta'=>$tkey_meta));
758
-
759
- }
760
- }
761
- }
762
 
763
- # processed successfully?
764
- if ($js !== false) {
765
-
766
- # collect and mark as done for html removal
767
- $scripts_footer[$tkey] = $js;
768
- $scripts_footer_log[$tkey] = $tkey;
769
 
770
- # mark as processed, unset and break inner loop
771
- $tag->outertext = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
772
  unset($allscripts[$k]);
773
  continue 2;
774
 
775
  }
776
-
777
  }
778
  }
779
  }
780
  }
781
-
782
- }
783
-
 
 
 
 
784
  }
785
- }
786
-
787
-
788
-
789
- # generate header merged scripts
790
- if(count($scripts_header) > 0) {
791
-
792
- # merge code, generate cache file paths and urls
793
- $fheader_code = implode('', $scripts_header);
794
- $js_header_uid = $tvers.'-'.hash('sha1', $fheader_code).'.header';
795
- $fheader = $fvm_cache_paths['cache_dir_min'] . DIRECTORY_SEPARATOR . $js_header_uid.'.min.js';
796
- $fheader_url = $fvm_cache_paths['cache_url_min'].'/'.$js_header_uid.'.min.js';
797
 
798
- # add cdn support
799
- if(isset($fvm_settings['cdn']['enable']) && $fvm_settings['cdn']['enable'] == true &&
800
- isset($fvm_settings['cdn']['domain']) && !empty($fvm_settings['cdn']['domain'])) {
801
- if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
802
- $fheader_url = str_replace('//'.$fvm_urls['wp_domain'], '//'.$fvm_settings['cdn']['domain'], $fheader_url);
 
 
 
803
  }
804
- }
805
-
806
- # generate cache file
807
- clearstatcache();
808
- if (!file_exists($fheader)) {
809
 
810
- # prepare log
811
- $log = (array) array_values($scripts_header_log);
812
- $log_meta = array('loc'=>home_url(add_query_arg(NULL, NULL)), 'fl'=>$fheader_url);
813
 
814
- # generate cache, write log
815
- if(!empty($fheader_code)) {
816
- fvm_save_log(array('uid'=>$fheader_url, 'date'=>$now, 'type'=>'js', 'meta'=>$log_meta, 'content'=>$log));
817
- fvm_save_file($fheader, $fheader_code);
818
- }
819
- }
820
-
821
- # preload and save for html implementation (with priority order prefix)
822
- if(!isset($fvm_settings['js']['nopreload']) || (isset($fvm_settings['js']['nopreload']) && $fvm_settings['js']['nopreload'] != true)) {
823
- $allpreloads['high'][] = '<link rel="preload" href="'.$fheader_url.'" as="script" importance="high" />';
824
- }
825
-
826
- # header
827
- $htmljscodeheader['c_'.$js_header_uid] = '<script data-cfasync="false" src="'.$fheader_url.'"></script>';
828
-
829
- }
830
-
831
- # generate footer merged scripts
832
- if(count($scripts_footer) > 0) {
833
-
834
- # merge code, generate cache file paths and urls
835
- $ffooter_code = implode('', $scripts_footer);
836
- $js_ffooter_uid = $tvers.'-'.hash('sha1', $ffooter_code).'.footer';
837
- $ffooter = $fvm_cache_paths['cache_dir_min'] . DIRECTORY_SEPARATOR . $js_ffooter_uid.'.min.js';
838
- $ffooter_url = $fvm_cache_paths['cache_url_min'].'/'.$js_ffooter_uid.'.min.js';
839
-
840
- # add cdn support
841
- if(isset($fvm_settings['cdn']['enable']) && $fvm_settings['cdn']['enable'] == true &&
842
- isset($fvm_settings['cdn']['domain']) && !empty($fvm_settings['cdn']['domain'])) {
843
- if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
844
- $ffooter_url = str_replace('//'.$fvm_urls['wp_domain'], '//'.$fvm_settings['cdn']['domain'], $ffooter_url);
845
-
846
  }
847
- }
848
-
849
- # generate cache file
850
- clearstatcache();
851
- if (!file_exists($ffooter)) {
852
 
853
- # prepare log
854
- $log = (array) array_values($scripts_footer_log);
855
- $log_meta = array('loc'=>home_url(add_query_arg(NULL, NULL)), 'fl'=>$ffooter_url);
856
-
857
- # generate cache, write log
858
- if(!empty($ffooter_code)) {
859
- fvm_save_log(array('uid'=>$ffooter_url, 'date'=>$now, 'type'=>'js', 'meta'=>$log_meta, 'content'=>$log));
860
- fvm_save_file($ffooter, $ffooter_code);
 
 
 
 
 
 
 
 
 
 
 
 
 
861
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
862
  }
863
-
864
- # preload and save for html implementation (with priority order prefix)
865
- if(!isset($fvm_settings['js']['nopreload']) || (isset($fvm_settings['js']['nopreload']) && $fvm_settings['js']['nopreload'] != true)) {
866
- $allpreloads['low'][] = '<link rel="preload" href="'.$ffooter_url.'" as="script" importance="low" />';
867
- }
868
-
869
- # header
870
- $htmljscodedefer['d_'.$js_ffooter_uid] = '<script data-cfasync="false" defer src="'.$ffooter_url.'"></script>';
871
-
872
  }
873
-
874
  }
875
-
876
-
 
 
 
 
 
 
 
 
 
877
 
878
- # process html, if not disabled
879
- if(isset($fvm_settings['html']['enable']) && $fvm_settings['html']['enable'] == true) {
 
 
880
 
881
- # Remove HTML comments and IE conditionals
882
- if(isset($fvm_settings['html']['nocomments']) && $fvm_settings['html']['nocomments'] == true) {
883
- foreach($html->find('comment') as $element) {
884
- $element->outertext = '';
885
- }
 
 
 
 
 
886
  }
887
 
888
- # cleanup header
889
- if(isset($fvm_settings['html']['cleanup_header']) && $fvm_settings['html']['cleanup_header'] == true) {
890
- foreach($html->find('head meta[name=generator], head link[rel=shortlink], head link[rel=dns-prefetch], head link[rel=preconnect], head link[rel=prefetch], head link[rel=prerender], head link[rel=EditURI], head link[rel=preconnect], head link[rel=wlwmanifest], head link[type=application/rss+xml], head link[rel=https://api.w.org/], head link[type=application/json+oembed], head link[type=text/xml+oembed], head meta[name*=msapplication], head link[rel=apple-touch-icon]') as $element) {
891
- $element->outertext = '';
892
- }
893
  }
894
 
 
 
 
895
  }
896
 
897
- # cdn rewrites, when needed
898
- $html = fvm_rewrite_assets_cdn($html);
899
-
900
- # build extra head and footer ###############################
901
-
902
- # header and footer markers
903
- $hm = '<!-- h_preheader --><!-- h_header_function --><!-- h_cssheader --><!-- h_jsheader -->';
904
- $fm = '<!-- h_footer_lozad -->';
905
-
906
- # add our function to head
907
- $hm = fvm_add_header_function($hm);
908
-
909
- # remove charset meta tag and collect it to first position
910
- if(!is_null($html->find('meta[charset]', 0))) {
911
- $hm = str_replace('<!-- h_preheader -->', $html->find('meta[charset]', 0)->outertext.'<!-- h_preheader -->', $hm);
912
- foreach($html->find('meta[charset]') as $element) { $element->outertext = ''; }
913
- }
914
-
915
- # preload headers, by importance
916
- if(is_array($allpreloads)) {
917
-
918
- # start
919
- $preload = '';
920
 
921
- # highest priority (rewritten as high, but earlier)
922
- if(isset($allpreloads['highest'])) {
923
- $preload.= implode(PHP_EOL, $allpreloads['highest']);
924
- }
925
-
926
- # high priority
927
- if(isset($allpreloads['high'])) {
928
- $preload.= implode(PHP_EOL, $allpreloads['high']);
929
- }
930
-
931
- # auto priority
932
- if(isset($allpreloads['auto'])) {
933
- $preload.= implode(PHP_EOL, $allpreloads['auto']);
934
- }
935
 
936
- # low priority
937
- if(isset($allpreloads['low'])) {
938
- $preload.= implode(PHP_EOL, $allpreloads['low']);
939
- }
940
-
941
- # add preload
942
- if(!empty($preload)) {
943
- $hm = str_replace('<!-- h_preheader -->', $preload.'<!-- h_preheader -->', $hm);
944
  }
945
- }
 
 
946
 
947
- # add critical path
948
- if(isset($critical_path)) {
949
- if(is_array($critical_path) && count($critical_path) > 0) {
950
- $hm = str_replace('<!-- h_preheader -->', implode(PHP_EOL, $critical_path).'<!-- h_preheader -->', $hm);
951
- }
952
  }
953
 
954
- # add stylesheets
955
- if(isset($htmlcssheader)) {
956
- if(is_array($htmlcssheader) && count($htmlcssheader) > 0) {
957
- ksort($htmlcssheader); # priority
958
- $hm = str_replace('<!-- h_cssheader -->', implode(PHP_EOL, $htmlcssheader).'<!-- h_cssheader -->', $hm);
 
 
 
 
 
 
 
959
  }
960
  }
961
 
962
- # add header scripts
963
- if(isset($htmljscodeheader)) {
964
- if(is_array($htmljscodeheader) && count($htmljscodeheader) > 0) {
965
- ksort($htmljscodeheader); # priority
966
- $hm = str_replace('<!-- h_jsheader -->', implode(PHP_EOL, $htmljscodeheader).'<!-- h_jsheader -->', $hm);
 
967
  }
968
- }
969
-
970
- # add defer scripts
971
- if(isset($htmljscodedefer)) {
972
- if(is_array($htmljscodedefer) && count($htmljscodedefer) > 0) {
973
- ksort($htmljscodedefer); # priority
974
- $hm = str_replace('<!-- h_jsheader -->', implode(PHP_EOL, $htmljscodedefer), $hm);
 
975
  }
976
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
977
 
978
- # cleanup leftover markers
979
- $hm = str_replace(
980
- array('<!-- h_preheader -->', '<!-- h_header_function -->', '<!-- h_cssheader -->', '<!-- h_jsheader -->'), '', $hm);
981
- $fm = str_replace('<!-- h_footer_lozad -->', '', $fm);
 
 
 
 
 
 
 
 
 
 
982
 
983
-
984
- # Save HTML and output page ###############################
 
985
 
986
- # append header and footer, if available
987
- if(!is_null($html->find('head', 0)) && !is_null($html->find('body', -1))) {
988
- if(!is_null($html->find('head', 0)->first_child()) && !is_null($html->find('body', -1)->last_child())) {
989
- $html->find('head', 0)->first_child()->outertext = $hm . $html->find('head', 0)->first_child()->outertext;
990
- $html->find('body', -1)->last_child()->outertext = $html->find('body', -1)->last_child ()->outertext . $fm;
 
 
 
991
  }
992
  }
993
 
994
- # convert html object to string
995
- $html = trim($html->save());
996
-
997
- # minify HTML, if not disabled
998
- if(!isset($fvm_settings['html']['min_disable']) || (isset($fvm_settings['html']['min_disable']) && $fvm_settings['html']['min_disable'] != true)) {
999
- $html = fvm_raisermin_html($html, true);
1000
  }
1001
 
1002
  }
1003
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1004
  # return html
1005
  return $html;
1006
 
34
 
35
  # start buffering before template
36
  function fvm_start_buffer() {
37
+ if(fvm_can_minify_css() || fvm_can_minify_js() || fvm_can_process_html()) {
38
  ob_start('fvm_process_page', 0, PHP_OUTPUT_HANDLER_REMOVABLE);
39
  }
40
  }
45
  # get globals
46
  global $fvm_settings, $fvm_cache_paths, $fvm_urls;
47
 
48
+ # get html into an object
49
+ # https://simplehtmldom.sourceforge.io/manual.htm
50
+ $html_object = str_get_html($html, false, true, 'UTF-8', false, PHP_EOL, ' ');
51
+
52
+ # return early if html is not an object, or overwrite html into an object for processing
53
+ if (!is_object($html_object)) {
54
+ return $html . '<!-- simplehtmldom failed to process the html -->';
55
+ } else {
56
+ $html = $html_object;
57
+ }
58
+
59
+ # get globals
60
+ global $fvm_settings, $fvm_urls;
61
+
62
+ # defaults
63
+ $tvers = get_option('fvm_last_cache_update', '0');
64
+ $httppreloads = array();
65
+ $htmlpreloads = array();
66
+ $htmlcssheader = array();
67
+ $htmljsheader = array();
68
+ $htmljsdefer = array();
69
+
70
+
71
+ # collect all link preload headers, skip amp
72
+ if(fvm_is_amp_page() !== true) {
73
+ # add other preloads
74
+ foreach($html->find('link[rel=preload]') as $tag) {
75
+ $htmlpreloads[] = $tag->outertext;
76
+ $tag->outertext = '';
77
  }
78
+ }
79
+
80
+
81
+ # START CSS PROCESSING
82
+ if(fvm_can_minify_css()) {
83
+
84
  # defaults
85
+ $fvm_styles = array();
86
+ $allcss = array();
87
+ $css_lowpriority_code = '';
88
+
89
+ # start log
90
+ $log = array();
91
+ $css_total = 0;
92
+
93
+ # start log
94
+ $log[]= 'PAGE - '. fvm_get_uripath(true) . PHP_EOL . '---' . PHP_EOL;
95
+
96
+
97
+ # exclude styles and link tags inside scripts, no scripts or html comments
98
+ $excl = array();
99
+ foreach($html->find('script link[rel=stylesheet], script style, noscript style, noscript link[rel=stylesheet], comment') as $element) {
100
+ $excl[] = $element->outertext;
101
+ }
102
 
103
+ # collect all styles, but filter out if excluded
104
+ foreach($html->find('link[rel=stylesheet], style') as $element) {
105
+ if(!in_array($element->outertext, $excl)) {
106
+ $allcss[] = $element;
107
+ }
108
  }
109
 
110
+ # START CSS LOOP
111
+ foreach($allcss as $k=>$tag) {
 
 
112
 
113
+ # mediatypes
114
+ if(isset($tag->media)) {
 
 
 
 
 
115
 
116
+ # Normalize mediatypes
117
+ if($tag->media == 'screen' || $tag->media == 'screen, print' || strlen($tag->media) == 0) {
118
+ $tag->media = 'all';
119
+ }
120
+
121
+ # Remove print styles
122
+ if(isset($fvm_settings['css']['noprint']) && $fvm_settings['css']['noprint'] == true && $tag->media == 'print'){
123
+ $tag->outertext = '';
124
+ unset($allcss[$k]);
125
+ continue;
126
+ }
127
+
128
+ } else {
129
+ # must have
130
+ $tag->media = 'all';
131
  }
132
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
+ # START CSS FILES
135
+ if($tag->tag == 'link' && isset($tag->href)) {
 
 
 
136
 
137
+ # Ignore css files
138
+ $ignore_css_merging = false;
139
+ if(isset($fvm_settings['css']['ignore']) && !empty($fvm_settings['css']['ignore'])) {
 
 
 
 
 
 
 
 
 
 
140
  $arr = fvm_string_toarray($fvm_settings['css']['ignore']);
141
  if(is_array($arr) && count($arr) > 0) {
142
  foreach ($arr as $e) {
143
  if(stripos($tag->href, $e) !== false) {
144
+ unset($allcss[$k]);
145
  continue 2;
146
  }
147
  }
148
  }
149
+ }
150
+
151
+ # Remove CSS files
152
+ if(isset($fvm_settings['css']['remove']) && !empty($fvm_settings['css']['remove'])) {
153
  $arr = fvm_string_toarray($fvm_settings['css']['remove']);
154
  if(is_array($arr) && count($arr) > 0) {
155
  foreach ($arr as $e) {
162
  }
163
  }
164
 
165
+ # css merging functionality
166
+ if(isset($fvm_settings['css']['combine']) && $fvm_settings['css']['combine'] == true) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
+ # download or fetch from transient, minified
169
+ $css = fvm_get_css_from_file($tag);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
+ if($css !== false && is_array($css)) {
 
 
 
172
 
173
+ # extract fonts and icons
174
+ if(isset($fvm_settings['css']['fonts']) && $fvm_settings['css']['fonts'] == true) {
175
+ $extract_fonts_arr = fvm_extract_fonts($css['code']);
176
+ $css_lowpriority_code.= '/* '.$tag->href.' */'. PHP_EOL . $extract_fonts_arr['fonts'];
177
+ $css_code = $extract_fonts_arr['code'];
178
+ } else {
179
+ $css_code = $css['code'];
180
+ }
 
181
 
182
+
183
+ # async from the list only
184
+ if(isset($fvm_settings['css']['async']) && $fvm_settings['css']['async'] == true) {
185
+ if(isset($fvm_settings['css']['async']) && !empty($fvm_settings['css']['async'])) {
186
+ $arr = fvm_string_toarray($fvm_settings['css']['async']);
187
+ if(is_array($arr) && count($arr) > 0) {
188
+ foreach ($arr as $aa) {
189
+ if(stripos($tag->href, $aa) !== false) {
190
 
191
+ # save css for merging
192
+ $fvm_styles[$tag->media]['async'][] = $css_code;
193
+
194
+ # log
195
+ $size = strlen($css['code']);
196
+ $css_total = $css_total + $size;
197
+ $log[] = '[CSS Async: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $css['url']). PHP_EOL;
 
 
 
 
 
 
198
 
199
+ # finish early
200
+ $tag->outertext = '';
201
+ unset($allcss[$k]);
202
+ continue 2;
203
+
204
+ }
205
+ }
206
+ }
207
  }
208
  }
209
+
210
+ # else render block
211
+
212
+ # save css for merging as fallback
213
+ $fvm_styles[$tag->media]['block'][] = $css_code;
214
+
215
+ # log
216
+ $size = strlen($css['code']);
217
+ $css_total = $css_total + $size;
218
+ $log[] = '[CSS Block: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $css['url']). PHP_EOL;
219
+
220
+ # finish early
221
+ $tag->outertext = '';
222
+ unset($allcss[$k]);
223
+ continue;
224
+
225
  }
226
+ }
227
+
228
+
229
+ # minify individually, if enabled
230
+ if(!isset($fvm_settings['css']['min_disable']) || (isset($fvm_settings['css']['min_disable'])&& $fvm_settings['css']['min_disable'] != true)) {
231
 
232
+ # download or fetch from transient, minified
233
+ $css = fvm_get_css_from_file($tag);
234
 
235
+ if($css !== false && is_array($css)) {
 
236
 
237
+ # extract fonts and icons
238
+ if(isset($fvm_settings['css']['fonts']) && $fvm_settings['css']['fonts'] == true) {
239
+ $extract_fonts_arr = fvm_extract_fonts($css['code']);
240
+ $css_lowpriority_code.= '/* '.$tag->href.' */'. PHP_EOL . $extract_fonts_arr['fonts'];
241
+ $css_code = $extract_fonts_arr['code'];
 
242
  } else {
243
+ $css_code = $css['code'];
244
+ }
245
+
246
+ # empty files
247
+ if(empty(trim($css_code))) {
248
  $tag->outertext = '';
249
  unset($allcss[$k]);
250
  continue;
251
+ } else {
252
+ $css_code = '/* '.$tag->href.' */'. PHP_EOL . $css_code;
253
  }
254
+
255
+ # generate url
256
+ $ind_css_url = fvm_generate_min_url($tag->href, $css['tkey'], 'css', $css_code);
257
+
258
+ # cdn
259
+ if(isset($fvm_settings['cdn']['cssok']) && $fvm_settings['cdn']['cssok'] == true) {
260
+ $ind_css_url = fvm_rewrite_cdn_url($ind_css_url);
261
+ }
262
+
263
+ # async from the list only
264
+ if(isset($fvm_settings['css']['async']) && !empty($fvm_settings['css']['async'])) {
265
+ $arr = fvm_string_toarray($fvm_settings['css']['async']);
266
+ if(is_array($arr) && count($arr) > 0) {
267
+ foreach ($arr as $aa) {
268
+ if(stripos($tag->href, $aa) !== false) {
269
 
270
+ # async attributes
271
+ $tag->rel = 'preload';
272
+ $tag->as = 'style';
273
+ $tag->onload = "this.rel='stylesheet';this.onload=null";
 
274
 
275
+ # log
276
+ $size = strlen($css['code']);
277
+ $css_total = $css_total + $size;
278
+ $log[] = '[CSS Async: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $css['url']). PHP_EOL;
279
+
280
+ # finish early
281
+ $tag->href = $ind_css_url;
282
+ unset($allcss[$k]);
283
+ continue 2;
284
+
285
+ }
286
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  }
288
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
 
290
+ # force render blocking for other files
291
+
292
+ # http and html preload for render blocking css
293
+ if(!isset($fvm_settings['css']['nopreload']) || (isset($fvm_settings['css']['nopreload']) && $fvm_settings['css']['nopreload'] != true)) {
294
+ $httppreloads[] = '<'.$ind_css_url.'>; rel=preload; as=style';
295
+ $htmlpreloads[] = '<link rel="preload" href="'.$ind_css_url.'" as="style" media="'.$tag->media.'" />';
296
  }
297
+
298
+ # log
299
+ $size = strlen($css['code']);
300
+ $css_total = $css_total + $size;
301
+ $log[] = '[CSS Block: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $css['url']). PHP_EOL;
302
+
303
+ # finish early
304
+ $tag->href = $ind_css_url;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  unset($allcss[$k]);
306
+
307
  }
 
308
  }
 
309
  }
310
+ # END CSS FILES
311
+
312
 
313
+ # START STYLE TAGS
314
+ if($tag->tag == 'style' && !isset($tag->href)) {
315
+
316
+ # remove if empty
317
+ if(strlen(trim($tag->innertext)) == 0) {
318
+ $tag->outertext = '';
319
+ unset($allcss[$k]);
320
+ continue;
321
+ }
322
 
323
+ # default
324
+ $css = $tag->innertext;
 
325
 
326
+ # minify?
327
+ if(!isset($fvm_settings['css']['min_disable_styles']) || (isset($fvm_settings['css']['min_disable_styles'])&& $fvm_settings['css']['min_disable_styles'] != true)) {
328
+ $css = fvm_minify_css_string($css);
329
+ }
 
 
 
 
330
 
331
+ # handle import rules
332
+ $css = fvm_replace_css_imports($css);
333
+
334
+ # simplify font face
335
+ $arr = fvm_simplify_fontface($css);
336
+ if($arr !== false && is_array($arr)) {
337
+ $css = str_replace($arr['before'], $arr['after'], $css);
338
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
 
340
+ # extract fonts and icons
341
+ if(isset($fvm_settings['css']['fonts']) && $fvm_settings['css']['fonts'] == true) {
342
+ $extract_fonts_arr = fvm_extract_fonts($css);
343
+ $css_lowpriority_code.= $extract_fonts_arr['fonts'];
344
+ $css = $extract_fonts_arr['code'];
345
+ }
346
+
347
+ # add filtered css code
348
+ if(!empty($css)) {
349
+ $tag->innertext = $css;
350
+ unset($allcss[$k]);
351
+ continue;
352
  }
353
 
354
+ }
355
+ # END STYLE TAGS
356
+
357
+ }
358
+ # END CSS LOOP
359
+
360
+ # START CSS LOG
361
+ if(count($log) > 1) {
362
+ $log[] = str_pad('-', 22, '-',STR_PAD_LEFT) . PHP_EOL;
363
+ $log[] = '[CSS Total: '.str_pad(fvm_format_filesize($css_total), 9,' ',STR_PAD_LEFT).']' . PHP_EOL;
364
+ $log[] = str_pad('-', 22, '-',STR_PAD_LEFT);
365
+ fvm_save_log(array('type'=>'min','msg'=>implode('', $log)));
366
+ }
367
+ # END CSS LOG
368
+
369
+
370
+ # START OPTIMIZED FONT DELIVERY
371
+ if(!empty($css_lowpriority_code)) {
372
+
373
+ # minify?
374
+ if(!isset($fvm_settings['css']['min_disable']) || (isset($fvm_settings['css']['min_disable'])&& $fvm_settings['css']['min_disable'] != true)) {
375
+ $css_lowpriority_code = fvm_minify_css_string($css_lowpriority_code);
376
+ }
377
+
378
+ # save transient, if not yet saved
379
+ $tkey = fvm_generate_hash_with_prefix(hash('sha256', $css_lowpriority_code), 'css');
380
+
381
+ # generate url
382
+ $css_fonts_url = fvm_generate_min_url('fonts', $tkey, 'css', $css_lowpriority_code);
383
+
384
+ # cdn
385
+ if(isset($fvm_settings['cdn']['cssok']) && $fvm_settings['cdn']['cssok'] == true) {
386
+ $css_fonts_url = fvm_rewrite_cdn_url($css_fonts_url);
387
+ }
388
+
389
+ # preload
390
+ $htmlcssheader[0] = '<link id="fvm-fonts" rel="stylesheet" href="'.$css_fonts_url.'" media="fonts" onload="if(fvmuag()){this.media=\'all\'}" />';
391
+
392
+ }
393
+ # END OPTIMIZED FONT DELIVERY
394
+
395
+ # START COMBINING CSS
396
+ if(is_array($fvm_styles) && count($fvm_styles) > 0) {
397
+
398
+ # process mediatypes
399
+ foreach ($fvm_styles as $mediatype=>$css_arr) {
400
 
401
+ # process types, block or async
402
+ foreach ($css_arr as $css_method=>$css_arr2) {
403
+
404
+ # merge and hash
405
+ $merged_css = implode(PHP_EOL, $css_arr2);
406
+ $tkey = fvm_generate_hash_with_prefix(hash('sha256', $merged_css), 'css');
407
 
408
+ # inline if small
409
+ if(strlen($merged_css) < 15000 && $css_method == 'block') {
410
+ $htmlcssheader[] = '<style type="text/css" media="'.$mediatype.'">'.$merged_css.'</style>';
411
+ continue;
412
+ }
413
 
414
+ # url, preload, add
415
+ $merged_css_url = fvm_generate_min_url('combined', $tkey, 'css', $merged_css);
 
 
 
416
 
417
+ # cdn
418
+ if(isset($fvm_settings['cdn']['cssok']) && $fvm_settings['cdn']['cssok'] == true) {
419
+ $merged_css_url = fvm_rewrite_cdn_url($merged_css_url);
 
 
 
420
  }
421
+
422
+ # http, html preload + header
423
+ if($css_method == 'block') {
424
 
425
+ # add to header
426
+ $htmlcssheader[] = '<link rel="stylesheet" href="'.$merged_css_url.'" media="'.$mediatype.'" />';
 
427
 
428
+ # http and html preload for render blocking css
429
+ if(!isset($fvm_settings['css']['nopreload']) || (isset($fvm_settings['css']['nopreload']) && $fvm_settings['css']['nopreload'] != true)) {
430
+ $httppreloads[] = '<'.$merged_css_url.'>; rel=preload; as=style';
431
+ $htmlpreloads[] = '<link rel="preload" href="'.$merged_css_url.'" as="style" media="'.$mediatype.'" />';
432
+ }
433
 
434
+ } else {
 
 
 
 
 
 
 
 
 
435
 
436
+ # async
437
+ $htmlcssheader[] = '<link rel="preload" as="style" href="'.$merged_css_url.'" media="'.$mediatype.'" onload="this.rel=\'stylesheet\'" />';
438
 
439
+ }
440
+
441
+ }
 
442
  }
443
  }
444
+ # END COMBINING CSS
445
+
446
+ }
447
+ # END CSS PROCESSING
448
+
449
+
450
+ # START JS PROCESSING
451
+ if(fvm_can_minify_js()) {
452
+
453
+ # defaults
454
+ $scripts_duplicate_check = array();
455
+ $fvm_scripts_header = array();
456
+ $fvm_scripts_defer = array();
457
 
458
+ # start log
459
+ $log = array();
460
+ $js_total = 0;
461
 
462
+ # start log
463
+ $log[]= 'PAGE - '. fvm_get_uripath(true) . PHP_EOL . '---' . PHP_EOL;
464
+
465
+ # get all scripts
466
+ $allscripts = array();
467
+ foreach($html->find('script') as $element) {
468
+ $allscripts[] = $element;
469
+ }
 
 
470
 
471
+ # START JS LOOP
472
+ if (is_array($allscripts) && count($allscripts) > 0) {
473
+ foreach($allscripts as $k=>$tag) {
474
+
475
+ # handle application/ld+json or application/json before anything else
476
+ if(isset($tag->type) && ($tag->type == 'application/ld+json' || $tag->type == 'application/json')) {
477
+
478
+ # minify
479
+ if(isset($fvm_settings['js']['js_enable_min_inline']) && $fvm_settings['js']['js_enable_min_inline'] == true) { $tag->innertext = fvm_minify_microdata($tag->innertext); }
480
+
481
+ # remove
482
+ unset($allscripts[$k]);
483
+ continue;
484
+ }
485
+
486
+ # skip unknown script types
487
+ if(isset($tag->type) && $tag->type != 'text/javascript') {
488
+ unset($allscripts[$k]);
489
+ continue;
490
+ }
491
+
492
+ # remove default script type
493
+ if(isset($tag->type) && $tag->type == 'text/javascript') { unset($tag->type); }
494
+
495
+ # START JS FILES
496
+ if(isset($tag->src)) {
497
+
498
+ # ignore js files
499
+ if(isset($fvm_settings['js']['ignore']) && !empty($fvm_settings['js']['ignore'])) {
500
+ $arr = fvm_string_toarray($fvm_settings['js']['ignore']);
501
+ if(is_array($arr) && count($arr) > 0) {
502
+ foreach ($arr as $a) {
503
+ if(stripos($tag->src, $a) !== false) {
504
+ unset($allscripts[$k]);
505
+ continue 2;
506
+ }
507
+ }
508
+ }
509
  }
510
 
511
+ # remove js files
512
+ if(isset($fvm_settings['js']['remove']) && !empty($fvm_settings['js']['remove'])) {
513
  $arr = fvm_string_toarray($fvm_settings['js']['remove']);
514
  if(is_array($arr) && count($arr) > 0) {
515
+ foreach ($arr as $a) {
516
+ if(stripos($tag->src, $a) !== false) {
517
  $tag->outertext = '';
518
  unset($allscripts[$k]);
519
  continue 2;
522
  }
523
  }
524
 
525
+
526
+ # JS files to delay until user interaction (unmergeable)
527
+ if(isset($fvm_settings['js']['thirdparty']) && !empty($fvm_settings['js']['thirdparty'])) {
528
+ $arr = fvm_string_toarray($fvm_settings['js']['thirdparty']);
529
+ if(is_array($arr) && count($arr) > 0) {
530
+ foreach ($arr as $ac) {
531
+ if(stripos($tag->src, $ac) !== false) {
532
+
533
+ # unique identifier
534
+ $uid = fvm_generate_hash_with_prefix(hash('sha256', $tag->outertext), 'js');
535
+
536
+ # remove exact duplicates, or replace transformed tag
537
+ if(isset($scripts_duplicate_check[$uid])) {
538
+ $tag->outertext = '';
539
+ } else {
540
+ $tag->type = 'fvm-script-delay';
541
+ $scripts_duplicate_check[$uid] = $uid;
542
+ }
543
+
544
+ # mark as processed, unset and break inner loop
545
+ unset($allscripts[$k]);
546
+ continue 2;
547
+
548
+ }
549
+ }
550
+ }
551
+ }
552
+
553
+
554
+ # START MERGING JS
555
+ if(isset($fvm_settings['js']['combine']) && $fvm_settings['js']['combine'] == true) {
556
+
557
+ # force render blocking
558
+ if(isset($fvm_settings['js']['merge_header']) && !empty($fvm_settings['js']['merge_header'])) {
559
+ $arr = fvm_string_toarray($fvm_settings['js']['merge_header']);
560
+ if(is_array($arr) && count($arr) > 0) {
561
+ foreach ($arr as $aa) {
562
+ if(stripos($tag->src, $aa) !== false) {
563
+
564
+ # download or fetch from transient, minified
565
+ $js = fvm_get_js_from_file($tag);
566
+ if($js !== false && is_array($js)) {
567
+
568
+ # save js for merging
569
+ $fvm_scripts_header[] = $js['code'];
570
+
571
+ # log
572
+ $size = strlen($js['code']);
573
+ $js_total = $js_total + $size;
574
+ $log[] = '[JS Block: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $js['url']). PHP_EOL;
575
+
576
+ # remove from html
577
+ $tag->outertext = '';
578
+ unset($allscripts[$k]);
579
+ continue 2;
580
+
581
  }
582
+ }
583
  }
584
  }
585
  }
586
 
587
+ # force defer
588
+ if(isset($fvm_settings['js']['merge_defer']) && !empty($fvm_settings['js']['merge_defer'])) {
589
+ $arr = fvm_string_toarray($fvm_settings['js']['merge_defer']);
590
  if(is_array($arr) && count($arr) > 0) {
591
+ foreach ($arr as $aa) {
592
+ if(stripos($tag->src, $aa) !== false) {
593
+
594
+ # download or fetch from transient, minified
595
+ $js = fvm_get_js_from_file($tag);
596
+ if($js !== false && is_array($js)) {
597
+
598
+ # save js for merging
599
+ $fvm_scripts_defer[] = $js['code'];
600
+
601
+ # log
602
+ $size = strlen($js['code']);
603
+ $js_total = $js_total + $size;
604
+ $log[] = '[JS Defer: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $js['url']). PHP_EOL;
605
+
606
+ # remove from html
607
+ $tag->outertext = '';
608
+ unset($allscripts[$k]);
609
+ continue 2;
610
+
611
+ }
612
  }
613
  }
614
  }
615
  }
 
616
 
617
+ # jquery needs to load earlier, if not being merged (while merging is active)
618
+ if(stripos($tag->src, '/jquery.js') !== false || stripos($tag->src, '/jquery.min.js') !== false || stripos($tag->src, '/jquery-migrate') !== false) {
619
 
620
+ # filter url
621
+ $href = fvm_normalize_url($tag->src);
622
+
623
+ # http and html preload for render blocking js
624
+ if(!isset($fvm_settings['js']['nopreload']) || (isset($fvm_settings['js']['nopreload']) && $fvm_settings['js']['nopreload'] != true)) {
625
+ $httppreloads[] = '<'.$href.'>; rel=preload; as=script';
626
+ $htmlpreloads[] = '<link rel="preload" href="'.$href.'" as="script" />';
 
 
 
 
 
 
 
 
 
 
 
627
  }
628
+
629
+ # header
630
+ if(stripos($tag->src, '/jquery-migrate') !== false) {
631
+ $htmljsheader[1] = "<script data-cfasync='false' src='".$href."'></script>"; # jquery migrate
632
+ } else {
633
+ $htmljsheader[0] = "<script data-cfasync='false' src='".$tag->src."'></script>"; # jquery
 
 
 
 
 
 
 
 
 
 
 
 
634
  }
635
+
636
+ # content
637
+ $tag->outertext = '';
638
+ unset($allscripts[$k]);
639
+ continue;
640
+ }
641
 
642
+ }
643
+ # END MERGING JS
644
+
645
+
646
+ # START INDIVIDUAL JS MINIFICATION
647
+ # minify individually, if enabled
648
+ if(!isset($fvm_settings['js']['min_disable']) || (isset($fvm_settings['js']['min_disable'])&& $fvm_settings['js']['min_disable'] != true)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
649
 
650
+ # force render blocking
651
  if(isset($fvm_settings['js']['merge_header']) && !empty($fvm_settings['js']['merge_header'])) {
652
  $arr = fvm_string_toarray($fvm_settings['js']['merge_header']);
653
  if(is_array($arr) && count($arr) > 0) {
654
+ foreach ($arr as $aa) {
655
+ if(stripos($tag->src, $aa) !== false) {
656
 
657
+ # download or fetch from transient, minified
658
+ $js = fvm_get_js_from_file($tag);
659
+ if($js !== false && is_array($js)) {
 
 
 
 
 
660
 
661
+ # generate url
662
+ $ind_js_url = fvm_generate_min_url($tag->src, $js['tkey'], 'js', $js['code']);
663
+
664
+ # cdn
665
+ if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
666
+ $ind_js_url = fvm_rewrite_cdn_url($ind_js_url);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
667
  }
 
 
 
 
 
 
 
 
668
 
669
+ # render block
670
+ if(isset($tag->async)) { unset($tag->async); }
671
+ if(isset($tag->defer)) { unset($tag->defer); }
672
+
673
+ # http and html preload for render blocking scripts
674
+ if(!isset($fvm_settings['js']['nopreload']) || (isset($fvm_settings['js']['nopreload']) && $fvm_settings['js']['nopreload'] != true)) {
675
+ $httppreloads[] = '<'.$ind_js_url.'>; rel=preload; as=script';
676
+ $htmlpreloads[] = '<link rel="preload" href="'.$ind_js_url.'" as="script" />';
677
+ }
678
+
679
+ # log
680
+ $size = strlen($js['code']);
681
+ $js_total = $js_total + $size;
682
+ $log[] = '[JS Block: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $js['url']). PHP_EOL;
683
+
684
+ # finish early
685
+ $tag->src = $ind_js_url;
686
  unset($allscripts[$k]);
687
  continue 2;
688
 
689
  }
 
690
  }
691
  }
692
  }
693
  }
694
+
695
+ # force defer
 
696
  if(isset($fvm_settings['js']['merge_defer']) && !empty($fvm_settings['js']['merge_defer'])) {
697
  $arr = fvm_string_toarray($fvm_settings['js']['merge_defer']);
698
  if(is_array($arr) && count($arr) > 0) {
699
+ foreach ($arr as $aa) {
700
+ if(stripos($tag->src, $aa) !== false) {
 
 
 
 
 
 
 
 
 
701
 
702
+ # download or fetch from transient, minified
703
+ $js = fvm_get_js_from_file($tag);
704
+ if($js !== false && is_array($js)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
705
 
706
+ # generate url
707
+ $ind_js_url = fvm_generate_min_url($tag->src, $js['tkey'], 'js', $js['code']);
 
 
 
 
708
 
709
+ # cdn
710
+ if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
711
+ $ind_js_url = fvm_rewrite_cdn_url($ind_js_url);
712
+ }
713
+
714
+ # add defer
715
+ if(!isset($tag->defer)) { $tag->defer = 'defer'; }
716
+
717
+ # log
718
+ $size = strlen($js['code']);
719
+ $js_total = $js_total + $size;
720
+ $log[] = '[JS Defer: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $js['url']). PHP_EOL;
721
+
722
+ # finish early
723
+ $tag->src = $ind_js_url;
724
  unset($allscripts[$k]);
725
  continue 2;
726
 
727
  }
 
728
  }
729
  }
730
  }
731
  }
732
+
733
+ # remove unprocessed scripts from loop
734
+ unset($allscripts[$k]);
735
+ continue;
736
+ }
737
+ # END INDIVIDUAL JS MINIFICATION
738
+
739
  }
740
+ # END JS FILES
741
+
 
 
 
 
 
 
 
 
 
 
742
 
743
+ # START INLINED SCRIPTS
744
+ if(!isset($tag->src)) {
745
+
746
+ # remove if empty
747
+ if(strlen(trim($tag->innertext)) == 0) {
748
+ $tag->outertext = '';
749
+ unset($allcss[$k]);
750
+ continue;
751
  }
 
 
 
 
 
752
 
753
+ # default
754
+ $js = ''; $js = $tag->innertext;
 
755
 
756
+ # minify?
757
+ if(!isset($fvm_settings['js']['min_disable_inline']) || (isset($fvm_settings['js']['min_disable_inline'])&& $fvm_settings['js']['min_disable_inline'] != true)) {
758
+ $js = PHP_EOL . fvm_maybe_minify_js($js, null, true) . PHP_EOL;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
759
  }
 
 
 
 
 
760
 
761
+ # delay inline scripts until user interaction (unmergeable)
762
+ if(isset($fvm_settings['js']['thirdparty']) && !empty($fvm_settings['js']['thirdparty'])) {
763
+ $arr = fvm_string_toarray($fvm_settings['js']['thirdparty']);
764
+ if(is_array($arr) && count($arr) > 0) {
765
+ foreach ($arr as $b) {
766
+ if(stripos($js, $b) !== false || stripos($js, $b) !== false) {
767
+
768
+ # delay
769
+ $tag->type = 'fvm-script-delay';
770
+
771
+ # minified
772
+ if(!empty($js)) {
773
+ $tag->innertext = $js;
774
+ }
775
+
776
+ # unset
777
+ unset($allscripts[$k]);
778
+ continue 2;
779
+ }
780
+ }
781
+ }
782
  }
783
+
784
+ # defer inline scripts
785
+ if(isset($fvm_settings['js']['defer_dependencies']) && !empty($fvm_settings['js']['defer_dependencies'])) {
786
+ $arr = fvm_string_toarray($fvm_settings['js']['defer_dependencies']);
787
+ if(is_array($arr) && count($arr) > 0) {
788
+ foreach ($arr as $b) {
789
+ if((stripos($js, $b) !== false || stripos($js, $b) !== false) && !isset($tag->src)) {
790
+
791
+ # defer
792
+ $tag->type = 'module';
793
+
794
+ # html comments are not supported inside module scripts
795
+ if(!empty($js)) {
796
+ $tag->innertext = preg_replace('/<!--(.|\s)*?-->/ui', '', $js);
797
+ }
798
+
799
+ # unset
800
+ unset($allscripts[$k]);
801
+ continue 2;
802
+ }
803
+ }
804
+ }
805
+ }
806
  }
807
+ # END INLINED SCRIPTS
808
+
 
 
 
 
 
 
 
809
  }
 
810
  }
811
+ # END JS LOOP
812
+
813
+
814
+ # START JS LOG
815
+ if(count($log) > 1) {
816
+ $log[] = str_pad('-', 21, '-',STR_PAD_LEFT) . PHP_EOL;
817
+ $log[] = '[JS Total: '.str_pad(fvm_format_filesize($js_total), 9,' ',STR_PAD_LEFT).']' . PHP_EOL;
818
+ $log[] = str_pad('-', 21, '-',STR_PAD_LEFT);
819
+ fvm_save_log(array('type'=>'min','msg'=>implode('', $log)));
820
+ }
821
+ # END JS LOG
822
 
823
+ # START COMBINING JS
824
+
825
+ # header scripts
826
+ if(is_array($fvm_scripts_header) && count($fvm_scripts_header) > 0) {
827
 
828
+ # merge code, hash
829
+ $merged_js = implode(PHP_EOL, $fvm_scripts_header);
830
+ $tkey = fvm_generate_hash_with_prefix(hash('sha256', $merged_js), 'js');
831
+
832
+ # generate url
833
+ $merged_js_url = fvm_generate_min_url('combined', $tkey, 'js', $merged_js);
834
+
835
+ # cdn
836
+ if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
837
+ $merged_js_url = fvm_rewrite_cdn_url($merged_js_url);
838
  }
839
 
840
+ # http and html preload for render blocking scripts
841
+ if(!isset($fvm_settings['js']['nopreload']) || (isset($fvm_settings['js']['nopreload']) && $fvm_settings['js']['nopreload'] != true)) {
842
+ $httppreloads[] = '<'.$merged_js_url.'>; rel=preload; as=script';
843
+ $htmlpreloads[] = '<link rel="preload" href="'.$merged_js_url.'" as="script" />';
 
844
  }
845
 
846
+ # add to header
847
+ $htmljsheader[] = "<script data-cfasync='false' src='".$merged_js_url."'></script>";
848
+
849
  }
850
 
851
+ # deferred scripts
852
+ if(is_array($fvm_scripts_defer) && count($fvm_scripts_defer) > 0) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
853
 
854
+ # merge code, hash
855
+ $merged_js = implode(PHP_EOL, $fvm_scripts_defer);
856
+ $tkey = fvm_generate_hash_with_prefix(hash('sha256', $merged_js), 'js');
857
+
858
+ # generate url
859
+ $merged_js_url = fvm_generate_min_url('combined', $tkey, 'js', $merged_js);
 
 
 
 
 
 
 
 
860
 
861
+ # cdn
862
+ if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
863
+ $merged_js_url = fvm_rewrite_cdn_url($merged_js_url);
 
 
 
 
 
864
  }
865
+
866
+ # header, no preload for deferred files
867
+ $htmljsheader[] = "<script defer='defer' src='".$merged_js_url."'></script>";
868
 
 
 
 
 
 
869
  }
870
 
871
+ }
872
+ # END JS PROCESSING
873
+
874
+
875
+
876
+ # process HTML minification, if not disabled ###############################
877
+ if(fvm_can_process_html()) {
878
+
879
+ # Remove HTML comments and IE conditionals
880
+ if(isset($fvm_settings['html']['nocomments']) && $fvm_settings['html']['nocomments'] == true) {
881
+ foreach($html->find('comment') as $element) {
882
+ $element->outertext = '';
883
  }
884
  }
885
 
886
+ # Remove generator tags
887
+ if(isset($fvm_settings['html']['cleanup_header']) && $fvm_settings['html']['cleanup_header'] == true) {
888
+
889
+ # remove
890
+ foreach($html->find('head meta[name=generator], head link[rel=shortlink], head link[rel=dns-prefetch], head link[rel=preconnect], head link[rel=prefetch], head link[rel=prerender], head meta[name*=msapplication], head link[rel=apple-touch-icon], head link[rel=EditURI], head link[rel=preconnect], head link[rel=wlwmanifest], head link[rel=https://api.w.org/], head link[href*=/wp-json/], head link[rel=pingback], head link[type=application/json+oembed], head link[type=text/xml+oembed]') as $element) {
891
+ $element->outertext = '';
892
  }
893
+
894
+ # allow only the last link[rel=icon]
895
+ $ic = array(); $ic = $html->find('head link[rel=icon]');
896
+ $i = 1; $len = count($ic);
897
+ if($len > 1) {
898
+ foreach($ic as $element) {
899
+ if ($i != $len) { $element->outertext = ''; } $i++; # delete except if last
900
+ }
901
  }
902
  }
903
+
904
+ }
905
+
906
+ # build extra head and footer ###############################
907
+
908
+ # header and footer markers
909
+ $hm = '<!-- h_preheader --><!-- h_header_function -->';
910
+ $hm_late = '<!-- h_cssheader --><!-- h_jsheader -->';
911
+ $fm = '<!-- h_footer_fvm_scripts -->';
912
+
913
+ # add our function to head
914
+ if(fvm_can_minify_css() || fvm_can_minify_js()) {
915
+ $hm = fvm_add_header_function($hm);
916
+ }
917
 
918
+ # remove charset meta tag and collect it to first position
919
+ if(!is_null($html->find('meta[charset]', 0))) {
920
+ $hm = str_replace('<!-- h_preheader -->', $html->find('meta[charset]', 0)->outertext.'<!-- h_preheader -->', $hm);
921
+ foreach($html->find('meta[charset]') as $element) { $element->outertext = ''; }
922
+ }
923
+
924
+ # remove other meta tag and collect them between preload and css/js files
925
+ foreach($html->find('head meta, head title, head link[rel=canonical], head link[rel=alternate], head link[rel=pingback], head script[type=application/ld+json]') as $element) {
926
+ $hm_late = str_replace('<!-- h_cssheader -->', $element->outertext.'<!-- h_cssheader -->', $hm_late);
927
+ $element->outertext = '';
928
+ }
929
+
930
+ # preload headers, by importance
931
+ if(is_array($htmlpreloads) || is_array($httppreloads)) {
932
 
933
+ # deduplicate
934
+ $htmlpreloads = array_unique($htmlpreloads);
935
+ $httppreloads = array_unique($httppreloads);
936
 
937
+ # get values
938
+ $pre_html = array_values($htmlpreloads);
939
+ $pre_http = array_values($httppreloads);
940
+
941
+ # add preload http header
942
+ if(count($pre_http) > 0) {
943
+ if(!headers_sent()) {
944
+ header("Link: " . implode(', ', $pre_http));
945
  }
946
  }
947
 
948
+ # add preload html header
949
+ if(count($pre_html) > 0) {
950
+ $hm = str_replace('<!-- h_preheader -->', implode(PHP_EOL, $pre_html).'<!-- h_preheader -->', $hm);
 
 
 
951
  }
952
 
953
  }
954
 
955
+ # add stylesheets
956
+ if(isset($htmlcssheader)) {
957
+ if(is_array($htmlcssheader) && count($htmlcssheader) > 0) {
958
+ ksort($htmlcssheader); # priority
959
+ $hm_late = str_replace('<!-- h_cssheader -->', implode(PHP_EOL, $htmlcssheader).'<!-- h_cssheader -->', $hm_late);
960
+ }
961
+ }
962
+
963
+ # add header scripts
964
+ if(isset($htmljsheader)) {
965
+ if(is_array($htmljsheader) && count($htmljsheader) > 0) {
966
+ ksort($htmljsheader); # priority
967
+ $hm_late = str_replace('<!-- h_jsheader -->', implode(PHP_EOL, $htmljsheader).'<!-- h_jsheader -->', $hm_late);
968
+ }
969
+ }
970
+
971
+ # add defer scripts
972
+ if(isset($htmljscodedefer)) {
973
+ if(is_array($htmljscodedefer) && count($htmljscodedefer) > 0) {
974
+ ksort($htmljscodedefer); # priority
975
+ $hm_late = str_replace('<!-- h_jsheader -->', implode(PHP_EOL, $htmljscodedefer), $hm_late);
976
+ }
977
+ }
978
+
979
+ # add fvm_footer scripts, if enabled
980
+ if(fvm_can_minify_js()) {
981
+ $fm = fvm_add_delay_scripts_logic($fm);
982
+ }
983
+
984
+ # cleanup leftover markers
985
+ $hm = str_replace(array('<!-- h_preheader -->', '<!-- h_header_function -->'), '', $hm);
986
+ $hm_late = str_replace(array('<!-- h_cssheader -->', '<!-- h_jsheader -->'), '', $hm_late);
987
+ $fm = str_replace('<!-- h_footer_fvm_scripts -->', '', $fm);
988
+
989
+ # append header and footer
990
+ if(!is_null($html->find('head', 0)) && !is_null($html->find('body', -1))) {
991
+ if(!is_null($html->find('head', 0)->first_child()) && !is_null($html->find('body', -1)->last_child())) {
992
+ $html->find('head', 0)->first_child()->outertext = $hm . $html->find('head', 0)->first_child()->outertext . $hm_late;
993
+ $html->find('body', -1)->last_child()->outertext = $html->find('body', -1)->last_child ()->outertext . $fm;
994
+ }
995
+ }
996
+
997
+
998
+ # convert html object to string, save all objects to string
999
+ $html = trim($html->save());
1000
+
1001
+ # process cdn optimization
1002
+ if(fvm_can_process_cdn()) {
1003
+ $html = fvm_process_cdn($html);
1004
+ }
1005
+
1006
+ # minify remaining HTML at the end, if enabled
1007
+ if(fvm_can_process_html()) {
1008
+ if(!isset($fvm_settings['html']['min_disable']) || (isset($fvm_settings['html']['min_disable']) && $fvm_settings['html']['min_disable'] != true)) {
1009
+ $html = fvm_raisermin_html($html);
1010
+ }
1011
+ }
1012
+
1013
+ # filter final html if needed
1014
+ if(function_exists('fvm_filter_final_html')) {
1015
+ $html = fvm_filter_final_html($html);
1016
+ }
1017
+
1018
  # return html
1019
  return $html;
1020
 
layout/admin-layout-help.php CHANGED
@@ -9,8 +9,8 @@
9
  <div>
10
  <p><strong>Notes:</strong></p>
11
  <p>JavaScript merging functionality went through a significant change on FVM 3 and it now requires manual configuration to work.</p>
12
- <p>If you are upgrading from FVM 2 please refer to the help section below, to understand how to reconfigure each plugin setting.</p>
13
- <p>If you just installed the plugin, please note that JS is not being optimized yet. You have to choose which files to be render blocking and which ones to be deferred, plus it's dependencies (if any). </p>
14
  <p>Previously, FVM merged everything and relied on having options to ignore scripts. This option frequently created issues with other plugin updates, when they changed something JavaScript related.</p>
15
  <p>Please understand that this plugin is and it has always been aimed at being a tool for advanced users and developers, so it's not meant just be plug and play, without manual settings in place.</p>
16
  <p>There is a new method to optimize third party scripts and load them on user interaction or automatically, after 5 seconds. This is a more recommended method to optimize scripts, as compared to FVM 2 which used document.write and other deprecated methods.</p>
@@ -45,17 +45,9 @@
45
  <h3>Purge Minified CSS/JS files instantly</h3>
46
  <div>
47
  <p><strong>Notes:</strong></p>
48
- <p>If your hosting has no page cache enabled, you can force the plugin to immediately purge it's cache files instead of waiting for 24 hours before deletion.</p>
49
- </div>
50
- <h3>Preserve settings on uninstall</h3>
51
- <div>
52
- <p><strong>Notes:</strong></p>
53
- <p>When you are testing things, sometimes you may want to preserve all FVM settings when you uninstall or delete the plugin.</p>
54
- </div>
55
- <h3>Force HTTPS urls on merged files</h3>
56
- <div>
57
- <p><strong>Notes:</strong></p>
58
- <p>This will make sure that when FVM generates a CSS and JS file, that it's linked on your page with https.</p>
59
  </div>
60
  </div>
61
 
@@ -68,27 +60,27 @@
68
  <p><strong>Notes:</strong></p>
69
  <p>You need to enable this option, for any other options in the HTML section to work.</p>
70
  </div>
71
- <h3>Disable HTML Minification</h3>
72
- <div>
73
- <p><strong>Notes:</strong></p>
74
- <p>Although rare, it's possible that HTML minification may strip too much code thus breaking something.</p>
75
- <p>You can use this option to test if that is the case.</p>
76
- </div>
77
  <h3>Strip HTML Comments</h3>
78
  <div>
79
  <p><strong>Notes:</strong></p>
80
- <p>Some plugins may need to use comments for certain functionality to work, however this is quite rare. This option is enabled by default.</p>
81
  </div>
82
  <h3>Cleanup Header</h3>
83
  <div>
84
  <p><strong>Notes:</strong></p>
85
- <p>This options removes resource hints, generator tag, shortlinks, emoji, manifest link, etc from the HTML header.</p>
86
- <p>This is recommended because the head section, should be kept as lean as possible for the best TTFB response times and LCP metrics.</p>
87
  </div>
88
  <h3>Remove Emoji</h3>
89
  <div>
90
  <p><strong>Notes:</strong></p>
91
- <p>This will remove the default emoji scripts from wordpress, thus reducing the amount of code during page loading.</p>
 
 
 
 
 
 
92
  </div>
93
  </div>
94
 
@@ -102,47 +94,52 @@
102
  <p><strong>Notes:</strong></p>
103
  <p>You need to enable this option, for any other options in the CSS section to work.</p>
104
  </div>
105
- <h3>Disable CSS Minification</h3>
106
  <div>
107
  <p><strong>Notes:</strong></p>
108
- <p>Although rare, it's possible that CSS minification may strip too much code thus breaking your styles.</p>
109
  </div>
110
- <h3>Disable Merging and Inline all CSS</h3>
111
  <div>
112
  <p><strong>Notes:</strong></p>
113
- <p>If your total CSS code is very small (under 25 Kb uncompressed), it's recommended to inline all CSS.</p>
114
- <p>If your CSS files combined are large, inlining it will delay the time needed for the first byte, as you are forcing the server to compress the HTML and the CSS on the same process.</p>
115
  </div>
116
- <h3>Remove "Print" stylesheets</h3>
117
  <div>
118
  <p><strong>Notes:</strong></p>
119
- <p>As a generic rule, it's safe to remove it for the vast majority of sites, unless your users often need to print pages from your site, and you have customized styles for when they do so.</p>
120
  </div>
121
- <h3>Merge Fonts and Icons Separately</h3>
122
  <div>
123
  <p><strong>Notes:</strong></p>
124
- <p>This will try to collect all your icon and animation know files into a separate file.</p>
125
- <p>It may be useful for debugging purposes or to evaluate how many fonts are in use.</p>
126
  </div>
127
- <h3>Load generated CSS files Async</h3>
128
  <div>
129
  <p><strong>Notes:</strong></p>
130
- <p>This will load the generated CSS files Async, however, without a manually added critical path code, you will likely see a Flash of Unstyled Content before that CSS finishes loading.</p>
131
- <p>Use your own PHP code or another plugin to add the critical path CSS code using conditional tags, filters, hooks or other method.</p>
 
 
 
 
 
132
  </div>
133
  <h3>Ignore CSS files</h3>
134
  <div>
135
  <p><strong>Notes:</strong></p>
136
- <p>You can use this option to prevent a certain CSS file from being merged, for example, when it breaks something when merged.</p>
137
- <p>This uses uses PHP stripos against the href attribute on the link tag, to decide if a CSS should be left alone or not.</p>
138
- <p>This should be empty by default, and only used strictly when a CSS being merged is breaking the page layout.</p>
 
 
 
139
  </div>
140
- <h3>Remove CSS files</h3>
141
  <div>
142
  <p><strong>Notes:</strong></p>
143
- <p>If you wish to remove a CSS file from the frontend without editing code or using other settings, you can use this option.</p>
144
- <p>For example, you can remove google fonts link tags, or the default Gutenberg CSS file enqueued by WordPress.</p>
145
- <p>You should still first try to remove it or dequeue it with PHP code, when possible.</p>
146
  </div>
147
  </div>
148
 
@@ -156,47 +153,50 @@
156
  <p><strong>Notes:</strong></p>
157
  <p>You need to enable this option, for any other options in the JS section to work.</p>
158
  </div>
159
- <h3>Disable JS Minification</h3>
160
  <div>
161
  <p><strong>Notes:</strong></p>
162
- <p>Although rare, it's possible that JS minification may strip too much white space, or fail to minify some more complex JavaScript code, which can lead to breaking some functionality or triggering browser console log errors.</p>
163
- <p>You can use this option to test if that is the case.</p>
164
  </div>
165
- <h3>Upgrade to jQuery 3</h3>
166
  <div>
167
  <p><strong>Notes:</strong></p>
168
- <p>If your theme and plugins make use of modern standards and doesn't include outdated jQuery code, you can force the usage of the smaller jQuery 3 instead of the older, default WordPress jQuery.</p>
169
- <p>You must check your browser console log in incognito mode, for possible errors after enabling this feature. Sometimes there are no errors but some scripts may not work as well, so use this feature with care.</p>
170
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
171
  <h3>Ignore Script Files</h3>
172
  <div>
173
  <p><strong>Notes:</strong></p>
174
- <p>When you are adding a lot of JS files to consider, it may be more convenient to add the default recommended paths and exclude individual files.</p>
175
- <p>This should be empty by default, and only used strictly when a CSS being merged is breaking the page layout.</p>
176
  </div>
177
- <h3>Merge render blocking JS files in the header</h3>
178
  <div>
179
  <p><strong>Notes:</strong></p>
180
- <p>In most WordPress themes and for a significant amount of plugins, you need to render block jQuery and possibly other scripts.</p>
181
- <p>If you are a developer and are sure that there is no inlined code requiring jQuery to be defined earlier, then leave this section empty and add your scripts on the "Merge and Defer Scripts" section instead.</p>
182
- <p>It's important for speed, that you keep this section to a bare minimum, usually, jQuery and jQuery migrate only.</p>
183
- <p>Some plugins such as gravity forms may also require to be render blocking, so you should look out for browser console log errors in incognito mode.</p>
184
  <p><strong>Recommended Default Settings:</strong></p>
185
  <p class="fvm-code-full">
186
- /jquery-migrate-<br>
187
- /jquery-migrate.js<br>
188
- /jquery-migrate.min.js<br>
189
  /jquery.js<br>
190
  /jquery.min.js<br>
191
  </p>
192
  </div>
193
- <h3>Merge and Defer Scripts</h3>
194
  <div>
195
  <p><strong>Notes:</strong></p>
196
- <p>This option uses PHP stripos against the script <code>outerHTML</code> to decide what to merge and defer.</p>
197
- <p>Very frequently, jQuery, jQuery migrate and some plugins, need to be render blocking for everything to work, so you cannot just put all scripts in this section.</p>
198
- <p>You must check your browser console log in incognito mode, for possible errors after enabling this feature, and either move them to the header, remove them from this list (be more specific with paths so it doesn't match certain files), or use the Inline JavaScript Dependencies section, to force inline scripts to wait for this file to load.</p>
199
- <p>Note that this is an advanced feature that can stop your scripts from working, hence it requires manual configuration.</p>
200
  <p><strong>Recommended Default Settings:</strong></p>
201
  <p class="fvm-code-full">
202
  /ajax.aspnetcdn.com/ajax/<br>
@@ -208,24 +208,27 @@
208
  /wp-includes/
209
  </p>
210
  </div>
211
- <h3>Inline JavaScript Dependencies</h3>
212
  <div>
213
  <p><strong>Notes:</strong></p>
214
- <p>This option uses PHP stripos against the script <code>innerHTML</code> to decide what to merge and defer.</p>
215
- <p>When you merge JS files and defer them, you are effectively changing the order in which they load, however for certain scripts, the order of loading matters.</p>
216
- <p>If you defer a certain script and you see an "undefined" error triggered on some inline code, you can try this option to force it to wait for the deferred scripts to finish, but it may still not work if dependencies are more complex.</p>
217
- <p>You must check your browser console log in incognito mode, for possible errors after enabling this feature, and either move them to the header, remove them from this list (be more specific with paths so it doesn't match certain files), or use the Inline JavaScript Dependencies to force inline scripts to wait for this file to load.</p>
218
- <p>This is empty by default, unless you determine that it's needed (the plugin is for advanced users and developers, so you need to debug yourself).</p>
 
 
 
 
 
 
219
  </div>
220
- <h3>Execute matching third party scripts after user interaction</h3>
221
  <div>
222
  <p><strong>Notes:</strong></p>
223
- <p>Scripts like analytics, ads, tracking codes, etc, consume important CPU and Network resources needed for the initial pageview.</p>
224
- <p>This option uses PHP stripos against the script <code>innerHTML</code> or <code>src</code> attribute for async/defer scripts.</p>
225
- <p>It will delay the specified script execution until the user interacts with the page, on the first <code>'mouseover','keydown','touchmove','touchstart'</code> event, or <code>up to 5 seconds after page load</code>(whichever happens first).</p>
226
- <p>FVM will delay most Async and Defer scripts, a well as inline code matching these settings.</p>
227
- <p>You can rewrite most scripts to support this feature by adding the Async or Defer attribute, however, note that if you blindly use this method for render blocking scripts, it may trigger "undefined" errors on the browser console log or some elements may stop working (some scripts only work in render blocking mode).</p>
228
- <p>If you have render blocking third party scripts, ask your provider if they can provide you with an async implementation (else remove them, because render blocking scripts are not recommended for speed).</p>
229
  <p><strong>Example Settings:</strong></p>
230
  <p class="fvm-code-full">
231
  function(w,d,s,l,i)<br>
@@ -239,9 +242,7 @@
239
  <h3>Remove JavaScript Scripts</h3>
240
  <div>
241
  <p><strong>Notes:</strong></p>
242
- <p>This option uses PHP stripos against the script <code>outerHTML</code> to decide what to remove.</p>
243
- <p>It can be used when you want to remove some JS file that you cannot remove directly from the source.</p>
244
- <p>If it's a third party script you added to the header or footer (or via some plugin), it's better if you delete it at the source.</p>
245
  </div>
246
  </div>
247
 
@@ -273,42 +274,14 @@
273
  <h3>CDN URL</h3>
274
  <div>
275
  <p><strong>Notes:</strong></p>
276
- <p>This is not required for providers such as cloudflare.com or sucuri.com as well as any reverse proxy CDN service that doesn't change your domain name (the whole site is proxified through their service).</p>
277
- <p>For other types of CDN, you are usually provided with an alternative domain name from where your static files can be served, and in those cases, you would introduce your new domain name here, for your static assets.</p>
278
  </div>
279
  <h3>CDN Integration</h3>
280
  <div>
281
  <p><strong>Notes:</strong></p>
282
- <p>Uses syntax from <a target="_blank" href="https://simplehtmldom.sourceforge.io/manual.htm">https://simplehtmldom.sourceforge.io/manual.htm</a> for modifying the urls on the HTML.</p>
283
- <p>The plugin will only replace your site domain, with the CDN domain for the matching HTML tags.</p>
284
- <p><strong>Recommended Default Settings:</strong></p>
285
- <p class="fvm-code-full">
286
- a[data-interchange*=/wp-content/]<br>
287
- image[height]<br>
288
- img[src*=/wp-content/], img[data-src*=/wp-content/], img[data-srcset*=/wp-content/]<br>
289
- link[rel=icon]<br>
290
- picture source[srcset*=/wp-content/]<br>
291
- video source[type*=video]
292
- </p>
293
- </div>
294
- </div>
295
-
296
-
297
- <div style="height: 20px;"></div>
298
- <h2 class="title">Cache Settings</h2>
299
-
300
- <div class="accordion">
301
- <h3>Public Cache Path</h3>
302
- <div>
303
- <p><strong>Notes:</strong></p>
304
- <p>This can be any writeable directory or mounting point on your server, as long as it's mapped to be served on publicly available URL.</p>
305
- <p>Should be left empty by default, unless your hosting blocks writing files to the default cache directory.</p>
306
- </div>
307
- <h3>Public Cache URL</h3>
308
- <div>
309
- <p><strong>Notes:</strong></p>
310
- <p>This must be a publicly available URL on your site, where users can download the generated js/css files.</p>
311
- <p>Should be left empty by default, unless your hosting blocks writing files to the default cache directory.</p>
312
  </div>
313
  </div>
314
 
@@ -369,15 +342,15 @@
369
  <div>
370
  <p><strong>Notes:</strong></p>
371
  <p>Simply disable the plugin, and make sure to purge all page caches (Cache Plugins, Hosting, OPCache, etc).</p>
372
- <p>Note that some hosts rate limit the amount of times you can purge caches to once every few minutes, so you may be purging and it doesn't work, because you are being rate limited by your hosting cache system. If that happens, jsut ask your hosting to manually purge all caches on the server.</p>
 
373
  <p>FVM does not modify your site. It runs after your template loads and filters the final HTML to present it to your users, in a more optimized way.</p>
374
  </div>
375
  <h3>I have disabled FVM but somehow the cache files are still being generated?</h3>
376
  <div>
377
  <p><strong>Notes:</strong></p>
378
- <p>If you have disabled the plugin and purged all caches available, this is simply not possible.</p>
379
- <p>Please ensure you have delete the plugin on the correct site location and that all caches are emptied.</p>
380
- <p>A few hosting providers will cache your disk in memory to speed things up when they use remote disk locations, which may cause code to be cached even if you have deleted it completely from the disk. In that case, restart the server or ask your hosting to purge all disk caches.</p>
381
  </div>
382
  <h3>Where can I get support or ask questions about the plugin?</h3>
383
  <div>
@@ -387,10 +360,10 @@
387
  <h3>How is it possible that some scan is showing malware on the plugin?</h3>
388
  <div>
389
  <p><strong>Notes:</strong></p>
390
- <p>I guarantee that the plugin is 100% clean of malware, provided you have downloaded the plugin from the official WordPress source.</p>
391
- <p>Understand that Malware can infect any plugin you have on your site (even security plugins), regardless of the point of entry. Sometimes it propagates to/from different areas (including other sites you may have on the same server). </p>
392
- <p>If there is any malware on any scripts being merged by FVM, they would be merged as they are until your next cache purge. </p>
393
- <p>If you are seeing malware on any file related to FVM, simply delete the plugin, purge all cache files and make sure to only download the plugin from the official source on wordpress.org or via wp-admin.</p>
394
  </div>
395
  <h3>How do I report a security issue or file a bug report?</h3>
396
  <div>
9
  <div>
10
  <p><strong>Notes:</strong></p>
11
  <p>JavaScript merging functionality went through a significant change on FVM 3 and it now requires manual configuration to work.</p>
12
+ <p>If you are upgrading from FVM 2 please refer to the help section below for more information on the settings.</p>
13
+ <p>If you just installed the plugin, please note that JS is not being optimized yet. You have to choose which files to be render blocking and which ones to be deferred, plus it's inline script dependencies (if any). </p>
14
  <p>Previously, FVM merged everything and relied on having options to ignore scripts. This option frequently created issues with other plugin updates, when they changed something JavaScript related.</p>
15
  <p>Please understand that this plugin is and it has always been aimed at being a tool for advanced users and developers, so it's not meant just be plug and play, without manual settings in place.</p>
16
  <p>There is a new method to optimize third party scripts and load them on user interaction or automatically, after 5 seconds. This is a more recommended method to optimize scripts, as compared to FVM 2 which used document.write and other deprecated methods.</p>
45
  <h3>Purge Minified CSS/JS files instantly</h3>
46
  <div>
47
  <p><strong>Notes:</strong></p>
48
+ <p>When you purge CSS/JS files instantly, all CSS and JS cache files are deleted immediately when you clear everything on FVM. While this is great during development, it may cause issues when your hosting is doing page caching that cannot be purged by FVM. For example, if you were to delete the CSS and JS files instantly without purging the full page cache, that page cache would now be pointing to deleted files.</p>
49
+ <p>If you deselect this option, whenever you clear everything on FVM, it will only try to delete files that are older than 24h (and hopefully this should be enough for your hosting to expire the page cache automatically). That way, even if your hosting is still showing your page cache to anonymous users, the referred CSS and JS files will still be available.</p>
50
+ <p>If you are not sure about page caching on your server or hosting provider, you should keep this option disabled.</p>
 
 
 
 
 
 
 
 
51
  </div>
52
  </div>
53
 
60
  <p><strong>Notes:</strong></p>
61
  <p>You need to enable this option, for any other options in the HTML section to work.</p>
62
  </div>
 
 
 
 
 
 
63
  <h3>Strip HTML Comments</h3>
64
  <div>
65
  <p><strong>Notes:</strong></p>
66
+ <p>Some plugins may need to use comments for certain functionality to work, however this is quite rare. The benefit of removing comments is usually very small, so if needed you can disable this setting.</p>
67
  </div>
68
  <h3>Cleanup Header</h3>
69
  <div>
70
  <p><strong>Notes:</strong></p>
71
+ <p>This options removes resource hints, generator tags, shortlinks, manifest link, etc from the header.</p>
72
+ <p>The header should be kept as lean as possible for the best TTFB response times and LCP metrics, but if you later find that you need some of the stuff that is removed by this option, you can disable this setting.</p>
73
  </div>
74
  <h3>Remove Emoji</h3>
75
  <div>
76
  <p><strong>Notes:</strong></p>
77
+ <p>This will remove the default emoji scripts from wordpress, thus reducing the amount of code during page loading. If you use WordPress emoji when posting content, you should keep this option disabled.</p>
78
+ </div>
79
+ <h3>Disable HTML Minification</h3>
80
+ <div>
81
+ <p><strong>Notes:</strong></p>
82
+ <p>Although rare, it's possible for the HTML minification to strip too much code thus breaking something. You can use this option to test if that is the case and keep this option disabled if that is the case.</p>
83
+ <p>HTML minification is no longer a recommendation by gtmetrix or pagespeed insights, so you can keep this option disabled if there is any incompatibility issue.</p>
84
  </div>
85
  </div>
86
 
94
  <p><strong>Notes:</strong></p>
95
  <p>You need to enable this option, for any other options in the CSS section to work.</p>
96
  </div>
97
+ <h3>Merge Fonts and Icons Separately</h3>
98
  <div>
99
  <p><strong>Notes:</strong></p>
100
+ <p>This will try to collect and simplify all your CSS font face rules into a separate CSS file and load it async. It may be useful for de-duplication of fonts, or to evaluate how many fonts are in use. </p>
101
  </div>
102
+ <h3>Remove "Print" stylesheets</h3>
103
  <div>
104
  <p><strong>Notes:</strong></p>
105
+ <p>As a generic rule this it's safe to remove it for the vast majority of sites, unless your users often need to print pages from your site and you have customized styles for when they do so.</p>
 
106
  </div>
107
+ <h3>Combine CSS Files</h3>
108
  <div>
109
  <p><strong>Notes:</strong></p>
110
+ <p>Merging CSS is no longer recommended if your server supports HTTP/2. The feature also usually causes conflicts when merging multiple CSS files into one, due to the lack of specificity or other errors in the code. It's still available for legacy support on old installations or outdated servers that do not support HTTP/2 delivery.</p>
111
  </div>
112
+ <h3>Disable CSS Files Minification</h3>
113
  <div>
114
  <p><strong>Notes:</strong></p>
115
+ <p>Although rare, it's possible that CSS files minification may strip too much code and break some style rules that are not supported by the minification library. You can always try to disable this and check if this fixes anything, then use the ignore list to exclude the file that is causing issues.</p>
 
116
  </div>
117
+ <h3>Disable CSS Styles Minification</h3>
118
  <div>
119
  <p><strong>Notes:</strong></p>
120
+ <p>Although rare, it's possible that CSS Styles minification may strip too much code and break some style rules that are not supported by the minification library. You can always try to disable this and check if this fixes anything.</p>
121
+ </div>
122
+ <h3>Disable CSS Link Preload</h3>
123
+ <div>
124
+ <p><strong>Notes:</strong></p>
125
+ <p>CSS Link Preloading is useful when you are merging CSS files or when you defined certain paths as Async CSS. By default, FVM will send an HTTP preload request as well as adding the html preload tag on the header, which will prioritize downloading the critical styles earlier than the other resources.</p>
126
+ <p>If you select this option, these headers will be removed and your default preload resources will load earlier than the CSS files. You need to test and see what works best for you.</p>
127
  </div>
128
  <h3>Ignore CSS files</h3>
129
  <div>
130
  <p><strong>Notes:</strong></p>
131
+ <p>If there is a conflict when merging CSS files or during individual minification of a specific CSS file, you can add the path on this section and FVM will ignore the file, thus leaving it alone.</p>
132
+ </div>
133
+ <h3>Remove CSS Files</h3>
134
+ <div>
135
+ <p><strong>Notes:</strong></p>
136
+ <p>If your plugins enqueue multiple duplicate libraries with different url paths, you can add the path on this section and FVM will remove the file from the frontend, thus reducing your total CSS size.</p>
137
  </div>
138
+ <h3>Async CSS Files</h3>
139
  <div>
140
  <p><strong>Notes:</strong></p>
141
+ <p>CSS files from plugins that are not rendered above the fold, should ideally be loaded async. For example, if a plugin has CSS files but you only use the element on the footer, you could add the /plugins/plugin-name/ here to async it. But you should not async CSS files that are needed for content that is visible on the critical path.</p>
142
+ <p>Also note that by loading certain CSS files async, you are changing the order of styles. This means, some styles may or may not work as intended, because now they load on a different position.</p>
 
143
  </div>
144
  </div>
145
 
153
  <p><strong>Notes:</strong></p>
154
  <p>You need to enable this option, for any other options in the JS section to work.</p>
155
  </div>
156
+ <h3>Combine JS Files</h3>
157
  <div>
158
  <p><strong>Notes:</strong></p>
159
+ <p>Merging JS is no longer recommended if your server supports HTTP/2. The feature also usually causes conflicts when merging multiple JS files into one, due to a different order of loading or other errors in the code. It's still available for legacy support on old installations or outdated servers that do not support HTTP/2 delivery.</p>
 
160
  </div>
161
+ <h3>Disable JS Files Minification</h3>
162
  <div>
163
  <p><strong>Notes:</strong></p>
164
+ <p>JS files minification may strip too much code and break some code that is not supported by the minification library. You can always try to disable this and check if this fixes anything, then use the ignore list to exclude the file that is causing issues.</p>
 
165
  </div>
166
+ <h3>Disable JS Inline Minification</h3>
167
+ <div>
168
+ <p><strong>Notes:</strong></p>
169
+ <p>Inline JS Styles minification may strip too much code and break some code that is not supported by the minification library. You can always try to disable this and check if this fixes anything.</p>
170
+ </div>
171
+ <h3>Disable JS Link Preload</h3>
172
+ <div>
173
+ <p><strong>Notes:</strong></p>
174
+ <p>JS Link Preloading is useful when you are merging JS files or when you defined certain paths as Defer JS. By default, FVM will send an HTTP preload request as well as adding the html preload tag on the header, which will prioritize downloading the render blocking scripts earlier than the other resources.</p>
175
+ <p>If you select this option, these headers will be removed and your default preload resources will load earlier than the JS files. You need to test and see what works best for you.</p>
176
+ </div>
177
+
178
  <h3>Ignore Script Files</h3>
179
  <div>
180
  <p><strong>Notes:</strong></p>
181
+ <p>When you are merging JS files, the order of scripts change positions and dependencies may break. Other times, a specific script is not supported by the minification and breaks as well. If you encounter issues while merging or minifying JS files, you can exclude them here and those files will be left alone.</p>
 
182
  </div>
183
+ <h3>Render Blocking JS files</h3>
184
  <div>
185
  <p><strong>Notes:</strong></p>
186
+ <p>In most WordPress themes and for a significant amount of plugins, you usually need to render block jQuery and jQuery Migrate for compatibility reasons.</p>
187
+ <p>Some plugins may not work at all if they are not render blocking, so you should look out for browser console log errors in incognito mode.</p>
 
 
188
  <p><strong>Recommended Default Settings:</strong></p>
189
  <p class="fvm-code-full">
190
+ /jquery-migrate<br>
 
 
191
  /jquery.js<br>
192
  /jquery.min.js<br>
193
  </p>
194
  </div>
195
+ <h3>Defer JS Files</h3>
196
  <div>
197
  <p><strong>Notes:</strong></p>
198
+ <p>Deferring every single script is not always the best solution, especially if those are needed to generate content above the fold. You must check your browser console log in incognito mode for possible errors after enabling this feature, and either move them to the render blocking section or check if there is any inline script that also needs to be deferred (so the order of loading is preserved).</p>
199
+ <p>Note that this is an advanced feature, hence it requires manual configuration for it to work.</p>
 
 
200
  <p><strong>Recommended Default Settings:</strong></p>
201
  <p class="fvm-code-full">
202
  /ajax.aspnetcdn.com/ajax/<br>
208
  /wp-includes/
209
  </p>
210
  </div>
211
+ <h3>Defer Inline JavaScript</h3>
212
  <div>
213
  <p><strong>Notes:</strong></p>
214
+ <p>When you merge JS files and defer them, you are effectively changing the order in which they load, however for certain scripts, the order of loading matters. If you are deferring a certain JS file and you see an "undefined" error triggered on some inline code, you can try this option to also defer the inline code and preserve the order of execution.</p>
215
+ <p>Note however, not all scripts can work with defer so you need to test if everything is working without errors.</p>
216
+ <p>This is empty by default, unless you determine that it's needed.</p>
217
+ <p><strong>Recommended Default Settings:</strong></p>
218
+ <p class="fvm-code-full">
219
+ wp.i18n<br>
220
+ wp.apiFetch.use<br>
221
+ window.lodash<br>
222
+ wp.hooks<br>
223
+ wp.url
224
+ </p>
225
  </div>
226
+ <h3>Delay third party scripts until user interaction</h3>
227
  <div>
228
  <p><strong>Notes:</strong></p>
229
+ <p>Scripts like analytics, ads, tracking codes, etc, consume important CPU and network resources needed for the initial page view. You can force certain plugins to wait for user interaction (mouseover, keydown, touchstart, touchmove and wheel) and the scripts will only run on these events.</p>
230
+ <p>Delaying these scripts will improve your speed because most third party scripts are not needed for showing any content (if they are, then they are on the critical path and you should not delay them). In addition, note that some codes make use of document.write and other methods, which do not support delaying (delaying will work as usual, but the script will not do anything or stop working).</p>
231
+ <p>If you have render blocking third party scripts, ask your provider if they can provide you with an async or defer implementation (else remove them, because render blocking scripts are not recommended for speed).</p>
 
 
 
232
  <p><strong>Example Settings:</strong></p>
233
  <p class="fvm-code-full">
234
  function(w,d,s,l,i)<br>
242
  <h3>Remove JavaScript Scripts</h3>
243
  <div>
244
  <p><strong>Notes:</strong></p>
245
+ <p>This can be used when you want to remove a duplicate JS file from the frontend source. However, if this is for a third party script you added to the header or footer (either code or via some plugin), it's better if you delete it at the source.</p>
 
 
246
  </div>
247
  </div>
248
 
274
  <h3>CDN URL</h3>
275
  <div>
276
  <p><strong>Notes:</strong></p>
277
+ <p>This is not required for providers such as Cloudflare.com as well as any reverse proxy CDN service that doesn't change your domain name (the whole site goes through their service).</p>
278
+ <p>For other types of CDN, you are usually provided with an alternative domain name from where your static files can be served and in those cases, you would introduce your new domain name here.</p>
279
  </div>
280
  <h3>CDN Integration</h3>
281
  <div>
282
  <p><strong>Notes:</strong></p>
283
+ <p>Uses syntax from <a target="_blank" href="https://simplehtmldom.sourceforge.io/manual.htm">https://simplehtmldom.sourceforge.io/manual.htm</a> for modifying the HTML.</p>
284
+ <p>The plugin will replace your site domain url with the CDN domain for the matching HTML tags.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  </div>
286
  </div>
287
 
342
  <div>
343
  <p><strong>Notes:</strong></p>
344
  <p>Simply disable the plugin, and make sure to purge all page caches (Cache Plugins, Hosting, OPCache, etc).</p>
345
+ <p>Note that some hosts rate limit the amount of times you can purge caches to once every few minutes, so you may be purging and it doesn't work, because you are being rate limited by your hosting cache system. If that happens, just wait and try again later or ask your hosting to manually purge all caches on the server.</p>
346
+ <p>You can also delete any database entries on the wp_options table starting with fastvelocity to completely purge it.</p>
347
  <p>FVM does not modify your site. It runs after your template loads and filters the final HTML to present it to your users, in a more optimized way.</p>
348
  </div>
349
  <h3>I have disabled FVM but somehow the cache files are still being generated?</h3>
350
  <div>
351
  <p><strong>Notes:</strong></p>
352
+ <p>If you already purged all caches available, please ensure you have deleted the plugin and that it's no longer visible via wp-admin. If you still see references to FVM in incognito mode via google chrome, that means your server still has full page cache in memory that needs to be cleared.</p>
353
+ <p>A few hosting providers will put your files on a remote storage and cache your disk and files in memory to speed things up, which may cause code to be cached even if you have completely deleted it from the remote storage. This means, it may take a few minutes, or several hours for the actual code to update. In that case, restart the server or ask your hosting to purge all disk and page caching memory.</p>
 
354
  </div>
355
  <h3>Where can I get support or ask questions about the plugin?</h3>
356
  <div>
360
  <h3>How is it possible that some scan is showing malware on the plugin?</h3>
361
  <div>
362
  <p><strong>Notes:</strong></p>
363
+ <p>I guarantee that the plugin is 100% clean of malware, provided you have downloaded the plugin from the official WordPress source AND that your other plugins, theme or core is not compromised.</p>
364
+ <p>Malware can infect any plugin (even security plugins) regardless of the point of entry. Sometimes it propagates from different areas (including other sites you may have on the same server) or through a vulnerability on another theme or plugin (even disabled plugins or themes sometimes). </p>
365
+ <p>For that reason, if there is already malware on any JS files or CSS being merged by FVM, they would still be merged as they are, as FVM also reads them as they are. </p>
366
+ <p>If you are seeing malware on any cache file related to FVM, simply purge all caches and delete the FVM plugin. Then hire someone to manually audit the site (plugins or automated malware checks are not 100% accurate). You can then reinstall the FVM plugin from the official source on wordpress.org or via wp-admin if you like.</p>
367
  </div>
368
  <h3>How do I report a security issue or file a bug report?</h3>
369
  <div>
layout/admin-layout-settings.php CHANGED
@@ -17,32 +17,12 @@
17
  <tr>
18
  <th scope="row"><?php _e( 'Global Options', 'fast-velocity-minify' ); ?></th>
19
  <td>
20
- <p class="fvm-bold-green fvm-rowintro"><?php _e( 'Recommended Settings', 'fast-velocity-minify' ); ?></p>
21
-
22
- <fieldset>
23
-
24
- <label for="fvm_settings_global_preserve_settings">
25
- <input name="fvm_settings[global][preserve_settings]" type="checkbox" id="fvm_settings_global_preserve_settings" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'global', 'preserve_settings')); ?>>
26
- <?php _e( 'Preserve settings on uninstall', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'If selected, all FVM settings will be preserved when you uninstall or delete the plugin.', 'fast-velocity-minify' ); ?> ]</span></label>
27
- <br />
28
-
29
- <label for="fvm_settings_global_force-ssl">
30
- <input name="fvm_settings[global][force-ssl]" type="checkbox" id="fvm_settings_global_force-ssl" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'global', 'force-ssl')); ?>>
31
- <?php _e( 'Force HTTPS urls on merged files', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Recommended if you have SSL but still allow http access to the site.', 'fast-velocity-minify' ); ?> ]</span></label>
32
- <br />
33
-
34
- </fieldset></td>
35
- </tr>
36
-
37
- <tr>
38
- <th scope="row"><?php _e( 'Advanced Global Options', 'fast-velocity-minify' ); ?></th>
39
- <td>
40
  <p class="fvm-bold-green fvm-rowintro"><?php _e( 'Handle with Care', 'fast-velocity-minify' ); ?></p>
41
 
42
  <fieldset>
43
  <label for="fvm_settings_cache_min_instant_purge">
44
  <input name="fvm_settings[cache][min_instant_purge]" type="checkbox" id="fvm_settings_cache_min_instant_purge" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'cache', 'min_instant_purge')); ?>>
45
- <?php _e( 'Purge Minified CSS/JS files instantly', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Cache files can take up to 24 hours to be deleted by default, for compatibility reasons with certain hosts.', 'fast-velocity-minify' ); ?> ]</span></label>
46
  <br />
47
 
48
  </fieldset></td>
@@ -95,7 +75,7 @@
95
  <fieldset>
96
  <label for="fvm_settings_html_min_disable">
97
  <input name="fvm_settings[html][min_disable]" type="checkbox" id="fvm_settings_html_min_disable" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'html', 'min_disable')); ?>>
98
- <?php _e( 'Disable HTML Minification', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will disable HTML minification for testing purposes', 'fast-velocity-minify' ); ?> ]</span></label>
99
  <br />
100
 
101
  </fieldset></td>
@@ -142,24 +122,24 @@
142
 
143
  <fieldset>
144
 
145
- <label for="fvm_settings_css_inline-all">
146
- <input name="fvm_settings[css][inline-all]" type="checkbox" id="fvm_settings_css_inline-all" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'css', 'inline-all')); ?>>
147
- <?php _e( 'Disable Merging and Inline all CSS', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'It will inline all CSS files, instead of merging CSS into an external file (not recommended)', 'fast-velocity-minify' ); ?> ]</span></label>
148
  <br />
149
 
150
  <label for="fvm_settings_css_min_disable">
151
  <input name="fvm_settings[css][min_disable]" type="checkbox" id="fvm_settings_css_min_disable" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'css', 'min_disable')); ?>>
152
- <?php _e( 'Disable CSS Minification', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will allow merging but without CSS minification for testing purposes', 'fast-velocity-minify' ); ?> ]</span></label>
153
  <br />
154
 
155
- <label for="fvm_settings_css_inline-all">
156
- <input name="fvm_settings[css][nopreload]" type="checkbox" id="fvm_settings_css_nopreload" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'css', 'nopreload')); ?>>
157
- <?php _e( 'Disable CSS link preload', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will remove the CSS link preload from the header (not recommended)', 'fast-velocity-minify' ); ?> ]</span></label>
158
  <br />
159
 
160
- <label for="fvm_settings_css_async">
161
- <input name="fvm_settings[css][async]" type="checkbox" id="fvm_settings_css_async" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'css', 'async')); ?>>
162
- <?php _e( 'Load generated CSS files Async', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Use your own critical path code like <code>&lt;style id=&quot;critical-path&quot;&gt; your code &lt;/style&gt;</code>', 'fast-velocity-minify' ); ?> ]</span></label>
163
  <br />
164
 
165
  </fieldset></td>
@@ -185,6 +165,16 @@
185
  </fieldset></td>
186
  </tr>
187
 
 
 
 
 
 
 
 
 
 
 
188
 
189
  </tbody>
190
  </table>
@@ -193,7 +183,7 @@
193
 
194
  <div style="height: 60px;"></div>
195
  <h2 class="title"><?php _e( 'JS Settings', 'fast-velocity-minify' ); ?></h2>
196
- <h3 class="fvm-bold-green"><?php _e( 'In this section, you can optimize your JS files and inline scripts', 'fast-velocity-minify' ); ?></h3>
197
 
198
  <table class="form-table fvm-settings">
199
  <tbody>
@@ -218,19 +208,26 @@
218
  <p class="fvm-bold-green fvm-rowintro"><?php _e( 'Handle with Care', 'fast-velocity-minify' ); ?></p>
219
 
220
  <fieldset>
 
 
 
 
 
 
 
221
  <label for="fvm_settings_js_min_disable">
222
  <input name="fvm_settings[js][min_disable]" type="checkbox" id="fvm_settings_js_min_disable" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'js', 'min_disable')); ?>>
223
- <?php _e( 'Disable JS Minification', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will disable JS minification (merge only) for testing purposes', 'fast-velocity-minify' ); ?> ]</span></label>
224
  <br />
225
 
226
- <label for="fvm_settings_js_inline-all">
227
- <input name="fvm_settings[js][nopreload]" type="checkbox" id="fvm_settings_js_nopreload" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'js', 'nopreload')); ?>>
228
- <?php _e( 'Disable JS link preload', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will remove the JS link preload from the header (not recommended)', 'fast-velocity-minify' ); ?> ]</span></label>
229
  <br />
230
 
231
- <label for="fvm_settings_js_jqupgrade">
232
- <input name="fvm_settings[js][jqupgrade]" type="checkbox" id="fvm_settings_js_jqupgrade" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'js', 'jqupgrade')); ?>>
233
- <?php _e( 'Upgrade to jQuery 3', 'fast-velocity-minify' ); ?> <span class="note-info">[<?php _e( 'Will use jQuery 3.5.1 and jQuery Migrate 3.3.1 from Cloudflare (if enqueued)', 'fast-velocity-minify' ); ?> ]</span></label>
234
  <br />
235
 
236
  </fieldset></td>
@@ -240,7 +237,7 @@
240
  <tr>
241
  <th scope="row"><?php _e( 'Ignore Script Files', 'fast-velocity-minify' ); ?></th>
242
  <td><fieldset>
243
- <label for="fvm_settings_js_ignore"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'Will prevent merging and minification for these files, regardless of any other broader rules in this page.', 'fast-velocity-minify' ); ?></span></label>
244
  <p><textarea name="fvm_settings[js][ignore]" rows="7" cols="50" id="fvm_settings_js_ignore" class="large-text code" placeholder="<?php _e( '--- ex: /plugins/something/assets/problem.js ---', 'fast-velocity-minify' ); ?>"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'ignore'); ?></textarea></p>
245
  <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the script <code>src</code> attribute', 'fast-velocity-minify' ); ?> ]</p>
246
  <p class="description">[ <?php _e( 'It is highly recommended to try to leave this empty and later be more specific on what to merge', 'fast-velocity-minify' ); ?> ]</p>
@@ -248,55 +245,55 @@
248
  </tr>
249
 
250
  <tr>
251
- <th scope="row"><?php _e( 'Merge render blocking JS files in the header', 'fast-velocity-minify' ); ?></th>
252
  <td><fieldset>
253
- <label for="fvm_settings_merge_header"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'This will merge and render block all JS files that match the paths below', 'fast-velocity-minify' ); ?></span></label>
254
- <p><textarea name="fvm_settings[js][merge_header]" rows="7" cols="50" id="fvm_settings_js_merge_header" class="large-text code" placeholder="<?php _e( '--- suggested ---', 'fast-velocity-minify' ); ?>
255
-
256
  /jquery-migrate.js
257
  /jquery.js
258
  /jquery.min.js"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'merge_header'); ?></textarea></p>
259
- <p class="description">[ <?php _e( 'One possible match per line, after minification and processing, as seen on the frontend.', 'fast-velocity-minify' ); ?> ]</p>
260
  <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the script <code>src attribute</code>', 'fast-velocity-minify' ); ?> ]</p>
261
  </fieldset></td>
262
  </tr>
263
 
264
  <tr>
265
- <th scope="row"><?php _e( 'Merge and Defer Scripts', 'fast-velocity-minify' ); ?></th>
266
  <td><fieldset>
267
- <label for="fvm_settings_merge_defer"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'This will merge and defer all JS files that match the paths below', 'fast-velocity-minify' ); ?></span></label>
268
- <p><textarea name="fvm_settings[js][merge_defer]" rows="7" cols="50" id="fvm_settings_js_merge_defer" class="large-text code" placeholder="<?php _e( '--- example ---', 'fast-velocity-minify' ); ?>
269
-
270
  /wp-admin/
271
  /wp-includes/
272
  /wp-content/"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'merge_defer'); ?></textarea></p>
273
- <p class="description">[ <?php _e( 'One possible match per line, after minification and processing, as seen on the frontend.', 'fast-velocity-minify' ); ?> ]</p>
274
  <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the script <code>src attribute', 'fast-velocity-minify' ); ?></code> ]</p>
275
  </fieldset></td>
276
  </tr>
277
 
278
  <tr>
279
- <th scope="row"><?php _e( 'Inline JavaScript Dependencies', 'fast-velocity-minify' ); ?></th>
280
  <td><fieldset>
281
- <label for="fvm_settings_defer_dependencies"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'Delay Inline JavaScript until after the deferred scripts merged above finish loading', 'fast-velocity-minify' ); ?></span></label>
282
- <p><textarea name="fvm_settings[js][defer_dependencies]" rows="7" cols="50" id="fvm_settings_js_defer_dependencies" class="large-text code" placeholder="<?php _e( '--- a small snippet that should match an inline script and make it wait for the deferred scripts above ---', 'fast-velocity-minify' ); ?>"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'defer_dependencies'); ?></textarea></p>
283
- <p class="description">[ <?php _e( 'Inline JavaScript matching these rules, will wait until after the window.load event', 'fast-velocity-minify' ); ?> ]</p>
 
 
 
 
 
284
  <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the script <code>innerHTML</code>', 'fast-velocity-minify' ); ?> ]</p>
285
  </fieldset></td>
286
  </tr>
287
 
288
  <tr>
289
- <th scope="row"><?php _e( 'Execute matching third party scripts after user interaction', 'fast-velocity-minify' ); ?></th>
290
  <td><fieldset>
291
- <label for="fvm_settings_js_thirdparty"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'Delay the following inline scripts until after user interaction', 'fast-velocity-minify' ); ?></span></label>
292
  <p><textarea name="fvm_settings[js][thirdparty]" rows="7" cols="50" id="fvm_settings_js_thirdparty" class="large-text code" placeholder="<?php _e( '--- example ---', 'fast-velocity-minify' ); ?>
293
-
294
  function(w,d,s,l,i)
295
  function(f,b,e,v,n,t,s)
296
  function(h,o,t,j,a,r)
297
  www.googletagmanager.com/gtm.js"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'thirdparty'); ?></textarea></p>
298
- <p class="description">[ <?php _e( 'If there is no interaction from the user, scripts will still load after 5 seconds automatically.', 'fast-velocity-minify' ); ?> ]</p>
299
- <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the script <code>innerHTML</code> or <code>src</code> attribute for async/defer scripts (only)', 'fast-velocity-minify' ); ?> ]</p>
300
  </fieldset></td>
301
  </tr>
302
 
@@ -304,7 +301,8 @@ www.googletagmanager.com/gtm.js"><?php echo fvm_get_settings_value($fvm_settings
304
  <th scope="row"><?php _e( 'Remove JavaScript Scripts', 'fast-velocity-minify' ); ?></th>
305
  <td><fieldset>
306
  <label for="fvm_settings_js_remove"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'Remove the following JS files or Inline Scripts', 'fast-velocity-minify' ); ?></span></label>
307
- <p><textarea name="fvm_settings[js][remove]" rows="7" cols="50" id="fvm_settings_js_remove" class="large-text code" placeholder="--- should be empty in most cases ---"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'remove'); ?></textarea></p>
 
308
  <p class="description">[ <?php _e( 'This will allow you to remove unwanted script tags from the frontend', 'fast-velocity-minify' ); ?> ]</p>
309
  <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the script <code>outerHTML</code>', 'fast-velocity-minify' ); ?> ]</p>
310
  </fieldset></td>
@@ -349,7 +347,7 @@ www.googletagmanager.com/gtm.js"><?php echo fvm_get_settings_value($fvm_settings
349
  <td><fieldset>
350
  <label for="fvm_settings_cdn_domain">
351
  <p><input type="text" name="fvm_settings[cdn][domain]" id="fvm_settings_cdn_domain" value="<?php echo fvm_get_settings_value($fvm_settings, 'cdn', 'domain'); ?>" size="80" /></p>
352
- <p class="description">[ <?php _e( 'Not needed for Cloudflare or same domain reverse proxy cdn services.', 'fast-velocity-minify' ); ?> ]</p>
353
  </label>
354
  <br />
355
  </fieldset></td>
@@ -357,39 +355,9 @@ www.googletagmanager.com/gtm.js"><?php echo fvm_get_settings_value($fvm_settings
357
  <tr>
358
  <th scope="row"><?php _e( 'CDN Integration', 'fast-velocity-minify' ); ?></th>
359
  <td><fieldset>
360
- <label for="fvm_settings_cdn_integration"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'Replace the following elements', 'fast-velocity-minify' ); ?></span></label>
361
  <p><textarea name="fvm_settings[cdn][integration]" rows="7" cols="50" id="fvm_settings_cdn_integration" class="large-text code" placeholder="--- check the help section for suggestions ---"><?php echo fvm_get_settings_value($fvm_settings, 'cdn', 'integration'); ?></textarea></p>
362
- <p class="description">[ <?php _e( 'Uses syntax from <code>https://simplehtmldom.sourceforge.io/manual.htm', 'fast-velocity-minify' ); ?></code> ]</p>
363
- <p class="description">[ <?php _e( 'You can target a child of a specific html tag, an element with a specific attribute, class or id.', 'fast-velocity-minify' ); ?> ]</p>
364
- </fieldset></td>
365
- </tr>
366
- </tbody></table>
367
-
368
-
369
-
370
- <div style="height: 60px;"></div>
371
- <h2 class="title"><?php _e( 'Cache Location', 'fast-velocity-minify' ); ?></h2>
372
- <h3 class="fvm-bold-green"><?php _e( 'FVM does not have page caching, so these settings are for the generated CSS and JS files only', 'fast-velocity-minify' ); ?></h3>
373
- <table class="form-table fvm-settings">
374
- <tbody>
375
- <tr>
376
- <th scope="row"><span class="fvm-label-special"><?php _e( 'Public Files Cache Path', 'fast-velocity-minify' ); ?></span></th>
377
- <td><fieldset>
378
- <label for="fvm_settings_cache_path">
379
- <p><input type="text" name="fvm_settings[cache][path]" id="fvm_settings_cache_path" value="<?php echo fvm_get_settings_value($fvm_settings, 'cache', 'path'); ?>" size="80" /></p>
380
- <p class="description">[ <?php _e( 'Current base path:', 'fast-velocity-minify' ); ?> <code><?php echo $fvm_cache_paths['cache_base_dir']; ?></code> ]</p>
381
- </label>
382
- <br />
383
- </fieldset></td>
384
- </tr>
385
- <tr>
386
- <th scope="row"><span class="fvm-label-special"><?php _e( 'Public Files Cache URL', 'fast-velocity-minify' ); ?></span></th>
387
- <td><fieldset>
388
- <label for="fvm_settings_cache_url">
389
- <p><input type="text" name="fvm_settings[cache][url]" id="fvm_settings_cache_url" value="<?php echo fvm_get_settings_value($fvm_settings, 'cache', 'url'); ?>" size="80" /></p>
390
- <p class="description">[ <?php _e( 'Current base url:', 'fast-velocity-minify' ); ?> <code><?php echo $fvm_cache_paths['cache_base_dirurl']; ?></code> ]</p>
391
- </label>
392
- <br />
393
  </fieldset></td>
394
  </tr>
395
  </tbody></table>
17
  <tr>
18
  <th scope="row"><?php _e( 'Global Options', 'fast-velocity-minify' ); ?></th>
19
  <td>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  <p class="fvm-bold-green fvm-rowintro"><?php _e( 'Handle with Care', 'fast-velocity-minify' ); ?></p>
21
 
22
  <fieldset>
23
  <label for="fvm_settings_cache_min_instant_purge">
24
  <input name="fvm_settings[cache][min_instant_purge]" type="checkbox" id="fvm_settings_cache_min_instant_purge" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'cache', 'min_instant_purge')); ?>>
25
+ <?php _e( 'Purge Minified CSS/JS files instantly', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Cache files are only deleted if older than 24h by default, for compatibility with certain hosting providers.', 'fast-velocity-minify' ); ?> ]</span></label>
26
  <br />
27
 
28
  </fieldset></td>
75
  <fieldset>
76
  <label for="fvm_settings_html_min_disable">
77
  <input name="fvm_settings[html][min_disable]" type="checkbox" id="fvm_settings_html_min_disable" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'html', 'min_disable')); ?>>
78
+ <?php _e( 'Disable HTML Minification', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will disable HTML minification for compatibility purposes', 'fast-velocity-minify' ); ?> ]</span></label>
79
  <br />
80
 
81
  </fieldset></td>
122
 
123
  <fieldset>
124
 
125
+ <label for="fvm_settings_css_nopreload">
126
+ <input name="fvm_settings[css][combine]" type="checkbox" id="fvm_settings_css_combine" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'css', 'combine')); ?>>
127
+ <?php _e( 'Combine CSS Files', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Deprecated: Will combine all CSS files by mediatype groups in the header (no longer recommended for HTTP/2 servers)', 'fast-velocity-minify' ); ?> ]</span></label>
128
  <br />
129
 
130
  <label for="fvm_settings_css_min_disable">
131
  <input name="fvm_settings[css][min_disable]" type="checkbox" id="fvm_settings_css_min_disable" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'css', 'min_disable')); ?>>
132
+ <?php _e( 'Disable CSS Files Minification', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will disable CSS Files minification for compatibility purposes', 'fast-velocity-minify' ); ?> ]</span></label>
133
  <br />
134
 
135
+ <label for="fvm_settings_css_min_disable">
136
+ <input name="fvm_settings[css][min_disable_styles]" type="checkbox" id="fvm_settings_css_min_disable_styles" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'css', 'min_disable_styles')); ?>>
137
+ <?php _e( 'Disable CSS Styles Minification', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will disable CSS Styles minification for compatibility purposes', 'fast-velocity-minify' ); ?> ]</span></label>
138
  <br />
139
 
140
+ <label for="fvm_settings_css_nopreload">
141
+ <input name="fvm_settings[css][nopreload]" type="checkbox" id="fvm_settings_css_nopreload" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'css', 'nopreload')); ?>>
142
+ <?php _e( 'Disable CSS Link Preload', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will remove the Render Blocking CSS files Link Preload from the header', 'fast-velocity-minify' ); ?> ]</span></label>
143
  <br />
144
 
145
  </fieldset></td>
165
  </fieldset></td>
166
  </tr>
167
 
168
+ <tr>
169
+ <th scope="row"><?php _e( 'Async CSS Files', 'fast-velocity-minify' ); ?></th>
170
+ <td><fieldset>
171
+ <label for="fvm_settings_css_async"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'Async the following CSS files', 'fast-velocity-minify' ); ?></span></label>
172
+ <p><textarea name="fvm_settings[css][async]" rows="7" cols="50" id="fvm_settings_css_async" class="large-text code" placeholder="ex: /plugins/something/assets/low-priority.css"><?php echo fvm_get_settings_value($fvm_settings, 'css', 'async'); ?></textarea></p>
173
+ <p class="description">[ <?php _e( 'This will allow you to remove unwanted CSS files by URL path from the frontend', 'fast-velocity-minify' ); ?> ]</p>
174
+ <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the <code>href attribute</code> on the <code>link tag</code>', 'fast-velocity-minify' ); ?> ]</p>
175
+ </fieldset></td>
176
+ </tr>
177
+
178
 
179
  </tbody>
180
  </table>
183
 
184
  <div style="height: 60px;"></div>
185
  <h2 class="title"><?php _e( 'JS Settings', 'fast-velocity-minify' ); ?></h2>
186
+ <h3 class="fvm-bold-green"><?php _e( 'In this section, you can optimize your JS files and inline scripts manually (by default all scripts are ignored for compatibility reasons).', 'fast-velocity-minify' ); ?></h3>
187
 
188
  <table class="form-table fvm-settings">
189
  <tbody>
208
  <p class="fvm-bold-green fvm-rowintro"><?php _e( 'Handle with Care', 'fast-velocity-minify' ); ?></p>
209
 
210
  <fieldset>
211
+
212
+ <label for="fvm_settings_js_combine">
213
+ <input name="fvm_settings[js][combine]" type="checkbox" id="fvm_settings_js_combine" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'js', 'combine')); ?>>
214
+ <?php _e( 'Combine JS Files', 'fast-velocity-minify' ); ?> <span class="note-info">[<?php _e( 'Deprecated: Will combine all JS files by render blocking type (no longer recommended for HTTP/2 servers)', 'fast-velocity-minify' ); ?> ]</span></label>
215
+ <br />
216
+
217
+
218
  <label for="fvm_settings_js_min_disable">
219
  <input name="fvm_settings[js][min_disable]" type="checkbox" id="fvm_settings_js_min_disable" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'js', 'min_disable')); ?>>
220
+ <?php _e( 'Disable JS Files Minification', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will disable JS Files minification for testing purposes', 'fast-velocity-minify' ); ?> ]</span></label>
221
  <br />
222
 
223
+ <label for="fvm_settings_js_min_disable_inline">
224
+ <input name="fvm_settings[js][min_disable_inline]" type="checkbox" id="fvm_settings_js_min_disable_inline" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'js', 'min_disable_inline')); ?>>
225
+ <?php _e( 'Disable JS Inline Minification', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will disable JS Inline minification for testing purposes', 'fast-velocity-minify' ); ?> ]</span></label>
226
  <br />
227
 
228
+ <label for="fvm_settings_js_inline-all">
229
+ <input name="fvm_settings[js][nopreload]" type="checkbox" id="fvm_settings_js_nopreload" value="1" <?php echo fvm_get_settings_checkbox(fvm_get_settings_value($fvm_settings, 'js', 'nopreload')); ?>>
230
+ <?php _e( 'Disable JS link Preload', 'fast-velocity-minify' ); ?> <span class="note-info">[ <?php _e( 'Will remove the Render Blocking JS files Link Preload from the header', 'fast-velocity-minify' ); ?> ]</span></label>
231
  <br />
232
 
233
  </fieldset></td>
237
  <tr>
238
  <th scope="row"><?php _e( 'Ignore Script Files', 'fast-velocity-minify' ); ?></th>
239
  <td><fieldset>
240
+ <label for="fvm_settings_js_ignore"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'Will prevent merging or minification for all JS files matching the paths below', 'fast-velocity-minify' ); ?></span></label>
241
  <p><textarea name="fvm_settings[js][ignore]" rows="7" cols="50" id="fvm_settings_js_ignore" class="large-text code" placeholder="<?php _e( '--- ex: /plugins/something/assets/problem.js ---', 'fast-velocity-minify' ); ?>"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'ignore'); ?></textarea></p>
242
  <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the script <code>src</code> attribute', 'fast-velocity-minify' ); ?> ]</p>
243
  <p class="description">[ <?php _e( 'It is highly recommended to try to leave this empty and later be more specific on what to merge', 'fast-velocity-minify' ); ?> ]</p>
245
  </tr>
246
 
247
  <tr>
248
+ <th scope="row"><?php _e( 'Render Blocking JS files', 'fast-velocity-minify' ); ?></th>
249
  <td><fieldset>
250
+ <label for="fvm_settings_merge_header"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'This will render block all JS files matching the paths below', 'fast-velocity-minify' ); ?></span></label>
251
+ <p><textarea name="fvm_settings[js][merge_header]" rows="7" cols="50" id="fvm_settings_js_merge_header" class="large-text code" placeholder="<?php _e( '--- example ---', 'fast-velocity-minify' ); ?>
 
252
  /jquery-migrate.js
253
  /jquery.js
254
  /jquery.min.js"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'merge_header'); ?></textarea></p>
 
255
  <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the script <code>src attribute</code>', 'fast-velocity-minify' ); ?> ]</p>
256
  </fieldset></td>
257
  </tr>
258
 
259
  <tr>
260
+ <th scope="row"><?php _e( 'Defer JS Files', 'fast-velocity-minify' ); ?></th>
261
  <td><fieldset>
262
+ <label for="fvm_settings_merge_defer"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'This will defer all JS files matching the paths below', 'fast-velocity-minify' ); ?></span></label>
263
+ <p><textarea name="fvm_settings[js][merge_defer]" rows="7" cols="50" id="fvm_settings_js_merge_defer" class="large-text code" placeholder="<?php _e( '--- example ---', 'fast-velocity-minify' ); ?>
 
264
  /wp-admin/
265
  /wp-includes/
266
  /wp-content/"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'merge_defer'); ?></textarea></p>
 
267
  <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the script <code>src attribute', 'fast-velocity-minify' ); ?></code> ]</p>
268
  </fieldset></td>
269
  </tr>
270
 
271
  <tr>
272
+ <th scope="row"><?php _e( 'Defer Inline JavaScript', 'fast-velocity-minify' ); ?></th>
273
  <td><fieldset>
274
+ <label for="fvm_settings_defer_dependencies"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'Preserve the order of scripts execution when deferring JS files dependencies', 'fast-velocity-minify' ); ?></span></label>
275
+ <p><textarea name="fvm_settings[js][defer_dependencies]" rows="7" cols="50" id="fvm_settings_js_defer_dependencies" class="large-text code" placeholder="<?php _e( '--- example ---', 'fast-velocity-minify' ); ?>
276
+ wp.i18n
277
+ wp.apiFetch.use
278
+ window.lodash
279
+ wp.hooks
280
+ wp.url"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'defer_dependencies'); ?></textarea></p>
281
+ <p class="description">[ <?php _e( 'Inline JavaScript matching these rules, will be deferred with script type module', 'fast-velocity-minify' ); ?> ]</p>
282
  <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the script <code>innerHTML</code>', 'fast-velocity-minify' ); ?> ]</p>
283
  </fieldset></td>
284
  </tr>
285
 
286
  <tr>
287
+ <th scope="row"><?php _e( 'Delay third party scripts until user interaction', 'fast-velocity-minify' ); ?></th>
288
  <td><fieldset>
289
+ <label for="fvm_settings_js_thirdparty"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'Delay JS files or inline scripts until user interaction', 'fast-velocity-minify' ); ?></span></label>
290
  <p><textarea name="fvm_settings[js][thirdparty]" rows="7" cols="50" id="fvm_settings_js_thirdparty" class="large-text code" placeholder="<?php _e( '--- example ---', 'fast-velocity-minify' ); ?>
 
291
  function(w,d,s,l,i)
292
  function(f,b,e,v,n,t,s)
293
  function(h,o,t,j,a,r)
294
  www.googletagmanager.com/gtm.js"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'thirdparty'); ?></textarea></p>
295
+ <p class="description">[ <?php _e( 'Used interaction events: mouseover, keydown, touchstart, touchmove and wheel', 'fast-velocity-minify' ); ?> ]</p>
296
+ <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the inline script <code>innerHTML</code> or <code>src</code> attribute for JS files', 'fast-velocity-minify' ); ?> ]</p>
297
  </fieldset></td>
298
  </tr>
299
 
301
  <th scope="row"><?php _e( 'Remove JavaScript Scripts', 'fast-velocity-minify' ); ?></th>
302
  <td><fieldset>
303
  <label for="fvm_settings_js_remove"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'Remove the following JS files or Inline Scripts', 'fast-velocity-minify' ); ?></span></label>
304
+ <p><textarea name="fvm_settings[js][remove]" rows="7" cols="50" id="fvm_settings_js_remove" class="large-text code" placeholder="<?php _e( '--- example ---', 'fast-velocity-minify' ); ?>
305
+ /some/duplicate/file.js"><?php echo fvm_get_settings_value($fvm_settings, 'js', 'remove'); ?></textarea></p>
306
  <p class="description">[ <?php _e( 'This will allow you to remove unwanted script tags from the frontend', 'fast-velocity-minify' ); ?> ]</p>
307
  <p class="description">[ <?php _e( 'Will match using <code>PHP stripos</code> against the script <code>outerHTML</code>', 'fast-velocity-minify' ); ?> ]</p>
308
  </fieldset></td>
347
  <td><fieldset>
348
  <label for="fvm_settings_cdn_domain">
349
  <p><input type="text" name="fvm_settings[cdn][domain]" id="fvm_settings_cdn_domain" value="<?php echo fvm_get_settings_value($fvm_settings, 'cdn', 'domain'); ?>" size="80" /></p>
350
+ <p class="description">[ <?php _e( 'You can ignore this if your CDN url matches your domain name (ie: Cloudflare)', 'fast-velocity-minify' ); ?> ]</p>
351
  </label>
352
  <br />
353
  </fieldset></td>
355
  <tr>
356
  <th scope="row"><?php _e( 'CDN Integration', 'fast-velocity-minify' ); ?></th>
357
  <td><fieldset>
358
+ <label for="fvm_settings_cdn_integration"><span class="fvm-bold-green fvm-rowintro"><?php _e( 'Missing HTML elements to replace', 'fast-velocity-minify' ); ?></span></label>
359
  <p><textarea name="fvm_settings[cdn][integration]" rows="7" cols="50" id="fvm_settings_cdn_integration" class="large-text code" placeholder="--- check the help section for suggestions ---"><?php echo fvm_get_settings_value($fvm_settings, 'cdn', 'integration'); ?></textarea></p>
360
+ <p class="description">[ <?php _e( 'Additional replacement rules with syntax from <code>https://simplehtmldom.sourceforge.io/manual.htm</code>', 'fast-velocity-minify' ); ?> ]</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  </fieldset></td>
362
  </tr>
363
  </tbody></table>
layout/admin-layout-status.php CHANGED
@@ -6,22 +6,11 @@ if( $active_tab == 'status' ) {
6
  <div class="fvm-wrapper">
7
 
8
  <div id="status">
9
- <h2 class="title"><?php _e( 'Cache Stats', 'fast-velocity-minify' ); ?></h2>
10
- <h3 class="fvm-cache-stats fvm-bold-green"></h3>
11
-
12
 
13
  <div style="height: 40px;"></div>
14
- <h2 class="title"><?php _e( 'CSS Logs', 'fast-velocity-minify' ); ?></h2>
15
- <h3 class="fvm-bold-green"><?php _e( 'In this section, you can check the latest CSS merging logs', 'fast-velocity-minify' ); ?></h3>
16
- <textarea rows="10" cols="50" class="large-text code row-log log-css" disabled></textarea>
17
-
18
-
19
- <div style="height: 40px;"></div>
20
- <h2 class="title"><?php _e( 'JS Logs', 'fast-velocity-minify' ); ?></h2>
21
- <h3 class="fvm-bold-green"><?php _e( 'In this section, you can check the latest JS merging logs', 'fast-velocity-minify' ); ?></h3>
22
- <textarea rows="10" cols="50" class="large-text code row-log log-js" disabled></textarea>
23
- <div style="height: 20px;"></div>
24
-
25
 
26
  <div style="height: 40px;"></div>
27
  <h2 class="title"><?php _e( 'Server Info', 'fast-velocity-minify' ); ?></h2>
6
  <div class="fvm-wrapper">
7
 
8
  <div id="status">
 
 
 
9
 
10
  <div style="height: 40px;"></div>
11
+ <h2 class="title"><?php _e( 'Latest Logs', 'fast-velocity-minify' ); ?></h2>
12
+ <h3 class="fvm-bold-green"><?php _e( 'In this section, you can check the latest logs for CSS and JS files', 'fast-velocity-minify' ); ?></h3>
13
+ <div class="row-log log-stats wpraiser-textarea"><textarea rows="10" cols="50" class="large-text code row-log log-css" disabled></textarea></div>
 
 
 
 
 
 
 
 
14
 
15
  <div style="height: 40px;"></div>
16
  <h2 class="title"><?php _e( 'Server Info', 'fast-velocity-minify' ); ?></h2>
libs/raisermin/minify.php CHANGED
@@ -38,7 +38,7 @@ function fvm_raisermin_js($code){
38
 
39
  # collapse consecutive line feeds into just 1
40
  $code = preg_replace('/\n+/', "\n", $code);
41
-
42
  # process horizontal space
43
  $code = preg_replace('/([\[\]\(\)\{\}\;\<\>])(\h+)([\[\]\(\)\{\}\;\<\>])/ui', '$1 $3', $code);
44
  $code = preg_replace('/([\)])(\h?)(\.)/ui', '$1$3', $code);
@@ -65,129 +65,48 @@ function fvm_min_remove_utf8_bom($text) {
65
 
66
 
67
  # minify html, don't touch certain tags
68
- function fvm_raisermin_html($html, $xtra) {
69
 
70
  # clone
71
  $content = $html;
72
 
73
  # get all scripts
74
- $allscripts = array();
75
- preg_match_all('/\<script(.*?)\<(\s*)\/script(\s*)\>/uis', $html, $allscripts);
76
 
77
- # replace all with a marker
78
- if(is_array($allscripts) && isset($allscripts[0]) && count($allscripts[0]) > 0) {
79
- foreach ($allscripts[0] as $k=>$v) {
80
- $content = str_replace($v, '<!-- SCRIPT '.$k.' -->', $content);
81
  }
82
  }
83
 
84
- # get all <code> sections
85
- $allcodes = array();
86
- preg_match_all('/\<code(.*?)\<(\s*)\/code(\s*)\>/uis', $html, $allcodes);
87
-
88
- # replace all with a marker
89
- if(is_array($allcodes) && isset($allcodes[0]) && count($allcodes[0]) > 0) {
90
- foreach ($allcodes[0] as $k=>$v) {
91
- $content = str_replace($v, '<!-- CODE '.$k.' -->', $content);
92
- }
93
- }
94
-
95
- # get all <pre> sections
96
- $allpres = array();
97
- preg_match_all('/\<pre(.*?)\<(\s*)\/pre(\s*)\>/uis', $html, $allpres);
98
-
99
- # replace all with a marker
100
- if(is_array($allpres) && isset($allpres[0]) && count($allpres[0]) > 0) {
101
- foreach ($allpres[0] as $k=>$v) {
102
- $content = str_replace($v, '<!-- PRE '.$k.' -->', $content);
103
- }
104
- }
105
-
106
  # remove line breaks, and colapse two or more white spaces into one
107
  $content = preg_replace('/\s+/u', " ", $content);
108
 
109
- # remove space between tags
110
- $content = str_replace('> <', '><', $content);
111
-
112
- # add extra line breaks to code?
113
- if($xtra === true) {
114
-
115
- # add linebreaks after meta tags, for readability
116
- $allmeta = array();
117
- preg_match_all('/\<meta(.*?)\>/uis', $html, $allmeta);
118
-
119
- # replace all scripts and styles with a marker
120
- if(is_array($allmeta) && isset($allmeta[0]) && count($allmeta[0]) > 0) {
121
- foreach ($allmeta[0] as $k=>$v) {
122
- $content = str_replace($v, PHP_EOL . $v . PHP_EOL, $content);
123
- }
124
- }
125
-
126
- # add linebreaks after link tags, for readability
127
- $alllink = array();
128
- preg_match_all('/\<link(.*?)\>/uis', $html, $alllink);
129
-
130
- # replace all scripts and styles with a marker
131
- if(is_array($alllink) && isset($alllink[0]) && count($alllink[0]) > 0) {
132
- foreach ($alllink[0] as $k=>$v) {
133
- $content = str_replace($v, PHP_EOL . $v . PHP_EOL, $content);
134
- }
135
- }
136
-
137
- # add linebreaks after style tags, for readability
138
- $allstyles = array();
139
- preg_match_all('/\<s(.*?)\<(\s*)\/style(\s*)\>/uis', $html, $allstyles);
140
-
141
- # replace all scripts and styles with a marker
142
- if(is_array($allstyles) && isset($allstyles[0]) && count($allstyles[0]) > 0) {
143
- foreach ($allstyles[0] as $k=>$v) {
144
- $content = str_replace($v, PHP_EOL . $v . PHP_EOL, $content);
145
- }
146
- }
147
-
148
- # add linebreaks after html and head tags, for readability
149
- $content = str_replace('<head>', PHP_EOL . '<head>' . PHP_EOL, $content);
150
- $content = str_replace('</head>', PHP_EOL . '</head>' . PHP_EOL, $content);
151
- $content = str_replace('<html', PHP_EOL . '<html', $content);
152
- $content = str_replace('</html>', PHP_EOL . '</html>', $content);
153
-
154
- }
155
-
156
- # replace markers for scripts
157
- if(is_array($allscripts) && isset($allscripts[0]) && count($allscripts[0]) > 0) {
158
- foreach ($allscripts[0] as $k=>$v) {
159
- if($xtra === true) {
160
- $content = str_replace('<!-- SCRIPT '.$k.' -->', PHP_EOL . $v . PHP_EOL, $content);
161
- } else {
162
- $content = str_replace('<!-- SCRIPT '.$k.' -->', $v, $content);
163
- }
164
- }
165
- }
166
 
167
- # no more than 1 linebreak
168
- $content = preg_replace('/\v{2,}/u', PHP_EOL, $content);
 
 
 
169
 
170
- # replace markers for <code>
171
- if(is_array($allcodes) && isset($allcodes[0]) && count($allcodes[0]) > 0) {
172
- foreach ($allcodes[0] as $k=>$v) {
173
- if($xtra === true) {
174
- $content = str_replace('<!-- CODE '.$k.' -->', PHP_EOL . $v . PHP_EOL, $content);
175
- } else {
176
- $content = str_replace('<!-- CODE '.$k.' -->', $v, $content);
177
- }
178
  }
179
  }
180
-
181
- # replace markers for <pre>
182
- if(is_array($allpres) && isset($allpres[0]) && count($allpres[0]) > 0) {
183
- foreach ($allpres[0] as $k=>$v) {
184
- if($xtra === true) {
185
- $content = str_replace('<!-- PRE '.$k.' -->', PHP_EOL . $v . PHP_EOL, $content);
186
- } else {
187
- $content = str_replace('<!-- PRE '.$k.' -->', $v, $content);
188
- }
189
- }
190
- }
191
 
192
  # save as html, if not empty
193
  if(!empty($content)) {
38
 
39
  # collapse consecutive line feeds into just 1
40
  $code = preg_replace('/\n+/', "\n", $code);
41
+
42
  # process horizontal space
43
  $code = preg_replace('/([\[\]\(\)\{\}\;\<\>])(\h+)([\[\]\(\)\{\}\;\<\>])/ui', '$1 $3', $code);
44
  $code = preg_replace('/([\)])(\h?)(\.)/ui', '$1$3', $code);
65
 
66
 
67
  # minify html, don't touch certain tags
68
+ function fvm_raisermin_html($html) {
69
 
70
  # clone
71
  $content = $html;
72
 
73
  # get all scripts
74
+ $skp = array();
75
+ preg_match_all('/(\<script(.*?)\<(\s*)\/script(\s*)\>|\<noscript(.*?)\<(\s*)\/noscript(\s*)\>|\<code(.*?)\<(\s*)\/code(\s*)\>|\<pre(.*?)\<(\s*)\/pre(\s*)\>)/uis', $html, $skp);
76
 
77
+ # replace all skippable patterns with comment
78
+ if(is_array($skp) && isset($skp[0]) && count($skp[0]) > 0) {
79
+ foreach ($skp[0] as $k=>$v) {
80
+ $content = str_replace($v, '<!-- SKIP '.$k.' -->', $content);
81
  }
82
  }
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  # remove line breaks, and colapse two or more white spaces into one
85
  $content = preg_replace('/\s+/u', " ", $content);
86
 
87
+ # add linebreaks after html and head tags, for readability
88
+ $content = str_replace('<head>', PHP_EOL . '<head>' . PHP_EOL, $content);
89
+ $content = str_replace('</head>', PHP_EOL . '</head>' . PHP_EOL, $content);
90
+ $content = str_replace('<html', PHP_EOL . '<html', $content);
91
+ $content = str_replace('</html>', PHP_EOL . '</html>', $content);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
+ # final readability adjustments
94
+ $content = str_replace('<meta ', PHP_EOL . '<meta ', $content);
95
+ $content = str_replace('<link ', PHP_EOL . '<link ', $content);
96
+ $content = str_replace('<style', PHP_EOL . '<style', $content);
97
+ $content = str_replace('<noscript', PHP_EOL . '<noscript>', $content);
98
 
99
+ # replace markers for scripts last
100
+ if(is_array($skp) && isset($skp[0]) && count($skp[0]) > 0) {
101
+ foreach ($skp[0] as $k=>$v) {
102
+ $content = str_replace('<!-- SKIP '.$k.' -->', PHP_EOL . $v . PHP_EOL, $content);
 
 
 
 
103
  }
104
  }
105
+
106
+ # no empty lines
107
+ $lines = explode(PHP_EOL, $content);
108
+ foreach($lines as $k=>$ln) { $ln = ltrim($ln); if(empty($ln)) { unset($lines[$k]); } else { $lines[$k] = $ln; } }
109
+ $content = implode(PHP_EOL, $lines);
 
 
 
 
 
 
110
 
111
  # save as html, if not empty
112
  if(!empty($content)) {
readme.txt CHANGED
@@ -1,26 +1,26 @@
1
  === Fast Velocity Minify ===
2
  Contributors: Alignak
3
  Tags: PHP Minify, Lighthouse, GTmetrix, Pingdom, Pagespeed, Merging, Minification, Optimization, Speed, Performance, FVM
4
- Requires at least: 4.7
5
  Requires PHP: 5.6
6
- Stable tag: 3.1.4
7
- Tested up to: 5.6
8
  Text Domain: fast-velocity-minify
9
  License: GPLv3 or later
10
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
11
 
12
- Improve your speed score on GTmetrix, Pingdom Tools and Google PageSpeed Insights by merging and minifying CSS and JavaScript, compressing HTML and a few more speed optimization options.
13
 
14
 
15
  == Description ==
16
- Speed optimization plugin for developers and advanced users. This plugin reduces HTTP requests by merging CSS & JavaScript files. It minifies CSS and JS files with PHP Minify, the same library used on most cache plugins.
17
 
18
- Minification is done on the frontend during the first uncached request. Once the first request is processed, any other pages that require the same set of CSS and JavaScript files, will reuse the same generated file.
19
 
20
  The plugin includes options for developers and advanced users, however the default settings should work just fine for most sites.
21
  Kindly read the HELP section after installing the plugin, about possible issues and how to solve them.
22
 
23
- = Aditional Optimization =
24
 
25
  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.
26
 
@@ -55,6 +55,15 @@ Version 3.0 is a major code rewrite to improve JS and CSS merging, but it requir
55
 
56
  == Changelog ==
57
 
 
 
 
 
 
 
 
 
 
58
  = 3.1.4 [2021.01.11] =
59
  * disable FVM update routines when a user runs wp-cli commands outside of the root directory
60
  * database routine improvements for users with custom table prefixes
1
  === Fast Velocity Minify ===
2
  Contributors: Alignak
3
  Tags: PHP Minify, Lighthouse, GTmetrix, Pingdom, Pagespeed, Merging, Minification, Optimization, Speed, Performance, FVM
4
+ Requires at least: 4.9
5
  Requires PHP: 5.6
6
+ Stable tag: 3.1.5
7
+ Tested up to: 5.7.1
8
  Text Domain: fast-velocity-minify
9
  License: GPLv3 or later
10
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
11
 
12
+ Improve your speed score on GTmetrix, Pingdom Tools and Google PageSpeed Insights by adjusting your CSS and JS files (defer, async, minify, combine, etc), compressing HTML, simplifying fonts and a few more speed optimization options.
13
 
14
 
15
  == Description ==
16
+ Speed optimization plugin for developers and advanced users.
17
 
18
+ Minification is done on the frontend during the first uncached request. Once the first request is processed, any other pages that require the same set of CSS and JS files, will be able to reuse the same generated file.
19
 
20
  The plugin includes options for developers and advanced users, however the default settings should work just fine for most sites.
21
  Kindly read the HELP section after installing the plugin, about possible issues and how to solve them.
22
 
23
+ = Additional Optimization =
24
 
25
  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.
26
 
55
 
56
  == Changelog ==
57
 
58
+ = 3.1.5 [2021.04.24] =
59
+ * added support for WP Cloudflare Super Page Cache plugin
60
+ * fixed support for LiteSpeed Cache purging
61
+ * changed the cache directory to the uploads directory (WP_Filesystem_Direct)
62
+ * deprecated CSS and JS merging as this is no longer recommended for HTTP/2 servers
63
+ * stop removing RSS feeds references on the header cleanup option
64
+ * changed some descriptions and updated the HELP section
65
+ * other bug fixes
66
+
67
  = 3.1.4 [2021.01.11] =
68
  * disable FVM update routines when a user runs wp-cli commands outside of the root directory
69
  * database routine improvements for users with custom table prefixes