<?php

/*

Plugin Name: Fast Velocity Minify

Plugin URI: http://fastvelocity.com

Description: Improve your speed score on GTmetrix, Pingdom Tools and Google PageSpeed Insights by merging and minifying CSS and JavaScript files into groups, compressing HTML and other speed optimizations. 

Author: Raul Peixoto

Author URI: http://fastvelocity.com

Version: 2.8.9

License: GPL2



------------------------------------------------------------------------

This program is free software; you can redistribute it and/or modify

it under the terms of the GNU General Public License as published by

the Free Software Foundation; either version 2 of the License, or

(at your option) any later version.



This program is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

GNU General Public License for more details.



You should have received a copy of the GNU General Public License

along with this program; if not, write to the Free Software

Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/



# check for minimum requirements and prevent activation or disable if not fully compatible

function fvm_compat_checker() {

	global $wp_version; 

	

	# defaults

	$error = '';



	# php version requirements

	if (version_compare( PHP_VERSION, '5.5', '<' )) { 

		$error = 'Fast Velocity Minify requires PHP 5.5 or higher. You’re still on '. PHP_VERSION; 

	}



	# php extension requirements	

	if (!extension_loaded('mbstring')) { 

		$error = 'Fast Velocity Minify requires the PHP mbstring module to be installed on the server.'; 

	}

	

	# wp version requirements

	if ( version_compare( $GLOBALS['wp_version'], '4.5', '<' ) ) {

		$error = 'Fast Velocity Minify requires WP 4.5 or higher. You’re still on ' . $GLOBALS['wp_version']; 

	}

	

	if ((is_plugin_active(plugin_basename( __FILE__ )) && !empty($error)) || !empty($error)) { 

		if (isset($_GET['activate'])) { unset($_GET['activate']); }

			deactivate_plugins( plugin_basename( __FILE__ )); 

			add_action('admin_notices', function() use ($error){ 

				echo '<div class="notice notice-error is-dismissible"><p><strong>'.$error.'</strong></p></div>'; 

			});

	} 

}

add_action('admin_init', 'fvm_compat_checker');





# get plugin version

$fastvelocity_plugin_version_get_data = get_file_data(__FILE__, array('Version' => 'Version'), false);

$fastvelocity_plugin_version = $fastvelocity_plugin_version_get_data['Version'];



# get the plugin directory

$plugindir = plugin_dir_path( __FILE__ ); # prints with trailing slash



# reusable functions

include($plugindir.'inc/functions.php');

include($plugindir.'inc/functions-serverinfo.php');

include($plugindir.'inc/functions-upgrade.php');

include($plugindir.'inc/functions-cache.php');



# wp-cli support

if ( defined( 'WP_CLI' ) && WP_CLI ) { 

	include($plugindir.'inc/functions-cli.php');

}





# get cache directories and urls

$cachepath = fvm_cachepath();

$tmpdir = $cachepath['tmpdir'];

$cachedir =  $cachepath['cachedir'];

$cachedirurl = $cachepath['cachedirurl'];



$wp_home = site_url();   # get the current wordpress installation url

$wp_domain = trim(str_ireplace(array('http://', 'https://'), '', trim($wp_home, '/')));

$wp_home_path = ABSPATH;



# default globals

$fastvelocity_min_global_js_done = array();

$fvm_collect_google_fonts = array();

$collect_preload_css = array();

$collect_preload_js = array();

$fvm_debug = get_option('fastvelocity_fvm_debug');



###########################################

# build control panel pages ###############

###########################################



# options from the database, false if not set

$ignore = array_filter(array_map('trim', explode(PHP_EOL, get_option('fastvelocity_min_ignore', ''))));

$blacklist = array_filter(array_map('trim', explode(PHP_EOL, get_option('fastvelocity_min_blacklist', ''))));

$ignorelist = array_filter(array_map('trim', explode(PHP_EOL, get_option('fastvelocity_min_ignorelist', ''))));

$fvm_min_excludecsslist = array_filter(array_map('trim', explode(PHP_EOL, get_option('fastvelocity_min_excludecsslist', ''))));

$fvm_min_excludejslist = array_filter(array_map('trim', explode(PHP_EOL, get_option('fastvelocity_min_excludejslist', ''))));



$fvm_enable_purgemenu = get_option('fastvelocity_min_enable_purgemenu');

$default_protocol = get_option('fastvelocity_min_default_protocol', 'dynamic');

$disable_js_merge = get_option('fastvelocity_min_disable_js_merge');

$disable_css_merge = get_option('fastvelocity_min_disable_css_merge');

$disable_js_minification = get_option('fastvelocity_min_disable_js_minification');

$disable_css_minification = get_option('fastvelocity_min_disable_css_minification');

$remove_print_mediatypes = get_option('fastvelocity_min_remove_print_mediatypes'); 

$skip_html_minification = get_option('fastvelocity_min_skip_html_minification');

$strip_htmlcomments = get_option('fastvelocity_min_strip_htmlcomments');

$skip_cssorder = get_option('fastvelocity_min_skip_cssorder');

$skip_google_fonts = get_option('fastvelocity_min_skip_google_fonts');

$skip_emoji_removal = get_option('fastvelocity_min_skip_emoji_removal');

$fvm_clean_header_one = get_option('fastvelocity_fvm_clean_header_one');

$enable_defer_js = get_option('fastvelocity_min_enable_defer_js');

$exclude_defer_jquery = get_option('fastvelocity_min_exclude_defer_jquery');

$force_inline_css = get_option('fastvelocity_min_force_inline_css');

$force_inline_css_footer = get_option('fastvelocity_min_force_inline_css_footer');

$remove_googlefonts = get_option('fastvelocity_min_remove_googlefonts');

$defer_for_pagespeed = get_option('fastvelocity_min_defer_for_pagespeed');

$defer_for_pagespeed_optimize = get_option('fastvelocity_min_defer_for_pagespeed_optimize');

$exclude_defer_login = get_option('fastvelocity_min_exclude_defer_login');

$skip_defer_lists = get_option('fastvelocity_min_skip_defer_lists');

$fvm_fix_editor = get_option('fastvelocity_min_fvm_fix_editor');

$fvmloadcss = get_option('fastvelocity_min_loadcss');

$fvm_remove_css = get_option('fastvelocity_min_fvm_removecss');

$fvm_cdn_url = get_option('fastvelocity_min_fvm_cdn_url');

$fvm_enabled_css_preload = get_option('fastvelocity_enabled_css_preload');

$fvm_enabled_js_preload = get_option('fastvelocity_enabled_css_preload');

$fvm_fawesome_method = get_option("fastvelocity_fontawesome_method");



# default options

$used_css_files = array();

$force_inline_googlefonts = true;

$min_async_googlefonts = false;

$css_hide_googlefonts = false;





# define google fonts options based on a radio form

$fvm_gfonts_method = get_option("fastvelocity_gfonts_method");

if($fvm_gfonts_method != false) {

	if($fvm_gfonts_method == 2) { # load Async

		$force_inline_googlefonts = false;

		$min_async_googlefonts = true;

		$css_hide_googlefonts = false;

	} 

	if($fvm_gfonts_method == 3) { # hide from PSI

		$force_inline_googlefonts = false;

		$min_async_googlefonts = false;

		$css_hide_googlefonts = true;

	}

}





# default ua list

$fvmualist = array('x11.*fox\/54', 'oid\s4.*xus.*ome\/62', 'oobot', 'ighth', 'tmetr', 'eadles', 'ingdo');



# header and footer markers

add_action('wp_head','fastvelocity_add_fvmuag', -PHP_INT_MAX);

function fastvelocity_add_fvmuag() {

	global $fvmualist;

	if(!fastvelocity_exclude_contents() || fastvelocity_load_fvuag()) {

		echo '<script>'.fastvelocity_get_fvmuag($fvmualist).'</script>';

	}

}



# generate fvmuag js function

function fastvelocity_get_fvmuag($fvmualist) {

	return 'function fvmuag(){if(navigator.userAgent.match(/'.implode('|', $fvmualist).'/i))return!1;if(navigator.userAgent.match(/x11.*ome\/75\.0\.3770\.100/i)){var e=screen.width,t=screen.height;if("number"==typeof e&&"number"==typeof t&&862==t&&1367==e)return!1}return!0}';

}







# add admin page and rewrite defaults

if(is_admin()) {

    add_action('admin_menu', 'fastvelocity_min_admin_menu');

    add_action('admin_enqueue_scripts', 'fastvelocity_min_load_admin_jscss');

    add_action('wp_ajax_fastvelocity_min_files', 'fastvelocity_min_files_callback');

    add_action('admin_init', 'fastvelocity_min_register_settings');

    

	# This function runs when WordPress updates or installs/remove something

	add_action('upgrader_process_complete', 'fastvelocity_purge_all_global');

	add_action('after_switch_theme', 'fastvelocity_purge_all_global');

	add_action('admin_init', 'fastvelocity_purge_onsave', 1);

	

	# activation, deactivation

	register_activation_hook( __FILE__, 'fastvelocity_plugin_activate' );

	register_deactivation_hook( __FILE__, 'fastvelocity_plugin_deactivate');

	register_uninstall_hook( __FILE__, 'fastvelocity_plugin_uninstall');

	

} else {

	add_action('setup_theme', 'fastvelocity_process_frontend' );

}



function fastvelocity_process_frontend() {

	global $disable_js_merge, $disable_css_merge, $force_inline_css, $skip_emoji_removal, $fvm_clean_header_one, $skip_html_minification, $fvmloadcss, $fvm_fawesome_method, $fvm_gfonts_method;

	

	# skip on certain post_types or if there are specific keys on the url or if editor or admin

	if(!fastvelocity_exclude_contents()) {

	

		# actions for frontend only

		if(!$disable_js_merge) { 

			add_action( 'wp_print_scripts', 'fastvelocity_min_merge_header_scripts', PHP_INT_MAX );

			add_action( 'wp_print_footer_scripts', 'fastvelocity_min_merge_footer_scripts', 9.999999 ); 

		}

		if(!$disable_css_merge) {

			add_action('wp_head', 'fvm_add_criticial_path', 2); 

			

			# merge, if inline is not selected

			if($force_inline_css != true) {

				add_action('wp_print_styles', 'fastvelocity_min_merge_header_css', PHP_INT_MAX ); 

				add_action('wp_print_footer_scripts', 'fastvelocity_min_merge_footer_css', 9.999999 );

			} else {

				add_filter('style_loader_tag', 'fastvelocity_optimizecss', PHP_INT_MAX, 4 );

				add_action('wp_print_styles','fastvelocity_add_google_fonts_merged', PHP_INT_MAX);

				add_action('wp_print_footer_scripts','fastvelocity_add_google_fonts_merged', PHP_INT_MAX );

			}

			

		}

		if(!$skip_emoji_removal) { 

			add_action( 'init', 'fastvelocity_min_disable_wp_emojicons' );

			add_filter( 'tiny_mce_plugins', 'fastvelocity_disable_emojis_tinymce' );

		}

		

		if($fvm_clean_header_one) { 

			# no resource hints, generator tag, shortlinks, manifest link, etc

			remove_action('wp_head', 'wp_resource_hints', 2);

			remove_action('wp_head', 'wp_generator');

			remove_action('template_redirect', 'wp_shortlink_header', 11);

			remove_action('wp_head', 'wlwmanifest_link');

			remove_action('wp_head', 'rsd_link');

			remove_action('wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0);

			remove_action('wp_head','feed_links', 2);

			remove_action('wp_head','feed_links_extra', 3);

			add_filter('after_setup_theme', 'fastvelocity_remove_redundant_shortlink');

		}

		

		# enable html minification

		if(!$skip_html_minification && !is_admin()) {

			add_action('template_redirect', 'fastvelocity_min_html_compression_start', PHP_INT_MAX);

		}

		

		# add the LoadCSS polyfil

		if($fvmloadcss || $fvm_fawesome_method == 2 || $fvm_gfonts_method == 2) {

			add_action('wp_footer', 'fvm_add_loadcss', PHP_INT_MAX);

		}

		

		# add the LoadAsync JavaScript function

		add_action('wp_head', 'fvm_add_loadasync', 0); 

		

		# remove query from static assets and process defering (if enabled)

		add_filter('style_loader_src', 'fastvelocity_remove_cssjs_ver', 10, 2);

		add_filter('script_loader_tag', 'fastvelocity_min_defer_js', 10, 3); 

		

		# headers

		add_action( 'send_headers', 'fvm_extra_preload_headers' );

		add_action( 'wp_footer', 'fastvelocity_generate_preload_headers', PHP_INT_MAX);

		add_filter( 'script_loader_tag', 'fastvelocity_collect_js_preload_headers', PHP_INT_MAX, 3 );



	}

}



# exclude processing for editors and administrators (fix editors)

add_action( 'plugins_loaded', 'fastvelocity_fix_editor' );

function fastvelocity_fix_editor() {

global $fvm_fix_editor;

	if($fvm_fix_editor == true && is_user_logged_in()) {

		remove_action('setup_theme', 'fastvelocity_process_frontend' );

	} 

}



# create admin menu

function fastvelocity_min_admin_menu() {

add_options_page('Fast Velocity Minify Settings', 'Fast Velocity Minify', 'manage_options', 'fastvelocity-min', 'fastvelocity_min_settings');

}





# add admin toolbar

if($fvm_enable_purgemenu == true) {

	add_action( 'admin_bar_menu', 'fastvelocity_admintoolbar', 100 );

}



# admin toolbar processing

function fastvelocity_admintoolbar() {

	if(current_user_can('manage_options')) {

		global $wp_admin_bar;



		# Create or add new items into the Admin Toolbar.

		$wp_admin_bar->add_node(array(

			'id'    => 'fvm',

			'title' => '<span class="ab-icon"></span><span class="ab-label">' . __("FVM Purge",'fvm') . '</span>',

			'href'  => wp_nonce_url( add_query_arg('_fvmcache', 'clear'), 'fvm_clear_nonce')

		));



	}

}





# function to list all cache files

function fastvelocity_min_files_callback() {

	

	# must be able to cleanup cache

	if (!current_user_can('manage_options')) {

		wp_die( __('You do not have sufficient permissions to access this page.')); 

	}

		

	global $cachedir;

	

	# default

	$size = fastvelocity_get_cachestats();

	$return = array('js' => array(), 'css' => array(), 'cachesize'=> $size);

	

	# inspect directory with opendir, since glob might not be available in some systems

	clearstatcache();

	if ($handle = opendir($cachedir.fastvelocity_get_os_slash())) {

		while (false !== ($file = readdir($handle))) {

			$file = $cachedir.fastvelocity_get_os_slash().$file;

			$ext = pathinfo($file, PATHINFO_EXTENSION);

			if (in_array($ext, array('js', 'css'))) {

				$log = ''; if (file_exists($file.'.txt')) { $log = file_get_contents($file.'.txt'); }

				$mincss = substr($file, 0, -4).'.min.css';

				$minjs = substr($file, 0, -3).'.min.js';

				$filename = basename($file);

				if ($ext == 'css' && file_exists($mincss)) { $filename = basename($mincss); }

				if ($ext == 'js' && file_exists($minjs)) { $filename = basename($minjs); }

				$fsize = fastvelocity_format_filesize(filesize($file));

				$uid = hash('sha1', $filename);

				array_push($return[$ext], array('uid'=>$uid, 'filename' => $filename, 'log' => $log, 'fsize' => $fsize));

			}

		}

	closedir($handle);

	}

	

	header('Content-Type: application/json');

	echo json_encode($return);

	wp_die();

}





# load wp-admin css and js files

function fastvelocity_min_load_admin_jscss($hook) {

	if ('settings_page_fastvelocity-min' != $hook) { return; }

	wp_enqueue_script('postbox');

    wp_enqueue_style('fastvelocity-min', plugins_url('fvm.css', __FILE__), array(), filemtime(plugin_dir_path( __FILE__).'fvm.css'));

    wp_enqueue_script('fastvelocity-min', plugins_url('fvm.js', __FILE__), array('jquery'), filemtime(plugin_dir_path( __FILE__).'fvm.js'), true);

}





# register plugin settings

function fastvelocity_min_register_settings() {

    register_setting('fvm-group', 'fastvelocity_min_enable_purgemenu');

	register_setting('fvm-group', 'fastvelocity_preserve_settings_on_uninstall');

	register_setting('fvm-group', 'fastvelocity_min_default_protocol');

    register_setting('fvm-group', 'fastvelocity_min_disable_js_merge');

    register_setting('fvm-group', 'fastvelocity_min_disable_css_merge');

    register_setting('fvm-group', 'fastvelocity_min_disable_js_minification');

    register_setting('fvm-group', 'fastvelocity_min_disable_css_minification');

    register_setting('fvm-group', 'fastvelocity_min_remove_print_mediatypes');

    register_setting('fvm-group', 'fastvelocity_min_skip_html_minification');

	register_setting('fvm-group', 'fastvelocity_min_strip_htmlcomments');

	register_setting('fvm-group', 'fastvelocity_min_skip_cssorder');

	register_setting('fvm-group', 'fastvelocity_min_skip_google_fonts');

	register_setting('fvm-group', 'fastvelocity_min_skip_fontawesome_fonts');

	register_setting('fvm-group', 'fastvelocity_min_skip_emoji_removal');

	register_setting('fvm-group', 'fastvelocity_fvm_clean_header_one');

	register_setting('fvm-group', 'fastvelocity_min_enable_defer_js');

	register_setting('fvm-group', 'fastvelocity_min_exclude_defer_jquery');

	register_setting('fvm-group', 'fastvelocity_min_force_inline_css');

	register_setting('fvm-group', 'fastvelocity_min_force_inline_css_footer');

	register_setting('fvm-group', 'fastvelocity_min_remove_googlefonts');

	register_setting('fvm-group', 'fastvelocity_gfonts_method');

	register_setting('fvm-group', 'fastvelocity_fontawesome_method');

	register_setting('fvm-group', 'fastvelocity_min_defer_for_pagespeed');

	register_setting('fvm-group', 'fastvelocity_min_defer_for_pagespeed_optimize');

	register_setting('fvm-group', 'fastvelocity_min_exclude_defer_login');

	register_setting('fvm-group', 'fastvelocity_min_skip_defer_lists');

	register_setting('fvm-group', 'fastvelocity_min_fvm_fix_editor');

	register_setting('fvm-group', 'fastvelocity_min_fvm_cdn_url');

	register_setting('fvm-group', 'fastvelocity_min_fvm_cdn_force');

	register_setting('fvm-group', 'fastvelocity_min_change_cache_base_url');

	register_setting('fvm-group', 'fastvelocity_min_change_cache_path');



	# pro tab

	register_setting('fvm-group-pro', 'fastvelocity_min_ignore');

    register_setting('fvm-group-pro', 'fastvelocity_min_ignorelist');

	register_setting('fvm-group-pro', 'fastvelocity_min_excludecsslist');

	register_setting('fvm-group-pro', 'fastvelocity_min_excludejslist');

    register_setting('fvm-group-pro', 'fastvelocity_min_blacklist');

    register_setting('fvm-group-pro', 'fastvelocity_min_merge_allowed_urls');

	

	# dev tab

	register_setting('fvm-group-dev', 'fastvelocity_fvm_debug');

	register_setting('fvm-group-dev', 'fastvelocity_enabled_css_preload');

	register_setting('fvm-group-dev', 'fastvelocity_enabled_js_preload');

	register_setting('fvm-group-dev', 'fastvelocity_min_hpreload');

	register_setting('fvm-group-dev', 'fastvelocity_min_hpreconnect');

	register_setting('fvm-group-dev', 'fastvelocity_min_loadcss');

	register_setting('fvm-group-dev', 'fastvelocity_min_fvm_removecss');

	register_setting('fvm-group-dev', 'fastvelocity_min_critical_path_css');

	register_setting('fvm-group-dev', 'fastvelocity_min_critical_path_css_is_front_page');

	

	

	

}







# add settings link on plugin page

function fastvelocity_min_settings_link($links) {

	if (is_plugin_active(plugin_basename( __FILE__ ))) { 

		$settings_link = '<a href="options-general.php?page=fastvelocity-min&tab=set">Settings</a>'; 

		array_unshift($links, $settings_link); 

	}

return $links;

}

add_filter("plugin_action_links_".plugin_basename(__FILE__), 'fastvelocity_min_settings_link' );





# purge all caches by request

add_action('init','fastvelocity_process_cache_purge_request');

function fastvelocity_process_cache_purge_request(){

	if((isset($_POST['purgeall']) && $_POST['purgeall'] == 1) || isset($_GET['_fvmcache'])) {

		

		# must be able to cleanup cache

		if (!current_user_can('manage_options')) { wp_die( __('You do not have sufficient permissions to access this page.')); }

		

		# validate nonce

		if(empty($_GET['_wpnonce']) || !wp_verify_nonce($_GET['_wpnonce'], 'fvm_clear_nonce')) {

			wp_die( __('Invalid or expired request... please go back and refresh before trying again!'));

		}

		

		if(is_admin()) {

			fvm_purge_all(); # purge all

			$others = fvm_purge_others(); # purge third party caches

			$notice = array('All caches from <strong>FVM</strong> have been purged!', strip_tags($others, '<strong>'));

			$notice = array_filter($notice);

			$notice = json_encode($notice); # encode

			set_transient( 'wordpress_fvmcache', $notice, 10);

			wp_safe_redirect(remove_query_arg('_wpnonce', remove_query_arg('_fvmcache', wp_get_referer())));

		} else {

			fvm_purge_all(); # purge all

			fvm_purge_others(); # purge third party caches

			wp_safe_redirect(remove_query_arg('_wpnonce', remove_query_arg('_fvmcache', wp_get_referer())));

		}

	}

}



# print admin notices after purging caches, if on wp-admin

add_action( 'admin_notices', 'fastvelocity_cachepurge_admin_notices' );

function fastvelocity_cachepurge_admin_notices() {

	

	# skip on submit

	if((isset($_POST['purgeall']) && $_POST['purgeall'] == 1) || isset($_GET['_fvmcache'])) {

		return true;

	}



	# cache purge notices

	$inf = get_transient('wordpress_fvmcache');

	if($inf != false && !empty($inf)) {

			

		# decode to array or null

		$jsonarr = json_decode($inf, true);

		if(!is_null($jsonarr) && is_array($jsonarr)){

			

			# print notices

			foreach ($jsonarr as $notice) {

				echo  __('<div class="notice notice-success is-dismissible"><p>'.$notice.'</p></div>');

			}

		}

		

		# remove

		delete_transient('wordpress_fvmcache');

	}

}





# print admin notices if we don't have enough file permissions to write

add_action( 'admin_notices', 'fastvelocity_check_permissions_admin_notices' );

function fastvelocity_check_permissions_admin_notices() {

	

	# get cache path

	$cachepath = fvm_cachepath();

	$cachebase = $cachepath['cachebase'];

	if(is_dir($cachebase) && !is_writable($cachebase)) {

		$chmod = substr(sprintf('%o', fileperms($cachebase)), -4);

		echo  __('<div class="notice notice-error is-dismissible"><p>FVM needs writting permissions on '.$cachebase.'</p></div>');

		echo  __('<div class="notice notice-error is-dismissible"><p>The current permissions for FVM are chmod '.$chmod.'</p></div>');

		echo  __('<div class="notice notice-error is-dismissible"><p>If you need something higher than 755 for it to work, your server is probaly misconfigured. Please contact your hosting provider or check the help section for other providers.</p></div>');

	}



}





# manage settings page

function fastvelocity_min_settings() {

if (!current_user_can('manage_options')) { wp_die( __('You do not have sufficient permissions to access this page.')); }



# tmp folder

global $tmpdir, $cachedir, $plugindir;



# get active tab, set default

$active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'status';



?>

<div class="wrap">

<h1>Fast Velocity Minify</h1>



<h2 class="nav-tab-wrapper wp-clearfix">

    <a href="?page=fastvelocity-min&tab=status" class="nav-tab <?php echo $active_tab == 'status' ? 'nav-tab-active' : ''; ?>">Status</a> 

    <a href="?page=fastvelocity-min&tab=set" class="nav-tab <?php echo $active_tab == 'set' ? 'nav-tab-active' : ''; ?>">Settings</a>

	<a href="?page=fastvelocity-min&tab=pro" class="nav-tab <?php echo $active_tab == 'pro' ? 'nav-tab-active' : ''; ?>">Pro</a>

	<a href="?page=fastvelocity-min&tab=dev" class="nav-tab <?php echo $active_tab == 'dev' ? 'nav-tab-active' : ''; ?>">Developers</a>

	<a href="?page=fastvelocity-min&tab=server" class="nav-tab <?php echo $active_tab == 'server' ? 'nav-tab-active' : ''; ?>">Server Info</a>

	<a href="?page=fastvelocity-min&tab=help" class="nav-tab <?php echo $active_tab == 'help' ? 'nav-tab-active' : ''; ?>">Help</a>

</h2>





<?php if( $active_tab == 'status' ) { ?>



<div id="fastvelocity-min">

    <div id="poststuff">

        <div id="fastvelocity_min_processed" class="postbox-container">

			<div class="meta-box">

			

				<div class="postbox" id="tab-purge">

                    <h3 class="hndle"><span>Purge the cache files </span></h3>

                    <div class="inside" id="fastvelocity_min_topbtns">

                        <ul class="processed">

						<li id="purgeall-row">

							<span class="filename">Purge FVM cache (<span id="fvm_cache_size"><?php echo fastvelocity_get_cachestats(); ?></span>)</span> 

							<span class="actions">

							<form method="post" id="fastvelocity_min_clearall" action="<?php echo wp_nonce_url( add_query_arg('_fvmcache', 'clear'), 'fvm_clear_nonce'); ?>">

							<input type="hidden" name="purgeall" value="1" />

							<?php submit_button('Delete', 'button-secondary', 'submit', false); ?>

							</form>

						</li>

						</ul>

                    </div>

                </div>				

			

                <div class="postbox" id="tab-js">

                    <h3 class="hndle"><span>List of processed JS files</span></h3>

                    <div class="inside" id="fastvelocity_min_jsprocessed">

					<ul class="processed"></ul>

                    </div>

                </div>



                <div class="postbox" id="tab-css">

                    <h3 class="hndle"><span>List of processed CSS files</span></h3>

                    <div class="inside" id="fastvelocity_min_cssprocessed">

						<?php

							$force_inline_css = get_option('fastvelocity_min_force_inline_css');

							if($force_inline_css != false) {

								echo '<p>There are no merged CSS files listed here, because you are inlining all CSS directly.</p>';

							} else { 

								echo '<ul class="processed"></ul>'; 

							}

						?>

                        

                    </div>

                </div>

					

            </div>

        </div>

    </div>

</div>

<?php } ?>



<?php if( $active_tab == 'set' ) { ?>

<form method="post" action="options.php">

<?php settings_fields('fvm-group'); do_settings_sections('fvm-group'); ?>





<div style="height: 20px;"></div>

<h2 class="title">Basic Settings</h2>

<p class="fvm-bold-green">These options are generaly safe to edit as needed. If you use a cache plugin, kindly purge all your caches once you're done with the changes.</p>



<table class="form-table fvm-settings">

<tbody>





<tr>

<th scope="row">Functionality</th>

<td>

<p class="fvm-bold-green fvm-rowintro">The HTML minification is ON by default, but you can:</p>



<fieldset>

<label for="fastvelocity_min_enable_purgemenu">

<input name="fastvelocity_min_enable_purgemenu" type="checkbox" id="fastvelocity_min_enable_purgemenu" value="1" <?php echo checked(1 == get_option('fastvelocity_min_enable_purgemenu'), true, false); ?>>

Admin Bar Purge <span class="note-info">[ If selected, a new option to purge FVM cache from the admin bar will show up ]</span></label>

<br />



<label for="fastvelocity_preserve_settings_on_uninstall">

<input name="fastvelocity_preserve_settings_on_uninstall" type="checkbox" id="fastvelocity_preserve_settings_on_uninstall" value="1" <?php echo checked(1 == get_option('fastvelocity_preserve_settings_on_uninstall'), true, false); ?>>

Preserve Settings<span class="note-info">[ If selected, all FVM settings will be preserved, even if you uninstall the plugin ]</span></label>

<br />



<label for="fastvelocity_min_fvm_fix_editor">

<input name="fastvelocity_min_fvm_fix_editor" type="checkbox" id="fastvelocity_min_fvm_fix_editor" value="1" <?php echo checked(1 == get_option('fastvelocity_min_fvm_fix_editor'), true, false); ?>>

Fix Page Editors <span class="note-info">[ Will disable merging of JS and CSS for logged in users, to improve compatibility with visual editors ]</span></label>

<br />



</fieldset></td>

</tr>





<tr>

<th scope="row">URL Options</th>

<td>

<?php 

# what to select

$sel = get_option('fastvelocity_min_default_protocol');

$a = ''; if($sel == 'dynamic' || empty($sel)) { $a = ' checked="checked"'; }

$b = ''; if($sel == 'http') { $b = ' checked="checked"'; }

$c = ''; if($sel == 'https') { $c = ' checked="checked"'; }

?>

<p class="fvm-bold-green fvm-rowintro">You may need to force http or https, for some CDN plugins to work:</p>

<fieldset>

	<label><input type="radio" name="fastvelocity_min_default_protocol" value="dynamic" <?php echo $a; ?>> Auto Detect </label><br>

	<label><input type="radio" name="fastvelocity_min_default_protocol" value="http"<?php echo $b; ?>> Force HTTP urls (if you don't have SSL)</label><br>

	<label><input type="radio" name="fastvelocity_min_default_protocol" value="https"<?php echo $c; ?>> Force HTTPS urls (recommended if you have SSL)</span></label><br>

</fieldset>

</td>

</tr>



<tr>

<th scope="row">HTML Options</th>

<td>

<p class="fvm-bold-green fvm-rowintro">The HTML minification is ON by default, but you can:</p>



<fieldset>

<label for="fastvelocity_min_skip_html_minification">

<input name="fastvelocity_min_skip_html_minification" type="checkbox" id="fastvelocity_min_skip_html_minification" value="1" <?php echo checked(1 == get_option('fastvelocity_min_skip_html_minification'), true, false); ?>>

Disable HTML Minification <span class="note-info">[ This will disable HTML minification ]</span></label>

<br />



<label for="fastvelocity_min_strip_htmlcomments">

<input name="fastvelocity_min_strip_htmlcomments" type="checkbox" id="fastvelocity_min_strip_htmlcomments" value="1" <?php echo checked(1 == get_option('fastvelocity_min_strip_htmlcomments'), true, false); ?>>

Strip HTML comments <span class="note-info">[ Only works with the default HTML minification, but note that some plugins need HTML comments to work properly ]</span></label>

<br />



<label for="fastvelocity_fvm_clean_header_one">

<input name="fastvelocity_fvm_clean_header_one" type="checkbox" id="fastvelocity_fvm_clean_header_one" value="1" <?php echo checked(1 == get_option('fastvelocity_fvm_clean_header_one'), true, false); ?>>

Cleanup Header <span class="note-info">[ Remove resource hints, generator tag, shortlinks, manifest link, etc ]</span></label>

<br />



</fieldset></td>

</tr>





<tr>

<th scope="row">Font Options</th>

<td>

<p class="fvm-bold-green fvm-rowintro">The default options are usually good for performance.</p>

<fieldset>

<label for="fastvelocity_min_skip_emoji_removal">

<input name="fastvelocity_min_skip_emoji_removal" type="checkbox" id="fastvelocity_min_skip_emoji_removal" class="jsprocessor" value="1" <?php echo checked(1 == get_option('fastvelocity_min_skip_emoji_removal'), true, false); ?> >

Stop removing Emojis and smileys <span class="note-info">[ If selected, Emojis will be left alone and won't be removed from wordpress ]</span></label>

<br />



<label for="fastvelocity_min_skip_google_fonts">

<input name="fastvelocity_min_skip_google_fonts" type="checkbox" id="fastvelocity_min_skip_google_fonts" value="1" <?php echo checked(1 == get_option('fastvelocity_min_skip_google_fonts'), true, false); ?> >

Disable Google Fonts merging <span class="note-info">[ If selected, Google Fonts will no longer be merged into one request ]</span></label>

<br />



<label for="fastvelocity_min_remove_googlefonts">

<input name="fastvelocity_min_remove_googlefonts" type="checkbox" id="fastvelocity_min_remove_googlefonts" value="1" <?php echo checked(1 == get_option('fastvelocity_min_remove_googlefonts'), true, false); ?> >

Remove Google Fonts completely <span class="note-info">[ If selected, all enqueued Google Fonts will be removed from the site ]</span></label>

<br />



</fieldset></td>

</tr>





<tr>

<th scope="row">Google Fonts</th>

<td>

<?php 

# what to select

$sel = get_option('fastvelocity_gfonts_method');

$a = ''; if($sel == 1 || empty($sel)) { $a = ' checked="checked"'; }

$b = ''; if($sel == 2) { $b = ' checked="checked"'; }

$c = ''; if($sel == 3) { $c = ' checked="checked"'; }

?>

<p class="fvm-bold-green fvm-rowintro">Choose how to include Google Fonts on your pages, when available:</p>

<fieldset>

	<label><input type="radio" name="fastvelocity_gfonts_method" value="1" <?php echo $a; ?>> Inline Google Fonts CSS</label> <span class="note-info">[ Will inline the <a target="_blank" href="https://caniuse.com/#feat=woff">woof</a> format only (with font hinting) ]</span><br>

	<label><input type="radio" name="fastvelocity_gfonts_method" value="2"<?php echo $b; ?>> Async Google Fonts CSS files</label> <span class="note-info">[ Will use <a target="_blank" href="https://caniuse.com/#feat=link-rel-preload">preload</a> with <a href="https://github.com/filamentgroup/loadCSS">LoadCSS</a> polyfill ]</span><br>

	<label><input type="radio" name="fastvelocity_gfonts_method" value="3"<?php echo $c; ?>> Async and exclude Google Fonts CSS from PSI</label> <span class="note-info">[ Will use JavaScript to load the fonts conditionally ] </span><br>

</fieldset>

</td>

</tr>



<tr>

<th scope="row">Font Awesome</th>

<td>

<?php 

# what to select

$sel = get_option('fastvelocity_fontawesome_method');

$a = ''; if($sel == 1 || empty($sel)) { $a = ' checked="checked"'; }

$b = ''; if($sel == 2) { $b = ' checked="checked"'; }

$c = ''; if($sel == 3) { $c = ' checked="checked"'; }

?>

<p class="fvm-bold-green fvm-rowintro">Only if available and if it has "font-awesome" in the url:</p>

<fieldset>

	<label><input type="radio" name="fastvelocity_fontawesome_method" value="1" <?php echo $a; ?>> Merge or Inline Font Awesome CSS</label> <span class="note-info">[ Depends on if you have the Inline CSS option enabled or not ]</span><br>

	<label><input type="radio" name="fastvelocity_fontawesome_method" value="2"<?php echo $b; ?>> Async Font Awesome CSS file</label> <span class="note-info">[ Will use <a target="_blank" href="https://caniuse.com/#feat=link-rel-preload">preload</a> with <a href="https://github.com/filamentgroup/loadCSS">LoadCSS</a> polyfill ]</span><br>

	<label><input type="radio" name="fastvelocity_fontawesome_method" value="3"<?php echo $c; ?>> Async and exclude Font Awesome CSS from PSI</label> <span class="note-info">[ Will use JavaScript to load the fonts conditionally ] </span><br>

</fieldset>

</td>

</tr>





<tr>

<th scope="row">CSS Options</th>

<td>

<p class="fvm-bold-green fvm-rowintro">It's recommended that you Inline all CSS files, if they are small enough.</p>



<fieldset>

<label for="fastvelocity_min_disable_css_merge">

<input name="fastvelocity_min_disable_css_merge" type="checkbox" id="fastvelocity_min_disable_css_merge" value="1" <?php echo checked(1 == get_option('fastvelocity_min_disable_css_merge'), true, false); ?>>

Disable CSS processing<span class="note-info">[ If selected, this plugin will ignore CSS files completely ]</span></label>

<br />

<label for="fastvelocity_min_disable_css_minification">

<input name="fastvelocity_min_disable_css_minification" type="checkbox" id="fastvelocity_min_disable_css_minification" value="1" <?php echo checked(1 == get_option('fastvelocity_min_disable_css_minification'), true, false); ?>>

Disable minification on CSS files <span class="note-info">[ If selected, CSS files will be merged but not minified ]</span></label>

<br />

<label for="fastvelocity_min_skip_cssorder">

<input name="fastvelocity_min_skip_cssorder" type="checkbox" id="fastvelocity_min_skip_cssorder" value="1" <?php echo checked(1 == get_option('fastvelocity_min_skip_cssorder'), true, false); ?> >

Preserve the order of CSS files <span class="note-info">[ If selected, you will have better CSS compatibility when merging but possibly more CSS files ]</span></label>

<br />

<label for="fastvelocity_min_remove_print_mediatypes">

<input name="fastvelocity_min_remove_print_mediatypes" type="checkbox" id="fastvelocity_min_remove_print_mediatypes" value="1" <?php echo checked(1 == get_option('fastvelocity_min_remove_print_mediatypes'), true, false); ?> >

Disable the "Print" related stylesheets <span class="note-info">[ If selected, CSS files of mediatype "print" will be removed from the site ]</span></label>

<br />

<label for="fastvelocity_min_force_inline_css_footer">

<input name="fastvelocity_min_force_inline_css_footer" type="checkbox" id="fastvelocity_min_force_inline_css_footer" value="1" <?php echo checked(1 == get_option('fastvelocity_min_force_inline_css_footer'), true, false); ?>>

Inline CSS in the footer <span class="note-info">[ If selected, any FVM generated CSS files in the footer, will be inlined ]</span></label>

<br />

<label for="fastvelocity_min_force_inline_css">

<input name="fastvelocity_min_force_inline_css" type="checkbox" id="fastvelocity_min_force_inline_css" value="1" <?php echo checked(1 == get_option('fastvelocity_min_force_inline_css'), true, false); ?>>

Inline CSS both in the header and footer <span class="note-info">[ If selected, any FVM generated CSS files (header + footer) will be inlined ]</span></label>

<br />

</fieldset></td>

</tr>





<tr>

<th scope="row">JavaScript Options</th>

<td>

<p class="fvm-bold-green fvm-rowintro">Try to disable minification (and purge the cache) first, if you have trouble with JavaScript in the frontend.</p>

<fieldset>

<label for="fastvelocity_min_disable_js_merge">

<input name="fastvelocity_min_disable_js_merge" type="checkbox" id="fastvelocity_min_disable_js_merge" value="1" <?php echo checked(1 == get_option('fastvelocity_min_disable_js_merge'), true, false); ?> >

Disable JavaScript processing <span class="note-info">[ If selected, this plugin will ignore JS files completely ]</span></label>

<br />



<label for="fastvelocity_min_disable_js_minification">

<input name="fastvelocity_min_disable_js_minification" type="checkbox" id="fastvelocity_min_disable_js_minification" value="1" <?php echo checked(1 == get_option('fastvelocity_min_disable_js_minification'), true, false); ?> >

Disable minification on JS files <span class="note-info">[ If selected, JS files will be merged but not minified ]</span></label>

<br />

</fieldset></td>

</tr>



<tr>

<th scope="row">Render-blocking JS</th>

<td>

<fieldset><legend class="screen-reader-text"><span>Render-blocking</span></legend>



<p class="fvm-bold-green fvm-rowintro">Some themes and plugins "need" render blocking scripts to work, so please take a look at the dev console for errors.</p>

<label for="fastvelocity_min_enable_defer_js">

<input name="fastvelocity_min_enable_defer_js" type="checkbox" id="fastvelocity_min_enable_defer_js" value="1" <?php echo checked(1 == get_option('fastvelocity_min_enable_defer_js'), true, false); ?>>

Enable defer parsing of FVM JS files globally <span class="note-info">[ Not all browsers, themes or plugins support this. Beware of broken functionality and design ]</span></label>

<br />



<label for="fastvelocity_min_exclude_defer_jquery">

<input name="fastvelocity_min_exclude_defer_jquery" type="checkbox" id="fastvelocity_min_exclude_defer_jquery" value="1" <?php echo checked(1 == get_option('fastvelocity_min_exclude_defer_jquery'), true, false); ?> >

Skip deferring the jQuery library <span class="note-info">[ Will probably fix "undefined jQuery" errors on the Google Chrome console log ]</span></label>

<br />

<label for="fastvelocity_min_exclude_defer_login">

<input name="fastvelocity_min_exclude_defer_login" type="checkbox" id="fastvelocity_min_exclude_defer_login" value="1" <?php echo checked(1 == get_option('fastvelocity_min_exclude_defer_login'), true, false); ?> >

Skip deferring JS on the login page <span class="note-info">[ If selected, will disable JS deferring on your login page ]</span></label>

<br />

<label for="fastvelocity_min_skip_defer_lists">

<input name="fastvelocity_min_skip_defer_lists" type="checkbox" id="fastvelocity_min_skip_defer_lists" value="1" <?php echo checked(1 == get_option('fastvelocity_min_skip_defer_lists'), true, false); ?> >

Skip deferring the ignore list <span class="note-info">[ If selected, files on the blacklist, ignore list, etc, won't be deferred ]</span></label>

<br />



</fieldset></td>

</tr>



<tr>

<th scope="row">PageSpeed Settings</th>

<td>

<p class="fvm-bold-green fvm-rowintro">Note that this will overwrite any other behaviour defined above and "may" cause errors.</p>

<fieldset>

<label for="fastvelocity_min_defer_for_pagespeed">

<input name="fastvelocity_min_defer_for_pagespeed" type="checkbox" id="fastvelocity_min_defer_for_pagespeed" value="1" <?php echo checked(1 == get_option('fastvelocity_min_defer_for_pagespeed'), true, false); ?>>

Enable defer of all JS files for PSI only <span class="note-info">[ Will use JavaScript to defer all JS files for PSI ]</span></label>



<br />

<label for="fastvelocity_min_defer_for_pagespeed_optimize">

<input name="fastvelocity_min_defer_for_pagespeed_optimize" type="checkbox" id="fastvelocity_min_defer_for_pagespeed_optimize" value="1" <?php echo checked(1 == get_option('fastvelocity_min_defer_for_pagespeed_optimize'), true, false); ?>>

Exclude JS files in the "ignore list" from PSI <span class="note-info">[ This will hide the "ignored files" from PSI instead of simply deferring ]</span></label>



</fieldset></td>

</tr>



</tbody></table>





<div style="height: 20px;"></div>

<h2 class="title">CDN Options</h2>

<p class="fvm-bold-green">When the "Enable defer of JS for Pagespeed Insights" option is enabled, JS and CSS files will not be loaded from the CDN due to <a target="_blank" href="https://www.chromestatus.com/feature/5718547946799104">compatibility</a> reasons.<br />However, you can define a CDN Domain below, in order to use it for all of the static assets "inside" your CSS and JS files.</p>



<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row"><span class="fvm-label-special">Your CDN domain</span></th>

<td><fieldset>

<label for="fastvelocity_min_fvm_cdn_url">

<p><input type="text" name="fastvelocity_min_fvm_cdn_url" id="fastvelocity_min_fvm_cdn_url" value="<?php echo get_option('fastvelocity_min_fvm_cdn_url', ''); ?>" size="80" /></p>

<p class="description">[ Will rewrite the static assets urls inside FVM merged files to your cdn domain. Usage: cdn.example.com ]</p></label>

</fieldset>

</td>

</tr>



<tr>

<th scope="row">Force the CDN Usage</th>

<td>

<p class="fvm-bold-green fvm-rowintro">If you force this, your JS files may not load for certain slow internet users on Google Chrome.</p>

<fieldset>

<label for="fastvelocity_min_fvm_cdn_force">

<input name="fastvelocity_min_fvm_cdn_force" type="checkbox" id="fastvelocity_min_fvm_cdn_force" value="1" <?php echo checked(1 == get_option('fastvelocity_min_fvm_cdn_force'), true, false); ?>>

I know what I'm doing... <span class="note-info">[ Load my JS files from the CDN, even when "defer for Pagespeed Insights" is enabled ]</span></label>

</fieldset></td>

</tr>



</tbody></table>



<div style="height: 20px;"></div>

<h2 class="title">Cache Location</h2>

<p class="fvm-bold-green">If your server blocks JavaScript on the uploads directory, you can change "wp-content/uploads" with "wp-content/cache" or other allowed public directory.</p>

<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row"><span class="fvm-label-special">Cache Path</span></th>

<td><fieldset>

<label for="fastvelocity_min_change_cache_path">

<p><input type="text" name="fastvelocity_min_change_cache_path" id="fastvelocity_min_change_cache_path" value="<?php echo get_option('fastvelocity_min_change_cache_path', ''); ?>" size="80" /></p>

<p class="description">[ Default cache path is: <?php echo rtrim(wp_upload_dir()['basedir'], '/'); ?> ]</p>

</label>

<br />

<label for="fastvelocity_min_change_cache_base_url">

<p><input type="text" name="fastvelocity_min_change_cache_base_url" id="fastvelocity_min_change_cache_base_url" value="<?php echo get_option('fastvelocity_min_change_cache_base_url', ''); ?>" size="80" /></p>

<p class="description">[ Default cache base url is: <?php echo rtrim(fvm_get_protocol(wp_upload_dir()['baseurl']), '/'); ?> ]</p>

</label>

</fieldset></td>

</tr>

</tbody></table>





<p class="submit"><input type="submit" name="fastvelocity_min_save_options" id="fastvelocity_min_save_options" class="button button-primary" value="Save Changes"></p>

</form>

<?php } ?>





<?php if( $active_tab == 'pro' ) { ?>



<form method="post" action="options.php">

<?php settings_fields('fvm-group-pro'); do_settings_sections('fvm-group-pro'); ?>





<div style="height: 20px;"></div>

<h2 class="title">Special JS and CSS Exceptions</h2>

<p class="fvm-bold-green">You can use this section to edit or change our default exclusions, as well as to add your own.<br />Make sure you understand the difference between Defer and Async.</p> 

<p class="fvm-bold-green">When you use an option here that uses "Async", styles and scripts load "out of order" and completely independent from the others. That means, the files that end up loading later, will overwrite any previously loaded code. On the other hand, when you use the "ignore list" or when you select an option to "defer", the order of scripts and styles is preserved and should not overwrite previously loaded code, unless there is an higher specificy somewhere else.</p>



<div style="height: 20px;"></div>

<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row">Ignore List</th>

<td><fieldset>

<label for="blacklist_keys"><span class="fvm-label-pad">Ignore the following CSS and JS paths below:</span></label>

<p>

<textarea name="fastvelocity_min_ignore" rows="7" cols="50" id="fastvelocity_min_ignore" class="large-text code" placeholder="ex: /wp-includes/js/jquery/jquery.js"><?php echo get_option('fastvelocity_min_ignore'); ?></textarea>

</p>

<p class="description">[ Your own list of js /css files to ignore with wildcard support (read the faqs) ]</p>

</fieldset></td>

</tr>

</tbody></table>





<div style="height: 20px;"></div>

<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row">External URLs to Merge</th>

<td><fieldset><label for="blacklist_keys"><span class="fvm-label-pad">List of external domains that can be fetched and merged together:</span></label>

<p>

<textarea name="fastvelocity_min_merge_allowed_urls" rows="7" cols="50" id="fastvelocity_min_merge_allowed_urls" class="large-text code" placeholder="ex: example.com"><?php echo get_option('fastvelocity_min_merge_allowed_urls'); ?></textarea>

</p>

<p class="description">[ Add any external "domains" for JS or CSS files than can be merged fetched and merged together by FVM, ie: cdnjs.cloudflare.com ]</p>

</fieldset></td>

</tr>

</tbody></table>





<div style="height: 20px;"></div>

<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row">Exclude JS files from PSI</th>

<td><fieldset><label for="fastvelocity_min_excludejslist"><span class="fvm-label-pad">Files will be loaded Async and excluded from PSI:</span></label>

<p>

<textarea name="fastvelocity_min_excludejslist" rows="7" cols="50" id="fastvelocity_min_excludejslist" class="large-text code" placeholder="ex: /pixelyoursite/js/public.js"><?php echo get_option('fastvelocity_min_excludejslist'); ?></textarea>

</p>

<p class="description">[ Any JS file that can load Async and completely independent, such as analytics or pixel scripts ]</p>



</fieldset></td>

</tr>

</tbody></table>





<div style="height: 20px;"></div>

<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row">Exclude CSS files from PSI</th>

<td><fieldset><label for="fastvelocity_min_excludecsslist"><span class="fvm-label-pad">Files will be loaded Async and excluded from PSI:</span></label>

<p>

<textarea name="fastvelocity_min_excludecsslist" rows="7" cols="50" id="fastvelocity_min_excludecsslist" class="large-text code" placeholder="ex: /wp-content/themes/my-theme/css/some-other-font.min.css"><?php echo get_option('fastvelocity_min_excludecsslist'); ?></textarea>

</p>

<p class="description">[ Any CSS file that can load completely independent, such as fontawesome or other icons ]</p>



</fieldset></td>

</tr>

</tbody></table>









<div style="height: 20px;"></div>

<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row">Default Ignore List</th>

<td>

<fieldset><label for="blacklist_keys"><span class="fvm-label-pad">Do not edit, if you're not sure what this is:</span></label>

<p>

<textarea name="fastvelocity_min_ignorelist" rows="7" cols="50" id="fastvelocity_min_ignorelist" class="large-text code" placeholder="ex: /wp-includes/js/jquery/jquery.js"><?php echo get_option('fastvelocity_min_ignorelist'); ?></textarea>

</p>

<p class="description">[ Files that have been consistently reported by other users to cause trouble when merged ]</p>

</fieldset></td>

</tr>

</tbody></table>



<div style="height: 20px;"></div>

<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row">Default Blacklist</th>

<td><fieldset><label for="blacklist_keys"><span class="fvm-label-pad">Do not edit, if you're not sure what this is:</span></label>

<p>

<textarea name="fastvelocity_min_blacklist" rows="7" cols="50" id="fastvelocity_min_blacklist" class="large-text code" placeholder="ex: /wp-includes/js/jquery/jquery.js"><?php echo get_option('fastvelocity_min_blacklist'); ?></textarea>

</p>

<p class="description">[ Usually, any IE css /js files that should always be ignored without incrementing the groups ]</p>

</fieldset></td>

</tr>

</tbody></table>





<p class="submit"><input type="submit" name="fastvelocity_min_save_options" id="fastvelocity_min_save_options" class="button button-primary" value="Save Changes"></p>

</form>



<?php 

}



# start developers tab

if( $active_tab == 'dev' ) { ?>



<form method="post" action="options.php">

<?php settings_fields('fvm-group-dev'); do_settings_sections('fvm-group-dev'); ?>



<div style="height: 20px;"></div>

<h2 class="title">Development</h2>

<p class="fvm-bold-green">This are handy things for the plugin author, but may be of use to you if you are looking to debug some issue.</p>

<p class="fvm-bold-green">Please note that the automatic headers, are only available after the first, uncached pageview (you may need to purge your cache to see them, or your server may not support this at all).</p>



<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row">Dev Options</th>

<td><fieldset>

<label for="fastvelocity_fvm_debug">

<input name="fastvelocity_fvm_debug" type="checkbox" id="fastvelocity_fvm_debug" value="1" <?php echo checked(1 == get_option('fastvelocity_fvm_debug'), true, false); ?>>

Enable FVM Debug Mode<span class="note-info">[ Add extra info to the "status page" logs as well as some comments on the HTML frontend (beta) ]</span></label>



<br />

<label for="fastvelocity_enabled_css_preload">

<input name="fastvelocity_enabled_css_preload" type="checkbox" id="fastvelocity_enabled_css_preload" value="1" <?php echo checked(1 == get_option('fastvelocity_enabled_css_preload'), true, false); ?>>

Enable FVM CSS files Preload<span class="note-info">[ Automatically create http headers for FVM generated CSS files (when not inlined) ]</span></label>



<br />

<label for="fastvelocity_enabled_js_preload">

<input name="fastvelocity_enabled_js_preload" type="checkbox" id="fastvelocity_enabled_js_preload" value="1" <?php echo checked(1 == get_option('fastvelocity_enabled_js_preload'), true, false); ?>>

Enable FVM JS files Preload<span class="note-info">[ Automatically create http headers for FVM generated JS files ]</span></label>





</fieldset>

</td>

</tr>

</tbody></table>













<div style="height: 20px;"></div>

<h2 class="title">HTTP Headers</h2>

<p class="fvm-bold-green">Preconnect Headers: This will add link headers to your http response to instruct the browser to preconnect to other domains (ex: fonts, images, videos, etc)</p>

<p class="fvm-bold-green">Preload Headers: Use this for preloading specific, high priority resources that exist across all of your pages.</p>

<p class="fvm-bold-green">Note: Some servers do not support http push or headers. If you get a server error: a) rename the plugin directory via SFTP or your hosting control panel, b) go to your plugins page (plugin will be disabled on access), c) rename it back and d) activate it back (reset to default settings).</p>



<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row">Preconnect Headers</th>

<td><fieldset><legend class="screen-reader-text"><span>Preconnect</span></legend>

<label for="fastvelocity_min_hpreconnect"><span class="fvm-label-pad">Use only the strictly minimum necessary domain names, (cdn or frequent embeds):</span></label>

<p>

<textarea name="fastvelocity_min_hpreconnect" rows="7" cols="50" id="fastvelocity_min_hpreconnect" class="large-text code" placeholder="https://cdn.example.com"><?php echo get_option('fastvelocity_min_hpreconnect'); ?></textarea>

</p>

<p class="description">[ Use the complete scheme (http:// or https://) followed by the domain name only (no file paths). ]</p>

<p class="description">[ Examples: ]</p>

<p class="description">https://fonts.googleapis.com</p>

<p class="description">https://fonts.gstatic.com</p>

</fieldset></td>

</tr>



</tbody></table>



<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row">Preload Headers</th>

<td><fieldset><legend class="screen-reader-text"><span>Preload Headers</span></legend>

<label for="fastvelocity_min_hpreload"><span class="fvm-label-pad">Insert your "complete php header code" here:</span></label>

<p>

<textarea name="fastvelocity_min_hpreload" rows="7" cols="50" id="fastvelocity_min_hpreload" class="large-text code" placeholder="Link: &lt;https://cdn.example.com/s/font/v15/somefile.woff&gt;; rel=preload; as=font; crossorigin"><?php echo get_option('fastvelocity_min_hpreload'); ?></textarea>

</p>

<p class="description">[ Example of a "complete php header code" to paste above ]</p>

<p class="description">Link: &lt;https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFVZ0d.woff&gt;; rel=preload; as=font; crossorigin</p>

<p class="description">Link: &lt;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2&gt;; rel=preload; as=font; crossorigin</p>

</fieldset></td>

</tr>

</tbody></table>





<div style="height: 20px;"></div>

<h2 class="title">Async CSS</h2>

<p class="fvm-bold-green">If you have multiple css files per media type, they may load out of order and break your design.<br />These options won't work, if you select "Disable CSS Processing" on the settings page. </p>



<table class="form-table fvm-settings">

<tbody>

<tr>

<th scope="row">Enable Async CSS</th>

<td><fieldset>

<label for="fastvelocity_min_loadcss">

<input name="fastvelocity_min_loadcss" type="checkbox" id="fastvelocity_min_loadcss" value="1" <?php echo checked(1 == get_option('fastvelocity_min_loadcss'), true, false); ?>>

Async CSS with LoadCSS <span class="note-info">[ Note that inline CSS won't work if this is active ]</span></label>



<br />

<label for="fastvelocity_min_fvm_removecss">

<input name="fastvelocity_min_fvm_removecss" type="checkbox" id="fastvelocity_min_fvm_removecss" value="1" <?php echo checked(1 == get_option('fastvelocity_min_fvm_removecss'), true, false); ?>>

Dequeue all CSS files <span class="note-info">[ Use this if you want to test how your Critical Path CSS looks like ]</span></label>



</fieldset>

</td>

</tr>



</tbody></table>





<div style="height: 20px;"></div>

<h2 class="title">Critical Path CSS</h2>

<p class="fvm-bold-green">Files that are inlined, or end up loading later (note: async css files load out of order) will overwritte existing styles, which can cause your design to break.</p>

<p class="fvm-bold-green">It's probably better to (uncss) remove all unused CSS on your site, select the "Dequeue all CSS files" and paste your code on the "Fallback CSS" section.</p>

<p class="fvm-bold-green">All code posted here will be inline early in the header, regardless of the "Async CSS with LoadCSS" being active or not (so you can use this to inline your extra css code without other plugins).</p>



<table class="form-table fvm-settings">

<tbody>



<tr>

<th scope="row">Fallback CSS</th>

<td>

<fieldset>

<p>

<textarea name="fastvelocity_min_critical_path_css" rows="7" cols="50" id="fastvelocity_min_critical_path_css" class="large-text code" placeholder="your css code here"><?php echo get_option('fastvelocity_min_critical_path_css'); ?></textarea>

</p>

<p class="description">[ It will be overwritten, if some other more specific critical path code exists below ]</p>

</fieldset>

</td>

</tr>



<tr>

<th scope="row">is_front_page (conditional)</th>

<td>

<fieldset>

<p>

<textarea name="fastvelocity_min_critical_path_css_is_front_page" rows="7" cols="50" id="fastvelocity_min_critical_path_css_is_front_page" class="large-text code" placeholder="your css code here"><?php echo get_option('fastvelocity_min_critical_path_css_is_front_page'); ?></textarea>

</p>

<p class="description">[ Will show up if your page matches the WP conditional, is_front_page() ]</p>

</fieldset>

</td>

</tr>



</tbody></table>







<p class="submit"><input type="submit" name="fastvelocity_min_save_options" id="fastvelocity_min_save_options" class="button button-primary" value="Save Changes"></p>

</form>



<?php 

}





# start server info tab

if( $active_tab == 'server' ) { 

fvm_get_generalinfo();

}





# start help tab

if( $active_tab == 'help' ) { ?>



<div class="wrap" id="fastvelocity-min">

    <div id="poststuff">

        <div id="fastvelocity_min_processed" class="postbox-container">

			<div class="meta-box-sortables ui-sortable">

			

				<div class="postbox" id="tab-info">

                    <h3 class="hndle"><span>Paid Clients / Custom Requests</span></h3>

                    <div class="inside">

					<p>Please Visit: <a href="https://www.upwork.com/fl/fvmpeixoto">https://www.upwork.com/fl/fvmpeixoto</a></p>

					<p>Alternatively: <a href="https://fastvelocity.com/">https://fastvelocity.com/</a></p>

					</div>

                </div>

		

				<div class="postbox" id="tab-info">

                    <h3 class="hndle"><span>Frequently Asked Questions</span></h3>

                    <div class="inside">

					<p>Please Visit: <a href="https://wordpress.org/plugins/fast-velocity-minify/#faq">https://wordpress.org/plugins/fast-velocity-minify/#faq</a></p>

					</div>

                </div>

				

				<div class="postbox" id="tab-info">

                    <h3 class="hndle"><span>Open Source Support / Bug Report</span></h3>

                    <div class="inside">

					<p>Please Visit: <a href="https://wordpress.org/support/plugin/fast-velocity-minify">https://wordpress.org/support/plugin/fast-velocity-minify</a></p>

					</div>

                </div>

				

				<div class="postbox" id="tab-info">

                    <h3 class="hndle"><span>Need faster hosting?</span></h3>

                    <div class="inside">

			<p>Digital Ocean: (aff) <a href="https://m.do.co/c/039860472caf">https://www.digitalocean.com/</a></p>

			<p>Vultr: (aff) <a href="https://www.vultr.com/?ref=6879450">https://www.vultr.com/</a></p>

			<p>Linode: (aff) <a href="https://www.linode.com/?r=4b0ae524a0e54b1c11abb8014be4068f5a5d607a">https://www.linode.com/</a></p>

			<p>Amazon Lightsail: <a href="https://aws.amazon.com/lightsail/">https://aws.amazon.com/lightsail/</a></p>

			<p>Google Cloud: <a href="https://cloud.google.com/">https://cloud.google.com/</a></p>

					</div>

                </div>

				

				<div class="postbox" id="tab-info">

                    <h3 class="hndle"><span>Donations (Thank You)</span></h3>

                    <div class="inside">

					<p>PayPal: <a href="https://goo.gl/vpLrSV">https://goo.gl/vpLrSV</a><br /></p>

					</div>

                </div>

				

            </div>

        </div>

    </div>

</div>



<?php } ?>







</div>



<div class="clear"></div>



<?php

}





###########################################

# process header javascript ###############

###########################################

function fastvelocity_min_merge_header_scripts() {

global $wp_scripts, $wp_domain, $wp_home, $wp_home_path, $cachedir, $cachedirurl, $ignore, $disable_js_merge, $disable_js_minification, $enable_defer_js, $exclude_defer_jquery, $fvm_debug, $fvm_min_excludejslist, $fvmualist;

if(!is_object($wp_scripts)) { return false; }

$scripts = wp_clone($wp_scripts);

$scripts->all_deps($scripts->queue);

$ctime = get_option('fvm-last-cache-update', '0'); 

$header = array();



# mark as done (as we go)

$done = $scripts->done;



# add defaults to ignore list

$ignore = fastvelocity_default_ignore($ignore);



# get groups of handles

foreach( $scripts->to_do as $handle ) :



# is it a footer script?

$is_footer = 0; 

if (isset($wp_scripts->registered[$handle]->extra["group"]) || isset($wp_scripts->registered[$handle]->args)) {

	$is_footer = 1; 

}



	# skip footer scripts for now

	if($is_footer != 1) {

		

	# get full url

	$hurl = fastvelocity_min_get_hurl($wp_scripts->registered[$handle]->src, $wp_domain, $wp_home);

	

	# inlined scripts without file

	if( empty($hurl)) {

		continue;

	}

	

	# Exclude JS files from PSI (Async) takes priority over the ignore list

	if($fvm_min_excludejslist != false || is_array($fvm_min_excludejslist)) {

		

		# check for string match

		$skipjs = false;

		foreach($fvm_min_excludejslist as $l) {

			if (stripos($hurl, $l) !== false) {

				# print code if there are no linebreaks, or return

				echo '<script type="text/javascript">if(fvmuag()){';

				echo "loadAsync('$hurl', null);";			

				echo '}</script>';

				$skipjs = true;

				break;

			}

		}

		if($skipjs != false) { continue; }

	}

	

	

	# IE only files don't increment things

	$ieonly = fastvelocity_ie_blacklist($hurl);

	if($ieonly == true) { continue; }

	

	# skip ignore list, scripts with conditionals, external scripts

	if ((!fastvelocity_min_in_arrayi($hurl, $ignore) && !isset($wp_scripts->registered[$handle]->extra["conditional"]) && fvm_internal_url($hurl, $wp_home)) || empty($hurl)) {

			

		# process

		if(isset($header[count($header)-1]['handle']) || count($header) == 0) {

			array_push($header, array('handles'=>array()));

		}

			

		# push it to the array

		array_push($header[count($header)-1]['handles'], $handle);



		# external and ignored scripts

	} else { 

		array_push($header, array('handle'=>$handle));

	}

	

	# make sure that the scripts skipped here, show up in the footer

	} else {

		$hurl = fastvelocity_min_get_hurl($wp_scripts->registered[$handle]->src, $wp_domain, $wp_home);

		

		# inlined scripts without file

		if( empty($hurl)) {

			wp_enqueue_script($handle, false);

		} else {

			wp_enqueue_script($handle, $hurl, array(), null, true);

		}

	}

endforeach;



# loop through header scripts and merge

for($i=0,$l=count($header);$i<$l;$i++) {

	if(!isset($header[$i]['handle'])) {

		

		# static cache file info + done

		$done = array_merge($done, $header[$i]['handles']);		

		$hash = 'header-'.hash('sha1',implode('',$header[$i]['handles']));



		# create cache files and urls

		$file = $cachedir.fastvelocity_get_os_slash().$hash.'.min.js';

		$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.js');

		

		# generate a new cache file

		clearstatcache();

		if (!file_exists($file)) {

			

			# code and log initialization

			$log = '';

			$code = '';	

		

			# minify and write to file

			foreach($header[$i]['handles'] as $handle) :

				if(!empty($wp_scripts->registered[$handle]->src)) {

					

					# get hurl per handle

					$hurl = fastvelocity_min_get_hurl($wp_scripts->registered[$handle]->src, $wp_domain, $wp_home);

					

					# inlined scripts without file

					if( empty($hurl)) {

						continue;

					}

					

					# print url

					$printurl = str_ireplace(array(site_url(), home_url(), 'http:', 'https:'), '', $hurl);

					

					# download, minify, cache

					$tkey = 'js-'.hash('sha1', $handle.$hurl).'.js';

					$json = false; $json = fvm_get_transient($tkey);

					if ( $json === false) {

						$json = fvm_download_and_minify($hurl, null, $disable_js_minification, 'js', $handle);

						if($fvm_debug == true) { echo "<!-- FVM DEBUG: Uncached file processing now for $handle / $hurl -->" . PHP_EOL; }

						fvm_set_transient($tkey, $json);

					}

					

					# decode 

					$res = json_decode($json, true);

					

					# response has failed

					if($res['status'] != true) {

						$log.= $res['log'];

						continue;

					}

					

					# Add extra data from wp_add_inline_script before

					if (!empty($wp_scripts->registered[$handle]->extra)){

						if (isset($wp_scripts->registered[$handle]->extra['before'])){

							if(is_array($wp_scripts->registered[$handle]->extra['before'])) {

								$arr = array_filter($wp_scripts->registered[$handle]->extra['before']);

								$code.= PHP_EOL . fastvelocity_try_catch_wrap(implode(PHP_EOL, $arr));

							}

						}

					}

										

					# append code to merged file

					$code.= "/* $hurl */". PHP_EOL . fastvelocity_try_catch_wrap($res['code']);

					$log.= $res['log'];

					

					# Add extra data from wp_add_inline_script after

					if (!empty($wp_scripts->registered[$handle]->extra)){

						if (isset($wp_scripts->registered[$handle]->extra['after'])){

							if(is_array($wp_scripts->registered[$handle]->extra['after'])) {

								$arr = array_filter($wp_scripts->registered[$handle]->extra['after']);

								$code.= PHP_EOL . fastvelocity_try_catch_wrap(implode(PHP_EOL, $arr));

							}

						}

					}	



				# consider dependencies on handles with an empty src

				} else {

					wp_dequeue_script($handle); wp_enqueue_script($handle);

				}

			endforeach;	

			

			# prepare log

			$log = "PROCESSED on ".date('r').PHP_EOL.$log."PROCESSED from ".home_url(add_query_arg( NULL, NULL )).PHP_EOL;

			

			# generate cache, write log

			if(!empty($code)) {

				file_put_contents($file.'.txt', $log);

				file_put_contents($file, $code);

				file_put_contents($file.'.gz', gzencode(file_get_contents($file), 9));

				

				# permissions

				fastvelocity_fix_permission_bits($file.'.txt');

				fastvelocity_fix_permission_bits($file);

				fastvelocity_fix_permission_bits($file.'.gz');

				

				# brotli static support

				if(function_exists('brotli_compress')) {

					file_put_contents($file.'.br', brotli_compress(file_get_contents($file), 11));

					fastvelocity_fix_permission_bits($file.'.br');

				}

			}

		}

		

		# register minified file

		wp_register_script("fvm-header-$i", $file_url, array(), null, false); 

		

		# add all extra data from wp_localize_script

		$data = array();

		foreach($header[$i]['handles'] as $handle) { 					

			if(isset($wp_scripts->registered[$handle]->extra['data'])) { $data[] = $wp_scripts->registered[$handle]->extra['data']; }

		}

		if(count($data) > 0) { $wp_scripts->registered["fvm-header-$i"]->extra['data'] = implode(PHP_EOL, $data); }

		

		# enqueue file, if not empty

		if(file_exists($file) && (filesize($file) > 0 || count($data) > 0)) {

			wp_enqueue_script("fvm-header-$i");

		} else {

			# file could not be generated, output something meaningful

			echo "<!-- ERROR: FVM was not allowed to save it's cache on - $file -->";

			echo "<!-- Please check if the path above is correct and ensure your server has writting permission there! -->";

			echo "<!-- If you found a bug, please report this on https://wordpress.org/support/plugin/fast-velocity-minify/ -->";

		}

	

	# other scripts need to be requeued for the order of files to be kept

	} else {

		wp_dequeue_script($header[$i]['handle']); 

		wp_enqueue_script($header[$i]['handle']);

	}

}



