933 lines
31 KiB
PHP
933 lines
31 KiB
PHP
|
|
<?php
|
||
|
|
/*
|
||
|
|
Plugin Name: WP Minify
|
||
|
|
Plugin URI: http://omninoggin.com/wordpress-plugins/wp-minify-wordpress-plugin/
|
||
|
|
Description: This plugin uses the Minify engine to combine and compress JS and CSS files to improve page load time.
|
||
|
|
Version: 1.2.0
|
||
|
|
Author: Thaya Kareeson
|
||
|
|
Author URI: http://omninoggin.com
|
||
|
|
*/
|
||
|
|
|
||
|
|
/*
|
||
|
|
Copyright 2009-2011 Thaya Kareeson (email : thaya.kareeson@gmail.com)
|
||
|
|
|
||
|
|
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 3 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, see <http://www.gnu.org/licenses/>.
|
||
|
|
*/
|
||
|
|
|
||
|
|
class WPMinify {
|
||
|
|
|
||
|
|
var $author_homepage = 'http://omninoggin.com/';
|
||
|
|
var $homepage = 'http://omninoggin.com/wordpress-plugins/wp-minify-wordpress-plugin/';
|
||
|
|
var $name = 'wp_minify';
|
||
|
|
var $name_dashed = 'wp-minify';
|
||
|
|
var $name_proper = 'WP Minify';
|
||
|
|
var $required_wp_version = '2.7';
|
||
|
|
var $version = '1.2.0';
|
||
|
|
|
||
|
|
var $c = null;
|
||
|
|
var $debug = false;
|
||
|
|
var $cache_location = 'wp-content/plugins/wp-minify/cache/';
|
||
|
|
var $url_len_limit = 2000;
|
||
|
|
var $minify_limit = 50;
|
||
|
|
var $buffer_started = false;
|
||
|
|
var $default_exclude = array();
|
||
|
|
|
||
|
|
function WPMinify() {
|
||
|
|
// initialize common functions
|
||
|
|
$this->c = new WPMinifyCommon($this);
|
||
|
|
|
||
|
|
// load translation
|
||
|
|
$this->c->load_text_domain();
|
||
|
|
|
||
|
|
// register admin scripts
|
||
|
|
add_action('admin_init', array($this->c, 'a_register_scripts'));
|
||
|
|
add_action('admin_init', array($this->c, 'a_register_styles'));
|
||
|
|
|
||
|
|
// check wp version
|
||
|
|
add_action('admin_head', array($this->c, 'a_check_version'));
|
||
|
|
|
||
|
|
// load admin menu
|
||
|
|
add_action('admin_menu', array($this, 'a_menu'));
|
||
|
|
|
||
|
|
// register ajax handler
|
||
|
|
add_action('wp_ajax_wpm', array($this, 'a_ajax_handler'));
|
||
|
|
|
||
|
|
// No need to minify admin stuff
|
||
|
|
if (!is_admin() && !is_feed() && !defined('XMLRPC_REQUEST')) {
|
||
|
|
// Don't minify if if user passes wp-minify-off=1 in GET parameter
|
||
|
|
if (!(isset($_GET['wp-minify-off']) && $_GET['wp-minify-off'])) {
|
||
|
|
add_action('init', array($this, 'pre_content'), 99999);
|
||
|
|
add_action('wp_footer', array($this, 'post_content'));
|
||
|
|
}
|
||
|
|
// advertise hook
|
||
|
|
add_action('wp_footer', array($this, 'advertise'));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// admin functions
|
||
|
|
|
||
|
|
function a_default_options() {
|
||
|
|
return array(
|
||
|
|
'cache_external' => false,
|
||
|
|
'cache_interval' => 900,
|
||
|
|
'css_exclude' => array(),
|
||
|
|
'css_include' => array(),
|
||
|
|
'debug_nominify' => false,
|
||
|
|
'debug_firephp' => false,
|
||
|
|
'enable_css' => true,
|
||
|
|
'enable_js' => true,
|
||
|
|
'enable_html' => true,
|
||
|
|
'auto_base' => true,
|
||
|
|
'extra_minify_options' => '',
|
||
|
|
'js_exclude' => array(),
|
||
|
|
'js_include' => array(),
|
||
|
|
'js_in_footer' => false,
|
||
|
|
'force_https' => false,
|
||
|
|
'pretty_url' => false,
|
||
|
|
'show_link' => false,
|
||
|
|
'show_advanced' => false,
|
||
|
|
'uri_exclude' => array(),
|
||
|
|
'version' => $this->version,
|
||
|
|
'deprecated' => array(
|
||
|
|
'wp_path', 'debug', 'debug_noprettyurl'
|
||
|
|
)
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_update_options() {
|
||
|
|
// new options
|
||
|
|
$wpm_new_options = stripslashes_deep($_POST['wpm_options_update']);
|
||
|
|
|
||
|
|
// current options
|
||
|
|
$wpm_current_options = get_option($this->name);
|
||
|
|
|
||
|
|
// convert "on" to true and "off" to false for checkbox fields
|
||
|
|
// and set defaults for fields that are left blank
|
||
|
|
if (isset($wpm_new_options['show_link']) && $wpm_new_options['show_link'] == "on")
|
||
|
|
$wpm_new_options['show_link'] = true;
|
||
|
|
else
|
||
|
|
$wpm_new_options['show_link'] = false;
|
||
|
|
|
||
|
|
if (isset($wpm_new_options['enable_js']))
|
||
|
|
$wpm_new_options['enable_js'] = true;
|
||
|
|
else
|
||
|
|
$wpm_new_options['enable_js'] = false;
|
||
|
|
|
||
|
|
if (isset($wpm_new_options['enable_css']))
|
||
|
|
$wpm_new_options['enable_css'] = true;
|
||
|
|
else
|
||
|
|
$wpm_new_options['enable_css'] = false;
|
||
|
|
|
||
|
|
if (isset($wpm_new_options['enable_html']))
|
||
|
|
$wpm_new_options['enable_html'] = true;
|
||
|
|
else
|
||
|
|
$wpm_new_options['enable_html'] = false;
|
||
|
|
|
||
|
|
if (isset($wpm_new_options['auto_base']))
|
||
|
|
$wpm_new_options['auto_base'] = true;
|
||
|
|
else
|
||
|
|
$wpm_new_options['auto_base'] = false;
|
||
|
|
|
||
|
|
if (isset($wpm_new_options['cache_external']))
|
||
|
|
$wpm_new_options['cache_external'] = true;
|
||
|
|
else
|
||
|
|
$wpm_new_options['cache_external'] = false;
|
||
|
|
|
||
|
|
if (isset($wpm_new_options['js_in_footer']))
|
||
|
|
$wpm_new_options['js_in_footer'] = true;
|
||
|
|
else
|
||
|
|
$wpm_new_options['js_in_footer'] = false;
|
||
|
|
|
||
|
|
if (isset($wpm_new_options['pretty_url']))
|
||
|
|
$wpm_new_options['pretty_url'] = true;
|
||
|
|
else
|
||
|
|
$wpm_new_options['pretty_url'] = false;
|
||
|
|
|
||
|
|
if (isset($wpm_new_options['debug_nominify']))
|
||
|
|
$wpm_new_options['debug_nominify'] = true;
|
||
|
|
else
|
||
|
|
$wpm_new_options['debug_nominify'] = false;
|
||
|
|
|
||
|
|
if (isset($wpm_new_options['debug_firephp']))
|
||
|
|
$wpm_new_options['debug_firephp'] = true;
|
||
|
|
else
|
||
|
|
$wpm_new_options['debug_firephp'] = false;
|
||
|
|
|
||
|
|
$this->a_set_minify_config($wpm_new_options['debug_nominify'], $wpm_new_options['debug_firephp']);
|
||
|
|
|
||
|
|
if ( isset($wpm_new_options['force_https']) )
|
||
|
|
$wpm_new_options['force_https'] = true;
|
||
|
|
else
|
||
|
|
$wpm_new_options['force_https'] = false;
|
||
|
|
|
||
|
|
if (strlen(trim($wpm_new_options['js_include'])) > 0)
|
||
|
|
$wpm_new_options['js_include'] = $this->array_trim(split(chr(10), str_replace(chr(13), '', $wpm_new_options['js_include'])));
|
||
|
|
else
|
||
|
|
$wpm_new_options['js_include'] = array();
|
||
|
|
|
||
|
|
if (strlen(trim($wpm_new_options['js_exclude'])) > 0)
|
||
|
|
$wpm_new_options['js_exclude'] = $this->array_trim(split(chr(10), str_replace(chr(13), '', $wpm_new_options['js_exclude'])));
|
||
|
|
else
|
||
|
|
$wpm_new_options['js_exclude'] = array();
|
||
|
|
|
||
|
|
if (strlen(trim($wpm_new_options['css_include'])) > 0)
|
||
|
|
$wpm_new_options['css_include'] = $this->array_trim(split(chr(10), str_replace(chr(13), '', $wpm_new_options['css_include'])));
|
||
|
|
else
|
||
|
|
$wpm_new_options['css_include'] = array();
|
||
|
|
|
||
|
|
if (strlen(trim($wpm_new_options['css_exclude'])) > 0)
|
||
|
|
$wpm_new_options['css_exclude'] = $this->array_trim(split(chr(10), str_replace(chr(13), '', $wpm_new_options['css_exclude'])));
|
||
|
|
else
|
||
|
|
$wpm_new_options['css_exclude'] = array();
|
||
|
|
|
||
|
|
if ( strlen(trim($wpm_new_options['uri_exclude'])) > 0 )
|
||
|
|
$wpm_new_options['uri_exclude'] = $this->array_trim(split(chr(10), str_replace(chr(13), '', $wpm_new_options['uri_exclude'])));
|
||
|
|
else
|
||
|
|
$wpm_new_options['uri_exclude'] = array();
|
||
|
|
|
||
|
|
// Update options
|
||
|
|
foreach ($wpm_new_options as $key => $value) {
|
||
|
|
$wpm_current_options[$key] = $value;
|
||
|
|
}
|
||
|
|
|
||
|
|
update_option($this->name, $wpm_current_options);
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_set_advanced_options($val) {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
$wpm_options['show_advanced'] = $val;
|
||
|
|
update_option($this->name, $wpm_options);
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_ajax_handler() {
|
||
|
|
check_ajax_referer($this->name);
|
||
|
|
if (isset($_POST['wpm_action'])) {
|
||
|
|
if (strtolower($_POST['wpm_action']) == 'show_advanced') {
|
||
|
|
$this->a_set_advanced_options(true);
|
||
|
|
}
|
||
|
|
elseif (strtolower($_POST['wpm_action']) == 'hide_advanced') {
|
||
|
|
$this->a_set_advanced_options(false);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
echo 'Invalid wpm_action.';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
exit();
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_request_handler() {
|
||
|
|
if (isset($_POST['wpm_options_update_submit'])) {
|
||
|
|
check_admin_referer($this->name);
|
||
|
|
$this->a_update_options();
|
||
|
|
add_action('admin_notices', array($this->c, 'a_notify_updated'));
|
||
|
|
}
|
||
|
|
elseif (isset($_POST['wpm_options_clear_cache_submit'])) {
|
||
|
|
// if user wants to regenerate nonce
|
||
|
|
check_admin_referer($this->name);
|
||
|
|
$this->c->a_clear_cache();
|
||
|
|
add_action('admin_notices', array($this->c, 'a_notify_cache_cleared'));
|
||
|
|
}
|
||
|
|
elseif (isset($_POST['wpm_options_upgrade_submit'])) {
|
||
|
|
// if user wants to upgrade options (for new options on version upgrades)
|
||
|
|
check_admin_referer($this->name);
|
||
|
|
$this->c->a_upgrade_options();
|
||
|
|
add_action('admin_notices', array($this->c, 'a_notify_upgraded'));
|
||
|
|
}
|
||
|
|
elseif (isset($_POST['wpm_options_reset_submit'])) {
|
||
|
|
// if user wants to reset all options
|
||
|
|
check_admin_referer($this->name);
|
||
|
|
$this->c->a_reset_options();
|
||
|
|
add_action('admin_notices', array($this->c, 'a_notify_reset'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// only check these on plugin settings page
|
||
|
|
$this->c->a_check_dir_writable($this->c->get_plugin_dir().'cache/', array($this, 'a_notify_cache_not_writable'));
|
||
|
|
$this->c->a_check_orphan_options(array($this, 'a_notify_orphan_options'));
|
||
|
|
if ($this->c->a_check_dir_writable($this->c->get_plugin_dir().'min/config.php', array($this, 'a_notify_config_not_writable'))) {
|
||
|
|
$this->a_check_minify_config();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_check_minify_config() {
|
||
|
|
$fname = $this->c->get_plugin_dir().'min/config.php';
|
||
|
|
$fhandle = fopen($fname,'r');
|
||
|
|
$content = fread($fhandle,filesize($fname));
|
||
|
|
|
||
|
|
$config_modified = false;
|
||
|
|
|
||
|
|
preg_match('/\/\/###WPM-CACHE-PATH-BEFORE###(.*)\/\/###WPM-CACHE-PATH-AFTER###/s', $content, $matches);
|
||
|
|
$cache_path_code = $matches[1];
|
||
|
|
if (!preg_match('/\$min_cachePath.*?/', $cache_path_code)) {
|
||
|
|
$content = preg_replace(
|
||
|
|
'/\/\/###WPM-CACHE-PATH-BEFORE###(.*)\/\/###WPM-CACHE-PATH-AFTER###/s',
|
||
|
|
"//###WPM-CACHE-PATH-BEFORE###\n".'$min_cachePath = \''.$this->c->get_plugin_dir()."cache/';\n//###WPM-CACHE-PATH-AFTER###",
|
||
|
|
$content);
|
||
|
|
$config_modified = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
preg_match('/\/\/###WPM-CACHE-AGE-BEFORE###(.*)\/\/###WPM-CACHE-AGE-AFTER###/s', $content, $matches);
|
||
|
|
$cache_age_code = $matches[1];
|
||
|
|
if (!preg_match('/\$min_serveOptions\[\'maxAge\'].*?/', $cache_age_code)) {
|
||
|
|
$content = preg_replace(
|
||
|
|
'/\/\/###WPM-CACHE-AGE-BEFORE###(.*)\/\/###WPM-CACHE-AGE-AFTER###/s',
|
||
|
|
"//###WPM-CACHE-AGE-BEFORE###\n".'$min_serveOptions[\'maxAge\'] = 2592000;'."\n//###WPM-CACHE-AGE-AFTER###",
|
||
|
|
$content);
|
||
|
|
$config_modified = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($config_modified) {
|
||
|
|
$this->a_notify_modified_minify_config();
|
||
|
|
}
|
||
|
|
|
||
|
|
$fhandle = fopen($fname,"w");
|
||
|
|
fwrite($fhandle,$content);
|
||
|
|
fclose($fhandle);
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_set_minify_config($nominify = false, $firephp = false) {
|
||
|
|
if ($nominify) {
|
||
|
|
$nominify = 'true';
|
||
|
|
} else {
|
||
|
|
$nominify = 'false';
|
||
|
|
}
|
||
|
|
if ($firephp) {
|
||
|
|
$firephp = 'true';
|
||
|
|
} else {
|
||
|
|
$firephp = 'false';
|
||
|
|
}
|
||
|
|
$fname = $this->c->get_plugin_dir().'min/config.php';
|
||
|
|
$fhandle = fopen($fname,'r');
|
||
|
|
$content = fread($fhandle,filesize($fname));
|
||
|
|
|
||
|
|
$content = preg_replace(
|
||
|
|
'/\/\/###WPM-DEBUG-FLAG-BEFORE###(.*)\/\/###WPM-DEBUG-FLAG-AFTER###/s',
|
||
|
|
"//###WPM-DEBUG-FLAG-BEFORE###\n".'$min_allowDebugFlag = '.$nominify.";\n//###WPM-DEBUG-FLAG-AFTER###",
|
||
|
|
$content);
|
||
|
|
|
||
|
|
$content = preg_replace(
|
||
|
|
'/\/\/###WPM-ERROR-LOGGER-BEFORE###(.*)\/\/###WPM-ERROR-LOGGER-AFTER###/s',
|
||
|
|
"//###WPM-ERROR-LOGGER-BEFORE###\n".'$min_errorLogger = '.$firephp.";\n//###WPM-ERROR-LOGGER-AFTER###",
|
||
|
|
$content);
|
||
|
|
|
||
|
|
$fhandle = fopen($fname,"w");
|
||
|
|
fwrite($fhandle,$content);
|
||
|
|
fclose($fhandle);
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_notify_cache_not_writable() {
|
||
|
|
$this->c->a_notify(
|
||
|
|
sprintf('%s: %s',
|
||
|
|
__('Cache directory is not writable. Please grant your server write permissions to the directory', $this->name),
|
||
|
|
$this->c->get_plugin_dir().'cache/'),
|
||
|
|
true);
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_notify_config_not_writable() {
|
||
|
|
$this->c->a_notify(
|
||
|
|
sprintf('%s: %s',
|
||
|
|
__('Minify Engine config.php is not writable. Please grant your server write permissions to file', $this->name),
|
||
|
|
$this->c->get_plugin_dir().'min/config.php'));
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_notify_orphan_options() {
|
||
|
|
$this->c->a_notify(
|
||
|
|
sprintf('%s',
|
||
|
|
__('Some option settings are missing (possibly from plugin upgrade).', $this->name)));
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_notify_modified_minify_config() {
|
||
|
|
$this->c->a_notify(__('Minify Engine config.php was configured automatically.', $this->name));
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_menu() {
|
||
|
|
$options_page = add_options_page($this->name_proper, $this->name_proper, 'manage_options', 'wp-minify', array($this, 'a_page'));
|
||
|
|
add_action('admin_head-'.$options_page, array($this, 'a_request_handler'));
|
||
|
|
add_action('admin_print_scripts-'.$options_page, array($this->c, 'a_enqueue_scripts'));
|
||
|
|
add_action('admin_print_styles-'.$options_page, array($this->c, 'a_enqueue_styles'));
|
||
|
|
}
|
||
|
|
|
||
|
|
function a_page() {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
printf('
|
||
|
|
<div class="wrap omni_admin_content">
|
||
|
|
<h2>%s</h2>
|
||
|
|
<div>
|
||
|
|
<a href="'.preg_replace('/&wpm-page=[^&]*/', '', $_SERVER['REQUEST_URI']).'">%s</a> |
|
||
|
|
<a href="'.$this->homepage.'">%s</a>
|
||
|
|
</div>',
|
||
|
|
__('WP Minify Options', $this->name),
|
||
|
|
__('General Configuration', $this->name),
|
||
|
|
__('Documentation', $this->name)
|
||
|
|
);
|
||
|
|
printf('<div class="omni_admin_main">');
|
||
|
|
if (isset($_GET['wpm-page'])) {
|
||
|
|
if ($_GET['wpm-page'] || !$_GET['wpm-page']) {
|
||
|
|
require_once('options-generic.php');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
require_once('options-generic.php');
|
||
|
|
}
|
||
|
|
printf('</div>'); // omni_admin_main
|
||
|
|
require_once('options-sidebar.php');
|
||
|
|
printf('</div>'); // wrap
|
||
|
|
|
||
|
|
} // admin_page()
|
||
|
|
|
||
|
|
// other functions
|
||
|
|
|
||
|
|
function fetch_and_cache($url, $cache_file) {
|
||
|
|
$ch = curl_init();
|
||
|
|
$timeout = 5; // set to zero for no timeout
|
||
|
|
curl_setopt ($ch, CURLOPT_URL, $url);
|
||
|
|
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
|
||
|
|
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
|
||
|
|
curl_setopt ($ch, CURLOPT_USERAGENT, 'WP-Minify');
|
||
|
|
$content = curl_exec($ch);
|
||
|
|
curl_close($ch);
|
||
|
|
if ($content) {
|
||
|
|
if (is_array($content)) {
|
||
|
|
$content = implode($content);
|
||
|
|
}
|
||
|
|
|
||
|
|
// save cache file
|
||
|
|
$fh = fopen($cache_file, 'w');
|
||
|
|
if ($fh) {
|
||
|
|
fwrite($fh, $content);
|
||
|
|
fclose($fh);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
// cannot open for write. no error b/c something else is probably writing to the file.
|
||
|
|
}
|
||
|
|
|
||
|
|
return $content;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
printf(
|
||
|
|
'%s: '.$url.'. %s<br/>',
|
||
|
|
__('Error: Could not fetch and cache URL'),
|
||
|
|
__('You might need to exclude this file in WP Minify options.')
|
||
|
|
);
|
||
|
|
return '';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function refetch_cache_if_expired($url, $cache_file) {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
$cache_file_mtime = filemtime($cache_file);
|
||
|
|
if ((time() - $cache_file_mtime) > $wpm_options['cache_interval']) {
|
||
|
|
$this->fetch_and_cache($url, $cache_file);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function tiny_filename($str) {
|
||
|
|
$f = __FILE__;
|
||
|
|
// no fancy shortening for Windows
|
||
|
|
return ('/' === $f[0]) ? strtr(base64_encode(md5($str, true)), '+/=', '-_(') : md5($str);
|
||
|
|
}
|
||
|
|
|
||
|
|
function array_trim($arr, $charlist=null) {
|
||
|
|
foreach ($arr as $key => $value) {
|
||
|
|
if (is_array($value)) $result[$key] = array_trim($value, $charlist);
|
||
|
|
else $result[$key] = trim($value, $charlist);
|
||
|
|
}
|
||
|
|
return $result;
|
||
|
|
}
|
||
|
|
|
||
|
|
function check_and_split_url($url, $latest_modified = 0) {
|
||
|
|
$url_chunk = explode('?f=', $url);
|
||
|
|
$base_url = array_shift($url_chunk);
|
||
|
|
$files = explode(',', array_shift($url_chunk));
|
||
|
|
$num_files = sizeof($files);
|
||
|
|
|
||
|
|
if ($this->url_needs_splitting($url, $files)) {
|
||
|
|
$first_half = $this->check_and_split_url($base_url . '?f=' . implode(',', array_slice($files, 0, $num_files/2)), $latest_modified);
|
||
|
|
$second_half = $this->check_and_split_url($base_url . '?f=' . implode(',', array_slice($files, $num_files/2)), $latest_modified);
|
||
|
|
return $first_half + $second_half;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
|
||
|
|
// append &debug if we need to
|
||
|
|
if ($wpm_options['debug_nominify']) {
|
||
|
|
$debug_string = '&debug=true';
|
||
|
|
} else {
|
||
|
|
$debug_string = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
// append base directory if needed
|
||
|
|
$base = $this->get_base();
|
||
|
|
if ($base != '') {
|
||
|
|
$base_string = '&b='.$base;
|
||
|
|
} else {
|
||
|
|
$base_string = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
// get rid of any base directory specification in extra options
|
||
|
|
$extra_minify_options = preg_replace('/(&|&|\b)b=[^&]*/', '', trim($wpm_options['extra_minify_options']));
|
||
|
|
if (trim($extra_minify_options) != '') {
|
||
|
|
$extra_string = '&'.$extra_minify_options;
|
||
|
|
} else {
|
||
|
|
$extra_string = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
// append last modified time
|
||
|
|
$latest_modified_string = '&m='.$latest_modified;
|
||
|
|
|
||
|
|
return array($base_url . '?f=' . implode(',', $files) . $debug_string . $base_string . $extra_string . $latest_modified_string);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function fetch_content($url, $type = '') {
|
||
|
|
$cache_file = $this->c->get_plugin_dir().'cache/'.md5($url).$type;
|
||
|
|
$content = '';
|
||
|
|
if (file_exists($cache_file)) {
|
||
|
|
// check cache expiration
|
||
|
|
$this->refetch_cache_if_expired($url, $cache_file);
|
||
|
|
|
||
|
|
$fh = fopen($cache_file, 'r');
|
||
|
|
if ($fh && filesize($cache_file) > 0) {
|
||
|
|
$content = fread($fh, filesize($cache_file));
|
||
|
|
fclose($fh);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
// cannot open cache file so fetch it
|
||
|
|
$content = $this->fetch_and_cache($url, $cache_file);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
// no cache file. fetch from internet and save to local cache
|
||
|
|
$content = $this->fetch_and_cache($url, $cache_file);
|
||
|
|
}
|
||
|
|
return $content;
|
||
|
|
}
|
||
|
|
|
||
|
|
function local_version($url) {
|
||
|
|
$site_url = trailingslashit(get_option('siteurl'));
|
||
|
|
$url = str_replace($site_url, '', $url); // relative paths only for local urls
|
||
|
|
$url = preg_replace('/^\//', '', $url); // strip front / if any
|
||
|
|
$url = preg_replace('/\?.*/i', '', $url); // throws away parameters, if any
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
function is_external($url, $localize=true) {
|
||
|
|
if ($localize) {
|
||
|
|
$url = $this->local_version($url);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (substr($url, 0, 4) != 'http'
|
||
|
|
&& (substr($url, -3, 3) == '.js' || substr($url, -4, 4) == '.css')) {
|
||
|
|
return false;
|
||
|
|
} else {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function get_js_location($src) {
|
||
|
|
if ($this->debug)
|
||
|
|
echo 'Script URL:'.$src."<br/>\n";
|
||
|
|
|
||
|
|
$script_path = $this->local_version($src);
|
||
|
|
if ($this->is_external($script_path, false)) {
|
||
|
|
// fetch scripts if necessary
|
||
|
|
$this->fetch_content($src, '.js');
|
||
|
|
$location = $this->cache_location . md5($src) . '.js';
|
||
|
|
if ($this->debug)
|
||
|
|
echo 'External script detected, cached as:'. md5($src) . "<br/>\n";
|
||
|
|
} else {
|
||
|
|
// if script is local to server
|
||
|
|
$location = $script_path;
|
||
|
|
if ($this->debug)
|
||
|
|
echo 'Local script detected:'.$script_path."<br/>\n";
|
||
|
|
}
|
||
|
|
|
||
|
|
return $location;
|
||
|
|
}
|
||
|
|
|
||
|
|
function get_css_location($src) {
|
||
|
|
if ($this->debug)
|
||
|
|
echo 'Style URL:'.$src."<br/>\n";
|
||
|
|
|
||
|
|
$css_path = $this->local_version($src);
|
||
|
|
if ($this->is_external($css_path, false)) {
|
||
|
|
// fetch scripts if necessary
|
||
|
|
$this->fetch_content($src, '.css');
|
||
|
|
$location = $this->cache_location . md5($src) . '.css';
|
||
|
|
if ($this->debug)
|
||
|
|
echo 'External css detected, cached as:'. md5($src) . "<br/>\n";
|
||
|
|
} else {
|
||
|
|
$location = $css_path;
|
||
|
|
// if css is local to server
|
||
|
|
if ($this->debug)
|
||
|
|
echo 'Local css detected:'.$css_path."<br/>\n";
|
||
|
|
}
|
||
|
|
|
||
|
|
return $location;
|
||
|
|
}
|
||
|
|
|
||
|
|
function url_needs_splitting($url, $locations) {
|
||
|
|
if ($url > $this->url_len_limit || count($locations) > $this->minify_limit) {
|
||
|
|
return true;
|
||
|
|
} else {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function build_minify_urls($locations, $type) {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
$minify_url = $this->c->get_plugin_url().'min/?f=';
|
||
|
|
if ($wpm_options['force_https'] && $_SERVER["HTTPS"] == "on") {
|
||
|
|
$minify_url = preg_replace('/^http:\/\//', 'https://', $minify_url);
|
||
|
|
}
|
||
|
|
$minify_url .= implode(',', $locations);
|
||
|
|
$latest_modified = $this->get_latest_modified_time($locations);
|
||
|
|
$minify_urls = $this->check_and_split_url($minify_url, $latest_modified);
|
||
|
|
|
||
|
|
if ($wpm_options['pretty_url']) {
|
||
|
|
return $this->get_cached_minify_urls($minify_urls, $type);
|
||
|
|
} else {
|
||
|
|
return $minify_urls;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function get_cached_minify_urls($urls, $type) {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
$cached_urls = array();
|
||
|
|
foreach ($urls as $url) {
|
||
|
|
$cache_file = $this->c->get_plugin_dir().'cache/'.md5($url).$type;
|
||
|
|
if (file_exists($cache_file)) {
|
||
|
|
// check cache expiration
|
||
|
|
$this->refetch_cache_if_expired($url, $cache_file);
|
||
|
|
|
||
|
|
$fh = fopen($cache_file, 'r');
|
||
|
|
if ($fh && filesize($cache_file) > 0) {
|
||
|
|
$content = fread($fh, filesize($cache_file));
|
||
|
|
fclose($fh);
|
||
|
|
} else {
|
||
|
|
// cannot open cache file so fetch it
|
||
|
|
$this->fetch_and_cache($url, $cache_file);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
// no cache file. fetch it
|
||
|
|
$this->fetch_and_cache($url, $cache_file);
|
||
|
|
}
|
||
|
|
$cache_url = $this->c->get_plugin_url().'cache/'.md5($url).$type.'?m='.filemtime($cache_file);
|
||
|
|
$cached_urls[] = $cache_url;
|
||
|
|
}
|
||
|
|
return $cached_urls;
|
||
|
|
}
|
||
|
|
|
||
|
|
function get_base_from_minify_args() {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
if (!empty($wpm_options['extra_minify_options'])) {
|
||
|
|
if (preg_match('/\bb=([^&]*?)(&|$)/', trim($wpm_options['extra_minify_options']), $matches)) {
|
||
|
|
return rtrim(trim($matches[1]), '\\/');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return '';
|
||
|
|
}
|
||
|
|
|
||
|
|
function get_base_from_siteurl() {
|
||
|
|
$site_url = trailingslashit(get_option('siteurl'));
|
||
|
|
return rtrim(preg_replace('/^https?:\/\/.*?\//', '', $site_url), '\\/');
|
||
|
|
}
|
||
|
|
|
||
|
|
function get_base() {
|
||
|
|
$base_from_min_args = $this->get_base_from_minify_args();
|
||
|
|
if ($base_from_min_args != '') {
|
||
|
|
return $base_from_min_args;
|
||
|
|
}
|
||
|
|
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
if ($wpm_options['auto_base']) {
|
||
|
|
return $this->get_base_from_siteurl();
|
||
|
|
} else {
|
||
|
|
return '';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function get_latest_modified_time($locations = array()) {
|
||
|
|
$latest_modified = 0;
|
||
|
|
if (!empty($locations)) {
|
||
|
|
$base_path = trailingslashit($_SERVER['DOCUMENT_ROOT']);
|
||
|
|
$base_path .= trailingslashit($this->get_base());
|
||
|
|
|
||
|
|
foreach ($locations as $location) {
|
||
|
|
$path = $base_path.$location;
|
||
|
|
$mtime = filemtime($path);
|
||
|
|
if ($latest_modified < $mtime) {
|
||
|
|
$latest_modified = $mtime;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return $latest_modified;
|
||
|
|
}
|
||
|
|
|
||
|
|
function extract_css($content) {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
$css_locations = array();
|
||
|
|
|
||
|
|
preg_match_all('/<link([^>]*?)>/i', $content, $link_tags_match);
|
||
|
|
|
||
|
|
foreach ($link_tags_match[0] as $link_tag) {
|
||
|
|
if (strpos(strtolower($link_tag), 'stylesheet')) {
|
||
|
|
// check CSS media type
|
||
|
|
if (!strpos(strtolower($link_tag), 'media=')
|
||
|
|
|| preg_match('/media=["\'](?:["\']|[^"\']*?(all|screen)[^"\']*?["\'])/', $link_tag)
|
||
|
|
) {
|
||
|
|
preg_match('/href=[\'"]([^\'"]+)/', $link_tag, $href_match);
|
||
|
|
if ($href_match[1]) {
|
||
|
|
// include it if it is in the include list
|
||
|
|
$include = false;
|
||
|
|
$inclusions = $wpm_options['css_include'];
|
||
|
|
foreach ($inclusions as $include_pat) {
|
||
|
|
$include_pat = trim($include_pat);
|
||
|
|
if (strlen($include_pat) > 0 && strpos($src_match[1], $include_pat) !== false) {
|
||
|
|
$include = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!$include) {
|
||
|
|
// support external files?
|
||
|
|
if (!$wpm_options['cache_external'] && $this->is_external($href_match[1])) {
|
||
|
|
continue; // skip if we don't cache externals and this file is external
|
||
|
|
}
|
||
|
|
|
||
|
|
// do not include anything in excluded list
|
||
|
|
$skip = false;
|
||
|
|
$exclusions = array_merge($this->default_exclude, $wpm_options['css_exclude']);
|
||
|
|
foreach ($exclusions as $exclude_pat) {
|
||
|
|
$exclude_pat = trim($exclude_pat);
|
||
|
|
if (strlen($exclude_pat) > 0 && strpos($href_match[1], $exclude_pat) !== false) {
|
||
|
|
$skip = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if ($skip) continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$content = str_replace($link_tag . '</link>', '', $content);
|
||
|
|
$content = str_replace($link_tag, '', $content);
|
||
|
|
$css_locations[] = $this->get_css_location($href_match[1]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$css_locations = array_unique($css_locations);
|
||
|
|
|
||
|
|
return array($content, $css_locations);
|
||
|
|
}
|
||
|
|
|
||
|
|
function inject_css($content, $css_locations) {
|
||
|
|
if (count($css_locations) > 0) {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
// build minify URLS
|
||
|
|
$css_tags = '';
|
||
|
|
$minify_urls = $this->build_minify_urls($css_locations, '.css');
|
||
|
|
|
||
|
|
foreach ($minify_urls as $minify_url) {
|
||
|
|
$minify_url = apply_filters('wp_minify_css_url', $minify_url); // Allow plugins to modify final minify URL
|
||
|
|
$css_tags .= "<link rel='stylesheet' href='$minify_url' type='text/css' media='screen' />";
|
||
|
|
}
|
||
|
|
|
||
|
|
$matches = preg_match('/<!-- WP-Minify CSS -->/', $content);
|
||
|
|
|
||
|
|
if ($matches) {
|
||
|
|
$content = preg_replace('/<!-- WP-Minify CSS -->/', "$css_tags", $content, 1); // limit 1 replacement
|
||
|
|
} else {
|
||
|
|
// HTML5 has <header> tags so account for those in regex
|
||
|
|
$content = preg_replace('/<head(>|\s[^>]*?>)/', "\\0\n$css_tags", $content, 1); // limit 1 replacement
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return $content;
|
||
|
|
}
|
||
|
|
|
||
|
|
function extract_conditionals($content) {
|
||
|
|
preg_match_all('/<!--\[if[^\]]*?\]>.*?<!\[endif\]-->/is', $content, $conditionals_match);
|
||
|
|
$content = preg_replace('/<!--\[if[^\]]*?\]>.*?<!\[endif\]-->/is', '###WPM-CSS-CONDITIONAL###', $content);
|
||
|
|
|
||
|
|
$conditionals = array();
|
||
|
|
foreach ($conditionals_match[0] as $conditional) {
|
||
|
|
$conditionals[] = $conditional;
|
||
|
|
}
|
||
|
|
|
||
|
|
return array($content, $conditionals);
|
||
|
|
}
|
||
|
|
|
||
|
|
function inject_conditionals($content, $conditionals) {
|
||
|
|
while (count($conditionals) > 0 && strpos($content, '###WPM-CSS-CONDITIONAL###')) {
|
||
|
|
$conditional = array_shift($conditionals);
|
||
|
|
$content = preg_replace('/###WPM-CSS-CONDITIONAL###/', $conditional, $content, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $content;
|
||
|
|
}
|
||
|
|
|
||
|
|
function extract_js($content) {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
$js_locations = array();
|
||
|
|
|
||
|
|
preg_match_all('/<script([^>]*?)><\/script>/i', $content, $script_tags_match);
|
||
|
|
|
||
|
|
foreach ($script_tags_match[0] as $script_tag) {
|
||
|
|
if (strpos(strtolower($script_tag), 'text/javascript') !== false) {
|
||
|
|
preg_match('/src=[\'"]([^\'"]+)/', $script_tag, $src_match);
|
||
|
|
if ($src_match[1]) {
|
||
|
|
// include it if it is in the include list
|
||
|
|
$include = false;
|
||
|
|
$inclusions = $wpm_options['js_include'];
|
||
|
|
foreach ($inclusions as $include_pat) {
|
||
|
|
$include_pat = trim($include_pat);
|
||
|
|
if (strlen($include_pat) > 0 && strpos($src_match[1], $include_pat) !== false) {
|
||
|
|
$include = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!$include) {
|
||
|
|
// support external files?
|
||
|
|
if (!$wpm_options['cache_external'] && $this->is_external($src_match[1])) {
|
||
|
|
continue; // skip if we don't cache externals and this file is external
|
||
|
|
}
|
||
|
|
|
||
|
|
// do not include anything in excluded list
|
||
|
|
$skip = false;
|
||
|
|
$exclusions = array_merge($this->default_exclude, $wpm_options['js_exclude']);
|
||
|
|
foreach ($exclusions as $exclude_pat) {
|
||
|
|
$exclude_pat = trim($exclude_pat);
|
||
|
|
if (strlen($exclude_pat) > 0 && strpos($src_match[1], $exclude_pat) !== false) {
|
||
|
|
$skip = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if ($skip) continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$content = str_replace($script_tag, '', $content);
|
||
|
|
$js_locations[] = $this->get_js_location($src_match[1]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$js_locations = array_unique($js_locations);
|
||
|
|
|
||
|
|
return array($content, $js_locations);
|
||
|
|
}
|
||
|
|
|
||
|
|
function inject_js($content, $js_locations) {
|
||
|
|
if (count($js_locations) > 0) {
|
||
|
|
// build minify URLS
|
||
|
|
$js_tags = '';
|
||
|
|
$minify_urls = $this->build_minify_urls($js_locations, '.js');
|
||
|
|
|
||
|
|
foreach ($minify_urls as $minify_url) {
|
||
|
|
$minify_url = apply_filters('wp_minify_js_url', $minify_url); // Allow plugins to modify final minify URL
|
||
|
|
$js_tags .= "<script type='text/javascript' src='$minify_url'></script>";
|
||
|
|
}
|
||
|
|
|
||
|
|
$matches = preg_match('/<!-- WP-Minify JS -->/', $content);
|
||
|
|
|
||
|
|
if ($matches) {
|
||
|
|
$content = preg_replace('/<!-- WP-Minify JS -->/', "$js_tags", $content, 1); // limit 1 replacement
|
||
|
|
} else {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
if ($wpm_options['js_in_footer']) {
|
||
|
|
$content = preg_replace('/<\/body>/', "$js_tags\n</body>", $content, 1); // limit 1 replacement
|
||
|
|
} else {
|
||
|
|
// HTML5 has <header> tags so account for those in regex
|
||
|
|
$content = preg_replace('/<head(>|\s[^>]*?>)/', "\\0\n$js_tags", $content, 1); // limit 1 replacement
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return $content;
|
||
|
|
}
|
||
|
|
|
||
|
|
function pre_content() {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
if ($wpm_options['uri_exclude'] && count($wpm_options['uri_exclude'])) {
|
||
|
|
foreach ($wpm_options['uri_exclude'] as $exclude_pat) {
|
||
|
|
$exclude_pat = trim($exclude_pat);
|
||
|
|
if (strlen($exclude_pat) > 0 && strpos($_SERVER['REQUEST_URI'], $exclude_pat) !== false) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ob_start(array($this, 'modify_buffer'));
|
||
|
|
|
||
|
|
// variable for sanity checking
|
||
|
|
$this->buffer_started = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
function modify_buffer($buffer) {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
|
||
|
|
// if we do not want to force http to https then we need to exclude https
|
||
|
|
if (!($wpm_options['force_https'] && $_SERVER["HTTPS"] == "on")) {
|
||
|
|
$this->default_exclude[] = 'https://';
|
||
|
|
}
|
||
|
|
|
||
|
|
// minify JS
|
||
|
|
if ($wpm_options['enable_js']) {
|
||
|
|
list($buffer, $js_locations) = $this->extract_js($buffer);
|
||
|
|
$buffer= $this->inject_js($buffer, $js_locations);
|
||
|
|
}
|
||
|
|
|
||
|
|
// minify CSS (make sure to exclude CSS conditionals)
|
||
|
|
if ($wpm_options['enable_css']) {
|
||
|
|
list($buffer, $conditionals) = $this->extract_conditionals($buffer);
|
||
|
|
list($buffer, $css_locations) = $this->extract_css($buffer);
|
||
|
|
$buffer = $this->inject_css($buffer, $css_locations);
|
||
|
|
$buffer = $this->inject_conditionals($buffer, $conditionals);
|
||
|
|
}
|
||
|
|
|
||
|
|
// get rid of empty lines
|
||
|
|
$buffer = preg_replace('/\s*(\r?\n)(\r?\n)*/', '$1', $buffer);
|
||
|
|
|
||
|
|
// minify HTML
|
||
|
|
if ($wpm_options['enable_html']) {
|
||
|
|
if (!class_exists('Minify_HTML')) {
|
||
|
|
require_once('min/lib/Minify/HTML.php');
|
||
|
|
}
|
||
|
|
$buffer = Minify_HTML::minify($buffer);
|
||
|
|
}
|
||
|
|
|
||
|
|
$buffer = apply_filters('wp_minify_content', $buffer); // allow plugins to modify buffer
|
||
|
|
|
||
|
|
return $buffer;
|
||
|
|
}
|
||
|
|
|
||
|
|
function post_content() {
|
||
|
|
// sanity checking
|
||
|
|
if ($this->buffer_started) {
|
||
|
|
ob_end_flush();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function advertise() {
|
||
|
|
$wpm_options = get_option($this->name);
|
||
|
|
if ($wpm_options['show_link']) {
|
||
|
|
printf("<p align='center'><small>Page optimized by <a href='$this->homepage' title='$this->name_proper WordPress Plugin' style='text-decoration:none;'>$this->name_proper</a> <a href='$this->author_homepage' title='WordPress Plugin' style='text-decoration:none;'>WordPress Plugin</a></small></p>");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
} // class WPMinify
|
||
|
|
|
||
|
|
require_once('common.php');
|
||
|
|
require_once('http_build_url.php');
|
||
|
|
$wp_minify = new WPMinify();
|
||
|
|
?>
|