# remove from queue

$wp_scripts->done = $done;

}

###########################################







###########################################

# process js in the footer ################

###########################################

function fastvelocity_min_merge_footer_scripts() {

global $wp_scripts, $wp_domain, $wp_home, $wp_home_path, $cachedir, $cachedirurl, $ignore, $disable_js_merge, $disable_js_minification, $enable_defer_js, $exclude_defer_jquery, $fvm_debug, $fvm_min_excludejslist, $fvmualist;

if(!is_object($wp_scripts)) { return false; }

$ctime = get_option('fvm-last-cache-update', '0'); 

$scripts = wp_clone($wp_scripts);

$scripts->all_deps($scripts->queue);

$footer = array();



# mark as done (as we go)

$done = $scripts->done;



# add defaults to ignore list

$ignore = fastvelocity_default_ignore($ignore);





# get groups of handles

foreach( $scripts->to_do as $handle ) :



	# get full url

	$hurl = fastvelocity_min_get_hurl($wp_scripts->registered[$handle]->src, $wp_domain, $wp_home);

	

	# inlined scripts without file

	if( empty($hurl)) {

		continue;

	}

	

	# Exclude JS files from PSI (Async) takes priority over the ignore list

	if($fvm_min_excludejslist != false || is_array($fvm_min_excludejslist)) {

		

		# check for string match

		$skipjs = false;

		foreach($fvm_min_excludejslist as $l) {

			if (stripos($hurl, $l) !== false) {

				# print code if there are no linebreaks, or return

				echo '<script type="text/javascript">if(fvmuag()){';

				echo "loadAsync('$hurl', null);";			

				echo '}</script>';

				$skipjs = true;

				break;

			}

		}

		if($skipjs != false) { continue; }

	}

	

	# IE only files don't increment things

	$ieonly = fastvelocity_ie_blacklist($hurl);

	if($ieonly == true) { continue; }

	

	# skip ignore list, scripts with conditionals, external scripts

	if ((!fastvelocity_min_in_arrayi($hurl, $ignore) && !isset($wp_scripts->registered[$handle]->extra["conditional"]) && fvm_internal_url($hurl, $wp_home)) || empty($hurl)) {

			

		# process

		if(isset($footer[count($footer)-1]['handle']) || count($footer) == 0) {

			array_push($footer, array('handles'=>array()));

		}

		

		# push it to the array

		array_push($footer[count($footer)-1]['handles'], $handle);

				

	# external and ignored scripts

	} else { 

		array_push($footer, array('handle'=>$handle));

	}

endforeach;



# loop through footer scripts and merge

for($i=0,$l=count($footer);$i<$l;$i++) {

	if(!isset($footer[$i]['handle'])) {

		

		# static cache file info + done

		$done = array_merge($done, $footer[$i]['handles']);		

		$hash = 'footer-'.hash('sha1',implode('',$footer[$i]['handles']));

		

		# create cache files and urls

		$file = $cachedir.fastvelocity_get_os_slash().$hash.'.min.js';

		$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.js');

	

		# generate a new cache file

		clearstatcache();

		if (!file_exists($file)) {

			

			# code and log initialization

			$log = '';

			$code = '';	

		

			# minify and write to file

			foreach($footer[$i]['handles'] as $handle) :

				if(!empty($wp_scripts->registered[$handle]->src)) {

					

					# get hurl per handle

					$hurl = fastvelocity_min_get_hurl($wp_scripts->registered[$handle]->src, $wp_domain, $wp_home);

					

					# inlined scripts without file

					if( empty($hurl)) {

						continue;

					}

					

					# print url

					$printurl = str_ireplace(array(site_url(), home_url(), 'http:', 'https:'), '', $hurl);

					

					

					# download, minify, cache

					$tkey = 'js-'.hash('sha1', $handle.$hurl).'.js';

					$json = false; $json = fvm_get_transient($tkey);

					if ( $json === false) {

						$json = fvm_download_and_minify($hurl, null, $disable_js_minification, 'js', $handle);

						if($fvm_debug == true) { echo "<!-- FVM DEBUG: Uncached file processing now for $handle / $hurl -->" . PHP_EOL; }

						fvm_set_transient($tkey, $json);

					}

					

					# decode 

					$res = json_decode($json, true);

					

					# response has failed

					if($res['status'] != true) {

						$log.= $res['log'];

						continue;

					}			

					

					# Add extra data from wp_add_inline_script before

					if (!empty($wp_scripts->registered[$handle]->extra)){

						if (isset($wp_scripts->registered[$handle]->extra['before'])){

							if(is_array($wp_scripts->registered[$handle]->extra['before'])) {

								$arr = array_filter($wp_scripts->registered[$handle]->extra['before']);

								$code.= PHP_EOL . fastvelocity_try_catch_wrap(implode(PHP_EOL, $arr));

							}

						}

					}

					

					# append code to merged file

					$code.= "/* $hurl */". PHP_EOL . fastvelocity_try_catch_wrap($res['code']);

					$log.= $res['log'];



					# Add extra data from wp_add_inline_script after

					if (!empty($wp_scripts->registered[$handle]->extra)){

						if (isset($wp_scripts->registered[$handle]->extra['after'])){

							if(is_array($wp_scripts->registered[$handle]->extra['after'])) {

								$arr = array_filter($wp_scripts->registered[$handle]->extra['after']);

								$code.= PHP_EOL . fastvelocity_try_catch_wrap(implode(PHP_EOL, $arr));

							}

						}

					}

			

				# consider dependencies on handles with an empty src

				} else {

					wp_dequeue_script($handle); 

					wp_enqueue_script($handle);

				}

			endforeach;	

			

			# prepare log

			$log = "PROCESSED on ".date('r').PHP_EOL.$log."PROCESSED from ".home_url(add_query_arg( NULL, NULL )).PHP_EOL;

		

			# generate cache, write log

			if(!empty($code)) {

				file_put_contents($file.'.txt', $log);

				file_put_contents($file, $code);

				file_put_contents($file.'.gz', gzencode(file_get_contents($file), 9));

				

				# permissions

				fastvelocity_fix_permission_bits($file.'.txt');

				fastvelocity_fix_permission_bits($file);

				fastvelocity_fix_permission_bits($file.'.gz');

				

				# brotli static support

				if(function_exists('brotli_compress')) {

					file_put_contents($file.'.br', brotli_compress(file_get_contents($file), 11));

					fastvelocity_fix_permission_bits($file.'.br');

				}

			}

		}

		

		# register minified file

		wp_register_script("fvm-footer-$i", $file_url, array(), null, false); 

		

		# add all extra data from wp_localize_script

		$data = array();

		foreach($footer[$i]['handles'] as $handle) { 					

			if(isset($wp_scripts->registered[$handle]->extra['data'])) { $data[] = $wp_scripts->registered[$handle]->extra['data']; }

		}

		if(count($data) > 0) { $wp_scripts->registered["fvm-footer-$i"]->extra['data'] = implode(PHP_EOL, $data); }

		

		# enqueue file, if not empty

		if(file_exists($file) && (filesize($file) > 0 || count($data) > 0)) {

			wp_enqueue_script("fvm-footer-$i");

		} else {

			# file could not be generated, output something meaningful

			echo "<!-- ERROR: FVM was not allowed to save it's cache on - $file -->";

			echo "<!-- Please check if the path above is correct and ensure your server has writting permission there! -->";

			echo "<!-- If you found a bug, please report this on https://wordpress.org/support/plugin/fast-velocity-minify/ -->";

		}

	

	# other scripts need to be requeued for the order of files to be kept

	} else {

		wp_dequeue_script($footer[$i]['handle']); wp_enqueue_script($footer[$i]['handle']);

	}

}



# remove from queue

$wp_scripts->done = $done;

}

##############################







###########################################

# enable defer for JavaScript (WP 4.1 and above) and remove query strings for ignored files

###########################################

function fastvelocity_min_defer_js($tag, $handle, $src) {

global $ignore, $blacklist, $ignorelist, $enable_defer_js, $defer_for_pagespeed, $wp_domain, $exclude_defer_login, $fvm_fix_editor, $fvmualist, $defer_for_pagespeed_optimize, $exclude_defer_jquery, $skip_defer_lists;



# no query strings

$tag = trim($tag); # must cleanup

if (stripos($src, '?ver') !== false) { 

	$srcf = stristr($src, '?ver', true); 

	$tag = str_ireplace($src, $srcf, $tag); 

	$src = $srcf; 

}





# fix page editors, admin, amp, etc

if(fastvelocity_exclude_contents()) { return $tag; }



# return if defer option is not selected

if ($defer_for_pagespeed != true && $enable_defer_js != true) { return $tag; }



# Skip deferring the jQuery library option

if($exclude_defer_jquery != false && (stripos($tag, '/jquery.js') !== false || stripos($tag, '/jquery.min.js') !== false || (stripos($tag, '/jquery-') !== false && stripos($tag, '.js') !== false))) {

	return $tag;

}



# return if external script url https://www.chromestatus.com/feature/5718547946799104

if (fvm_is_local_domain($src) !== true) { return $tag; }



# bypass if there are linebreaks (will break document.write) or already being optimized

if (stripos($tag, PHP_EOL) !== false || stripos($tag, 'navigator.userAgent.match') !== false) { 

	return $tag;

}



# should we exclude defer on the login page?

if($exclude_defer_login == true && stripos($_SERVER["SCRIPT_NAME"], strrchr(wp_login_url(), '/')) !== false){ 

	return $tag; 

}



# add defer attribute, but only if not having async or defer already

if (stripos($tag, 'defer') === false && stripos($tag, 'async') === false) {

	

	# defer tag globally

	$jsdefer = str_ireplace('<script ', '<script defer ', $tag);

	$jsdeferpsi = $jsdefer;

	

	# add cdn for PSI

	$fvm_cdn_url = get_option('fastvelocity_min_fvm_cdn_url');

	if(!empty($fvm_cdn_url)) {

		$fvm_cdn_url = trim(trim(str_ireplace(array('http://', 'https://'), '', trim($fvm_cdn_url, '/'))), '/');

		$jsdeferpsi = str_ireplace($src, $fvm_cdn_url, $jsdefer);

	}

	

	

	# defer tag for PSI only

	$jsdeferpsionly = '<script type="text/javascript">if(navigator.userAgent.match(/'.implode('|', $fvmualist).'/i)){document.write('.fastvelocity_escape_url_js($jsdeferpsi).');}else{document.write('.fastvelocity_escape_url_js($tag).');}</script>';

	

	# hide tag from PSI

	$jsdeferhidepsi = '<script type="text/javascript">if(fvmuag()){document.write('.fastvelocity_escape_url_js($tag).');}</script>';

	

	# must return by this order...

	

	# remove FVM from the ignore list

	array_filter($ignore, function ($var) { return (stripos($var, '/fvm/') === false); });

	

	# Exclude JS files in the "ignore list" from PSI

	if($defer_for_pagespeed_optimize != false) {

		if((count($ignore) > 0 && fastvelocity_min_in_arrayi($src, $ignore)) || (count($blacklist) > 0 && fastvelocity_min_in_arrayi($src, $blacklist)) || (count($ignorelist) > 0 && fastvelocity_min_in_arrayi($src, $ignorelist))) {

			return $jsdeferhidepsi;

		}

	}

	

	# Enable defer of JS files for PSI

	if($defer_for_pagespeed != false) {

		return $jsdeferpsionly;

	}

	

	# Enable defer parsing of FVM JS files globally

	if($enable_defer_js == true) {

		

		# consider "Skip deferring the ignore list"

		if($skip_defer_lists != false && ((count($ignore) > 0 && fastvelocity_min_in_arrayi($src, $ignore)) || (count($blacklist) > 0 && fastvelocity_min_in_arrayi($src, $blacklist)) || (count($ignorelist) > 0 && fastvelocity_min_in_arrayi($src, $ignorelist)))) {

			return $tag;

		} else {

			return $jsdefer;

		}

	}



}



# fallback

return $tag;

}

###########################################





###########################################

# process header css ######################

###########################################

function fastvelocity_min_merge_header_css() {

global $wp_styles, $wp_domain, $wp_home, $wp_home_path, $cachedir, $cachedirurl, $ignore, $disable_css_merge, $disable_css_minification, $skip_google_fonts, $skip_cssorder, $remove_print_mediatypes, $force_inline_googlefonts, $css_hide_googlefonts, $min_async_googlefonts, $remove_googlefonts, $fvmloadcss, $fvm_remove_css, $fvmualist, $fvm_min_excludecsslist, $fvm_debug, $fvm_min_excludecsslist, $fvm_fawesome_method;

if(!is_object($wp_styles)) { return false; }

$ctime = get_option('fvm-last-cache-update', '0'); 

$styles = wp_clone($wp_styles);

$styles->all_deps($styles->queue);

$done = $styles->done;

$header = array();

$google_fonts = array();

$process = array();

$inline_css = array();

$log = '';



# dequeue all styles

if($fvm_remove_css != false) {

	foreach( $styles->to_do as $handle ) :

		$done = array_merge($done, array($handle));

	endforeach;

	

	# remove from queue

	$wp_styles->done = $done;

	return false;

}



# add defaults to ignore list

$ignore = fastvelocity_default_ignore($ignore);



# get list of handles to process, dequeue duplicate css urls and keep empty source handles (for dependencies)

$uniq = array(); $gfonts = array();

foreach( $styles->to_do as $handle):



	# conditionals

	$conditional = NULL; if(isset($wp_styles->registered[$handle]->extra["conditional"])) { 

		$conditional = $wp_styles->registered[$handle]->extra["conditional"]; # such as ie7, ie8, ie9, etc

	}

	

	# mediatype

	$mt = isset($wp_styles->registered[$handle]->args) ? $wp_styles->registered[$handle]->args : 'all';

	if ($mt == 'screen' || $mt == 'screen, print' || empty($mt) || is_null($mt) || $mt == false) { $mt = 'all'; } 

	$mediatype = $mt;

	

	# full url or empty

	$hurl = fastvelocity_min_get_hurl($wp_styles->registered[$handle]->src, $wp_domain, $wp_home);

	

	# inlined scripts without file

	if( empty($hurl)) {

		continue;

	}

	

	# mark duplicates as done and remove from the queue

	if(!empty($hurl)) {

		$key = hash('sha1', $hurl); 

		if (isset($uniq[$key])) { $done = array_merge($done, array($handle)); continue; } else { $uniq[$key] = $handle; }

	}

	

	# Exclude specific CSS files from PSI?

	if($fvm_min_excludecsslist != false && is_array($fvm_min_excludecsslist) && fastvelocity_min_in_arrayi($hurl, $fvm_min_excludecsslist)) {

		$cssguid = 'fvm'.hash('sha1', $hurl);

		echo '<script type="text/javascript">if(fvmuag()){';

		echo 'var '.$cssguid.'=document.createElement("link");'.$cssguid.'.rel="stylesheet",'.$cssguid.'.type="text/css",'.$cssguid.'.media="async",'.$cssguid.'.href="'.$hurl.'",'.$cssguid.'.onload=function(){'.$cssguid.'.media="'.$mediatype.'"},document.getElementsByTagName("head")[0].appendChild('.$cssguid.');';

		echo '}</script>';

		$done = array_merge($done, array($handle)); continue;

	}

	

	# font awesome processing, async css

	if($fvm_fawesome_method == 2 && stripos($hurl, 'font-awesome') !== false) {

		echo '<link rel="preload" href="'.$hurl.'" as="style" media="'.$mediatype.'" onload="this.onload=null;this.rel=\'stylesheet\'" />';

		echo '<noscript><link rel="stylesheet" href="'.$hurl.'" media="'.$mediatype.'" /></noscript>';

		echo '<!--[if IE]><link rel="stylesheet" href="'.$hurl.'" media="'.$mediatype.'" /><![endif]-->';

		$done = array_merge($done, array($handle)); continue;

	}	

	

	# font awesome processing, async and exclude from PSI

	if($fvm_fawesome_method == 3 && stripos($hurl, 'font-awesome') !== false) {

		$cssguid = 'fvm'.hash('sha1', $hurl);

		echo '<script type="text/javascript">if(fvmuag()){';

		echo 'var '.$cssguid.'=document.createElement("link");'.$cssguid.'.rel="stylesheet",'.$cssguid.'.type="text/css",'.$cssguid.'.media="async",'.$cssguid.'.href="'.$hurl.'",'.$cssguid.'.onload=function(){'.$cssguid.'.media="'.$mediatype.'"},document.getElementsByTagName("head")[0].appendChild('.$cssguid.');';

		echo '}</script>';

		$done = array_merge($done, array($handle)); continue;

	}

	

	# array of info to save

	$arr = array('handle'=>$handle, 'url'=>$hurl, 'conditional'=>$conditional, 'mediatype'=>$mediatype);

	

	# google fonts to the top (collect and skip process array)

	if (stripos($hurl, 'fonts.googleapis.com') !== false) { 

	if($remove_googlefonts != false) { $done = array_merge($done, array($handle)); continue; } # mark as done if to be removed

	if($skip_google_fonts != true || $force_inline_googlefonts != false) { 

		$google_fonts[$handle] = $hurl; 



	} else {

		wp_enqueue_style($handle); # skip google fonts optimization?

	}

	continue; 

	} 

	

	# all else

	$process[$handle] = $arr;



endforeach;





# concat google fonts, if enabled

if(!$skip_google_fonts && count($google_fonts) > 0 || ($force_inline_googlefonts != false && count($google_fonts) > 0)) {

	foreach ($google_fonts as $h=>$a) { $done = array_merge($done, array($h)); } # mark as done

	

	# merge google fonts if force inlining is enabled?

	$nfonts = array();

	if($skip_google_fonts != true) {

		$nfonts[] = fvm_get_protocol(fastvelocity_min_concatenate_google_fonts($google_fonts));

	} else {

		foreach ($google_fonts as $a) { if(!empty($a)) { $nfonts[] = $a; } }

	}

	

	# foreach google font (will be one if merged is not disabled)

	if(count($nfonts) > 0) {

		foreach($nfonts as $gfurl) {

	

			# hide from PSI, async, inline, or default

			if($css_hide_googlefonts == true) {

				

				# make a stylesheet, hide from PSI

				$cssguid = 'fvm'.hash('sha1', $gfurl);

				echo '<script type="text/javascript">if(fvmuag()){';

				echo 'var '.$cssguid.'=document.createElement("link");'.$cssguid.'.rel="stylesheet",'.$cssguid.'.type="text/css",'.$cssguid.'.media="async",'.$cssguid.'.href="'.$gfurl.'",'.$cssguid.'.onload=function(){'.$cssguid.'.media="all"},document.getElementsByTagName("head")[0].appendChild('.$cssguid.');';

				echo '}</script>';	

				

			# async CSS

			} elseif ($min_async_googlefonts == true) {

				echo '<link rel="preload" href="'.$gfurl.'" as="style" media="all" onload="this.onload=null;this.rel=\'stylesheet\'" />';

				echo '<noscript><link rel="stylesheet" href="'.$gfurl.'" media="all" /></noscript>';

				echo '<!--[if IE]><link rel="stylesheet" href="'.$gfurl.'" media="all" /><![endif]-->';

			

			# inline css

			} elseif($force_inline_googlefonts == true) {

				

				# download, minify, cache

				$tkey = 'css-'.hash('sha1', $gfurl).'.css';

				$json = false; $json = fvm_get_transient($tkey);

				if ( $json === false) {

					$json = fvm_download_and_minify($gfurl, null, $disable_css_minification, 'css', null);

					if($fvm_debug == true) { echo "<!-- FVM DEBUG: Uncached file processing now for $gfurl -->" . PHP_EOL; }

					fvm_set_transient($tkey, $json);

				}

				

				# decode 

				$res = json_decode($json, true);

				

				# response has failed

				if($res['status'] != true) {

					$log.= $res['log'];

					continue;

				}

				

				# inline css or fail

				if($res['code'] !== false) { 

				

					# add font-display

					# https://developers.google.com/web/updates/2016/02/font-display

					$res['code'] = str_ireplace('font-style:normal;', 'font-display:block;font-style:normal;', $res['code']);

					

					# inline

					echo '<style type="text/css" media="all">'.$res['code'].'</style>'.PHP_EOL;				

				} else {

					echo "<!-- GOOGLE FONTS REQUEST FAILED for $gfurl -->\n";

				}

				

			# fallback, enqueue google fonts

			} else {

				wp_enqueue_style('header-fvm-fonts', $gfurl, array(), null, 'all');

			}

			

		}

	}

}





# get groups of handles

foreach( $styles->to_do as $handle ) :



# skip already processed google fonts and empty dependencies

if(isset($google_fonts[$handle])) { continue; }                     # skip google fonts

if(empty($wp_styles->registered[$handle]->src)) { continue; } 		# skip empty src

if (fastvelocity_min_in_arrayi($handle, $done)) { continue; }       # skip if marked as done before

if (!isset($process[$handle])) { continue; } 						# skip if not on our unique process list



# get full url

$hurl = $process[$handle]['url'];

$conditional = $process[$handle]['conditional'];

$mediatype = $process[$handle]['mediatype'];



	# IE only files don't increment things

	$ieonly = fastvelocity_ie_blacklist($hurl);

	if($ieonly == true) { continue; }

	

	# skip ignore list, conditional css, external css, font-awesome merge

	if ( (!fastvelocity_min_in_arrayi($hurl, $ignore) && !isset($conditional) && fvm_internal_url($hurl, $wp_home)) 

		|| empty($hurl) 

		|| ($fvm_fawesome_method == 1 && stripos($hurl, 'font-awesome') !== false)) {

	

	# colect inline css for this handle

	if(isset($wp_styles->registered[$handle]->extra['after']) && is_array($wp_styles->registered[$handle]->extra['after'])) { 

		$inline_css[$handle] = fastvelocity_min_minify_css_string(implode('', $wp_styles->registered[$handle]->extra['after'])); # save

		$wp_styles->registered[$handle]->extra['after'] = null; # dequeue

	}	

	

	# process

	if(isset($header[count($header)-1]['handle']) || count($header) == 0 || $header[count($header)-1]['media'] != $mediatype) {

		array_push($header, array('handles'=>array(), 'media'=>$mediatype)); 

	}

	

	# push it to the array

	array_push($header[count($header)-1]['handles'], $handle);



	# external and ignored css

	} else {

		

		# normal enqueuing

		array_push($header, array('handle'=>$handle));

	}

endforeach;



# reorder CSS by mediatypes

if(!$skip_cssorder) {

	if(count($header) > 0) {



		# get unique mediatypes

		$allmedia = array(); 

		foreach($header as $array) { 

			if(isset($array['media'])) { $allmedia[$array['media']] = ''; } 

		}

		

		# extract handles by mediatype

		$grouphandles = array(); 

		foreach ($allmedia as $md=>$var) { 

			foreach($header as $array) { 

				if (isset($array['media']) && $array['media'] === $md) { 

					foreach($array['handles'] as $h) { $grouphandles[$md][] = $h; } 

				} 

			} 

		}



		# reset and reorder header by mediatypes

		$newheader = array();

		foreach ($allmedia as $md=>$var) { $newheader[] = array('handles' => $grouphandles[$md], 'media'=>$md); }

		if(count($newheader) > 0) { $header = $newheader; }

	}

}



# loop through header css and merge

for($i=0,$l=count($header);$i<$l;$i++) {

	if(!isset($header[$i]['handle'])) {

		

		# get has for the inline css in this group

		$inline_css_group = array();

		foreach($header[$i]['handles'] as $h) { if(isset($inline_css[$h]) && !empty($inline_css[$h])) { $inline_css_group[] = $inline_css[$h]; } }

		$inline_css_hash = md5(implode('',$inline_css_group));

		

		# static cache file info + done

		$done = array_merge($done, $header[$i]['handles']);		

		$hash = 'header-'.hash('sha1',implode('',$header[$i]['handles']).$inline_css_hash);



		# create cache files and urls

		$file = $cachedir.fastvelocity_get_os_slash().$hash.'.min.css';

		$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.css'); 

		

		# generate a new cache file

		clearstatcache();

		if (!file_exists($file)) {

			

			# code and log initialization

			$log = '';

			$code = '';	

		

			# minify and write to file

			foreach($header[$i]['handles'] as $handle) :

				if(!empty($wp_styles->registered[$handle]->src)) {

					

					# get hurl per handle

					$hurl = fastvelocity_min_get_hurl($wp_styles->registered[$handle]->src, $wp_domain, $wp_home);

					

					# inlined scripts without file

					if( empty($hurl)) {

						continue;

					}

					

					# print url

					$printurl = str_ireplace(array(site_url(), home_url(), 'http:', 'https:'), '', $hurl);

					

					# download, minify, cache

					$tkey = 'css-'.hash('sha1', $handle.$hurl).'.css';

					$json = false; $json = fvm_get_transient($tkey);

					if ( $json === false) {

						$json = fvm_download_and_minify($hurl, null, $disable_css_minification, 'css', $handle);

						if($fvm_debug == true) { echo "<!-- FVM DEBUG: Uncached file processing now for $handle / $hurl -->" . PHP_EOL; }

						fvm_set_transient($tkey, $json);

					}

					

					# decode 

					$res = json_decode($json, true);

					

					# response has failed

					if($res['status'] != true) {

						$log.= $res['log'];

						continue;

					}

					

					# append code to merged file

					$code.= $res['code'];

					$log.= $res['log'];

					

					# append inlined styles

					if(isset($inline_css[$handle]) && !empty($inline_css[$handle])) { 

						$code.= $inline_css[$handle]; 

					}

				

				# consider dependencies on handles with an empty src

				} else {

					wp_dequeue_script($handle); 

					wp_enqueue_script($handle);

				}

			endforeach;	

			

			# prepare log

			$log = "PROCESSED on ".date('r').PHP_EOL.$log."PROCESSED from ".home_url(add_query_arg( NULL, NULL )).PHP_EOL;

			

			# generate cache, write log

			if(!empty($code)) {

				file_put_contents($file.'.txt', $log);

				file_put_contents($file, $code);

				file_put_contents($file.'.gz', gzencode(file_get_contents($file), 9));

				

				# permissions

				fastvelocity_fix_permission_bits($file.'.txt');

				fastvelocity_fix_permission_bits($file);

				fastvelocity_fix_permission_bits($file.'.gz');

				

				# brotli static support

				if(function_exists('brotli_compress')) {

					file_put_contents($file.'.br', brotli_compress(file_get_contents($file), 11));

					fastvelocity_fix_permission_bits($file.'.br');

				}

			}

		}

		

		# register and enqueue minified file, consider excluding of mediatype "print" and inline css

		if ($remove_print_mediatypes != true || ($remove_print_mediatypes == true && $header[$i]['media'] != 'print')) {



			# the developers tab, takes precedence

			

			# Async CSS with loadCSS ?

			if($fvmloadcss != false && $fvm_remove_css != true) {

				$mt = $header[$i]['media'];

				echo '<link rel="preload" href="'.$file_url.'" as="style" media="'.$mt.'" onload="this.onload=null;this.rel=\'stylesheet\'" />';

				echo '<noscript><link rel="stylesheet" href="'.$file_url.'" media="'.$mt.'" /></noscript>';

				echo '<!--[if IE]><link rel="stylesheet" href="'.$file_url.'" media="'.$mt.'" /><![endif]-->';

			

			# enqueue file, if not empty

			} else {

				if(file_exists($file) && filesize($file) > 0) {

					

					# inline CSS if mediatype is not of type "all" (such as mobile only), if the file is smaller than 20KB

					if(filesize($file) < 20000 && $header[$i]['media'] != 'all') {

						echo '<style id="fvm-header-'.$i.'" media="'.$header[$i]['media'].'">'.file_get_contents($file).'</style>';

					} else {

						# enqueue it

						wp_enqueue_style("fvm-header-$i", $file_url, array(), null, $header[$i]['media']);  

					}

				} else {

					# file could not be generated, output something meaningful

					echo "<!-- ERROR: FVM was not allowed to save it's cache on - $file -->";

					echo "<!-- Please check if the path above is correct and ensure your server has writting permission there! -->";

					echo "<!-- If you found a bug, please report this on https://wordpress.org/support/plugin/fast-velocity-minify/ -->";

				}

			}

		}



	# other css need to be requeued for the order of files to be kept

	} else {

		wp_dequeue_style($header[$i]['handle']); 

		wp_enqueue_style($header[$i]['handle']);

	}

}



# remove from queue

$wp_styles->done = $done;



}

###########################################





###########################################

# process css in the footer ###############

###########################################

function fastvelocity_min_merge_footer_css() {

global $wp_styles, $wp_domain, $wp_home, $wp_home_path, $cachedir, $cachedirurl, $ignore, $disable_css_merge, $disable_css_minification, $skip_google_fonts, $skip_cssorder, $remove_print_mediatypes, $force_inline_googlefonts, $css_hide_googlefonts, $min_async_googlefonts, $remove_googlefonts, $fvmloadcss, $fvm_remove_css, $fvmualist, $fvm_debug, $fvm_fawesome_method, $fvm_min_excludecsslist, $force_inline_css_footer;



if(!is_object($wp_styles)) { return false; }

$ctime = get_option('fvm-last-cache-update', '0'); 

$styles = wp_clone($wp_styles);

$styles->all_deps($styles->queue);

$done = $styles->done;

$footer = array();

$google_fonts = array();

$inline_css = array();

$code = '';

$log = '';



# dequeue all styles

if($fvm_remove_css != false) {

	foreach( $styles->to_do as $handle ) :

		$done = array_merge($done, array($handle));

	endforeach;

	

	# remove from queue

	$wp_styles->done = $done;

	return false;

}





# add defaults to ignore list

$ignore = fastvelocity_default_ignore($ignore);



# google fonts to the top

foreach( $styles->to_do as $handle ) :



	# dequeue and get a list of google fonts, or requeue external

	$hurl = fastvelocity_min_get_hurl($wp_styles->registered[$handle]->src, $wp_domain, $wp_home);

	

	# inlined scripts without file

	if( empty($hurl)) {

		continue;

	}

	

	if (stripos($hurl, 'fonts.googleapis.com') !== false) { 

		wp_dequeue_style($handle); 

		if($remove_googlefonts != false) { $done = array_merge($done, array($handle)); continue; } # mark as done if to be removed

		if($skip_google_fonts != true || $force_inline_googlefonts != false) { 

			$google_fonts[$handle] = $hurl; 

		} else {

			wp_enqueue_style($handle); # skip google fonts optimization?

		}

	} else { 

		wp_dequeue_style($handle); wp_enqueue_style($handle); # failsafe

	}

	

endforeach;





# concat google fonts, if enabled

if(!$skip_google_fonts && count($google_fonts) > 0 || ($force_inline_googlefonts != false && count($google_fonts) > 0)) {

	foreach ($google_fonts as $h=>$a) { $done = array_merge($done, array($h)); } # mark as done

	

	# merge google fonts if force inlining is enabled?

	$nfonts = array();

	if($skip_google_fonts != true) {

		$nfonts[] = fvm_get_protocol(fastvelocity_min_concatenate_google_fonts($google_fonts));

	} else {

		foreach ($google_fonts as $a) { if(!empty($a)) { $nfonts[] = $a; } }

	}

	

	# foreach google font (will be one if merged is not disabled)

	if(count($nfonts) > 0) {

		foreach($nfonts as $gfurl) {

	

			# hide from PSI, async, inline, or default

			if($css_hide_googlefonts == true) {

				

				# make a stylesheet, hide from PSI

				$cssguid = 'fvm'.hash('sha1', $gfurl);

				echo '<script type="text/javascript">if(fvmuag()){';

				echo 'var '.$cssguid.'=document.createElement("link");'.$cssguid.'.rel="stylesheet",'.$cssguid.'.type="text/css",'.$cssguid.'.media="async",'.$cssguid.'.href="'.$gfurl.'",'.$cssguid.'.onload=function(){'.$cssguid.'.media="all"},document.getElementsByTagName("head")[0].appendChild('.$cssguid.');';

				echo '}</script>';	

				

			# async CSS

			} elseif ($min_async_googlefonts == true) {

				echo '<link rel="preload" href="'.$gfurl.'" as="style" media="all" onload="this.onload=null;this.rel=\'stylesheet\'" />';

				echo '<noscript><link rel="stylesheet" href="'.$gfurl.'" media="all" /></noscript>';

				echo '<!--[if IE]><link rel="stylesheet" href="'.$gfurl.'" media="all" /><![endif]-->';

			

			# inline css

			} elseif($force_inline_googlefonts == true) {

				

				# download, minify, cache

				$tkey = 'css-'.hash('sha1', $gfurl).'.css';

				$json = false; $json = fvm_get_transient($tkey);

				if ( $json === false) {

					$json = fvm_download_and_minify($gfurl, null, $disable_css_minification, 'css', null);

					if($fvm_debug == true) { echo "<!-- FVM DEBUG: Uncached file processing now for $gfurl -->" . PHP_EOL; }

					fvm_set_transient($tkey, $json);

				}

				

				# decode 

				$res = json_decode($json, true);

				

				# response has failed

				if($res['status'] != true) {

					$log.= $res['log'];

					continue;

				}

				

				# append code to merged file

				$code.= $res['code'];

				$log.= $res['log'];

				

				# inline css or fail

				if($res['code'] !== false) { 

					echo '<style type="text/css" media="all">'.$res['code'].'</style>'.PHP_EOL;				

				} else {

					echo "<!-- GOOGLE FONTS REQUEST FAILED for $gfurl -->\n";

				}

				

			# fallback, enqueue google fonts

			} else {

				wp_enqueue_style('footer-fvm-fonts', $gfurl, array(), null, 'all');

			}

			

		}

	}

}





# get groups of handles

$uniq = array(); 

foreach( $styles->to_do as $handle ) :



	# skip already processed google fonts

	if(isset($google_fonts[$handle])) { continue; }

	

	# conditionals

	$conditional = NULL; if(isset($wp_styles->registered[$handle]->extra["conditional"])) { 

		$conditional = $wp_styles->registered[$handle]->extra["conditional"]; # such as ie7, ie8, ie9, etc

	}

	

	# mediatype

	$mt = isset($wp_styles->registered[$handle]->args) ? $wp_styles->registered[$handle]->args : 'all';

	if ($mt == 'screen' || $mt == 'screen, print' || empty($mt) || is_null($mt) || $mt == false) { $mt = 'all'; } 

	$mediatype = $mt;

	

	# get full url

	$hurl = fastvelocity_min_get_hurl($wp_styles->registered[$handle]->src, $wp_domain, $wp_home);

	

	# inlined scripts without file

	if( empty($hurl)) {

		continue;

	}

	

	# mark duplicates as done and remove from the queue

	if(!empty($hurl)) {

		$key = hash('sha1', $hurl); 

		if (isset($uniq[$key])) { $done = array_merge($done, array($handle)); continue; } else { $uniq[$key] = $handle; }

	}

	

	# IE only files don't increment things

	$ieonly = fastvelocity_ie_blacklist($hurl);

	if($ieonly == true) { continue; }

	

	

	# Exclude specific CSS files from PSI?

	if($fvm_min_excludecsslist != false && is_array($fvm_min_excludecsslist) && fastvelocity_min_in_arrayi($hurl, $fvm_min_excludecsslist)) {

		$cssguid = 'fvm'.hash('sha1', $hurl);

		echo '<script type="text/javascript">if(fvmuag()){';

		echo 'var '.$cssguid.'=document.createElement("link");'.$cssguid.'.rel="stylesheet",'.$cssguid.'.type="text/css",'.$cssguid.'.media="async",'.$cssguid.'.href="'.$hurl.'",'.$cssguid.'.onload=function(){'.$cssguid.'.media="'.$mediatype.'"},document.getElementsByTagName("head")[0].appendChild('.$cssguid.');';

		echo '}</script>';

		$done = array_merge($done, array($handle)); continue;

	}

	

	# font awesome processing, async css

	if($fvm_fawesome_method == 2 && stripos($hurl, 'font-awesome') !== false) {

		echo '<link rel="preload" href="'.$hurl.'" as="style" media="'.$mediatype.'" onload="this.onload=null;this.rel=\'stylesheet\'" />';

		echo '<noscript><link rel="stylesheet" href="'.$hurl.'" media="'.$mediatype.'" /></noscript>';

		echo '<!--[if IE]><link rel="stylesheet" href="'.$hurl.'" media="'.$mediatype.'" /><![endif]-->';

		$done = array_merge($done, array($handle)); continue;

	}	

	

	# font awesome processing, async and exclude from PSI

	if($fvm_fawesome_method == 3 && stripos($hurl, 'font-awesome') !== false) {

		$cssguid = 'fvm'.hash('sha1', $hurl);

		echo '<script type="text/javascript">if(fvmuag()){';

		echo 'var '.$cssguid.'=document.createElement("link");'.$cssguid.'.rel="stylesheet",'.$cssguid.'.type="text/css",'.$cssguid.'.media="async",'.$cssguid.'.href="'.$hurl.'",'.$cssguid.'.onload=function(){'.$cssguid.'.media="'.$mediatype.'"},document.getElementsByTagName("head")[0].appendChild('.$cssguid.');';

		echo '}</script>';

		$done = array_merge($done, array($handle)); continue;

	}

	

	# skip ignore list, conditional css, external css, font-awesome merge

	if ( (!fastvelocity_min_in_arrayi($hurl, $ignore) && !isset($conditional) && fvm_internal_url($hurl, $wp_home)) 

		|| empty($hurl) 

		|| ($fvm_fawesome_method == 1 && stripos($hurl, 'font-awesome') !== false)) {

			

		# colect inline css for this handle

		if(isset($wp_styles->registered[$handle]->extra['after']) && is_array($wp_styles->registered[$handle]->extra['after'])) { 

			$inline_css[$handle] = fastvelocity_min_minify_css_string(implode('', $wp_styles->registered[$handle]->extra['after'])); # save

			$wp_styles->registered[$handle]->extra['after'] = null; # dequeue

		}	

			

		# process

		if(isset($footer[count($footer)-1]['handle']) || count($footer) == 0 || $footer[count($footer)-1]['media'] != $wp_styles->registered[$handle]->args) {

			array_push($footer, array('handles'=>array(),'media'=>$mediatype));

		}

	

		# push it to the array get latest modified time

		array_push($footer[count($footer)-1]['handles'], $handle);

		

	# external and ignored css

	} else {

		

		# normal enqueueing

		array_push($footer, array('handle'=>$handle));

	}

endforeach;





# reorder CSS by mediatypes

if(!$skip_cssorder) {

	if(count($footer) > 0) {



		# get unique mediatypes

		$allmedia = array(); 

		foreach($footer as $key=>$array) { 

			if(isset($array['media'])) { $allmedia[$array['media']] = ''; } 

		}



		# extract handles by mediatype

		$grouphandles = array(); 

		foreach ($allmedia as $md=>$var) { 

			foreach($footer as $array) { 

				if (isset($array['media']) && $array['media'] === $md) { 

					foreach($array['handles'] as $h) { $grouphandles[$md][] = $h; } 

				} 

			} 

		}



		# reset and reorder footer by mediatypes

		$newfooter = array();

		foreach ($allmedia as $md=>$var) { $newfooter[] = array('handles' => $grouphandles[$md], 'media'=>$md); }

		if(count($newfooter) > 0) { $footer = $newfooter; }

	}

}



# loop through footer css and merge

for($i=0,$l=count($footer);$i<$l;$i++) {

	if(!isset($footer[$i]['handle'])) {

		

		# get has for the inline css in this group

		$inline_css_group = array();

		foreach($footer[$i]['handles'] as $h) { if(isset($inline_css[$h]) && !empty($inline_css[$h])) { $inline_css_group[] = $inline_css[$h]; } }

		$inline_css_hash = md5(implode('',$inline_css_group));

		

		# static cache file info + done

		$done = array_merge($done, $footer[$i]['handles']);		

		$hash = 'footer-'.hash('sha1',implode('',$footer[$i]['handles']).$inline_css_hash);



		# create cache files and urls

		$file = $cachedir.fastvelocity_get_os_slash().$hash.'.min.css';

		$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.css');

		

		# generate a new cache file

		clearstatcache();

		if (!file_exists($file)) {

			

			# code and log initialization

			$log = '';

			$code = '';	

		

			# minify and write to file

			foreach($footer[$i]['handles'] as $handle) :

				if(!empty($wp_styles->registered[$handle]->src)) {

					

					# get hurl per handle

					$hurl = fastvelocity_min_get_hurl($wp_styles->registered[$handle]->src, $wp_domain, $wp_home);

					

					# inlined scripts without file

					if( empty($hurl)) {

						continue;

					}

					

					# print url

					$printurl = str_ireplace(array(site_url(), home_url(), 'http:', 'https:'), '', $hurl);

					

					# download, minify, cache

					$tkey = 'css-'.hash('sha1', $handle.$hurl).'.css';

					$json = false; $json = fvm_get_transient($tkey);

					if ( $json === false) {

						$json = fvm_download_and_minify($hurl, null, $disable_css_minification, 'css', $handle);

						if($fvm_debug == true) { echo "<!-- FVM DEBUG: Uncached file processing now for $handle / $hurl -->" . PHP_EOL; }

						fvm_set_transient($tkey, $json);

					}

					

					# decode 

					$res = json_decode($json, true);

					

					# response has failed

					if($res['status'] != true) {

						$log.= $res['log'];

						continue;

					}

					

					# append code to merged file

					$code.= $res['code'];

					$log.= $res['log'];

					

					# append inlined styles

					if(isset($inline_css[$handle]) && !empty($inline_css[$handle])) { 

						$code.= $inline_css[$handle]; 

					}

				

				# consider dependencies on handles with an empty src

				} else {

					wp_dequeue_script($handle); 

					wp_enqueue_script($handle);

				}

			endforeach;	

			

			# prepare log

			$log = "PROCESSED on ".date('r').PHP_EOL.$log."PROCESSED from ".home_url(add_query_arg( NULL, NULL )).PHP_EOL;

			

			# generate cache, add inline css, write log

			if(!empty($code)) {

				file_put_contents($file.'.txt', $log);

				file_put_contents($file, $code); # preserve style tags

				file_put_contents($file.'.gz', gzencode(file_get_contents($file), 9));

				

				# permissions

				fastvelocity_fix_permission_bits($file.'.txt');

				fastvelocity_fix_permission_bits($file);

				fastvelocity_fix_permission_bits($file.'.gz');

				

				# brotli static support

				if(function_exists('brotli_compress')) {

					file_put_contents($file.'.br', brotli_compress(file_get_contents($file), 11));

					fastvelocity_fix_permission_bits($file.'.br');

				}

			}

		}



		# register and enqueue minified file, consider excluding of mediatype "print" and inline css

		if ($remove_print_mediatypes != true || ($remove_print_mediatypes == true && $footer[$i]['media'] != 'print')) {



			# the developers tab, takes precedence

			

			# Async CSS with loadCSS ?

			if($fvmloadcss != false && $fvm_remove_css != true) {

				$mt = $footer[$i]['media'];

				echo '<link rel="preload" href="'.$file_url.'" as="style" media="'.$mt.'" onload="this.onload=null;this.rel=\'stylesheet\'" />';

				echo '<noscript><link rel="stylesheet" href="'.$file_url.'" media="'.$mt.'" /></noscript>';

				echo '<!--[if IE]><link rel="stylesheet" href="'.$file_url.'" media="'.$mt.'" /><![endif]-->';

			

			# enqueue file, if not empty

			} else {

				if(file_exists($file) && filesize($file) > 0) {



					# inline if the file is smaller than 20KB or option has been enabled

					if(filesize($file) < 20000 || $force_inline_css_footer != false) {

						echo '<style id="fvm-footer-'.$i.'" media="'.$footer[$i]['media'].'">'.file_get_contents($file).'</style>';

					} else {

						# enqueue it

						wp_enqueue_style("fvm-footer-$i", $file_url, array(), null, $footer[$i]['media']); 

					}

				} else {

					# file could not be generated, output something meaningful

					echo "<!-- ERROR: FVM was not allowed to save it's cache on - $file -->";

					echo "<!-- Please check if the path above is correct and ensure your server has writting permission there! -->";

					echo "<!-- If you found a bug, please report this on https://wordpress.org/support/plugin/fast-velocity-minify/ -->";

				}

			}

		}



	# other css need to be requeued for the order of files to be kept

	} else {

		wp_dequeue_style($footer[$i]['handle']); 

		wp_enqueue_style($footer[$i]['handle']);

	}

}



# remove from queue

$wp_styles->done = $done;

}

###########################################









###########################################

# defer CSS globally from the header (order matters)

# dev: https://www.filamentgroup.com/lab/async-css.html

###########################################

function fvm_add_loadcss() { 



echo <<<EOF

<script>

/* loadCSS. [c]2017 Filament Group, Inc. MIT License */

(function(w){if(!w.loadCSS)w.loadCSS=function(){};var rp=loadCSS.relpreload={};rp.support=function(){var ret;try{ret=w.document.createElement("link").relList.supports("preload")}catch(e){ret=false}return function(){return ret}}();rp.bindMediaToggle=function(link){var finalMedia=link.media||"all";function enableStylesheet(){if(link.addEventListener)link.removeEventListener("load",enableStylesheet);else if(link.attachEvent)link.detachEvent("onload",enableStylesheet);link.setAttribute("onload",null);link.media=finalMedia}if(link.addEventListener)link.addEventListener("load",enableStylesheet);else if(link.attachEvent)link.attachEvent("onload",enableStylesheet);setTimeout(function(){link.rel="stylesheet";link.media="only x"});setTimeout(enableStylesheet,3E3)};rp.poly=function(){if(rp.support())return;var links=w.document.getElementsByTagName("link");for(var i=0;i<links.length;i++){var link=links[i];if(link.rel==="preload"&&link.getAttribute("as")==="style"&&!link.getAttribute("data-loadcss")){link.setAttribute("data-loadcss", true);rp.bindMediaToggle(link)}}};if(!rp.support()){rp.poly();var run=w.setInterval(rp.poly,500);if(w.addEventListener)w.addEventListener("load",function(){rp.poly();w.clearInterval(run)});else if(w.attachEvent)w.attachEvent("onload",function(){rp.poly();w.clearInterval(run)})}if(typeof exports!=="undefined")exports.loadCSS=loadCSS;else w.loadCSS=loadCSS})(typeof global!=="undefined"?global:this);

</script>

EOF;



}



# fvm load async scripts with callback

function fvm_add_loadasync() { 

global $fvm_min_excludejslist;

if($fvm_min_excludejslist != false && is_array($fvm_min_excludejslist) && count($fvm_min_excludejslist) > 0) {



echo <<<EOF

<script>function loadAsync(e,a){var t=document.createElement("script");t.src=e,null!==a&&(t.readyState?t.onreadystatechange=function(){"loaded"!=t.readyState&&"complete"!=t.readyState||(t.onreadystatechange=null,a())}:t.onload=function(){a()}),document.getElementsByTagName("head")[0].appendChild(t)}</script>

EOF;



}

}







# add inline CSS code / Critical Path

function fvm_add_criticial_path() {

	$no_global_critical_path_css = false;

	$critical_path_css = get_option('fastvelocity_min_critical_path_css');

	$critical_path_css_is_front_page = get_option('fastvelocity_min_critical_path_css_is_front_page');



	# critical path (is_front_page only)

	if(!empty($critical_path_css_is_front_page) && $critical_path_css_is_front_page !== false) {

		echo '<style id="critical-path-is-front-page" type="text/css" media="all">'.$critical_path_css_is_front_page.'</style>'.PHP_EOL;

		$no_global_critical_path_css = 1;

	}



	# global path, except if there's something else more specific

	if(!empty($critical_path_css) && $critical_path_css !== false && $no_global_critical_path_css === false) {

		echo '<style id="critical-path-global" type="text/css" media="all">'.$critical_path_css.'</style>'.PHP_EOL; 

	}

}











###########################################

# add preconnect and preload headers

###########################################

function fvm_extra_preload_headers() { 



# fetch headers

$preload = array_map('trim', explode(PHP_EOL, get_option('fastvelocity_min_hpreload')));

$preconnect = array_map('trim', explode(PHP_EOL, get_option('fastvelocity_min_hpreconnect')));



# preconnect

if(is_array($preload) && count($preload) > 0) {

	foreach ($preload as $h) {

		if(!empty($h)) {

			header($h, false);

		}

	}

}



# preload

if(is_array($preconnect) && count($preconnect) > 0) {

	foreach ($preconnect as $url) {

		if(!empty($url) && filter_var($url, FILTER_VALIDATE_URL)) {

			header("Link: <$url>; rel=preconnect", false);

		}

	}

}



# fvm css and js generated files

$fvm_headers = fastvelocity_get_preload_headers();

if($fvm_headers != false) {

	$nh = array_map('trim', explode(PHP_EOL, $fvm_headers));

	foreach ($nh as $h) {

		if(!empty($h)) {

			header($h, false);

		}

	}

}



}







# inline css in place, instead of inlining the large file

function fastvelocity_optimizecss($html, $handle, $href, $media){

	global $fvm_debug, $wp_domain, $wp_home, $force_inline_css, $fvmualist, $fvm_collect_google_fonts, $force_inline_googlefonts, $min_async_googlefonts, $remove_googlefonts, $skip_google_fonts, $css_hide_googlefonts, $remove_print_mediatypes, $ignore, $blacklist, $ignorelist, $wp_home, $fvmloadcss, $fvm_remove_css, $fvm_cdn_url, $disable_minification, $fvm_min_excludecsslist, $disable_css_minification, $fvm_fix_editor, $fvm_fawesome_method;

		

		# current timestamp

		$ctime = get_option('fvm-last-cache-update', '0'); 

		

		# make sure href is complete

		$href = fastvelocity_min_get_hurl($href, $wp_domain, $wp_home);

		

		if($fvm_debug == true) { echo "<!-- FVM DEBUG: Inline CSS processing start $handle / $href -->" . PHP_EOL; }

		

		# prevent optimization for these locations

		if(fastvelocity_exclude_contents()) {

			return $html;

		}

		

		# skip all this, if the async css option is enabled

		if($fvmloadcss != false) {

			return $html;

		}

		

		# remove all css?

		if($fvm_remove_css != false) {

			return false; 

		}

		

		# leave conditionals alone

		$conditional = wp_styles()->get_data($handle, 'conditional');

		if($conditional != false) {

			return $html;

		}

		

		# mediatype fix for some plugins + remove print mediatypes

		if ($media == 'screen' || $media == 'screen, print' || empty($media) || is_null($media) || $media == false) { $media = 'all'; }

		if($remove_print_mediatypes != false && $media == 'print') {

			return false; 

		}

		

		# Exclude specific CSS files from PSI?

		if($fvm_min_excludecsslist != false && is_array($fvm_min_excludecsslist) && fastvelocity_min_in_arrayi($href, $fvm_min_excludecsslist)) {

			$cssguid = 'fvm'.hash('sha1', $href);

			echo '<script type="text/javascript">if(fvmuag()){';

			echo 'var '.$cssguid.'=document.createElement("link");'.$cssguid.'.rel="stylesheet",'.$cssguid.'.type="text/css",'.$cssguid.'.media="async",'.$cssguid.'.href="'.$href.'",'.$cssguid.'.onload=function(){'.$cssguid.'.media="'.$media.'"},document.getElementsByTagName("head")[0].appendChild('.$cssguid.');';

			echo '}</script>';

			return false;

		}

		

		# remove FVM from the ignore list

		array_filter($ignore, function ($var) { return (stripos($var, '/fvm/') === false); });

		

		# return if in any ignore or black list

		if (count($ignore) > 0 && fastvelocity_min_in_arrayi($href, $ignore) || count($blacklist) > 0 && fastvelocity_min_in_arrayi($href, $blacklist) || count($ignorelist) > 0 && fastvelocity_min_in_arrayi($href, $ignorelist)) { 

				return $html;

		}

		

		# remove google fonts completely?

		if($remove_googlefonts != false && stripos($href, 'fonts.googleapis.com') !== false) {

			return false; 

		}

		

		# handle google fonts here, when merging is disabled

		if(stripos($href, 'fonts.googleapis.com') !== false && $skip_google_fonts != false) {

			

			# hide google fonts from PSI

			if($css_hide_googlefonts == true) {

				$cssguid = 'fvm'.hash('sha1', $href);

				echo '<script type="text/javascript">if(fvmuag()){';

				echo 'var '.$cssguid.'=document.createElement("link");'.$cssguid.'.rel="stylesheet",'.$cssguid.'.type="text/css",'.$cssguid.'.media="async",'.$cssguid.'.href="'.$href.'",'.$cssguid.'.onload=function(){'.$cssguid.'.media="all"},document.getElementsByTagName("head")[0].appendChild('.$cssguid.');';

				echo '}</script>';

				return false; 

			}

			

			# load google fonts async

			if($min_async_googlefonts != false) {

				echo '<link rel="preload" href="'.$href.'" as="style" media="all" onload="this.onload=null;this.rel=\'stylesheet\'" />';

				echo '<noscript><link rel="stylesheet" href="'.$href.'" media="all" /></noscript>';

				echo '<!--[if IE]><link rel="stylesheet" href="'.$href.'" media="all" /><![endif]-->';

				return false; 

			}

		}

		

		# font awesome processing, async css

		if($fvm_fawesome_method == 2 && stripos($href, 'font-awesome') !== false) {

			echo '<link rel="preload" href="'.$href.'" as="style" media="'.$media.'" onload="this.onload=null;this.rel=\'stylesheet\'" />';

			echo '<noscript><link rel="stylesheet" href="'.$href.'" media="'.$media.'" /></noscript>';

			echo '<!--[if IE]><link rel="stylesheet" href="'.$href.'" media="'.$media.'" /><![endif]-->';

			return false;

		}	

		

		# font awesome processing, async and exclude from PSI

		if($fvm_fawesome_method == 3 && stripos($href, 'font-awesome') !== false) {

			$cssguid = 'fvm'.hash('sha1', $href);

			echo '<script type="text/javascript">if(fvmuag()){';

			echo 'var '.$cssguid.'=document.createElement("link");'.$cssguid.'.rel="stylesheet",'.$cssguid.'.type="text/css",'.$cssguid.'.media="async",'.$cssguid.'.href="'.$href.'",'.$cssguid.'.onload=function(){'.$cssguid.'.media="'.$media.'"},document.getElementsByTagName("head")[0].appendChild('.$cssguid.');';

			echo '}</script>';

			return false;

		}

		

		# font awesome processing, inline

		if($fvm_fawesome_method == 1 && stripos($href, 'font-awesome') !== false) {

			

			# download, minify, cache

			$tkey = 'css-'.hash('sha1', $handle.$href).'.css';

			$json = false; $json = fvm_get_transient($tkey);

			if ( $json === false) {

				$json = fvm_download_and_minify($href, null, $disable_css_minification, 'css', $handle);

				if($fvm_debug == true) { echo "<!-- FVM DEBUG: Uncached file processing now for $handle / $href -->" . PHP_EOL; }

				fvm_set_transient($tkey, $json);

			}

			

			# decode 

			$res = json_decode($json, true);

			

			# add font-display

			# https://developers.google.com/web/updates/2016/02/font-display

			$res['code'] = str_ireplace('font-style:normal;', 'font-display:block;font-style:normal;', $res['code']);

			

			# inline css or fail

			if($res['status'] != false) { 

				echo '<style type="text/css" media="all">'.$res['code'].'</style>'.PHP_EOL;

				return false;

			} else {

				if($fvm_debug == true) { echo "<!-- FVM DEBUG: Font Awesome request failed for $href -->" . PHP_EOL; }

				return $html;

			}

		}

		

		# inline google fonts, do not collect

		if(stripos($href, 'fonts.googleapis.com') !== false && $force_inline_googlefonts != false && $css_hide_googlefonts != true && $min_async_googlefonts != true) {

			

			# download, minify, cache

			$tkey = 'css-'.hash('sha1', $handle.$href).'.css';

			$json = false; $json = fvm_get_transient($tkey);

			if ( $json === false) {

				$json = fvm_download_and_minify($href, null, $disable_css_minification, 'css', $handle);

				if($fvm_debug == true) { echo "<!-- FVM DEBUG: Uncached file processing now for $handle / $href -->" . PHP_EOL; }

				fvm_set_transient($tkey, $json);

			}

			

			# decode 

			$res = json_decode($json, true);

			

			# add font-display

			# https://developers.google.com/web/updates/2016/02/font-display

			$res['code'] = str_ireplace('font-style:normal;', 'font-display:block;font-style:normal;', $res['code']);

			

			# inline css or fail

			if($res['status'] != false) { 

				echo '<style type="text/css" media="all">'.$res['code'].'</style>'.PHP_EOL;

				return false;

			} else {

				if($fvm_debug == true) { echo "<!-- FVM DEBUG: Google fonts request failed for $href -->" . PHP_EOL; }

				return $html;

			}

		}

		

		# collect and remove google fonts for merging

		if(stripos($href, 'fonts.googleapis.com') !== false){

			$fvm_collect_google_fonts[$handle] = $href;

			return false; 

		}

		

		# skip external scripts that are not specifically allowed

		if (fvm_internal_url($href, $wp_home) === false || empty($href)) {

			if($fvm_debug == true) { echo "<!-- FVM DEBUG: Skipped the next external enqueued CSS -->" . PHP_EOL; }

			return $html;

		}

		

		# download, minify, cache

		$tkey = 'css-'.hash('sha1', $handle.$href).'.css';

		$json = false; $json = fvm_get_transient($tkey);

		if ( $json === false) {

			$json = fvm_download_and_minify($href, null, $disable_css_minification, 'css', $handle);

			if($fvm_debug == true) { echo "<!-- FVM DEBUG: Uncached file processing now for $handle / $href -->" . PHP_EOL; }

			fvm_set_transient($tkey, $json);

		}

		

		# decode 

		$res = json_decode($json, true);

		

		# inline it + other inlined children styles

		if($res['status'] != false) {

			echo '<style type="text/css" media="'.$media.'">'.$res['code'].'</style>'; 

			

			# get inline_styles for this handle, minify and print

			$inline_styles = array();

			$inline_styles = wp_styles()->get_data( $handle, 'after' );

			if($inline_styles != false) {



				# string type

				if(is_string($inline_styles)) {

					$code = fastvelocity_min_get_css($href, $inline_styles, $disable_css_minification);

					if(!empty($code) && $code != false) { 

						echo '<style type="text/css" media="'.$media.'">'.$code.'</style>'; 

					}

				}

				

				# array type

				if(is_array($inline_styles)) {

					foreach ($inline_styles as $st) {

						$code = fastvelocity_min_get_css($href, $st, $disable_css_minification);

						if(!empty($code) && $code != false) { 

							echo '<style type="text/css" media="'.$media.'">'.$code.'</style>'; 

						}

					}

				}

			}

			

			# prevent default

			return false;

			

		} else {

			if($fvm_debug == true) { echo "<!-- FVM DEBUG:  $handle / $href returned an empty from minification -->" . PHP_EOL; }

			return $html;

		}

		

	# fallback, for whatever reason

	echo "<!-- ERROR: FVM couldn't catch the CSS file below. Please report this on https://wordpress.org/support/plugin/fast-velocity-minify/ -->";

	return $html;

}





# critical css for the page

function fastvelocity_add_google_fonts_merged() {

	global $fvm_collect_google_fonts, $fvmualist, $css_hide_googlefonts, $skip_google_fonts, $min_async_googlefonts, $fvm_debug;

	

	# prevent optimization for logged in users

	if (is_admin() || is_preview() || is_customize_preview()) {

		return false;

	}

	

	# must have something to do

	if(!is_array($fvm_collect_google_fonts) || count($fvm_collect_google_fonts) == 0) {

		return false;

	}

	

	# merge google fonts

	$gfurl = fastvelocity_min_concatenate_google_fonts($fvm_collect_google_fonts);

	if(empty($gfurl)) {

		return false;

	}

	

	# hide google fonts from PSI

	if($css_hide_googlefonts == true) {

		

		# make a stylesheet, hide from PSI

		$cssguid = 'fvm'.hash('sha1', $gfurl);

		echo '<script type="text/javascript">if(fvmuag()){';

		echo 'var '.$cssguid.'=document.createElement("link");'.$cssguid.'.rel="stylesheet",'.$cssguid.'.type="text/css",'.$cssguid.'.media="async",'.$cssguid.'.href="'.$gfurl.'",'.$cssguid.'.onload=function(){'.$cssguid.'.media="all"},document.getElementsByTagName("head")[0].appendChild('.$cssguid.');';

		echo '}</script>';

		

	# load google fonts async	

	} elseif($min_async_googlefonts != false) {

		echo '<link rel="preload" href="'.$gfurl.'" as="style" media="all" onload="this.onload=null;this.rel=\'stylesheet\'" />';

		echo '<noscript><link rel="stylesheet" href="'.$gfurl.'" media="all" /></noscript>';

		echo '<!--[if IE]><link rel="stylesheet" href="'.$gfurl.'" media="all" /><![endif]-->';

	

	# fallback to normal inline

	} else {

		echo '<link rel="stylesheet" href="'.$gfurl.'" media="all" />';

	}

	

	# unset per hook

	foreach($fvm_collect_google_fonts as $k=>$v) {

		unset($fvm_collect_google_fonts[$k]);

	}



} 







# collect all fvm JS files and save them to an headers file

function fastvelocity_collect_js_preload_headers($html, $handle, $src){

	global $cachedirurl, $collect_preload_js, $fvm_enabled_css_preload, $fvm_enabled_js_preload;

	

	# return if disabled

	if ($fvm_enabled_js_preload != true) { 

		return $html;

	}

	

	# collect

	if (stripos($src, $cachedirurl) !== false) { 

		$collect_preload_js[] = $src;

	}

	return $html;

}



# generate preload headers file

function fastvelocity_generate_preload_headers(){

	global $cachedirurl, $collect_preload_css, $collect_preload_js, $fvm_enabled_css_preload, $fvm_enabled_js_preload;

	

	# return if disabled

	if ($fvm_enabled_css_preload != true && $fvm_enabled_js_preload != true) { 

		return false;

	}



	# get host with multisite support and query strings

	$host = htmlentities($_SERVER['SERVER_NAME']);

	if(empty($hosts)) { $host = htmlentities($_SERVER['HTTP_HOST']); }

	$request_query = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY);

	$request_uri = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );

	$is_admin = strpos( $request_uri, '/wp-admin/' );

	

	# always false for admin pages

	if( false !== $is_admin){ 

		return false;

	}

	

	# initialize headers

	$headers = array();

	

	# css headers

	if ($fvm_enabled_css_preload != false && is_array($collect_preload_css) && count($collect_preload_css) > 0) { 

		foreach($collect_preload_css as $u) {

			

			# filter out footer footer files, because they are not in the critical path

			if(stripos($u, $cachedirurl . '/footer-') !== false) { continue; }

			

			# add headers

			$headers[] = "Link: <$u>; rel=preload; as=style";

		}

	}

	

	# js headers

	if ($fvm_enabled_js_preload != false && is_array($collect_preload_js) && count($collect_preload_js) > 0) { 

		foreach($collect_preload_js as $u) {

			

			# filter out footer footer files, because they are not in the critical path

			if(stripos($u, $cachedirurl . '/footer-') !== false) { continue; }

			

			# add headers

			$headers[] = "Link: <$u>; rel=preload; as=script";

		}

	}

	

	# must have something

	if(count($headers) == 0) {

		return false;

	} else {

		$headers = implode(PHP_EOL, $headers);

	}

	

	# get cache path

	$cachepath = fvm_cachepath();

	$headerdir = $cachepath['headerdir'];

	$cachefilebase = $headerdir.'/';

	

	# possible cache file locations

	$b = $cachefilebase . md5($host.'-'.$request_uri).'.header';

	$a = $cachefilebase . md5($host.'-'.$request_uri.$request_query).'.header';

	

	# reset file cache

	clearstatcache();

	

	# if there are no query strings

	if($b == $a) {

		if(!file_exists($a)) { 

			file_put_contents($a, $headers); 

			fastvelocity_fix_permission_bits($a);

		}

		return false;

	}

	

	# b fallback

	if($b != $a && !file_exists($b)) {

		file_put_contents($b, $headers);

		fastvelocity_fix_permission_bits($b);

	}

	

	return false;

}





# get current headers file for the url

function fastvelocity_get_preload_headers(){

	global $fvm_enabled_css_preload, $fvm_enabled_js_preload;

	

	# return if disabled

	if ($fvm_enabled_css_preload != true && $fvm_enabled_js_preload != true) { 

		return false;

	}

	

	# get host with multisite support and query strings

	$host = htmlentities($_SERVER['SERVER_NAME']);

	if(empty($hosts)) { $host = htmlentities($_SERVER['HTTP_HOST']); }

	$request_query = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY);

	$request_uri = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );

	$is_admin = strpos( $request_uri, '/wp-admin/' );

	

	# always false for admin pages

	if( false !== $is_admin){ 

		return false;

	}

	

	# get cache path

	$cachepath = fvm_cachepath();

	$headerdir = $cachepath['headerdir'];

	$cachefilebase = $headerdir.'/';

	

	# possible cache file locations

	$b = $cachefilebase . md5($host.'-'.$request_uri).'.header';

	$a = $cachefilebase . md5($host.'-'.$request_uri.$request_query).'.header';

	

	# reset file cache

	clearstatcache();

	

	# return header files or fallback

	if($b == $a && file_exists($a)) { return file_get_contents($a); }

	if($b != $a && file_exists($b)) { return file_get_contents($b); }

	

	return false;

}







# cron job to delete old FVM cache

add_action('fastvelocity_purge_old_cron_event', 'fvm_purge_old');



